summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS6
-rw-r--r--ObsoleteFiles.inc17
-rw-r--r--bin/kill/kill.c2
-rw-r--r--bin/pkill/pkill.17
-rw-r--r--bin/pkill/pkill.c7
-rw-r--r--bin/sh/parser.c2
-rw-r--r--cddl/Makefile.inc1
-rw-r--r--cddl/lib/drti/Makefile5
-rw-r--r--cddl/lib/libavl/Makefile1
-rw-r--r--cddl/lib/libctf/Makefile11
-rw-r--r--cddl/lib/libdtrace/Makefile10
-rw-r--r--cddl/lib/libnvpair/Makefile1
-rw-r--r--cddl/lib/libumem/Makefile1
-rw-r--r--cddl/lib/libuutil/Makefile1
-rw-r--r--cddl/lib/libzfs/Makefile1
-rw-r--r--cddl/lib/libzpool/Makefile1
-rw-r--r--cddl/sbin/zfs/Makefile1
-rw-r--r--cddl/sbin/zpool/Makefile1
-rw-r--r--cddl/usr.bin/ctfconvert/Makefile18
-rw-r--r--cddl/usr.bin/ctfdump/Makefile17
-rw-r--r--cddl/usr.bin/ctfmerge/Makefile19
-rw-r--r--cddl/usr.bin/sgsmsg/Makefile11
-rw-r--r--cddl/usr.bin/zinject/Makefile3
-rw-r--r--cddl/usr.bin/ztest/Makefile1
-rw-r--r--cddl/usr.sbin/dtrace/Makefile21
-rw-r--r--cddl/usr.sbin/lockstat/Makefile24
-rw-r--r--cddl/usr.sbin/zdb/Makefile4
-rw-r--r--contrib/bc/AUTHORS4
-rw-r--r--contrib/bc/ChangeLog1043
-rw-r--r--contrib/bc/Examples/ckbook.b16
-rw-r--r--contrib/bc/Examples/pi.b53
-rw-r--r--contrib/bc/Examples/primes.b32
-rw-r--r--contrib/bc/Examples/twins.b40
-rw-r--r--contrib/bc/FAQ17
-rw-r--r--contrib/bc/FREEBSD-upgrade14
-rw-r--r--contrib/bc/INSTALL176
-rw-r--r--contrib/bc/Makefile.am18
-rw-r--r--contrib/bc/Makefile.in368
-rw-r--r--contrib/bc/NEWS68
-rw-r--r--contrib/bc/README86
-rw-r--r--contrib/bc/Test/BUG.bc40
-rw-r--r--contrib/bc/Test/array.b14
-rw-r--r--contrib/bc/Test/arrayp.b30
-rw-r--r--contrib/bc/Test/aryprm.b16
-rw-r--r--contrib/bc/Test/atan.b5
-rw-r--r--contrib/bc/Test/checklib.b109
-rw-r--r--contrib/bc/Test/div.b8
-rw-r--r--contrib/bc/Test/exp.b3
-rw-r--r--contrib/bc/Test/fact.b12
-rw-r--r--contrib/bc/Test/jn.b6
-rw-r--r--contrib/bc/Test/ln.b4
-rw-r--r--contrib/bc/Test/mul.b13
-rw-r--r--contrib/bc/Test/raise.b7
-rw-r--r--contrib/bc/Test/signum87
-rw-r--r--contrib/bc/Test/sine.b5
-rw-r--r--contrib/bc/Test/sqrt.b13
-rw-r--r--contrib/bc/Test/sqrt1.b13
-rw-r--r--contrib/bc/Test/sqrt2.b10
-rw-r--r--contrib/bc/Test/testfn.b47
-rwxr-xr-xcontrib/bc/Test/timetest16
-rw-r--r--contrib/bc/acconfig.h24
-rw-r--r--contrib/bc/aclocal.m4136
-rw-r--r--contrib/bc/bc/Makefile.am42
-rw-r--r--contrib/bc/bc/Makefile.in345
-rw-r--r--contrib/bc/bc/bc.y654
-rw-r--r--contrib/bc/bc/bcdefs.h188
-rw-r--r--contrib/bc/bc/const.h98
-rw-r--r--contrib/bc/bc/execute.c788
-rwxr-xr-xcontrib/bc/bc/fix-libmath_h9
-rw-r--r--contrib/bc/bc/global.c42
-rw-r--r--contrib/bc/bc/global.h154
-rw-r--r--contrib/bc/bc/libmath.b287
-rw-r--r--contrib/bc/bc/libmath.h40
-rw-r--r--contrib/bc/bc/load.c351
-rw-r--r--contrib/bc/bc/main.c358
-rw-r--r--contrib/bc/bc/proto.h148
-rw-r--r--contrib/bc/bc/sbc.y448
-rw-r--r--contrib/bc/bc/scan.l374
-rw-r--r--contrib/bc/bc/storage.c1067
-rw-r--r--contrib/bc/bc/util.c873
-rw-r--r--contrib/bc/config.h.in81
-rwxr-xr-xcontrib/bc/configure2656
-rw-r--r--contrib/bc/configure.in89
-rw-r--r--contrib/bc/dc/Makefile.am14
-rw-r--r--contrib/bc/dc/Makefile.in296
-rw-r--r--contrib/bc/dc/array.c122
-rw-r--r--contrib/bc/dc/dc-proto.h90
-rw-r--r--contrib/bc/dc/dc-regdef.h43
-rw-r--r--contrib/bc/dc/dc.c183
-rw-r--r--contrib/bc/dc/dc.h82
-rw-r--r--contrib/bc/dc/eval.c682
-rw-r--r--contrib/bc/dc/misc.c179
-rw-r--r--contrib/bc/dc/numeric.c600
-rw-r--r--contrib/bc/dc/stack.c494
-rw-r--r--contrib/bc/dc/string.c211
-rw-r--r--contrib/bc/doc/Makefile.am12
-rw-r--r--contrib/bc/doc/Makefile.in355
-rw-r--r--contrib/bc/doc/bc.1793
-rw-r--r--contrib/bc/doc/bc.texi1014
-rw-r--r--contrib/bc/doc/dc.1490
-rw-r--r--contrib/bc/doc/dc.texi526
-rw-r--r--contrib/bc/h/number.h153
-rwxr-xr-xcontrib/bc/install-sh238
-rw-r--r--contrib/bc/lib/Makefile.am26
-rw-r--r--contrib/bc/lib/Makefile.in283
-rw-r--r--contrib/bc/lib/number.c1793
-rw-r--r--contrib/bc/lib/testmul.c244
-rw-r--r--contrib/bc/lib/vfprintf.c31
-rwxr-xr-xcontrib/bc/missing134
-rwxr-xr-xcontrib/bc/mkinstalldirs36
-rw-r--r--contrib/bc/stamp-h.in1
-rw-r--r--contrib/csup/GNUmakefile64
-rw-r--r--contrib/csup/Makefile48
-rw-r--r--contrib/dtc/Documentation/dtc-paper.bib43
-rw-r--r--contrib/dtc/Documentation/dtc-paper.tex597
-rw-r--r--contrib/dtc/Documentation/dts-format.txt110
-rw-r--r--contrib/dtc/Documentation/manual.txt652
-rw-r--r--contrib/dtc/GPL340
-rw-r--r--contrib/dtc/Makefile245
-rw-r--r--contrib/dtc/Makefile.convert-dtsv013
-rw-r--r--contrib/dtc/Makefile.ftdump12
-rw-r--r--contrib/dtc/README.license56
-rw-r--r--contrib/dtc/TODO8
-rw-r--r--contrib/dtc/checks.c611
-rw-r--r--contrib/dtc/convert-dtsv0-lexer.l238
-rw-r--r--contrib/dtc/data.c321
-rw-r--r--contrib/dtc/dtc-lexer.l266
-rw-r--r--contrib/dtc/dtc-parser.y321
-rw-r--r--contrib/dtc/dtc.c247
-rw-r--r--contrib/dtc/dtc.h231
-rw-r--r--contrib/dtc/flattree.c927
-rw-r--r--contrib/dtc/fstree.c92
-rw-r--r--contrib/dtc/ftdump.c208
-rw-r--r--contrib/dtc/libfdt/Makefile.libfdt9
-rw-r--r--contrib/dtc/libfdt/TODO3
-rw-r--r--contrib/dtc/libfdt/fdt.c213
-rw-r--r--contrib/dtc/libfdt/fdt.h60
-rw-r--r--contrib/dtc/libfdt/fdt_ro.c523
-rw-r--r--contrib/dtc/libfdt/fdt_rw.c465
-rw-r--r--contrib/dtc/libfdt/fdt_strerror.c96
-rw-r--r--contrib/dtc/libfdt/fdt_sw.c256
-rw-r--r--contrib/dtc/libfdt/fdt_wip.c118
-rw-r--r--contrib/dtc/libfdt/libfdt.h1132
-rw-r--r--contrib/dtc/libfdt/libfdt_env.h23
-rw-r--r--contrib/dtc/libfdt/libfdt_internal.h94
-rw-r--r--contrib/dtc/libfdt/version.lds54
-rw-r--r--contrib/dtc/livetree.c320
-rwxr-xr-xcontrib/dtc/scripts/setlocalversion22
-rw-r--r--contrib/dtc/srcpos.c240
-rw-r--r--contrib/dtc/srcpos.h104
-rw-r--r--contrib/dtc/treesource.c279
-rw-r--r--contrib/dtc/util.c30
-rw-r--r--contrib/dtc/util.h55
-rw-r--r--contrib/gcc/config/mips/freebsd.h87
-rw-r--r--contrib/gdb/gdb/config/mips/nm-fbsd.h48
-rw-r--r--contrib/gdb/gdb/config/mips/tm-fbsd.h43
-rw-r--r--contrib/gdb/gdb/mips-tdep.h11
-rw-r--r--contrib/gdb/gdb/mipsfbsd-nat.c108
-rw-r--r--contrib/gdb/gdb/mipsfbsd-tdep.c579
-rw-r--r--contrib/gdb/gdb/mipsfbsd-tdep.h40
-rw-r--r--contrib/tzcode/stdtime/asctime.c (renamed from lib/libc/stdtime/asctime.c)0
-rw-r--r--contrib/tzcode/stdtime/ctime.3 (renamed from lib/libc/stdtime/ctime.3)0
-rw-r--r--contrib/tzcode/stdtime/difftime.c (renamed from lib/libc/stdtime/difftime.c)0
-rw-r--r--contrib/tzcode/stdtime/localtime.c (renamed from lib/libc/stdtime/localtime.c)0
-rw-r--r--contrib/tzcode/stdtime/private.h (renamed from lib/libc/stdtime/private.h)0
-rw-r--r--contrib/tzcode/stdtime/time2posix.3 (renamed from lib/libc/stdtime/time2posix.3)0
-rw-r--r--contrib/tzcode/stdtime/tzfile.5 (renamed from lib/libc/stdtime/tzfile.5)0
-rw-r--r--contrib/tzcode/stdtime/tzfile.h (renamed from lib/libc/stdtime/tzfile.h)0
-rw-r--r--contrib/tzcode/zic/README88
-rw-r--r--contrib/tzcode/zic/Theory (renamed from usr.sbin/zic/Theory)0
-rw-r--r--contrib/tzcode/zic/ialloc.c (renamed from usr.sbin/zic/ialloc.c)0
-rw-r--r--contrib/tzcode/zic/private.h (renamed from usr.sbin/zic/private.h)0
-rw-r--r--contrib/tzcode/zic/scheck.c (renamed from usr.sbin/zic/scheck.c)0
-rw-r--r--contrib/tzcode/zic/zdump.8 (renamed from usr.sbin/zic/zdump.8)0
-rw-r--r--contrib/tzcode/zic/zdump.c (renamed from usr.sbin/zic/zdump.c)0
-rw-r--r--contrib/tzcode/zic/zdump/Makefile15
-rw-r--r--contrib/tzcode/zic/zic.8 (renamed from usr.sbin/zic/zic.8)0
-rw-r--r--contrib/tzcode/zic/zic.c (renamed from usr.sbin/zic/zic.c)0
-rw-r--r--contrib/tzcode/zic/zic/Makefile16
-rw-r--r--contrib/tzdata/africa (renamed from share/zoneinfo/africa)0
-rw-r--r--contrib/tzdata/antarctica (renamed from share/zoneinfo/antarctica)0
-rw-r--r--contrib/tzdata/asia (renamed from share/zoneinfo/asia)0
-rw-r--r--contrib/tzdata/australasia (renamed from share/zoneinfo/australasia)0
-rw-r--r--contrib/tzdata/backward (renamed from share/zoneinfo/backward)0
-rw-r--r--contrib/tzdata/etcetera (renamed from share/zoneinfo/etcetera)0
-rw-r--r--contrib/tzdata/europe (renamed from share/zoneinfo/europe)0
-rw-r--r--contrib/tzdata/factory (renamed from share/zoneinfo/factory)0
-rw-r--r--contrib/tzdata/leapseconds (renamed from share/zoneinfo/leapseconds)0
-rw-r--r--contrib/tzdata/northamerica (renamed from share/zoneinfo/northamerica)0
-rw-r--r--contrib/tzdata/pacificnew (renamed from share/zoneinfo/pacificnew)0
-rw-r--r--contrib/tzdata/southamerica (renamed from share/zoneinfo/southamerica)22
-rw-r--r--contrib/tzdata/systemv (renamed from share/zoneinfo/systemv)0
-rwxr-xr-xcontrib/tzdata/yearistype.sh (renamed from share/zoneinfo/yearistype.sh)0
-rw-r--r--contrib/tzdata/zone.tab (renamed from share/zoneinfo/zone.tab)0
-rw-r--r--etc/defaults/rc.conf3
-rw-r--r--etc/mtree/BSD.usr.dist4
-rwxr-xr-xetc/rc.d/Makefile2
-rw-r--r--etc/rc.d/hastd28
-rwxr-xr-xetc/rc.d/rtsold2
-rw-r--r--games/fortune/datfiles/fortunes16
-rw-r--r--games/fortune/fortune/fortune.c2
-rw-r--r--gnu/usr.bin/Makefile5
-rw-r--r--gnu/usr.bin/bc/Makefile21
-rw-r--r--gnu/usr.bin/bc/config.h84
-rw-r--r--gnu/usr.bin/binutils/ld/Makefile.mips3
-rwxr-xr-xgnu/usr.bin/binutils/ld/elf32btsmipn32_fbsd.sh4
-rwxr-xr-xgnu/usr.bin/binutils/ld/elf32ltsmipn32_fbsd.sh4
-rwxr-xr-xgnu/usr.bin/binutils/ld/genscripts.sh1
-rw-r--r--gnu/usr.bin/dc/Makefile15
-rw-r--r--gnu/usr.bin/dc/doc/Makefile11
-rw-r--r--gnu/usr.bin/diff/Makefile2
-rw-r--r--gnu/usr.bin/diff3/Makefile2
-rw-r--r--gnu/usr.bin/dtc/Makefile51
-rw-r--r--gnu/usr.bin/gdb/arch/mips/Makefile4
-rw-r--r--gnu/usr.bin/gdb/arch/mips/init.c4
-rw-r--r--gnu/usr.bin/gdb/gdbserver/Makefile2
-rw-r--r--gnu/usr.bin/gdb/gdbserver/fbsd-amd64-low.c213
-rw-r--r--gnu/usr.bin/gdb/gdbserver/reg-x86-64.c99
-rw-r--r--gnu/usr.bin/gdb/kgdb/trgt_mips.c23
-rw-r--r--gnu/usr.bin/sdiff/Makefile2
-rw-r--r--lib/libalias/Makefile.inc3
-rw-r--r--lib/libalias/libalias/Makefile1
-rw-r--r--lib/libarchive/archive_write_disk.34
-rw-r--r--lib/libarchive/test/Makefile1
-rw-r--r--lib/libbsnmp/Makefile.inc4
-rw-r--r--lib/libbsnmp/libbsnmp/Makefile5
-rw-r--r--lib/libc/gen/fmtcheck.37
-rw-r--r--lib/libc/gen/pause.c8
-rw-r--r--lib/libc/gen/stringlist.37
-rw-r--r--lib/libc/gen/sysconf.c2
-rw-r--r--lib/libc/gen/sysctl.36
-rw-r--r--lib/libc/gen/sysctl.c11
-rw-r--r--lib/libc/gen/sysctlbyname.c18
-rw-r--r--lib/libc/gen/sysctlnametomib.c6
-rw-r--r--lib/libc/include/reentrant.h7
-rw-r--r--lib/libc/nls/msgcat.c55
-rw-r--r--lib/libc/stdio/mktemp.c4
-rw-r--r--lib/libc/stdlib/malloc.c30
-rw-r--r--lib/libc/stdlib/rb.h1579
-rw-r--r--lib/libc/stdtime/Makefile.inc5
-rw-r--r--lib/libc/sys/mlockall.27
-rw-r--r--lib/libc/sys/ntp_adjtime.27
-rw-r--r--lib/libc/sys/utrace.27
-rw-r--r--lib/libdwarf/Makefile4
-rw-r--r--lib/libedit/editline.33
-rw-r--r--lib/libedit/editrc.53
-rw-r--r--lib/libedit/read.h3
-rw-r--r--lib/libkvm/Makefile1
-rw-r--r--lib/libkvm/kvm.c23
-rw-r--r--lib/libkvm/kvm.h1
-rw-r--r--lib/libkvm/kvm_getpcpu.337
-rw-r--r--lib/libkvm/kvm_pcpu.c140
-rw-r--r--lib/libkvm/kvm_private.h15
-rw-r--r--lib/libkvm/kvm_vnet.c4
-rw-r--r--lib/libpam/Makefile.inc2
-rw-r--r--lib/libpam/modules/Makefile.inc1
-rw-r--r--lib/libpam/modules/pam_krb5/Makefile2
-rw-r--r--lib/libproc/Makefile4
-rw-r--r--lib/librt/Makefile3
-rw-r--r--lib/libutil/humanize_number.37
-rw-r--r--libexec/rpc.rstatd/Makefile4
-rw-r--r--libexec/rtld-elf/powerpc/reloc.c85
-rw-r--r--libexec/rtld-elf/powerpc/rtld_machdep.h1
-rw-r--r--libexec/rtld-elf/powerpc/rtld_start.S6
-rw-r--r--libexec/ulog-helper/Makefile4
-rw-r--r--sbin/Makefile2
-rw-r--r--sbin/atacontrol/atacontrol.c1
-rw-r--r--sbin/camcontrol/camcontrol.c2
-rw-r--r--sbin/ddb/Makefile2
-rw-r--r--sbin/devfs/devfs.89
-rw-r--r--sbin/geom/class/part/Makefile1
-rw-r--r--sbin/ggate/ggatec/ggatec.c2
-rw-r--r--sbin/ggate/ggated/ggated.c2
-rw-r--r--sbin/ggate/ggatel/ggatel.c2
-rw-r--r--sbin/ggate/shared/ggate.c8
-rw-r--r--sbin/hastctl/Makefile35
-rw-r--r--sbin/hastctl/hastctl.8217
-rw-r--r--sbin/hastctl/hastctl.c526
-rw-r--r--sbin/hastd/Makefile37
-rw-r--r--sbin/hastd/activemap.c691
-rw-r--r--sbin/hastd/activemap.h69
-rw-r--r--sbin/hastd/control.c426
-rw-r--r--sbin/hastd/control.h44
-rw-r--r--sbin/hastd/ebuf.c252
-rw-r--r--sbin/hastd/ebuf.h (renamed from sys/amd64/isa/icu.h)40
-rw-r--r--sbin/hastd/hast.conf.5267
-rw-r--r--sbin/hastd/hast.h190
-rw-r--r--sbin/hastd/hast_proto.c401
-rw-r--r--sbin/hastd/hast_proto.h48
-rw-r--r--sbin/hastd/hastd.8232
-rw-r--r--sbin/hastd/hastd.c522
-rw-r--r--sbin/hastd/hastd.h48
-rw-r--r--sbin/hastd/hooks.c148
-rw-r--r--sbin/hastd/hooks.h40
-rw-r--r--sbin/hastd/metadata.c222
-rw-r--r--sbin/hastd/metadata.h (renamed from sys/ia64/include/sapicreg.h)36
-rw-r--r--sbin/hastd/nv.c882
-rw-r--r--sbin/hastd/nv.h158
-rw-r--r--sbin/hastd/parse.y507
-rw-r--r--sbin/hastd/pjdlog.c367
-rw-r--r--sbin/hastd/pjdlog.h88
-rw-r--r--sbin/hastd/primary.c1769
-rw-r--r--sbin/hastd/proto.c261
-rw-r--r--sbin/hastd/proto.h54
-rw-r--r--sbin/hastd/proto_common.c85
-rw-r--r--sbin/hastd/proto_impl.h75
-rw-r--r--sbin/hastd/proto_socketpair.c275
-rw-r--r--sbin/hastd/proto_tcp4.c447
-rw-r--r--sbin/hastd/proto_uds.c330
-rw-r--r--sbin/hastd/rangelock.c137
-rw-r--r--sbin/hastd/rangelock.h46
-rw-r--r--sbin/hastd/secondary.c697
-rw-r--r--sbin/hastd/subr.c118
-rw-r--r--sbin/hastd/subr.h51
-rw-r--r--sbin/hastd/synch.h162
-rw-r--r--sbin/hastd/token.l66
-rw-r--r--sbin/ifconfig/Makefile2
-rw-r--r--sbin/ifconfig/ifconfig.814
-rw-r--r--sbin/ifconfig/ifconfig.c2
-rw-r--r--sbin/ifconfig/ifvlan.c2
-rw-r--r--sbin/ipf/ipftest/Makefile3
-rw-r--r--sbin/ipfw/altq.c1
-rw-r--r--sbin/ipfw/dummynet.c848
-rw-r--r--sbin/ipfw/ipfw.8142
-rw-r--r--sbin/ipfw/ipfw2.c311
-rw-r--r--sbin/ipfw/ipfw2.h29
-rw-r--r--sbin/ipfw/main.c144
-rw-r--r--sbin/mount_hpfs/Makefile3
-rw-r--r--sbin/mount_hpfs/mount_hpfs.c19
-rw-r--r--sbin/mount_ntfs/Makefile3
-rw-r--r--sbin/mount_ntfs/mount_ntfs.c15
-rw-r--r--sbin/restore/restore.h2
-rw-r--r--sbin/route/Makefile2
-rw-r--r--sbin/route/route.c302
-rw-r--r--sbin/routed/Makefile16
-rw-r--r--sbin/routed/if.c6
-rw-r--r--sbin/routed/rtquery/Makefile2
-rw-r--r--sbin/rtsol/Makefile2
-rw-r--r--secure/libexec/sftp-server/Makefile5
-rw-r--r--secure/usr.sbin/sshd/Makefile4
-rw-r--r--share/examples/Makefile6
-rw-r--r--share/examples/autofs/driver/Makefile6
-rwxr-xr-xshare/examples/hast/ucarp.sh69
-rwxr-xr-xshare/examples/hast/ucarp_down.sh98
-rwxr-xr-xshare/examples/hast/ucarp_up.sh105
-rwxr-xr-xshare/examples/hast/vip-down.sh5
-rwxr-xr-xshare/examples/hast/vip-up.sh7
-rw-r--r--share/man/man4/Makefile1
-rw-r--r--share/man/man4/ahci.428
-rw-r--r--share/man/man4/bwn.44
-rw-r--r--share/man/man4/man4.powerpc/Makefile1
-rw-r--r--share/man/man4/man4.powerpc/smu.4125
-rw-r--r--share/man/man4/msk.48
-rw-r--r--share/man/man4/ng_ipfw.421
-rw-r--r--share/man/man4/siis.428
-rw-r--r--share/man/man5/core.548
-rw-r--r--share/man/man5/devfs.rules.512
-rw-r--r--share/man/man5/rc.conf.523
-rw-r--r--share/man/man9/BUF_ISLOCKED.91
-rw-r--r--share/man/man9/BUF_RECURSED.91
-rw-r--r--share/man/man9/DEVICE_PROBE.91
-rw-r--r--share/man/man9/VOP_LOCK.91
-rw-r--r--share/man/man9/devfs_set_cdevpriv.92
-rw-r--r--share/man/man9/ieee80211_scan.96
-rw-r--r--share/man/man9/namei.92
-rw-r--r--share/man/man9/netisr.95
-rw-r--r--share/man/man9/vm_page_alloc.940
-rw-r--r--share/mk/bsd.cpu.mk11
-rw-r--r--share/mk/bsd.libnames.mk2
-rw-r--r--share/zoneinfo/Makefile6
-rw-r--r--sys/amd64/amd64/atpic_vector.S (renamed from sys/amd64/isa/atpic_vector.S)0
-rw-r--r--sys/amd64/amd64/busdma_machdep.c31
-rw-r--r--sys/amd64/amd64/exception.S2
-rw-r--r--sys/amd64/amd64/identcpu.c2
-rw-r--r--sys/amd64/amd64/intr_machdep.c4
-rw-r--r--sys/amd64/amd64/machdep.c2
-rw-r--r--sys/amd64/amd64/mca.c2
-rw-r--r--sys/amd64/amd64/nexus.c2
-rw-r--r--sys/amd64/amd64/pmap.c11
-rw-r--r--sys/amd64/amd64/vm_machdep.c2
-rw-r--r--sys/amd64/include/sysarch.h4
-rw-r--r--sys/amd64/isa/atpic.c613
-rw-r--r--sys/amd64/isa/clock.c665
-rw-r--r--sys/amd64/isa/isa.c167
-rw-r--r--sys/amd64/isa/isa.h80
-rw-r--r--sys/amd64/isa/nmi.c99
-rw-r--r--sys/arm/arm/cpufunc.c3
-rw-r--r--sys/arm/arm/identcpu.c4
-rw-r--r--sys/arm/at91/if_ate.c14
-rw-r--r--sys/arm/conf/BWCT2
-rw-r--r--sys/arm/conf/HL2002
-rw-r--r--sys/arm/conf/KB920X2
-rw-r--r--sys/arm/include/armreg.h4
-rw-r--r--sys/arm/include/md_var.h1
-rw-r--r--sys/arm/mv/mv_machdep.c3
-rw-r--r--sys/arm/xscale/ixp425/cambria_fled.c2
-rw-r--r--sys/boot/forth/loader.conf1
-rw-r--r--sys/boot/powerpc/ofw/Makefile5
-rw-r--r--sys/boot/powerpc/uboot/Makefile8
-rw-r--r--sys/boot/powerpc/uboot/conf.c2
-rw-r--r--sys/boot/sparc64/loader/main.c2
-rw-r--r--sys/boot/uboot/common/main.c25
-rw-r--r--sys/boot/uboot/lib/disk.c8
-rw-r--r--sys/boot/uboot/lib/time.c2
-rw-r--r--sys/boot/zfs/zfs.c2
-rw-r--r--sys/cam/ata/ata_xpt.c90
-rw-r--r--sys/cam/cam_xpt.c158
-rw-r--r--sys/cam/cam_xpt_internal.h3
-rw-r--r--sys/cam/scsi/scsi_xpt.c99
-rw-r--r--sys/cddl/contrib/opensolaris/common/atomic/ia64/opensolaris_atomic.S2
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c10
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c11
-rw-r--r--sys/compat/linux/linux_getcwd.c7
-rw-r--r--sys/compat/linux/linux_stats.c2
-rw-r--r--sys/compat/linux/linux_time.c7
-rw-r--r--sys/conf/NOTES5
-rw-r--r--sys/conf/files13
-rw-r--r--sys/conf/files.amd6432
-rw-r--r--sys/conf/files.i38634
-rw-r--r--sys/conf/files.mips3
-rw-r--r--sys/conf/files.pc988
-rw-r--r--sys/conf/ldscript.mips.cfe2
-rw-r--r--sys/conf/options1
-rw-r--r--sys/conf/options.mips5
-rw-r--r--sys/contrib/libfdt/fdt.c213
-rw-r--r--sys/contrib/libfdt/fdt.h60
-rw-r--r--sys/contrib/libfdt/fdt_ro.c523
-rw-r--r--sys/contrib/libfdt/fdt_rw.c465
-rw-r--r--sys/contrib/libfdt/fdt_strerror.c96
-rw-r--r--sys/contrib/libfdt/fdt_sw.c256
-rw-r--r--sys/contrib/libfdt/fdt_wip.c118
-rw-r--r--sys/contrib/libfdt/libfdt.h1132
-rw-r--r--sys/contrib/libfdt/libfdt_env.h23
-rw-r--r--sys/contrib/libfdt/libfdt_internal.h94
-rw-r--r--sys/dev/aac/aac.c3
-rw-r--r--sys/dev/aac/aac_cam.c1
-rw-r--r--sys/dev/age/if_age.c31
-rw-r--r--sys/dev/alc/if_alc.c46
-rw-r--r--sys/dev/ale/if_ale.c31
-rw-r--r--sys/dev/ata/ata-all.c18
-rw-r--r--sys/dev/ata/ata-pci.c12
-rw-r--r--sys/dev/ata/ata-pci.h1
-rw-r--r--sys/dev/ata/ata-sata.c2
-rw-r--r--sys/dev/ata/chipsets/ata-acerlabs.c3
-rw-r--r--sys/dev/ata/chipsets/ata-intel.c16
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212.h3
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212_attach.c3
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c11
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_reset.c6
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar9285_attach.c2
-rw-r--r--sys/dev/ath/if_ath.c38
-rw-r--r--sys/dev/bce/if_bce.c302
-rw-r--r--sys/dev/bge/if_bge.c45
-rw-r--r--sys/dev/bwn/if_bwn.c123
-rw-r--r--sys/dev/bwn/if_bwnvar.h2
-rw-r--r--sys/dev/cm/if_cm_isa.c7
-rw-r--r--sys/dev/cm/smc90cx6.c7
-rw-r--r--sys/dev/cm/smc90cx6reg.h7
-rw-r--r--sys/dev/cm/smc90cx6var.h7
-rw-r--r--sys/dev/cxgb/common/cxgb_common.h8
-rw-r--r--sys/dev/cxgb/common/cxgb_t3_hw.c6
-rw-r--r--sys/dev/cxgb/common/cxgb_version.h41
-rw-r--r--sys/dev/cxgb/cxgb_adapter.h9
-rw-r--r--sys/dev/cxgb/cxgb_config.h40
-rw-r--r--sys/dev/cxgb/cxgb_main.c144
-rw-r--r--sys/dev/cxgb/cxgb_offload.h2
-rw-r--r--sys/dev/cxgb/cxgb_osdep.h30
-rw-r--r--sys/dev/cxgb/cxgb_sge.c113
-rw-r--r--sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb.c3
-rw-r--r--sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_qp.c4
-rw-r--r--sys/dev/cxgb/ulp/tom/cxgb_cpl_socket.c1
-rw-r--r--sys/dev/fb/fb.c6
-rw-r--r--sys/dev/fb/vesa.c101
-rw-r--r--sys/dev/gem/if_gem.c5
-rw-r--r--sys/dev/isp/isp.c459
-rw-r--r--sys/dev/isp/isp_freebsd.c10
-rw-r--r--sys/dev/isp/isp_library.c35
-rw-r--r--sys/dev/isp/isp_library.h1
-rw-r--r--sys/dev/isp/isp_pci.c20
-rw-r--r--sys/dev/isp/isp_target.c4
-rw-r--r--sys/dev/isp/ispmbox.h18
-rw-r--r--sys/dev/isp/ispreg.h4
-rw-r--r--sys/dev/jme/if_jme.c5
-rw-r--r--sys/dev/md/md.c2
-rw-r--r--sys/dev/mfi/mfi_cam.c1
-rw-r--r--sys/dev/mfi/mfi_pci.c1
-rw-r--r--sys/dev/mii/brgphy.c26
-rw-r--r--sys/dev/mii/miidevs1
-rw-r--r--sys/dev/mpt/mpt_raid.c3
-rw-r--r--sys/dev/msk/if_msk.c429
-rw-r--r--sys/dev/msk/if_mskreg.h13
-rw-r--r--sys/dev/mxge/if_mxge.c12
-rw-r--r--sys/dev/ofw/ofw_pci.h7
-rw-r--r--sys/dev/re/if_re.c29
-rw-r--r--sys/dev/sound/pci/hda/hdac.c4
-rw-r--r--sys/dev/stge/if_stge.c7
-rw-r--r--sys/dev/stge/if_stgereg.h7
-rw-r--r--sys/dev/syscons/scvidctl.c81
-rw-r--r--sys/dev/syscons/snake/snake_saver.c55
-rw-r--r--sys/dev/syscons/syscons.c135
-rw-r--r--sys/dev/syscons/syscons.h6
-rw-r--r--sys/dev/uart/uart_bus_pci.c2
-rw-r--r--sys/dev/xen/netfront/netfront.c38
-rw-r--r--sys/fs/ext2fs/ext2_vnops.c2
-rw-r--r--sys/fs/msdosfs/msdosfs_denode.c12
-rw-r--r--sys/fs/msdosfs/msdosfs_fat.c87
-rw-r--r--sys/fs/msdosfs/msdosfs_fileno.c16
-rw-r--r--sys/fs/msdosfs/msdosfs_lookup.c104
-rw-r--r--sys/fs/msdosfs/msdosfs_vfsops.c17
-rw-r--r--sys/fs/msdosfs/msdosfs_vnops.c4
-rw-r--r--sys/fs/msdosfs/msdosfsmount.h14
-rw-r--r--sys/geom/gate/g_gate.c190
-rw-r--r--sys/geom/gate/g_gate.h18
-rw-r--r--sys/geom/geom_subr.c1
-rw-r--r--sys/geom/multipath/g_multipath.c86
-rw-r--r--sys/geom/stripe/g_stripe.c2
-rw-r--r--sys/i386/conf/XEN6
-rw-r--r--sys/i386/i386/atpic_vector.s (renamed from sys/i386/isa/atpic_vector.s)0
-rw-r--r--sys/i386/i386/exception.s2
-rw-r--r--sys/i386/i386/machdep.c2
-rw-r--r--sys/i386/i386/mca.c2
-rw-r--r--sys/i386/i386/nexus.c2
-rw-r--r--sys/i386/i386/pmap.c9
-rw-r--r--sys/i386/i386/vm_machdep.c2
-rw-r--r--sys/i386/isa/elcr.c139
-rw-r--r--sys/i386/isa/isa_dma.c610
-rw-r--r--sys/i386/xen/clock.c4
-rw-r--r--sys/i386/xen/pmap.c9
-rw-r--r--sys/i386/xen/xen_machdep.c131
-rw-r--r--sys/ia64/ia64/context.S16
-rw-r--r--sys/ia64/ia64/exception.S40
-rw-r--r--sys/ia64/ia64/interrupt.c119
-rw-r--r--sys/ia64/ia64/locore.S18
-rw-r--r--sys/ia64/ia64/nexus.c1
-rw-r--r--sys/ia64/ia64/pmap.c5
-rw-r--r--sys/ia64/ia64/sapic.c154
-rw-r--r--sys/ia64/ia64/support.S28
-rw-r--r--sys/ia64/ia64/syscall.S20
-rw-r--r--sys/ia64/include/intr.h20
-rw-r--r--sys/ia64/include/pmap.h1
-rw-r--r--sys/ia64/include/sapicvar.h65
-rw-r--r--sys/kern/imgact_elf.c172
-rw-r--r--sys/kern/kern_conf.c7
-rw-r--r--sys/kern/kern_gzio.c406
-rw-r--r--sys/kern/kern_kthread.c25
-rw-r--r--sys/kern/kern_proc.c12
-rw-r--r--sys/kern/kern_sig.c130
-rw-r--r--sys/kern/kern_thr.c21
-rw-r--r--sys/kern/subr_hash.c132
-rw-r--r--sys/kern/subr_param.c10
-rw-r--r--sys/kern/subr_uio.c (renamed from sys/kern/kern_subr.c)93
-rw-r--r--sys/kern/uipc_socket.c5
-rw-r--r--sys/kern/uipc_syscalls.c4
-rw-r--r--sys/kern/vfs_default.c5
-rw-r--r--sys/kern/vfs_mount.c11
-rw-r--r--sys/kern/vfs_syscalls.c3
-rw-r--r--sys/mips/alchemy/obio.c41
-rw-r--r--sys/mips/atheros/ar71xxreg.h6
-rw-r--r--sys/mips/cavium/dev/rgmii/octeon_fpa.c8
-rw-r--r--sys/mips/cavium/octeon_machdep.c16
-rw-r--r--sys/mips/cavium/octeon_pcmap_regs.h5
-rw-r--r--sys/mips/conf/ADM51201
-rw-r--r--sys/mips/conf/MALTA1
-rw-r--r--sys/mips/conf/MALTA641
-rw-r--r--sys/mips/conf/OCTEON11
-rw-r--r--sys/mips/conf/OCTEON1-321
-rw-r--r--sys/mips/conf/QEMU1
-rw-r--r--sys/mips/conf/SWARM5
-rw-r--r--sys/mips/conf/XLR2
-rw-r--r--sys/mips/include/asm.h299
-rw-r--r--sys/mips/include/bus.h1
-rw-r--r--sys/mips/include/cdefs.h30
-rw-r--r--sys/mips/include/intr_machdep.h14
-rw-r--r--sys/mips/include/ucontext.h8
-rw-r--r--sys/mips/mips/elf_trampoline.c2
-rw-r--r--sys/mips/mips/exception.S16
-rw-r--r--sys/mips/rmi/board.c15
-rw-r--r--sys/mips/rmi/bus_space_rmi.c205
-rw-r--r--sys/mips/rmi/bus_space_rmi_pci.c761
-rw-r--r--sys/mips/rmi/files.xlr6
-rw-r--r--sys/mips/rmi/interrupt.h12
-rw-r--r--sys/mips/rmi/intr_machdep.c54
-rw-r--r--sys/mips/rmi/iodi.c34
-rw-r--r--sys/mips/rmi/pcibus.h39
-rw-r--r--sys/mips/rmi/xlr_pci.c471
-rw-r--r--sys/mips/rmi/xls_ehci.c226
-rw-r--r--sys/modules/Makefile2
-rw-r--r--sys/modules/ath/Makefile1
-rw-r--r--sys/modules/bios/smbios/Makefile2
-rw-r--r--sys/modules/bios/vpd/Makefile2
-rw-r--r--sys/modules/cpufreq/Makefile2
-rw-r--r--sys/modules/cxgb/cxgb/Makefile8
-rw-r--r--sys/net/bpf.c21
-rw-r--r--sys/net/if.c84
-rw-r--r--sys/net/if.h1
-rw-r--r--sys/net/if_bridge.c9
-rw-r--r--sys/net/if_ethersubr.c11
-rw-r--r--sys/net/if_gre.c7
-rw-r--r--sys/net/if_gre.h7
-rw-r--r--sys/net/if_loop.c4
-rw-r--r--sys/net/if_tap.c13
-rw-r--r--sys/net/if_tun.c11
-rw-r--r--sys/net/if_vlan.c22
-rw-r--r--sys/net/netisr.c329
-rw-r--r--sys/net/netisr.h90
-rw-r--r--sys/net/netisr_internal.h127
-rw-r--r--sys/net/radix.c2
-rw-r--r--sys/net/zlib.h7
-rw-r--r--sys/net/zutil.h231
-rw-r--r--sys/netinet/in_proto.c3
-rw-r--r--sys/netinet/ip_dummynet.h467
-rw-r--r--sys/netinet/ip_fw.h22
-rw-r--r--sys/netinet/ip_gre.c7
-rw-r--r--sys/netinet/ip_gre.h7
-rw-r--r--sys/netinet/ip_input.c42
-rw-r--r--sys/netinet/ip_mroute.c2
-rw-r--r--sys/netinet/ip_options.c2
-rw-r--r--sys/netinet/ip_var.h3
-rw-r--r--sys/netinet/ipfw/dn_heap.c550
-rw-r--r--sys/netinet/ipfw/dn_heap.h191
-rw-r--r--sys/netinet/ipfw/dn_sched.h170
-rw-r--r--sys/netinet/ipfw/dn_sched_fifo.c120
-rw-r--r--sys/netinet/ipfw/dn_sched_qfq.c864
-rw-r--r--sys/netinet/ipfw/dn_sched_rr.c307
-rw-r--r--sys/netinet/ipfw/dn_sched_wf2q.c373
-rw-r--r--sys/netinet/ipfw/dummynet.txt860
-rw-r--r--sys/netinet/ipfw/ip_dn_glue.c843
-rw-r--r--sys/netinet/ipfw/ip_dn_io.c781
-rw-r--r--sys/netinet/ipfw/ip_dn_private.h387
-rw-r--r--sys/netinet/ipfw/ip_dummynet.c3732
-rw-r--r--sys/netinet/ipfw/ip_fw2.c66
-rw-r--r--sys/netinet/ipfw/ip_fw_dynamic.c14
-rw-r--r--sys/netinet/ipfw/ip_fw_log.c2
-rw-r--r--sys/netinet/ipfw/ip_fw_pfil.c8
-rw-r--r--sys/netinet/ipfw/ip_fw_private.h27
-rw-r--r--sys/netinet/ipfw/ip_fw_sockopt.c196
-rw-r--r--sys/netinet/ipfw/ip_fw_table.c1
-rw-r--r--sys/netinet/ipfw/test/Makefile50
-rw-r--r--sys/netinet/ipfw/test/dn_test.h155
-rw-r--r--sys/netinet/ipfw/test/main.c636
-rw-r--r--sys/netinet/ipfw/test/mylist.h49
-rw-r--r--sys/netinet/ipfw/test/test_dn_heap.c162
-rw-r--r--sys/netinet/ipfw/test/test_dn_sched.c76
-rw-r--r--sys/netinet/sctp_input.c12
-rw-r--r--sys/netinet/sctp_output.c16
-rw-r--r--sys/netinet/sctp_output.h2
-rw-r--r--sys/netinet/sctp_usrreq.c11
-rw-r--r--sys/netinet/sctputil.c5
-rw-r--r--sys/netinet/tcp_syncache.c26
-rw-r--r--sys/netinet6/in6_pcb.c2
-rw-r--r--sys/netinet6/nd6.c9
-rw-r--r--sys/netipsec/keydb.h2
-rw-r--r--sys/nfsclient/nfs_kdtrace.c6
-rw-r--r--sys/pc98/pc98/machdep.c2
-rw-r--r--sys/powerpc/aim/machdep.c5
-rw-r--r--sys/powerpc/aim/mmu_oea.c4
-rw-r--r--sys/powerpc/aim/mmu_oea64.c136
-rw-r--r--sys/powerpc/aim/trap.c23
-rw-r--r--sys/powerpc/aim/uma_machdep.c21
-rw-r--r--sys/powerpc/booke/copyinout.c15
-rw-r--r--sys/powerpc/include/pte.h1
-rw-r--r--sys/powerpc/include/sr.h1
-rw-r--r--sys/powerpc/include/vmparam.h10
-rw-r--r--sys/powerpc/powermac/smu.c667
-rw-r--r--sys/powerpc/powerpc/cpu.c12
-rw-r--r--sys/powerpc/powerpc/mem.c6
-rw-r--r--sys/security/mac_biba/mac_biba.c1
-rw-r--r--sys/security/mac_lomac/mac_lomac.c1
-rw-r--r--sys/security/mac_mls/mac_mls.c1
-rw-r--r--sys/sparc64/include/cache.h2
-rw-r--r--sys/sparc64/include/cpu.h2
-rw-r--r--sys/sparc64/include/md_var.h4
-rw-r--r--sys/sparc64/include/pcpu.h1
-rw-r--r--sys/sparc64/include/pmap.h2
-rw-r--r--sys/sparc64/include/smp.h2
-rw-r--r--sys/sparc64/include/tick.h4
-rw-r--r--sys/sparc64/include/ver.h26
-rw-r--r--sys/sparc64/sparc64/cache.c58
-rw-r--r--sys/sparc64/sparc64/cheetah.c4
-rw-r--r--sys/sparc64/sparc64/identcpu.c3
-rw-r--r--sys/sparc64/sparc64/iommu.c3
-rw-r--r--sys/sparc64/sparc64/machdep.c30
-rw-r--r--sys/sparc64/sparc64/mp_locore.S12
-rw-r--r--sys/sparc64/sparc64/mp_machdep.c40
-rw-r--r--sys/sparc64/sparc64/nexus.c3
-rw-r--r--sys/sparc64/sparc64/pmap.c4
-rw-r--r--sys/sparc64/sparc64/spitfire.c2
-rw-r--r--sys/sparc64/sparc64/tick.c6
-rw-r--r--sys/sparc64/sparc64/trap.c3
-rw-r--r--sys/sys/ata.h2
-rw-r--r--sys/sys/eventhandler.h13
-rw-r--r--sys/sys/fbio.h1
-rw-r--r--sys/sys/imgact.h2
-rw-r--r--sys/sys/imgact_aout.h3
-rw-r--r--sys/sys/imgact_elf.h2
-rw-r--r--sys/sys/queue.h20
-rw-r--r--sys/sys/sysctl.h4
-rw-r--r--sys/sys/sysent.h2
-rw-r--r--sys/sys/systm.h5
-rw-r--r--sys/sys/user.h4
-rw-r--r--sys/vm/vm_init.c2
-rw-r--r--sys/vm/vm_page.c7
-rw-r--r--sys/vm/vnode_pager.c3
-rw-r--r--sys/x86/bios/smbios.c (renamed from sys/i386/bios/smbios.c)0
-rw-r--r--sys/x86/bios/vpd.c (renamed from sys/i386/bios/vpd.c)0
-rw-r--r--sys/x86/cpufreq/est.c (renamed from sys/i386/cpufreq/est.c)0
-rw-r--r--sys/x86/cpufreq/hwpstate.c (renamed from sys/i386/cpufreq/hwpstate.c)0
-rw-r--r--sys/x86/cpufreq/p4tcc.c (renamed from sys/i386/cpufreq/p4tcc.c)0
-rw-r--r--sys/x86/cpufreq/powernow.c (renamed from sys/i386/cpufreq/powernow.c)0
-rw-r--r--sys/x86/cpufreq/smist.c (renamed from sys/i386/cpufreq/smist.c)0
-rw-r--r--sys/x86/isa/atpic.c (renamed from sys/i386/isa/atpic.c)15
-rw-r--r--sys/x86/isa/atrtc.c (renamed from sys/isa/atrtc.c)0
-rw-r--r--sys/x86/isa/clock.c (renamed from sys/i386/isa/clock.c)30
-rw-r--r--sys/x86/isa/elcr.c (renamed from sys/amd64/isa/elcr.c)0
-rw-r--r--sys/x86/isa/icu.h (renamed from sys/i386/isa/icu.h)6
-rw-r--r--sys/x86/isa/isa.c (renamed from sys/i386/isa/isa.c)2
-rw-r--r--sys/x86/isa/isa.h (renamed from sys/i386/isa/isa.h)6
-rw-r--r--sys/x86/isa/isa_dma.c (renamed from sys/amd64/isa/isa_dma.c)2
-rw-r--r--sys/x86/isa/nmi.c (renamed from sys/i386/isa/nmi.c)0
-rw-r--r--sys/x86/isa/orm.c (renamed from sys/isa/orm.c)0
-rw-r--r--sys/xen/evtchn/evtchn_dev.c2
-rw-r--r--tools/build/mk/OptionalObsoleteFiles.inc246
-rw-r--r--tools/regression/file/closefrom/Makefile2
-rw-r--r--tools/regression/file/flock/Makefile4
-rw-r--r--tools/regression/gaithrstress/Makefile3
-rw-r--r--tools/regression/kgssapi/Makefile1
-rw-r--r--tools/regression/kqueue/Makefile2
-rw-r--r--tools/regression/kthread/kld/Makefile10
-rw-r--r--tools/regression/kthread/kld/kthrdlk.c204
-rw-r--r--tools/regression/mqueue/mqtest1/Makefile3
-rw-r--r--tools/regression/mqueue/mqtest2/Makefile3
-rw-r--r--tools/regression/mqueue/mqtest3/Makefile3
-rw-r--r--tools/regression/mqueue/mqtest4/Makefile3
-rw-r--r--tools/regression/mqueue/mqtest5/Makefile3
-rw-r--r--tools/regression/netipx/ipxdgramloopback/Makefile2
-rw-r--r--tools/regression/netipx/spxabort/Makefile2
-rw-r--r--tools/regression/netipx/spxloopback/Makefile2
-rw-r--r--tools/regression/priv/Makefile2
-rw-r--r--tools/regression/pthread/cv_cancel1/Makefile2
-rw-r--r--tools/regression/pthread/mutex_isowned_np/Makefile2
-rw-r--r--tools/regression/rpcsec_gss/Makefile1
-rw-r--r--tools/regression/sigqueue/sigqtest1/Makefile1
-rw-r--r--tools/regression/sigqueue/sigqtest2/Makefile1
-rw-r--r--tools/regression/sockets/sendfile/Makefile2
-rw-r--r--tools/regression/sockets/sendfile/sendfile.c410
-rw-r--r--tools/regression/sockets/unix_gc/Makefile2
-rw-r--r--tools/regression/sockets/unix_sorflush/Makefile2
-rw-r--r--tools/regression/sysvsem/semtest.c7
-rw-r--r--tools/regression/tls/libxx/Makefile3
-rw-r--r--tools/regression/tls/libyy/Makefile3
-rw-r--r--tools/regression/tls/ttls1/Makefile4
-rw-r--r--tools/regression/tls/ttls2/Makefile3
-rw-r--r--tools/regression/tls/ttls4/Makefile3
-rw-r--r--tools/regression/tmpfs/Makefile2
-rw-r--r--tools/tools/ether_reflect/Makefile4
-rw-r--r--tools/tools/mcgrab/Makefile6
-rw-r--r--tools/tools/mcgrab/mcgrab.1 (renamed from tools/tools/mctest/mcgrab.1)29
-rw-r--r--tools/tools/mcgrab/mcgrab.cc (renamed from tools/tools/mctest/mcgrab.cc)0
-rw-r--r--tools/tools/mctest/Makefile8
-rw-r--r--tools/tools/mctest/mctest.152
-rw-r--r--tools/tools/net80211/stumbler/Makefile2
-rw-r--r--tools/tools/net80211/w00t/Makefile.inc3
-rw-r--r--tools/tools/netrate/http/Makefile2
-rw-r--r--tools/tools/netrate/httpd/Makefile2
-rw-r--r--tools/tools/netrate/juggle/Makefile5
-rw-r--r--tools/tools/netrate/tcpconnect/Makefile2
-rw-r--r--tools/tools/netrate/tcpp/Makefile2
-rw-r--r--tools/tools/netrate/tcpreceive/Makefile2
-rw-r--r--tools/tools/umastat/Makefile3
-rw-r--r--usr.bin/Makefile1
-rw-r--r--usr.bin/cpio/Makefile5
-rw-r--r--usr.bin/cpio/bsdcpio.12
-rw-r--r--usr.bin/csup/Makefile46
-rw-r--r--usr.bin/csup/README (renamed from contrib/csup/README)0
-rw-r--r--usr.bin/csup/TODO (renamed from contrib/csup/TODO)5
-rw-r--r--usr.bin/csup/attrstack.c (renamed from contrib/csup/attrstack.c)0
-rw-r--r--usr.bin/csup/attrstack.h (renamed from contrib/csup/attrstack.h)0
-rw-r--r--usr.bin/csup/auth.c (renamed from contrib/csup/auth.c)0
-rw-r--r--usr.bin/csup/auth.h (renamed from contrib/csup/auth.h)0
-rw-r--r--usr.bin/csup/config.c (renamed from contrib/csup/config.c)0
-rw-r--r--usr.bin/csup/config.h (renamed from contrib/csup/config.h)0
-rw-r--r--usr.bin/csup/cpasswd.1 (renamed from contrib/csup/cpasswd.1)0
-rwxr-xr-xusr.bin/csup/cpasswd.sh (renamed from contrib/csup/cpasswd.sh)0
-rw-r--r--usr.bin/csup/csup.1 (renamed from contrib/csup/csup.1)0
-rw-r--r--usr.bin/csup/detailer.c (renamed from contrib/csup/detailer.c)0
-rw-r--r--usr.bin/csup/detailer.h (renamed from contrib/csup/detailer.h)0
-rw-r--r--usr.bin/csup/diff.c (renamed from contrib/csup/diff.c)0
-rw-r--r--usr.bin/csup/diff.h (renamed from contrib/csup/diff.h)0
-rw-r--r--usr.bin/csup/fattr.c (renamed from contrib/csup/fattr.c)0
-rw-r--r--usr.bin/csup/fattr.h (renamed from contrib/csup/fattr.h)0
-rw-r--r--usr.bin/csup/fattr_bsd.h (renamed from contrib/csup/fattr_bsd.h)0
-rw-r--r--usr.bin/csup/fattr_posix.h (renamed from contrib/csup/fattr_posix.h)0
-rw-r--r--usr.bin/csup/fixups.c (renamed from contrib/csup/fixups.c)0
-rw-r--r--usr.bin/csup/fixups.h (renamed from contrib/csup/fixups.h)0
-rw-r--r--usr.bin/csup/fnmatch.c (renamed from contrib/csup/fnmatch.c)0
-rw-r--r--usr.bin/csup/fnmatch.h (renamed from contrib/csup/fnmatch.h)0
-rw-r--r--usr.bin/csup/globtree.c (renamed from contrib/csup/globtree.c)0
-rw-r--r--usr.bin/csup/globtree.h (renamed from contrib/csup/globtree.h)0
-rw-r--r--usr.bin/csup/idcache.c (renamed from contrib/csup/idcache.c)0
-rw-r--r--usr.bin/csup/idcache.h (renamed from contrib/csup/idcache.h)0
-rw-r--r--usr.bin/csup/keyword.c (renamed from contrib/csup/keyword.c)0
-rw-r--r--usr.bin/csup/keyword.h (renamed from contrib/csup/keyword.h)0
-rw-r--r--usr.bin/csup/lex.rcs.c (renamed from contrib/csup/lex.rcs.c)0
-rw-r--r--usr.bin/csup/lister.c (renamed from contrib/csup/lister.c)0
-rw-r--r--usr.bin/csup/lister.h (renamed from contrib/csup/lister.h)0
-rw-r--r--usr.bin/csup/main.c (renamed from contrib/csup/main.c)0
-rw-r--r--usr.bin/csup/main.h (renamed from contrib/csup/main.h)0
-rw-r--r--usr.bin/csup/misc.c (renamed from contrib/csup/misc.c)0
-rw-r--r--usr.bin/csup/misc.h (renamed from contrib/csup/misc.h)0
-rw-r--r--usr.bin/csup/mux.c (renamed from contrib/csup/mux.c)0
-rw-r--r--usr.bin/csup/mux.h (renamed from contrib/csup/mux.h)0
-rw-r--r--usr.bin/csup/parse.y (renamed from contrib/csup/parse.y)0
-rw-r--r--usr.bin/csup/pathcomp.c (renamed from contrib/csup/pathcomp.c)0
-rw-r--r--usr.bin/csup/pathcomp.h (renamed from contrib/csup/pathcomp.h)0
-rw-r--r--usr.bin/csup/proto.c (renamed from contrib/csup/proto.c)0
-rw-r--r--usr.bin/csup/proto.h (renamed from contrib/csup/proto.h)0
-rw-r--r--usr.bin/csup/queue.h (renamed from contrib/csup/queue.h)0
-rw-r--r--usr.bin/csup/rcsfile.c (renamed from contrib/csup/rcsfile.c)0
-rw-r--r--usr.bin/csup/rcsfile.h (renamed from contrib/csup/rcsfile.h)0
-rw-r--r--usr.bin/csup/rcsparse.c (renamed from contrib/csup/rcsparse.c)0
-rw-r--r--usr.bin/csup/rcsparse.h (renamed from contrib/csup/rcsparse.h)0
-rw-r--r--usr.bin/csup/rcstokenizer.h (renamed from contrib/csup/rcstokenizer.h)0
-rw-r--r--usr.bin/csup/rcstokenizer.l (renamed from contrib/csup/rcstokenizer.l)0
-rw-r--r--usr.bin/csup/rsyncfile.c (renamed from contrib/csup/rsyncfile.c)0
-rw-r--r--usr.bin/csup/rsyncfile.h (renamed from contrib/csup/rsyncfile.h)0
-rw-r--r--usr.bin/csup/status.c (renamed from contrib/csup/status.c)0
-rw-r--r--usr.bin/csup/status.h (renamed from contrib/csup/status.h)0
-rw-r--r--usr.bin/csup/stream.c (renamed from contrib/csup/stream.c)0
-rw-r--r--usr.bin/csup/stream.h (renamed from contrib/csup/stream.h)0
-rw-r--r--usr.bin/csup/threads.c (renamed from contrib/csup/threads.c)0
-rw-r--r--usr.bin/csup/threads.h (renamed from contrib/csup/threads.h)0
-rw-r--r--usr.bin/csup/token.h (renamed from contrib/csup/token.h)0
-rw-r--r--usr.bin/csup/token.l (renamed from contrib/csup/token.l)0
-rw-r--r--usr.bin/csup/updater.c (renamed from contrib/csup/updater.c)0
-rw-r--r--usr.bin/csup/updater.h (renamed from contrib/csup/updater.h)0
-rw-r--r--usr.bin/fetch/Makefile4
-rw-r--r--usr.bin/gcore/Makefile3
-rw-r--r--usr.bin/hexdump/hexdump.14
-rw-r--r--usr.bin/hexdump/od.14
-rw-r--r--usr.bin/jot/jot.13
-rw-r--r--usr.bin/locale/Makefile6
-rw-r--r--usr.bin/netstat/Makefile2
-rw-r--r--usr.bin/netstat/main.c20
-rw-r--r--usr.bin/netstat/netisr.c518
-rw-r--r--usr.bin/netstat/netstat.111
-rw-r--r--usr.bin/netstat/netstat.h5
-rw-r--r--usr.bin/pr/Makefile2
-rw-r--r--usr.bin/pr/egetopt.c2
-rw-r--r--usr.bin/pr/pr.c11
-rw-r--r--usr.bin/seq/Makefile8
-rw-r--r--usr.bin/seq/seq.1187
-rw-r--r--usr.bin/seq/seq.c453
-rw-r--r--usr.bin/systat/Makefile4
-rw-r--r--usr.bin/tar/Makefile3
-rw-r--r--usr.bin/tar/test/test_option_T.c2
-rw-r--r--usr.bin/tar/test/test_option_s.c2
-rw-r--r--usr.bin/tar/tree.c2
-rw-r--r--usr.bin/unifdef/unifdef.114
-rw-r--r--usr.bin/unifdef/unifdef.c63
-rw-r--r--usr.bin/unzip/Makefile4
-rw-r--r--usr.bin/xinstall/xinstall.c2
-rw-r--r--usr.sbin/auditd/Makefile4
-rw-r--r--usr.sbin/bluetooth/bthidd/Makefile1
-rw-r--r--usr.sbin/boot0cfg/Makefile4
-rw-r--r--usr.sbin/bsnmpd/modules/Makefile.inc3
-rw-r--r--usr.sbin/chown/chgrp.110
-rw-r--r--usr.sbin/chown/chown.812
-rw-r--r--usr.sbin/chown/chown.c17
-rw-r--r--usr.sbin/cxgbtool/cxgbtool.c205
-rw-r--r--usr.sbin/cxgbtool/reg_defs.c22
-rw-r--r--usr.sbin/cxgbtool/reg_defs_t3.c48
-rw-r--r--usr.sbin/cxgbtool/reg_defs_t3b.c48
-rw-r--r--usr.sbin/cxgbtool/reg_defs_t3c.c48
-rw-r--r--usr.sbin/fwcontrol/Makefile2
-rw-r--r--usr.sbin/mfiutil/Makefile1
-rw-r--r--usr.sbin/mptable/mptable.c2
-rw-r--r--usr.sbin/mptutil/Makefile4
-rw-r--r--usr.sbin/mptutil/mpt_cam.c222
-rw-r--r--usr.sbin/mptutil/mpt_show.c16
-rw-r--r--usr.sbin/mtree/mtree.54
-rw-r--r--usr.sbin/pmcstat/Makefile2
-rw-r--r--usr.sbin/rtsold/Makefile4
-rw-r--r--usr.sbin/rtsold/dump.c8
-rw-r--r--usr.sbin/rtsold/if.c1
-rw-r--r--usr.sbin/rtsold/rtsock.c6
-rw-r--r--usr.sbin/rtsold/rtsol.c17
-rw-r--r--usr.sbin/rtsold/rtsold.c11
-rw-r--r--usr.sbin/rtsold/rtsold.h2
-rw-r--r--usr.sbin/sysinstall/devices.c1
-rw-r--r--usr.sbin/uhsoctl/Makefile2
-rw-r--r--usr.sbin/zic/zdump/Makefile4
-rw-r--r--usr.sbin/zic/zic/Makefile4
892 files changed, 46263 insertions, 31785 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 2a6bfe8..316d226 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -125,6 +125,12 @@ gnu/usr.bin/send-pr bugmaster Pre-commit review requested.
ncurses rafan Heads-up appreciated, try not to break it.
*env(3) secteam Due to the problematic security history of this
code, please have patches reviewed by secteam.
+share/zoneinfo edwin Heads-up appreciated, since our data is coming
+ from a third party source.
+usr.sbin/zic edwin Heads-up appreciated, since this code is
+ maintained by a third party source.
+lib/libc/stdtime edwin Heads-up appreciated, since parts of this code
+ is maintained by a third party source.
Following are the entries from the Makefiles, and a few other sources.
Please remove stale entries from both their origin, and this file.
diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc
index 0c37471..ff811b7 100644
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -14,6 +14,21 @@
# The file is partitioned: OLD_FILES first, then OLD_LIBS and OLD_DIRS last.
#
+# 20100227: [ia64] removed <machine/sapicreg.h> and <machine/sapicvar.h>
+.if ${TARGET_ARCH} == "ia64"
+OLD_FILES+=usr/include/machine/sapicreg.h
+OLD_FILES+=usr/include/machine/sapicvar.h
+.endif
+# 20100208: man pages moved
+.if ${TARGET_ARCH} == "i386"
+OLD_FILES+=usr/share/man/man4/i386/alpm.4.gz
+OLD_FILES+=usr/share/man/man4/i386/amdpm.4.gz
+OLD_FILES+=usr/share/man/man4/i386/mcd.4.gz
+OLD_FILES+=usr/share/man/man4/i386/padlock.4.gz
+OLD_FILES+=usr/share/man/man4/i386/pcf.4.gz
+OLD_FILES+=usr/share/man/man4/i386/scd.4.gz
+OLD_FILES+=usr/share/man/man4/i386/viapm.4.gz
+.endif
# 20100122: move BSDL bc/dc USD documents to /usr/share/doc/usd
OLD_FILES+=usr/share/doc/papers/bc.ascii.gz
OLD_FILES+=usr/share/doc/papers/dc.ascii.gz
@@ -2275,7 +2290,7 @@ OLD_FILES+=usr/lib/libpam_ssh.a
OLD_FILES+=usr/lib/libpam_ssh_p.a
OLD_FILES+=usr/bin/help
OLD_FILES+=usr/bin/sccs
-.if ${TARGET_ARCH} != "arm" && ${TARGET_ARCH} != "i386" && ${TARGET_ARCH} != "powerpc"
+.if ${TARGET_ARCH} != "amd64" && ${TARGET_ARCH} != "arm" && ${TARGET_ARCH} != "i386" && ${TARGET_ARCH} != "powerpc"
OLD_FILES+=usr/bin/gdbserver
.endif
OLD_FILES+=usr/bin/ssh-keysign
diff --git a/bin/kill/kill.c b/bin/kill/kill.c
index bb9982e..8ee1d85 100644
--- a/bin/kill/kill.c
+++ b/bin/kill/kill.c
@@ -108,7 +108,7 @@ main(int argc, char *argv[])
numsig = strtol(*argv, &ep, 10);
if (!**argv || *ep)
errx(1, "illegal signal number: %s", *argv);
- if (numsig < 0 || numsig >= sys_nsig)
+ if (numsig < 0)
nosig(*argv);
} else
nosig(*argv);
diff --git a/bin/pkill/pkill.1 b/bin/pkill/pkill.1
index 5eec10f..0c666e5 100644
--- a/bin/pkill/pkill.1
+++ b/bin/pkill/pkill.1
@@ -16,13 +16,6 @@
.\" 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.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the NetBSD
-.\" Foundation, Inc. and its contributors.
-.\" 4. Neither the name of The NetBSD Foundation nor the names of its
-.\" contributors may be used to endorse or promote products derived
-.\" from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/bin/pkill/pkill.c b/bin/pkill/pkill.c
index a2d5f47..7876b87 100644
--- a/bin/pkill/pkill.c
+++ b/bin/pkill/pkill.c
@@ -16,13 +16,6 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/bin/sh/parser.c b/bin/sh/parser.c
index f8fd0ed..d8903c9 100644
--- a/bin/sh/parser.c
+++ b/bin/sh/parser.c
@@ -1641,7 +1641,7 @@ getprompt(void *unused __unused)
case 'w':
ps[i] = '\0';
getcwd(&ps[i], PROMPTLEN - i);
- if (*fmt == 'W') {
+ if (*fmt == 'W' && ps[i + 1] != '\0') {
/* Final path component only. */
trim = 1;
for (j = i; ps[j] != '\0'; j++)
diff --git a/cddl/Makefile.inc b/cddl/Makefile.inc
index 4161c27..d3a4914 100644
--- a/cddl/Makefile.inc
+++ b/cddl/Makefile.inc
@@ -7,4 +7,5 @@ IGNORE_PRAGMA= YES
CFLAGS+= -DNEED_SOLARIS_BOOLEAN
+WARNS?= 6
CSTD?= gnu89
diff --git a/cddl/lib/drti/Makefile b/cddl/lib/drti/Makefile
index 4be57a5..ffd161c 100644
--- a/cddl/lib/drti/Makefile
+++ b/cddl/lib/drti/Makefile
@@ -1,8 +1,6 @@
# $FreeBSD$
-.include "../../Makefile.inc"
-
-.PATH: ${OPENSOLARIS_USR_DISTDIR}/lib/libdtrace/common
+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/common
SRCS= drti.c
FILES= ${SRCS:R:S/$/.o/g}
@@ -10,7 +8,6 @@ FILESOWN= ${LIBOWN}
FILESGRP= ${LIBGRP}
FILESMODE= ${LIBMODE}
FILESDIR= ${LIBDIR}/dtrace
-WARNS?= 6
CLEANFILES= ${FILES}
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
diff --git a/cddl/lib/libavl/Makefile b/cddl/lib/libavl/Makefile
index 8cbaff1..f4db92f 100644
--- a/cddl/lib/libavl/Makefile
+++ b/cddl/lib/libavl/Makefile
@@ -4,6 +4,7 @@
LIB= avl
SRCS= avl.c
+WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
diff --git a/cddl/lib/libctf/Makefile b/cddl/lib/libctf/Makefile
index 6309ee4..5829111 100644
--- a/cddl/lib/libctf/Makefile
+++ b/cddl/lib/libctf/Makefile
@@ -1,10 +1,10 @@
# $FreeBSD$
-.include "../../Makefile.inc"
+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/common/ctf
+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libctf/common
+.PATH: ${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/ctf
LIB= ctf
-SHLIB_MAJOR= 2
-
SRCS= ctf_create.c \
ctf_decl.c \
ctf_error.c \
@@ -17,10 +17,7 @@ SRCS= ctf_create.c \
ctf_types.c \
ctf_util.c
-.PATH: ${OPENSOLARIS_USR_DISTDIR}/common/ctf
-.PATH: ${OPENSOLARIS_USR_DISTDIR}/lib/libctf/common
-.PATH: ${OPENSOLARIS_SYS_DISTDIR}/common/ctf
-
+WARNS?= 0
CFLAGS+= -DCTF_OLD_VERSIONS
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
diff --git a/cddl/lib/libdtrace/Makefile b/cddl/lib/libdtrace/Makefile
index e2537ff..fdeaa50 100644
--- a/cddl/lib/libdtrace/Makefile
+++ b/cddl/lib/libdtrace/Makefile
@@ -1,12 +1,9 @@
# $FreeBSD$
-.include "../../Makefile.inc"
+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/common
+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libgen/common
LIB= dtrace
-SHLIB_MAJOR= 2
-
-WARNS= 1
-
SRCS= dt_aggregate.c \
dt_as.c \
dt_buf.c \
@@ -51,8 +48,7 @@ DSRCS= errno.d \
signal.d \
unistd.d
-.PATH: ${OPENSOLARIS_USR_DISTDIR}/lib/libdtrace/common
-.PATH: ${OPENSOLARIS_USR_DISTDIR}/lib/libgen/common
+WARNS?= 1
CFLAGS+= -I${.OBJDIR} \
-I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
diff --git a/cddl/lib/libnvpair/Makefile b/cddl/lib/libnvpair/Makefile
index 7bf5001..da0c7f3 100644
--- a/cddl/lib/libnvpair/Makefile
+++ b/cddl/lib/libnvpair/Makefile
@@ -10,6 +10,7 @@ SRCS= libnvpair.c \
nvpair_alloc_fixed.c \
nvpair.c
+WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/include
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
diff --git a/cddl/lib/libumem/Makefile b/cddl/lib/libumem/Makefile
index 6b6881e..0ce73f8 100644
--- a/cddl/lib/libumem/Makefile
+++ b/cddl/lib/libumem/Makefile
@@ -4,6 +4,7 @@
LIB= umem
SRCS= umem.c
+WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/lib/libumem
.include <bsd.lib.mk>
diff --git a/cddl/lib/libuutil/Makefile b/cddl/lib/libuutil/Makefile
index 309ffd0..7521747 100644
--- a/cddl/lib/libuutil/Makefile
+++ b/cddl/lib/libuutil/Makefile
@@ -15,6 +15,7 @@ SRCS= avl.c \
uu_pname.c \
uu_strtoint.c
+WARNS?= 0
CFLAGS+= -DNATIVE_BUILD
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libuutil/common
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
diff --git a/cddl/lib/libzfs/Makefile b/cddl/lib/libzfs/Makefile
index 30c516b..3023a1de 100644
--- a/cddl/lib/libzfs/Makefile
+++ b/cddl/lib/libzfs/Makefile
@@ -32,6 +32,7 @@ SRCS+= zfs_deleg.c \
libzfs_sendrecv.c \
libzfs_status.c
+WARNS?= 0
CFLAGS+= -DZFS_NO_ACL
CFLAGS+= -I${.CURDIR}/../../../sbin/mount
CFLAGS+= -I${.CURDIR}/../../../cddl/lib/libumem
diff --git a/cddl/lib/libzpool/Makefile b/cddl/lib/libzpool/Makefile
index 808f583..2a33381 100644
--- a/cddl/lib/libzpool/Makefile
+++ b/cddl/lib/libzpool/Makefile
@@ -33,6 +33,7 @@ SRCS= ${ZFS_COMMON_SRCS} ${ZFS_SHARED_SRCS} \
${KERNEL_SRCS} ${LIST_SRCS} ${ATOMIC_SRCS} \
${UNICODE_SRCS}
+WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/include
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/lib/libumem
diff --git a/cddl/sbin/zfs/Makefile b/cddl/sbin/zfs/Makefile
index 4a9274e..591ef06 100644
--- a/cddl/sbin/zfs/Makefile
+++ b/cddl/sbin/zfs/Makefile
@@ -6,6 +6,7 @@ PROG= zfs
MAN= zfs.8
SRCS= zfs_main.c zfs_iter.c
+WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzpool/common
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/include
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/lib/libumem
diff --git a/cddl/sbin/zpool/Makefile b/cddl/sbin/zpool/Makefile
index 4b24dfb..06fd238 100644
--- a/cddl/sbin/zpool/Makefile
+++ b/cddl/sbin/zpool/Makefile
@@ -7,6 +7,7 @@ PROG= zpool
MAN= zpool.8
SRCS= zpool_main.c zpool_vdev.c zpool_iter.c zpool_util.c zfs_comutil.c
+WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzpool/common
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/include
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/lib/libumem
diff --git a/cddl/usr.bin/ctfconvert/Makefile b/cddl/usr.bin/ctfconvert/Makefile
index 57a08dd..08be1f0 100644
--- a/cddl/usr.bin/ctfconvert/Makefile
+++ b/cddl/usr.bin/ctfconvert/Makefile
@@ -1,13 +1,12 @@
# $FreeBSD$
-.include <bsd.own.mk>
-
-.include "../../Makefile.inc"
+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/tools/ctf/common
+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/tools/ctf/cvt
DEBUG_FLAGS= -g
PROG= ctfconvert
-
+NO_MAN=
SRCS= alist.c \
ctf.c \
ctfconvert.c \
@@ -29,8 +28,6 @@ SRCS= alist.c \
traverse.c \
util.c
-WARNS?= 6
-
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
-I${.CURDIR}/../../../cddl/compat/opensolaris/include \
-I${OPENSOLARIS_USR_DISTDIR} \
@@ -40,12 +37,7 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
-I${OPENSOLARIS_USR_DISTDIR}/tools/ctf/cvt \
-I${OPENSOLARIS_SYS_DISTDIR}/uts/common
-LDADD+= -lctf -ldwarf -lelf -lz -lthr
-
-.PATH: ${.CURDIR}
-.PATH: ${OPENSOLARIS_USR_DISTDIR}/tools/ctf/common
-.PATH: ${OPENSOLARIS_USR_DISTDIR}/tools/ctf/cvt
-
-MK_MAN= no
+DPADD= ${LIBCTF} ${LIBDWARF} ${LIBELF} ${LIBZ} ${LIBPTHREAD}
+LDADD= -lctf -ldwarf -lelf -lz -lpthread
.include <bsd.prog.mk>
diff --git a/cddl/usr.bin/ctfdump/Makefile b/cddl/usr.bin/ctfdump/Makefile
index 9a65c15..9b713c2 100644
--- a/cddl/usr.bin/ctfdump/Makefile
+++ b/cddl/usr.bin/ctfdump/Makefile
@@ -1,15 +1,14 @@
# $FreeBSD$
-.include "../../Makefile.inc"
+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/tools/ctf/common
+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/tools/ctf/dump
PROG= ctfdump
-
+NO_MAN=
SRCS= dump.c \
symbol.c \
utils.c
-WARNS?= 6
-
CFLAGS+= -I${OPENSOLARIS_USR_DISTDIR} \
-I${OPENSOLARIS_SYS_DISTDIR} \
-I${OPENSOLARIS_USR_DISTDIR}/head \
@@ -19,13 +18,7 @@ CFLAGS+= -I${OPENSOLARIS_USR_DISTDIR} \
-I${OPENSOLARIS_USR_DISTDIR}/tools/ctf/common \
-I${OPENSOLARIS_SYS_DISTDIR}/uts/common
-LDFLAGS+= -pthread
-
-LDADD+= -lelf -lz
-
-.PATH: ${OPENSOLARIS_USR_DISTDIR}/tools/ctf/common
-.PATH: ${OPENSOLARIS_USR_DISTDIR}/tools/ctf/dump
-
-NO_MAN=
+DPADD= ${LIBPTHREAD} ${LIBELF} ${LIBZ}
+LDADD= -lpthread -lelf -lz
.include <bsd.prog.mk>
diff --git a/cddl/usr.bin/ctfmerge/Makefile b/cddl/usr.bin/ctfmerge/Makefile
index 051fa0b..ef3b4bf 100644
--- a/cddl/usr.bin/ctfmerge/Makefile
+++ b/cddl/usr.bin/ctfmerge/Makefile
@@ -1,13 +1,10 @@
# $FreeBSD$
-.include <bsd.own.mk>
-
-.include "../../Makefile.inc"
-
-WARNS= 1
+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/tools/ctf/common
+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/tools/ctf/cvt
PROG= ctfmerge
-
+NO_MAN=
SRCS= alist.c \
barrier.c \
ctf.c \
@@ -26,7 +23,7 @@ SRCS= alist.c \
traverse.c \
util.c
-WARNS?= 6
+WARNS?= 1
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
-I${.CURDIR}/../../../cddl/compat/opensolaris/include \
@@ -37,11 +34,7 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
-I${OPENSOLARIS_USR_DISTDIR}/tools/ctf/cvt \
-I${OPENSOLARIS_SYS_DISTDIR}/uts/common
-LDADD+= -lctf -ldwarf -lelf -lz -lthr
-
-.PATH: ${OPENSOLARIS_USR_DISTDIR}/tools/ctf/common
-.PATH: ${OPENSOLARIS_USR_DISTDIR}/tools/ctf/cvt
-
-MK_MAN= no
+DPADD= ${LIBCTF} ${LIBDWARF} ${LIBELF} ${LIBZ} ${LIBPTHREAD}
+LDADD= -lctf -ldwarf -lelf -lz -lpthread
.include <bsd.prog.mk>
diff --git a/cddl/usr.bin/sgsmsg/Makefile b/cddl/usr.bin/sgsmsg/Makefile
index 5414414..8d1f70f 100644
--- a/cddl/usr.bin/sgsmsg/Makefile
+++ b/cddl/usr.bin/sgsmsg/Makefile
@@ -1,20 +1,17 @@
# $FreeBSD$
-.include "../../Makefile.inc"
+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/cmd/sgs/tools/common
+.PATH: ${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/avl
# This program is required as a bootstrap tool for 'make buildworld'
PROG= sgsmsg
-
+NO_MAN=
SRCS= avl.c sgsmsg.c string_table.c findprime.c
+WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
-I${.CURDIR}/../../../cddl/compat/opensolaris/include \
-I${OPENSOLARIS_USR_DISTDIR}/cmd/sgs/include \
-I${OPENSOLARIS_SYS_DISTDIR}/uts/common
-.PATH: ${OPENSOLARIS_USR_DISTDIR}/cmd/sgs/tools/common
-.PATH: ${OPENSOLARIS_SYS_DISTDIR}/common/avl
-
-NO_MAN=
-
.include <bsd.prog.mk>
diff --git a/cddl/usr.bin/zinject/Makefile b/cddl/usr.bin/zinject/Makefile
index c8693fe..dc6de45 100644
--- a/cddl/usr.bin/zinject/Makefile
+++ b/cddl/usr.bin/zinject/Makefile
@@ -6,6 +6,7 @@ PROG= zinject
SRCS= zinject.c translate.c
NO_MAN=
+WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
CFLAGS+= -I${.CURDIR}/../../compat/opensolaris/include
CFLAGS+= -I${.CURDIR}/../../compat/opensolaris/lib/libumem
@@ -19,7 +20,7 @@ CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/head
CFLAGS+= -I${.CURDIR}/../../lib/libumem
DPADD= ${LIBAVL} ${LIBGEOM} ${LIBM} ${LIBNVPAIR} ${LIBUMEM} ${LIBUUTIL} \
- ${LIBZFS} ${LIBZPOOL} ${LIBUUTIL}
+ ${LIBZFS} ${LIBZPOOL}
LDADD= -lavl -lgeom -lm -lnvpair -lumem -luutil -lzfs -lzpool
.include <bsd.prog.mk>
diff --git a/cddl/usr.bin/ztest/Makefile b/cddl/usr.bin/ztest/Makefile
index 67ade45ad..8bb69b1 100644
--- a/cddl/usr.bin/ztest/Makefile
+++ b/cddl/usr.bin/ztest/Makefile
@@ -5,6 +5,7 @@
PROG= ztest
NO_MAN=
+WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
CFLAGS+= -I${.CURDIR}/../../compat/opensolaris/include
CFLAGS+= -I${.CURDIR}/../../compat/opensolaris/lib/libumem
diff --git a/cddl/usr.sbin/dtrace/Makefile b/cddl/usr.sbin/dtrace/Makefile
index 44116fc..b8c668b 100644
--- a/cddl/usr.sbin/dtrace/Makefile
+++ b/cddl/usr.sbin/dtrace/Makefile
@@ -1,14 +1,12 @@
# $FreeBSD$
-.include "../../Makefile.inc"
+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/cmd/dtrace
PROG= dtrace
-
-BINDIR?= /usr/sbin
-
SRCS= dtrace.c
+BINDIR?= /usr/sbin
-WARNS= 1
+WARNS?= 1
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
-I${.CURDIR}/../../../cddl/compat/opensolaris/include \
@@ -18,20 +16,11 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
-I${OPENSOLARIS_SYS_DISTDIR}/uts/common \
-I${OPENSOLARIS_SYS_DISTDIR}/compat
-.PATH: ${OPENSOLARIS_USR_DISTDIR}/cmd/dtrace
-
# Optional debugging stuff...
#CFLAGS+= -DNEED_ERRLOC
#YFLAGS+= -d
-LDFLAGS+= -pthread \
- -L${.OBJDIR}/../../lib/libdtrace \
- -L${.OBJDIR}/../../lib/libproc \
- -L${.OBJDIR}/../../lib/libctf \
- -L${.OBJDIR}/../../../lib/libelf
-
-LDADD+= -ldtrace -ly -ll -lproc -lctf -lelf -lz
-
-DPADD+= ${LIBDTRACE} ${LIBCTF} ${LIBELF} ${LIBPTHREAD} ${LIBL} ${LIBY} ${LIBZ}
+DPADD= ${LIBPTHREAD} ${LIBDTRACE} ${LIBY} ${LIBL} ${LIBPROC} ${LIBCTF} ${LIBELF} ${LIBZ}
+LDADD= -lpthread -ldtrace -ly -ll -lproc -lctf -lelf -lz
.include <bsd.prog.mk>
diff --git a/cddl/usr.sbin/lockstat/Makefile b/cddl/usr.sbin/lockstat/Makefile
index 9c135f9..6cf7009 100644
--- a/cddl/usr.sbin/lockstat/Makefile
+++ b/cddl/usr.sbin/lockstat/Makefile
@@ -1,14 +1,13 @@
# $FreeBSD$
-.include "../../Makefile.inc"
+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/cmd/lockstat
PROG= lockstat
-
-BINDIR?= /usr/sbin
-
+NO_MAN=
SRCS= lockstat.c sym.c
+BINDIR?= /usr/sbin
-WARNS= 1
+WARNS?= 1
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
-I${.CURDIR}/../../../cddl/compat/opensolaris/include \
@@ -19,22 +18,11 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
-I${OPENSOLARIS_SYS_DISTDIR}/compat \
-I${.CURDIR}/../../../sys
-.PATH: ${OPENSOLARIS_USR_DISTDIR}/cmd/lockstat
-
CFLAGS+= -DNEED_ERRLOC -g
#YFLAGS+= -d
-LDFLAGS+= -pthread \
- -L${.OBJDIR}/../../lib/libdtrace \
- -L${.OBJDIR}/../../lib/libproc \
- -L${.OBJDIR}/../../lib/libctf \
- -L${.OBJDIR}/../../../lib/libelf
-
-LDADD+= -ldtrace -ly -ll -lproc -lctf -lelf -lz -lrt
-
-#DPADD+= ${LIBDTRACE} ${LIBPTHREAD} ${LIBL} ${LIBY} ${LIBZ}
-
-NO_MAN=
+DPADD= ${LIBPTHREAD} ${LIBDTRACE} ${LIBY} ${LIBL} ${LIBPROC} ${LIBCTF} ${LIBELF} ${LIBZ} ${LIBRT}
+LDADD= -lpthread -ldtrace -ly -ll -lproc -lctf -lelf -lz -lrt
.include <bsd.prog.mk>
diff --git a/cddl/usr.sbin/zdb/Makefile b/cddl/usr.sbin/zdb/Makefile
index 35ad2a1..b98038e 100644
--- a/cddl/usr.sbin/zdb/Makefile
+++ b/cddl/usr.sbin/zdb/Makefile
@@ -6,6 +6,9 @@ PROG= zdb
MAN= zdb.8
SRCS= zdb.c zdb_il.c
+WARNS?= 0
+CSTD= c99
+
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/include
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/lib/libumem
@@ -23,6 +26,5 @@ DPADD= ${LIBAVL} ${LIBGEOM} ${LIBM} ${LIBNVPAIR} ${LIBPTHREAD} ${LIBUMEM} \
${LIBUUTIL} ${LIBZ} ${LIBZFS} ${LIBZPOOL}
LDADD= -lavl -lgeom -lm -lnvpair -lpthread -lumem -luutil -lz -lzfs -lzpool
-CSTD= c99
.include <bsd.prog.mk>
diff --git a/contrib/bc/AUTHORS b/contrib/bc/AUTHORS
deleted file mode 100644
index b665a63..0000000
--- a/contrib/bc/AUTHORS
+++ /dev/null
@@ -1,4 +0,0 @@
-Phil Nelson <philnelson@acm.org> wrote bc, including the number.c
-source in the "lib" directory.
-
-Ken Pizzini wrote dc.
diff --git a/contrib/bc/ChangeLog b/contrib/bc/ChangeLog
deleted file mode 100644
index f277079..0000000
--- a/contrib/bc/ChangeLog
+++ /dev/null
@@ -1,1043 +0,0 @@
-Wed Sep 27 17:19:48 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * doc/bc.texi: Added new file. Mainly translated from bc.1
- by Brian Youmans.
- doc/bc.1: Minor changes made as part of reviewing bc.texi.
-
-Wed Sep 20 11:45:00 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/bc.y: Added a comment on the meanings of lvals.
-
-Wed Sep 13 11:40:24 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/main.c: add --interactive to long options.
- bc/bc.1: add -i/--interactive to doc.
- MANY: Update FSF address and Phil's e-mail.
-
-Tue Sep 12 13:58:16 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * NEWS: update for recent changes.
- bc/bc.y: remove required parens around return expression.
- doc/bc.1: update for recent changes.
-
-Fri Sep 8 10:20:01 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/Makefile.am, dc/Makefile.am, lib/Makefile.am:
- Compile with unsigned characters.
- bc/main.c: Add --help option.
- bc/scan.l: Print illegal, non-printable characters in octal.
-
-Fri Sep 8 09:36:54 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/bc.y: Allow more newlines in function definitions.
- bc/proto.h: Don't prototype main.
-
-Fri Sep 1 16:09:50 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/bc.y: Spelling correction
- bc/execute.c: Correct expressions for multi-byte names.
- bc/load.c: Add parens for correct casting.
- doc/bc.1: Typos.
- Above fixes pointed out by kwzh@gnu.org (Karl Heuer).
-
-Tue Aug 29 23:03:30 PDT 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * lib/testmul.c: #ifdef out a declaration matching #ifdef out
- code.
-
-Mon Jul 31 07:01:42 2000 Ken Pizzini <ken@gnu.org>
-
- * dc/numeric.c: use of the "n" command can cause a number to be printed
- without a trailing newline, which would cause the column counter to
- fail to be reset and result in inappropriately wrapped numeric outputs.
- Fixed by always clearing the column counter before outputting each number.
-
- * dc/stack.c: if a stack is used without ever using the correspondingly
- named register, it is perfectly legitimate for the register to be
- uninitialized; added an "else if" to handle this case without aborting.
-
- * dc/eval.c: updated the comment explaining the restrictions
- on the | command to better reflect reality.
-
- * doc/dc.texi: update the FSF office address in the copyright notice
-
-Thu Jul 13 18:13:00 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * README: note --with-libedit configure parameter.
-
-Tue Jun 20 22:52:10 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/bcdefs.h: Include <readline/history.h> to quiet warnings.
-
- * configure.in: make --with-readline and --with-libedit work correctly.
-
- * Makefile.am: use $(MAKE) instead of directly calling make.
-
- * lib/testmul.c: Update to use bc_ on all number.c routines.
-
-Sat Jun 10 22:44:29 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/Makefile.am: Add scan.c to maintainer-clean target.
-
- * acconfig.h configure.in stamp-h.in bc/Makefile.am bc/execute.c
- bc/fix-libmath_h bc/global.c bc/load.c bc/main.c bc/storage.c:
- Remove long string for libmath. Clean up for compiler errors.
-
- * dc/numeric.c: Correct parameter name.
-
-Wed May 10 15:51:16 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * {bc,doc,dc,lib}/Makefile.am: Add Makefile.in to maintainer-clean.
-
- * bootstrap.sh: Added script to run the auto* tools.
-
- * Imported all into CVS tree.
-
-Sun 2000-05-07 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/Makefile.am, dc/Makefile.am, lib/Makefile.am: Add -Wall to CFLAGS.
-
- * bc/{execute.c,proto.h,storage.c,util.c}, dc/numeric.c: Changes for
- -Wall and for name changes in lib/number.c. (Added bc_ to several
- routine. Updated copyright notice.)
-
- * h/number.h, lib/number.c: Now comes from bcmath library which is
- distributed in a different place.
-
-Wed Mar 29 17:47:34 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/{bc.y,bcdefs.h,global.h,main.c,proto.h,scan.l,storage.c}:
- Added BSD libedit support. Generic support for both where possible.
- Fixed bugs in readline support noticed during libedit addition.
- Works with NetBSD-1.4.1 libedit.
- * doc/bc.1: Documented libedit addition.
-
-Wed Mar 29 10:20:18 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * FAQ: Added this file.
- * Makfile.am: Added FAQ to distribution
-
-Tue Mar 28 13:52:35 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * lib/number.c, h/number.h: Moved definitions so
- number.c/number.h is a stand-alone "library".
- Changed definition of out_num to not reference a global.
- * lib/testmul.c: updated #includes for number.h changes.
- * h/{bcdefs.h,const.h,global.h,proto.h} moved to
- bc where they really belong.
- * bc/execute.c: Changed calls to out_num for correctness.
- * dc/numeric.c: Changed calls to out_num for correctness,
- include only number.h now and not all the other junk.
- * configure.in, acconfig.h: Start of support for BSD libedit,
- added --with-pkg for NetBSD /usr/pkg tree.
-
-Tue Mar 28 11:20:00 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * Test/{exp.b,fact.b,jn.b,mul.b,raise.b}: Tweeks on the tests
- run to do more computation and test the recursive multiply.
- * bc/scan.l: Removed a printf('\r') that was unneeded.
-
-Mon Mar 27 14:00:00 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * NEWS: Updated for 1.06.
- * lib/number.c, h/number.h: Fixed bugs in recursive multiply.
- Changed these files to be under the LGPL.
- * Tests/jn.b: Added more tests.
- * lib/Makefile.am: Only generate a timed version of number.o if
- requested.
- * README: Updated with information on how to generate a timed
- version of number.o.
- * h/version.h: Updated copyright and version number for dc.
-
-Thu Mar 16 14:01:45 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * doc/bc.1, doc/dc.1, doc/dc.texi: Changed bug reporting address
- to bug-bc@gnu.org to update with what we hope will be reality.
-
-Tue Feb 8 08:54:19 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * doc/bc.1, bc/util.c: Removed "multiply digits"
- limit due to new recursive algorithm that doesn't
- have those limits.
-
-Tue Feb 8 08:47:05 2000 Phil Nelson <phil@cs.wwu.edu>
-
- * lib/Makefile.am, lib/testmul.c, lib/number.c, Makefile.am:
- Finally got a resonable version of the program
- to test the crossover between non-recursive and
- recursive multiply algorithms. Added to distribution
- and build process. Does increase build time by
- about 10 minutes.
-
-Wed Oct 6 13:28:59 1999 Phil Nelson <phil@cs.wwu.edu>
-
- * lib/Makefile.am: Added rules to allow DEFSADD definitions.
-
-Sat Oct 2 19:59:51 1999 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/libmath.b: Correctly do the cosine accuracy.
-
-Fri Oct 1 12:41:51 1999 Phil Nelson <phil@cs.wwu.edu>
-
- * lib/number.c: Increase accuracy of computing raise.
- Also turn off use of recursive multiply routines
- until furthur testing.
- * bc/libmath.b: Increase accuracy of cosine.
- * bc/Makefile.am: Remove -lfl from items to make.
-
-Wed Jul 28 10:29:28 1999 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/scan.l: rl_len from char to int. (From FreeBSD
- bug tracking system and Nick Hibma <nick.hibma@jrc.it>)
-
-Tue Jun 22 08:00:28 1999 Phil Nelson <phil@cs.wwu.edu>
-
- * lib/number.c: Rewrote bc_multiply to use a faster
- algorithm. Old code not removed yet.
-
-Mon Jun 21 03:08:02 1999 Phil Nelson <phil@cs.wwu.edu>
-
- * h/version.h: Updated version number to 1.06.
- bc/bc.y: Corrected bug in for statement, not popping.
- bc/execute.c: Improved stack dump/instruction tracing.
-
-Tue Jun 15 22:30:42 1999 Phil Nelson <phil@cs.wwu.edu>
-
- * configure.in: Updated bc version to 1.06.
-
-Tue Jun 15 22:27:44 1999 Phil Nelson <phil@cs.wwu.edu>
-
- * h/bcdefs.h, h/const.h, bc/execute.c, bc/load.c, bc/storage.c,
- bc/util.c: Removed segmented function storaged. Now
- dynamically expands (by doubling, starting at 1024 bytes)
- to allow arbitrary sized functions.
-
-Thu Jun 10 22:33:44 1999 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/libmath.b: change scaling in computation of j(n,x) so
- it correctly computes the value.
-
-Wed Jun 10 10:10:10 1998 Release of bc-1.05a.
-
-Fri Apr 17 10:40:59 1998 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/main.c: Enable readline only if interactive.
-
-Thu Apr 16 16:49:22 1998 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/configure.in: Tweeking of AM_PROG_LEX and associated
- special case goo for solaris.
-
-Sat Mar 28 21:43:18 1998 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/Makefile.am: Added "YFLAGS = -d" to get bc.h to build properly.
-
-Mon Mar 9 12:54:42 PST 1998 Ken Pizzini <ken@halcyon.com>
-
- * doc/dc.texi, doc/dc.1: correct some documentation bugs.
-
-Sun Mar 8 23:56:24 PST 1998 Ken Pizzini <ken@halcyon.com>
-
- * dc/numeric.c: eliminate superfluous variable from dc_dump_num();
- annotate unused parameters in dc_add() and dc_sub().
-
- * h/version.h: change dc version number to 1.2 for release.
-
-Sun Mar 8 21:13:50 1998 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/main.c: Applied patch from Ken Pizzini to force line
- mode buffering on stdout.
-
-Tue Jan 6 09:15:04 PST 1998 Ken Pizzini <ken@halcyon.com>
-
- * h/version.h: dc is now up to version 1.1.5.
-
- * dc/eval.c, dc/numeric.c, doc/dc.texi, doc/dc.1: once again
- changed the behavior of the 'P' command with a numeric argument
- to make it more general. It now dumps out the *whole* number
- (or rather, the whole of its positive integer portion) as a
- byte stream. (For small values this is still the same as 'aP'.)
-
- * dc/dc-proto.h, dc/dc.h, dc/eval.c, dc/misc.c, dc/numeric.c,
- dc/stack.c, dc/string.c: Changed most uses of dc_boolean to
- either dc_discard or dc_newline, and instances of DC_TRUE and
- DC_FALSE to appropriate instances of DC_TOSS, DC_KEEP, DC_NONL,
- or DC_WITHNL so that the code self-documents a little better.
-
-Sun Jan 4 15:39:46 PST 1998 Ken Pizzini <ken@halcyon.com>
-
- * dc/eval.c, doc/dc.texi, doc/dc.1: Changed the functionality
- of the 'P' command, and added the 'n' command. Due to
- a quirk of the implementation of traditional dc, some
- people have come to expect that the 'P' command on a
- numeric argument in the range of 1 to 99 should output
- the corresponding character, despite the fact that this
- usage can have very weird results for numbers outside
- that range. This functionality is why the 'a' command
- was introduced last March, but people really want it to
- "just work" without needing to use the 'a' command.
- Bowing to this demand, the 'P' command now does the
- equivalent of "aP" if the argument is numeric, and the
- 'n' command has been added to support the previous
- functionality of the 'P' command.
-
- * dc/misc.c, dc/eval.c, dc/stack.c, dc/dc-proto.h:
- Changed prototype for dc_print(). It now additionally
- takes two flags, newline_p and discard_p, which it
- passes through to dc_out_num() and dc_out_str() as
- needed.
-
- * h/version.h: dc is now up to version 1.1.4.
-
-Sat Sep 27 13:48:53 1997 Ken Pizzini <ken@halcyon.com>
-
- * h/version.h: dc is now up to version 1.1.3.
-
- * dc/stack.c, dc/array.c, dc/dc-proto.h, doc/dc.texi, doc/dc.1:
- It has come to my attention that, though undocumented,
- traditional dc stacked its arrays in parallel with the
- stacking of simple registers. I have now duplicated
- this functionality.
-
- * dc/dc.c, configure.in: line-buffer dc's output if setvbuf()
- is supported. This was requested to simplify using dc as
- an inferior process under emacs.
-
-Fri Sep 26 19:56:15 1997 Ken Pizzini <ken@halcyon.com>
-
- * dc/dc.c: fixed bug reporting address for --help.
-
- * doc/dc.1, doc/dc.texi: corrected documentation of the maximum
- admissible input base.
-
- * doc/dc.texi: corrected sample code equivalence for the | command.
-
- * lib/number.c: added a warning for non-zero scale in the base
- for bc_raisemod().
-
-Fri Sep 26 18:15:31 1997 Ken Pizzini <ken@halcyon.com>
-
- * dc/eval.c, doc/dc.1, doc/dc.texi: added !=, !<, and !> commands.
-
- * dc/eval.c: eliminated double-free in 'a' command.
-
- * dc/dc.c: changed placment of check for filename "-" so that
- "-f -" will work.
-
- * h/version.h: updated dc version to 1.1.2.
-
-Thu Sep 18 17:41:10 1997 Ken Pizzini <ken@halcyon.com>
-
- * dc/eval.c: fixed off-by-one error for Q and q commands.
-
- * dc/dc.c: added missing f: to third argument of getopt().
-
- * h/version.h: updated dc version to 1.1.1.
-
-Thu May 22 08:24:08 1997 Phil Nelson <phil@cs.wwu.edu>
-
- * lib/number.c(bc_sqrt): Fixed a bug that computed 0 for sqrt
- of most numbers less than .000001.
-
-Thu May 1 10:41:38 1997 Phil Nelson <phil@cs.wwu.edu>
-
- * Test/timetest: change path to bc executable.
-
-Wed Apr 30 12:00:00 1997 Phil Nelson <phil@cs.wwu.edu>
-
- * Froze bc-1.04, started new directory for bc-1.05.
- Fixes to bc-1.04 will be distributed as bc-1.05.
-
-Mon Apr 21 14:57:14 1997 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/scan.l: Changed rules for single line comment to work
- with lex as well as flex. Also, do not include \n in the
- comment.
-
- * doc/bc.1: Clarified the single line comment and that \n
- is processed outside of the comment.
-
-Sun Apr 20 22:21:30 1997 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/scan.l: Added rules for a single line comment starting
- with the # character.
-
- * doc/bc.1: Documented the single line comment.
-
- * bc/Makefile.am: Added DISTCLEANFILES for proper clean up.
-
-Sat Apr 19 22:08:05 1997 Phil Nelson <phil@cs.wwu.edu>
-
- * dc/Makefile.am: Removed file from distribution list.
-
- * h/version.h: Updated dc version to 1.1.
-
-Fri Apr 18 16:43:04 1997 Phil Nelson <phil@cs.wwu.edu>
-
- * lib/number.c (bc_add, bc_sub) Added 1 to the length
- of the memset call to make sure it zeroed all the
- storage.
-
-Fri Apr 18 13:58:56 1997 Phil Nelson <phil@cs.wwu.edu>
-
- * configure.in: Tweeks to get things right. Not sure if things
- changed much. Still working with autoconf/automake to do
- the right thing.
-
-Wed Apr 16 16:49:17 1997 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/main.c (main): Changed processing of BC_ENV_ARGS.
-
- * bc/main.c (parse_args): Removed "start" parameter.
-
-Tue Apr 15 13:21:28 1997 Phil Nelson <phil@cs.wwu.edu>
-
- * acconfig.h: Included support for PACKAGE and VERSION.
-
- * configure.in: More tweeks for automake support.
-
- * h/number.h: Improve definition of MIN and MAX.
-
- * doc/bc.1: Changed copyright, tweeked other text, added
- e-mail address for bugs.
-
- * doc/dc.1: Added copyright and GPL license information,
- Changed a few .SH formats.
-
-Fri Apr 11 16:14:42 1997 Phil Nelson <phil@cs.wwu.edu>
-
- * Makefile.am configure.in doc/Makefile.am lib/Makefile.am
- bc/Makefile.am bc/bc.y dc/Makefile.am: Changes to accomodate
- automake-1.1n (pre-release version of automake 1.2).
-
- * bc/bc.y bc/sbc.y: Changes to make sure tokens are numbered the
- same in bc/bc.h and bc/sbc.h.
-
- * bc/scan.l: Changes for automake's naming convention.
-
- * NEWS: Fixed a typo.
-
-Thu Apr 10 14:42:55 1997 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/{execute.c, global.c, libmath.b, load.c, main.c, sbc.y
- scan.l, storage.c, util.c}: Changed copyright comment and
- added 1997 to copyright years.
-
- * h/{bcdefs.h, const.h, global.h, number.h proto.h, version.h}:
- Changed copyright comment and added 1997 to copyright years.
-
- * h/version.h: Changed bc version to 1.04.
-
- * lib/number.c: Changed copyright comment and added 1997 to
- copyright years.
-
- * lib/vfprintf.c: Noted that this was only for minix.
-
- * NEWS, README: README is now comp.sources.reviewed readme only.
- NEWS now lists changes from version to version.
-
-Thu Apr 10 13:41:56 1997 Phil Nelson <phil@fawn.cs.wwu.edu>
-
- * Makefile.am: Removed FIXME stuff.
-
-Thu Apr 8 13:39:53 1997 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/Makefile.am: Remove files that should not be distributed.
-
-Mon Apr 7 17:14:28 1997 Phil Nelson <phil@cs.wwu.edu>
-
- * Makefile.am: Removed Misc directory from distribution.
-
-Mon Apr 7 16:16:01 1997 Phil Nelson <phil@cs.wwu.edu>
-
- * bc/sbc.y: Corrected use of nextarg().
-
-Tue Mar 25 19:32:28 1997 Ken Pizzini <ken@halcyon.com>
-
- * dc/eval.c, dc/misc.c, dc/stack.c, dc/string.c,
- dc/dc.h, dc/dc-proto.h, dc/dc.c, dc/numeric.c,
- doc/dc.texi: updated years in copyright
- notices.
-
- * dc/dc.1: updated last-revision date.
-
-Tue Mar 25 16:35:46 1997 Ken Pizzini <ken@halcyon.com>
-
- * lib/number.c: give a run-time warning in bc_raisemod()
- if the modulus does not appear to be an integer.
-
- * doc/dc.texi, doc/dc.1: documented a warning against
- the use of the new | command in conjunction with a
- non-integral modulus.
-
-Tue Mar 25 15:36:04 1997 Ken Pizzini <ken@halcyon.com>
-
- * dc/string.c: dc_out_str() updated to use fwrite()
- instead of printf(), to allow for the existence of
- a NUL character in the string.
-
-Tue Mar 25 13:42:51 1997 Ken Pizzini <ken@halcyon.com>
-
- * doc/dc.texi, doc/dc.1: added documentation for new | command.
-
-Tue Mar 25 13:19:55 1997 Ken Pizzini <ken@halcyon.com>
-
- * dc/dc-proto.h: added prototype for dc_triop().
-
-Tue Mar 25 12:00:38 1997 Ken Pizzini <ken@halcyon.com>
-
- * lib/number.c: add bc_modexp() modular-exponentiation function.
-
- * h/proto.h: add prototypes for bc_modexp() and bc_divmod().
-
-Tue Mar 25 09:07:13 1997 Ken Pizzini <ken@halcyon.com>
-
- * doc/dc.texi, doc/dc.1: updated documentation with the
- new command-line options.
-
- * doc/dc.texi, doc/dc.1: updated documentation with the
- new '~', 'r', and 'a' commands.
-
- * dc/dc.c: added bug reporting information to --version text.
-
-Mon Mar 24 19:37:30 1997 Ken Pizzini <ken@halcyon.com>
-
- * lib/number.c: added new "bc_divmod" function.
-
- * dc/numeric.c: added new "dc_divrem" glue function to bc_divmod.
-
- * dc/stack.c: added new "dc_binop2" function.
-
- * dc/dc-proto.h: added new prototypes for dc_divrem() and dc_binop2().
-
- * dc/eval.c, dc/numeric.c: add new '~' command which
- returns both the quotient and remainder from division.
-
-Mon Mar 24 18:13:42 1997 Ken Pizzini <ken@halcyon.com>
-
- * dc/eval.c: Add new 'r' (reverse top two stack elements) command.
-
-Mon Mar 24 17:47:02 1997 Ken Pizzini <ken@halcyon.com>
-
- * dc/misc.c: split out the main() related functions into
- a seperate dc/dc.c file.
-
- * dc/Makefile.am: updated to reflect this split.
-
-Sat Mar 1 04:57:54 1997 Ken Pizzini <ken@halcyon.com>
-
- * dc/misc.c: added "--file" option.
-
-Sat Mar 1 02:13:06 1997 Ken Pizzini <ken@halcyon.com>
-
- * dc/eval.c: fixed bug of an excess increment in
- dc_evalstr()'s DC_COMMENT case. (Probably would
- never show up in practice, but did violate the
- letter of the C Standard.)
-
- * renamed dc/number.c to dc/numeric.c, to avoid
- confusion with lib/number.c.
-
-Thu Feb 27 19:45:45 1997 Ken Pizzini <ken@halcyon.com>
-
- * dc/string.c, dc/dc.h: changed implementation of dc_str
- type from a void * to a type which is only completed
- in dc/string.c. No functional change, just prettier code.
-
-Thu Feb 27 18:25:19 1997 Ken Pizzini <ken@halcyon.com>
-
- * Cleaned up Makefile.am files.
-
-Thu Feb 6 00:41:02 1997 Ken Pizzini <ken@halcyon.com>
-
- * Noticed pre-autoconf vestages (NO_XXX configuration options);
- fixed to refer to autoconf HAVE_XXX definitions.
-
- * The definition of BC_XXX values in h/const.h might
- conflict with values of the same name from <limits.h>;
- fixed to override without spewing warnings.
-
- * Added check for ptrdiff_t to configure.in; removed
- special ptrdiff_t definition from dc/string.c .
-
-Wed Feb 5 22:28:37 1997 Ken Pizzini <ken@halcyon.com>
-
- * Only compile (guts of) lib/vfprintf.c if system does
- not have its own version.
-
-Wed Feb 5 22:26:16 1997 Ken Pizzini <ken@halcyon.com>
-
- * Changed dc/misc.c source to use standard GNU option
- parsing routine (instead of special-case code).
-
- * Added "-e" option to dc.
-
- * Bumped dc version number to 1.0.4.
-
-Wed Feb 5 22:08:06 1997 Ken Pizzini <ken@halcyon.com>
-
- * rearranged source layout (added subdirectory structure);
- removed "dc-" prefix from dc C source in its new home.
-
- * merged bc's "version.h" and dc's "dc-version.h" files
- into h/version.h; patched dc/misc.c to refer to new
- DC_VERSION macro name.
-
- * Tweaked configure.in in anticipation of using automake.
-
-Wed Jul 24 16:27:20 1996 Phil Nelson <phil@cs.wwu.edu>
-
- * number.c (out_num): Move free of t_num to proper place.
-
-Mon Jun 3 00:31:10 1996 Phil Nelson <phil@cs.wwu.edu>
-
- * number.c: (bc_sqrt, is_near_zero) Was hanging in an infinite
- loop on sqrt(.9999). Rewrote to take difference. New routine
- is_near_zero to check for one digit off.
-
-Thu Feb 22 12:14:38 1996 Phil Nelson <phil@cs.wwu.edu>
-
- * dc-eval.c (dc_func): Added the 'a' (number to ascii character)
- command.
-
-Thu Feb 22 11:55:15 1996 Phil Nelson <phil@cs.wwu.edu>
-
- * dc-eval.c: (Changes from Ken) Changes dealing with stdin_lookahead
- and peekc.
-
- * dc-misc.c: (Changes from Ken) Changes in option processing.
-
- * dc-version.c: (Change from Ken) Version is 1.0.2.
-
-Mon Oct 9 15:40:06 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * execute.c (execute): Add a pop to 'W' and 'P' codes. Otherwise,
- the stack continues to grow.
-
- * number.c (out_num): Free all bc_nums used.
-
-Thu Jun 29 00:35:57 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * bc.1: Added information about long options and use of the
- readline library.
-
-Wed Jun 28 21:03:45 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * scan.l: rl_input: detect EOF.
-
-Wed Jun 28 19:03:51 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * Makefile.in: fbc target, changed $(LEXLIB) => $(LIBS)
-
-Wed Jun 28 01:33:07 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * acconfig.h, bc.y, scan.l, storage.c, util.c, configure.in:
- Improved readline support with a new pseudo variable "history"
- that controls the number of history lines available.
- Also removed "optional" history.
-
-Wed Jun 28 01:03:52 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * getopt.h, getopt.c, getopt1.c: Imported from glibc-1.09
- to allow long option processing.
-
- * main.c (parse_args): Make it use long arguments.
-
- * global.h: Change option flag variables from "char" to "int"
- to allow long_arguments easy access to the variables.
-
- * Makefile.in: Add getopt.h, getopt.c, and getopt1.c in the
- proper places in the Makefile.
-
-Fri Jun 23 12:00:16 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * scan.l, main.c (main), acconfig.h, configure.in:
- Added support for readline input on stdin.
-
-Thu Jun 22 20:08:57 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * bc.1: Change documentation on POSIX array parameter support.
-
-Fri Apr 7 12:29:28 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * main.c (parse_args): change "char ch" to "int optch" with
- related changes.
-
-Thu Mar 23 04:11:00 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * bc.1: Update documentation to include new -q
- option and the environment variables.
-
-Thu Mar 23 03:30:38 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * bcdefs.h, global.h, main.c, util.c, bc.y: Reworked
- argument processing to allow for getting arguments
- from the environment and the command line. Added
- a new mechanism to access file names for opening
- and for error messages. Also added a "quiet"
- option to turn off the welcome banner.
-
-Thu Mar 23 03:12:11 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * util.c: Corrected a comment.
-
-Tue Mar 21 13:36:24 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * bc.y: Added "opt_newline" to allow more newlines
- in non-POSIX mode.
-
-Tue Mar 21 09:38:28 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * execute.c, main.c, util.c: Add support for user
- defined line length, "correct POSIX line length",
- no breaking of strings in std_only mode. This
- included adding a new function "out_schar" to
- util.c. Also removed "if (interactive)" before
- all fflushes.
-
-Tue Mar 21 09:12:16 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * global.h: Added new variable "line_size". Cleaned up
- some definitions by adding comments.
-
-Mon Mar 20 23:33:01 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * proto.h: Define getopt only if no unistd.h file.
-
-Mon Mar 20 23:23:34 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * number.c, proto.h, execute.c, storage.c, dc-number.c:
- Changes to bc_add and bc_sub parameters to allow for
- different scale results than were possible. This is
- for correct implementation of modulo. All calls were
- updated.
-
-Mon Mar 20 19:26:06 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * sbc.y: Removed second parameter on calls to arg_str to match
- real function.
-
-Tue Feb 28 14:30:18 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * Makefile.in: Change realclean to maintainer-clean. Added warning.
-
-Mon Feb 27 17:08:24 1995 Phil Nelson <phil@cs.wwu.edu>
-
- * number.c: Change output to conform with POSIX standard for zero
- only when the -s flag is given. Otherwise it does the tradational
- thing.
-
- * dc-misc.c: Add the "std_only" flag, always set to zero. This is
- needed due to the above change.
-
-Tue Nov 29 15:18:20 1994 Phil Nelson <phil@cs.wwu.edu>
-
- * bc.1: Remove the "then" keyword in the if statement documentation.
-
-Mon Nov 28 16:50:25 1994 Phil Nelson <phil@cs.wwu.edu>
-
- * bc.1: Fixed a font change error.
-
- * Makefile.in: Added missing \ in two targets.
-
-Tue Nov 22 11:09:08 1994 Phil Nelson <phil@cs.wwu.edu>
-
- * bc.1: clarified ibase and math routines.
-
-Thu Nov 3 14:09:31 1994 Phil Nelson (phil@cs.wwu.edu)
-
- * Makefile.in: added targets uninstall, installdirs and modified
- other targets to get makes in a directory other than srcdir to
- work.
-
- * configure.in: added shell commands to get configure to work
- correctly in directories other than srcdir.
-
-Wed Nov 2 10:18:19 1994 Phil Nelson (phil@cs.wwu.edu)
-
- * bc.1 bc.y bcdefs.h const.h execute.c global.c global.h load.c
- main.c number.c number.h proto.h sbc.y scan.l storage.c util.c:
- updated copyright to 1994.
-
- * version.h: updated version number and copyright date.
-
- * Makefile.in, configure.in, Install: updated for use with
- autoconf-2.0 and install-sh. Changed target install a bit.
-
- * install-sh: Included this file from the autoconf-2.0
- distribution to have configure run without errors.
-
- * README: updated to version 1.03.
-
-Mon Oct 31 10:26:28 1994 Phil Nelson (phil@cs.wwu.edu)
-
- * Added Ken Pizzini's dc implementation that uses bc numeric
- routines. The following files have been added:
- dc-Concerns dc-array.c dc-eval.c dc-misc.c dc-number.c
- dc-proto.h dc-regdef.h dc-stack.c dc-string.c dc-version.h
- dc.1 dc.h dc.texinfo
-
- * dc-array.c: Added a conditional include of stdlib.h to get
- size_t defined on my SunOS 4.1.3 system.
-
- * configure.in: Added support for dc.
-
- * Makefile.in: Added support for dc. Added rule to make
- config.h.in.
-
-Sun Aug 7 15:09:19 1994 Phil Nelson (phil@cs.wwu.edu)
-
- * configure.in, Makefile.in, acconfig.h: Add support for autoconf.
- Removed old Makefile.
-
-Wed Jul 20 22:46:32 1994 Phil Nelson (phil@cs.wwu.edu)
-
- * bc.y: change definition of next_label in function definition.
- Previous value of 0 caused break to not work. It is now 1.
-
-Fri Apr 8 14:16:37 1994 Phil Nelson (phil@cs.wwu.edu)
-
- * Makefile: Change the distribution to include libmath.h.dist
- which is a copy of libmath.h that has the compiled libmath.b.
-
-Sun Feb 13 01:08:14 1994 Phil Nelson (phil@cs.wwu.edu)
-
- * execute.c: Change the string quote characters to be more like
- C. \a => alert (bell) \b => backspace and added \q => ".
-
- * bc.1: Updated information on above changes.
-
-Wed Oct 27 23:34:40 1993 Phil Nelson (phil@cs.wwu.edu)
-
- * Makefile: Changed compress to gzip. Changed the
- comment and definition of the DOT_IS_LAST compile option.
-
- * scan.l: Changed DOT_IS_LAST to NO_DOT_LAST and changed
- the test so "." is the last variable is standard.
-
-Wed May 19 15:15:12 1993 Phil Nelson (phil at cs.wwu.edu)
-
- * number.c: Fixed output of negative numbers in bases other than
- base 10.
-
-Wed Apr 21 11:56:31 1993 Phil Nelson (phil at cs.wwu.edu)
-
- * bc.1: Changed Steve Sommars e-mail address.
-
-Wed Apr 14 12:13:39 1993 Phil Nelson (phil at cs.wwu.edu)
-
- * sbc.y: removed leading , on first line.
-
-Wed Mar 31 16:12:39 1993 Phil Nelson (phil at cs.wwu.edu)
-
- * bc.1: Updated segment number for function bodies.
-
-Thu Mar 11 15:34:34 1993 Phil Nelson (phil at cs.wwu.edu)
-
- * Makefile: added version.h to bc.o's dependency list.
-
-Mon Mar 1 14:00:46 1993 Phil Nelson (phil at cs.wwu.edu)
-
- * util.c: (nextarg) changed parameter "val" to be an int.
-
-Tue Feb 16 10:06:45 1993 Phil Nelson (phil at cs.wwu.edu)
-
- * util.c: (call_str, arg_str) added a function call_str that
- correctly produces the string of argmuent types for a function
- call. arg_str produced them in the reverse order. This
- eliminated the need for the "comma" argument to arg_str, which
- was removed.
-
- * bc.y: changed the calls to arg_str to have only one parameter
- in the function definition rule and replaced the call to arg_str
- with call_str in the function call rule.
-
-Tue Nov 24 17:38:40 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * Makefile: Added LEXLIB definitions for use with lex.
-
-Thu Oct 22 13:43:16 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * number.c (bc_raise): Rearranged and added code to speed up
- the computation by not doing unneeded multiplications.
-
-Wed Sep 30 10:43:52 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * global.h: Fixed documentation.
-
-Tue Sep 29 15:27:50 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * storage.c (process_params): Changed processing of more arguments
- than in a function definition to just a return.
-
- * Makefile: Made changes to make it more in conformance with the
- GNU coding standards.
-
-Tue Jul 7 21:09:07 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * (const.h, bc.y, util.c) Added code so that when the math
- library is loaded, redefinition of any math library function
- will not cause the other functions to quit working correctly.
- Before this change, redefining a(x) would cause s(x) and c(x)
- to quit working and redefining s(x) would cause c(x) to quit
- working.
-
-Wed Jul 1 14:35:29 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * (libmath.b) Changed the calculation of scale for computing
- e(x) and l(x). This provides a little more accuracy in the
- last digit at the expense of a little speed.
-
- * (Test/checklib.b) Changed tests to be parameterized and test
- more values.
-
-Thu Jun 25 09:22:59 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * (configure) changed the script from looking in the
- include directory for a .h file to asking cc (gcc) to
- find the .h file. This will allow better detection
- of include files available to the C compiler.
-
-Wed Jun 24 22:11:37 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * (bc.y) Added a warning for the "last" variable.
-
- * (scan.l) Added code to allow for a single dot (.) to be the
- same as the variable "last". This is not a "standard" feature,
- but is provided for those who want it.
-
- * (Install) Documented the new define for dot (.).
-
- * (bc.1) Documented the use of dot (.) for "last".
-
- * (Makefile) Added an easy method for adding extra defines for
- use during the compile. Set DOT_IS_LAST as a standard
- extra define.
-
- * (number.c) Changed the code for sqrt for better speed.
-
-Mon Jun 22 21:47:05 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * Changed the name of math.h to libmath.h to avoid conflict
- with /usr/include/math.h. Changed all references to math.h
- to libmath.h in all files.
-
- * (configure) Changed the test for long strings accepted by
- cc to not include libmath.h and thus not need to distribute
- a file that is generated by the system.
-
- * (Makefile) Changed PREFIX, BINDIR, LIBDIR, and MANDIR to
- lower case.
-
-Tue Mar 3 10:16:07 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * (main.c) Added missing } at line 140.
-
- * (version.h) Changed date of version 1.02 to March 3, 1992.
-
-Mon Feb 3 16:07:57 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * (version.h) Updated version number and date.
-
- * (bc.1) Added a new "VERSION" section.
-
-Wed Jan 29 14:13:55 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * (execute.c) Removed the setjmp and longjmp calls that may have
- caused some problems with interrupted programs.
-
-Thu Jan 16 17:08:16 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * (Makefile) Changed install to install the manual.
-
-Wed Jan 8 13:23:42 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * Change all copyright notices to include 1992.
-
- * (load.c) Added termination to "load_code" to ignore code
- after an error has been found.
-
- * (scan.l) Changed the check for NUL characters in STRING tokens
- (before the close quote) to work correctly. Also added code to
- report illegal characters in a more readable output format.
-
- * (bc.1) Added the exclusion of NUL characters from strings in
- the "differences" section and updated date of last change.
-
- * (const.h) Changed BC_MAX_SEGS to 16.
-
-Mon Jan 6 14:20:02 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * (number.c) Changed the out_num routine to use a correct field
- size for bases greater than 16. e.g. For base 1000, each
- "digit" is a three digit number.
-
- * (Makefile) Added the "8" flag to get an 8 bit scanner.
-
- * (scan.l) Changed "char *" to "unsigned char *" to match the
- declaration of yytext for the 8 bit scanner. Also added code
- to detect the null character in strings and generate an error.
-
-Sat Jan 4 20:32:20 1992 Phil Nelson (phil at cs.wwu.edu)
-
- * (const.h) Changed BC_BASE_MAX to INT_MAX to allow more bases!
-
-Mon Dec 30 21:47:28 1991 Phil Nelson (phil at cs.wwu.edu)
-
- * (main.c) Fixed the bug that loaded the math library before
- every file.
-
- * (bc.y) Removed some type declarations that duplicated token
- definitions so it could be run through bison.
-
- * (load.c) Added a check for maximum code size.
-
- * (Makefile) Added a prefix for LIBDIR and BINDIR so it can be
- changed easily.
-
-Mon Nov 25 13:11:17 1991 Phil Nelson (phil at cs.wwu.edu)
-
- * Changed version number in version.h to 1.01 with current date.
-
- * Changed LIBFILE definition in Makefile.
-
- * Added a recursive function example to bc.1.
-
-Sun Nov 24 21:24:01 1991 Phil Nelson (phil at cs.wwu.edu)
-
- * Changed the Makefile to make sure configure is run first.
- Added the $(CC) the configure call. Moved some defines
- toward the front of the Makefile to make sure they are
- read by installers. Also added SUBDIRS variable and updated
- the GNU distribution to include the subdirectories. Included
- math.h in the distribution for use by configure. Included
- ChangeLog in the distribution.
-
- * Split the README into README and Install. Changed Install
- to have current information. Documented the STRINGS_H define.
- Updated the version number in README.
-
- * Added a check for <strings.h> in configure.
-
-Fri Nov 22 15:06:32 1991 Phil Nelson (phil at cs.wwu.edu)
-
- * Changed configure to check for varargs.h first. Also, added
- checks to see if long strings (math.h) are accepted by the
- C compiler. Also added parameters to configure.
-
- * Deleted #include <sys/types.h> from proto.h. Also made only
- ANSI C compilers include <stdlib.h>.
-
- * Changed the Makefile to have the install bin directory be
- /usr/local/bin and the install lib directory be /usr/local/lib.
-
- * Changed some files in the Test directory to eliminate the
- <op>= form that some older bcs don't like.
-
- * Made some small corrections in bc.1.
-
-Tue Oct 29 10:06:32 1991 Phil Nelson (phil at cs.wwu.edu)
-
- * Called current version 1.00.
-
- * Submitted GNU bc-1.00 to comp.sources.reviewed
diff --git a/contrib/bc/Examples/ckbook.b b/contrib/bc/Examples/ckbook.b
deleted file mode 100644
index 5815ea0..0000000
--- a/contrib/bc/Examples/ckbook.b
+++ /dev/null
@@ -1,16 +0,0 @@
-scale=2
-print "\nCheck book program!\n"
-print " Remember, deposits are negative transactions.\n"
-print " Exit by a 0 transaction.\n\n"
-
-print "Initial balance? "; bal = read()
-bal /= 1
-print "\n"
-while (1) {
- "current balance = "; bal
- "transaction? "; trans = read()
- if (trans == 0) break;
- bal -= trans
- bal /= 1
-}
-quit
diff --git a/contrib/bc/Examples/pi.b b/contrib/bc/Examples/pi.b
deleted file mode 100644
index 0d840cf..0000000
--- a/contrib/bc/Examples/pi.b
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- This is a program to determine the distribution of digits in the
- fraction part of PI. It will look at the first scale digits.
-
- The results are left in the global variable digits.
- digits[0] is the number of 0's in PI.
-
- This program requires the math library.
-*/
-
-define pi () {
- auto ix, pi, save_scale, work;
-
- save_scale = scale;
- scale += 5;
- print "\n\nCalculating PI to ",scale," digits. Please wait . . .";
- pi = 4*a(1);
- scale -= 5;
- work = pi;
-
- print "\nCounting digits. . .";
- for (ix = 0; ix < 10; ix++) digits[ix] = 0;
-
- /* Extract the One's digit from pi. */
- scale = 0;
- one_digit = work / 1;
-
- for (ix = save_scale; ix > 0; ix--) {
-
- /* Remove the One's digit and multiply by 10. */
- scale = ix;
- work = (work - one_digit) / 1 * 10;
-
- /* Extract the One's digit. */
- scale = 0;
- one_digit = work / 1;
-
- digits[one_digit] += 1;
- }
-
- /* Restore the scale. */
- scale = save_scale;
-
- /* Report. */
- print "\n\n"
- print "PI to ", scale, " digits is:\n", pi/1, "\n\n"
- print "The frequency of the digits are:\n"
- for (ix = 0; ix < 10; ix++) {
- print " ", ix, " - ", digits[ix], " times\n"
- }
-
- print "\n\n"
-}
diff --git a/contrib/bc/Examples/primes.b b/contrib/bc/Examples/primes.b
deleted file mode 100644
index 2b52ca7..0000000
--- a/contrib/bc/Examples/primes.b
+++ /dev/null
@@ -1,32 +0,0 @@
-
-/* An example that finds all primes between 2 and limit. */
-
-define primes (limit) {
- auto num, p, root, i
-
- prime[1] = 2;
- prime[2] = 3;
- num = 2;
- if (limit >= 2) print "prime 1 = 2\n"
- if (limit >= 3) print "prime 2 = 3\n";
- scale = 0;
-
- for ( p=5; p <= limit; p += 2) {
- root = sqrt(p);
- isprime = 1;
- for ( i = 1; i < num && prime[i] <= root; i++ ) {
- if ( p % prime[i] == 0 ) {
- isprime = 0;
- break;
- }
- }
- if (isprime) {
- num += 1;
- prime [num] = p;
- print "prime ", num, " = ", p, "\n"
- }
- }
-}
-
-
-print "\ntyping 'primes (10)' will print all primes less than 10.\n"
diff --git a/contrib/bc/Examples/twins.b b/contrib/bc/Examples/twins.b
deleted file mode 100644
index de910a7..0000000
--- a/contrib/bc/Examples/twins.b
+++ /dev/null
@@ -1,40 +0,0 @@
-
-/* An example that finds all primes between 2 and limit. */
-
-define primes (limit) {
- auto num, p, root, i
-
- prime[1] = 2;
- prime[2] = 3;
- num = 2;
- scale = 0;
-
- for ( p=5; p <= limit; p += 2) {
- root = sqrt(p);
- isprime = 1;
- for ( i = 1; i < num && prime[i] <= root; i++ ) {
- if ( p % prime[i] == 0 ) {
- isprime = 0;
- break;
- }
- }
- if (isprime) {
- num += 1;
- prime [num] = p;
- }
- }
-}
-
-
-print "\ntyping 'twins (10)' will print all twin primes less than 10.\n"
-
-define twins (limit) {
- auto i;
-
- i = primes(limit+2);
-
- for (i=1; prime[i] > 0; i++) {
- if ((prime[i]+2) == prime[i+1]) \
- print "twins are ", prime[i], " and ", prime[i+1], "\n"
- }
-}
diff --git a/contrib/bc/FAQ b/contrib/bc/FAQ
deleted file mode 100644
index 32dd051..0000000
--- a/contrib/bc/FAQ
+++ /dev/null
@@ -1,17 +0,0 @@
-Because of frequent questions ....... here is the BC FAQ
-
-
-1) Why does BC have its own arbitrary precision number routines
- (found in lib/number.c) rather than using GMP?
-
-GMP has "integers" (no digits after a decimal), "rational numbers"
-(stored as 2 integers) and "floats". None of these will correctly
-represent a POSIX BC number. Floats are the closest, but will not
-behave correctly for many computations. For example, BC numbers have
-a "scale" that represent the number of digits to represent after the
-decimal point. The multiplying two of these numbers requires one to
-calculate an exact number of digits after the decimal point regardless
-of the number of digits in the integer part. GMP floats have a
-"fixed, but arbitrary" mantissa and so multiplying two floats will end
-up dropping digits BC must calculate.
-
diff --git a/contrib/bc/FREEBSD-upgrade b/contrib/bc/FREEBSD-upgrade
deleted file mode 100644
index 0174d7b..0000000
--- a/contrib/bc/FREEBSD-upgrade
+++ /dev/null
@@ -1,14 +0,0 @@
-$FreeBSD$
-
-bc 1.0.5a
- originals can be found at: ftp://prep.ai.mit.edu/pub/gnu/
- removed no subdirectories
- removed bc/scan.c bc/bc.c bc/bc.h doc/texinfo.tex doc/dc.info
- removed */getopt*
- obrien@FreeBSD.ORG
-
- Imported with the commands:
-
- tar xvzf bc-1.0.5a.tar.gz
- cd bc-1.0.5
- cvs import src/contrib/bc BC bc_1_0_5a
diff --git a/contrib/bc/INSTALL b/contrib/bc/INSTALL
deleted file mode 100644
index 3b50ea9..0000000
--- a/contrib/bc/INSTALL
+++ /dev/null
@@ -1,176 +0,0 @@
-Basic Installation
-==================
-
- These are generic installation instructions.
-
- The `configure' shell script attempts to guess correct values for
-various system-dependent variables used during compilation. It uses
-those values to create a `Makefile' in each directory of the package.
-It may also create one or more `.h' files containing system-dependent
-definitions. Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, a file
-`config.cache' that saves the results of its tests to speed up
-reconfiguring, and a file `config.log' containing compiler output
-(useful mainly for debugging `configure').
-
- If you need to do unusual things to compile the package, please try
-to figure out how `configure' could check whether to do them, and mail
-diffs or instructions to the address given in the `README' so they can
-be considered for the next release. If at some point `config.cache'
-contains results you don't want to keep, you may remove or edit it.
-
- The file `configure.in' is used to create `configure' by a program
-called `autoconf'. You only need `configure.in' if you want to change
-it or regenerate `configure' using a newer version of `autoconf'.
-
-The simplest way to compile this package is:
-
- 1. `cd' to the directory containing the package's source code and type
- `./configure' to configure the package for your system. If you're
- using `csh' on an old version of System V, you might need to type
- `sh ./configure' instead to prevent `csh' from trying to execute
- `configure' itself.
-
- Running `configure' takes a while. While running, it prints some
- messages telling which features it is checking for.
-
- 2. Type `make' to compile the package.
-
- 3. Optionally, type `make check' to run any self-tests that come with
- the package.
-
- 4. Type `make install' to install the programs and any data files and
- documentation.
-
- 5. You can remove the program binaries and object files from the
- source code directory by typing `make clean'. To also remove the
- files that `configure' created (so you can compile the package for
- a different kind of computer), type `make distclean'. There is
- also a `make maintainer-clean' target, but that is intended mainly
- for the package's developers. If you use it, you may have to get
- all sorts of other programs in order to regenerate files that came
- with the distribution.
-
-Compilers and Options
-=====================
-
- Some systems require unusual options for compilation or linking that
-the `configure' script does not know about. You can give `configure'
-initial values for variables by setting them in the environment. Using
-a Bourne-compatible shell, you can do that on the command line like
-this:
- CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
-
-Or on systems that have the `env' program, you can do it like this:
- env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
-
-Compiling For Multiple Architectures
-====================================
-
- You can compile the package for more than one kind of computer at the
-same time, by placing the object files for each architecture in their
-own directory. To do this, you must use a version of `make' that
-supports the `VPATH' variable, such as GNU `make'. `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script. `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'.
-
- If you have to use a `make' that does not supports the `VPATH'
-variable, you have to compile the package for one architecture at a time
-in the source code directory. After you have installed the package for
-one architecture, use `make distclean' before reconfiguring for another
-architecture.
-
-Installation Names
-==================
-
- By default, `make install' will install the package's files in
-`/usr/local/bin', `/usr/local/man', etc. You can specify an
-installation prefix other than `/usr/local' by giving `configure' the
-option `--prefix=PATH'.
-
- You can specify separate installation prefixes for
-architecture-specific files and architecture-independent files. If you
-give `configure' the option `--exec-prefix=PATH', the package will use
-PATH as the prefix for installing programs and libraries.
-Documentation and other data files will still use the regular prefix.
-
- If the package supports it, you can cause programs to be installed
-with an extra prefix or suffix on their names by giving `configure' the
-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
-
-Optional Features
-=================
-
- Some packages pay attention to `--enable-FEATURE' options to
-`configure', where FEATURE indicates an optional part of the package.
-They may also pay attention to `--with-PACKAGE' options, where PACKAGE
-is something like `gnu-as' or `x' (for the X Window System). The
-`README' should mention any `--enable-' and `--with-' options that the
-package recognizes.
-
- For packages that use the X Window System, `configure' can usually
-find the X include and library files automatically, but if it doesn't,
-you can use the `configure' options `--x-includes=DIR' and
-`--x-libraries=DIR' to specify their locations.
-
-Specifying the System Type
-==========================
-
- There may be some features `configure' can not figure out
-automatically, but needs to determine by the type of host the package
-will run on. Usually `configure' can figure that out, but if it prints
-a message saying it can not guess the host type, give it the
-`--host=TYPE' option. TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name with three fields:
- CPU-COMPANY-SYSTEM
-
-See the file `config.sub' for the possible values of each field. If
-`config.sub' isn't included in this package, then this package doesn't
-need to know the host type.
-
- If you are building compiler tools for cross-compiling, you can also
-use the `--target=TYPE' option to select the type of system they will
-produce code for and the `--build=TYPE' option to select the type of
-system on which you are compiling the package.
-
-Sharing Defaults
-================
-
- If you want to set default values for `configure' scripts to share,
-you can create a site shell script called `config.site' that gives
-default values for variables like `CC', `cache_file', and `prefix'.
-`configure' looks for `PREFIX/share/config.site' if it exists, then
-`PREFIX/etc/config.site' if it exists. Or, you can set the
-`CONFIG_SITE' environment variable to the location of the site script.
-A warning: not all `configure' scripts look for a site script.
-
-Operation Controls
-==================
-
- `configure' recognizes the following options to control how it
-operates.
-
-`--cache-file=FILE'
- Use and save the results of the tests in FILE instead of
- `./config.cache'. Set FILE to `/dev/null' to disable caching, for
- debugging `configure'.
-
-`--help'
- Print a summary of the options to `configure', and exit.
-
-`--quiet'
-`--silent'
-`-q'
- Do not print messages saying which checks are being made.
-
-`--srcdir=DIR'
- Look for the package's source code in directory DIR. Usually
- `configure' can determine that directory automatically.
-
-`--version'
- Print the version of Autoconf used to generate the `configure'
- script, and exit.
-
-`configure' also accepts some other, not widely useful, options.
-
diff --git a/contrib/bc/Makefile.am b/contrib/bc/Makefile.am
deleted file mode 100644
index 6703d74..0000000
--- a/contrib/bc/Makefile.am
+++ /dev/null
@@ -1,18 +0,0 @@
-## Process this file with automake to produce Makefile.in
-
-SUBDIRS = lib bc dc doc
-
-MAINTAINERCLEANFILES = aclocal.m4 config.h.in configure Makefile.in \
- $(distdir).tar.gz h/number.h
-
-dist-hook:
- mkdir $(distdir)/h $(distdir)/Examples $(distdir)/Test
- cp -p $(srcdir)/h/*.h $(distdir)/h
- cp -p $(srcdir)/Examples/*.b $(distdir)/Examples
- cp -p $(srcdir)/Test/*.b $(srcdir)/Test/*.bc $(distdir)/Test
- cp -p $(srcdir)/Test/signum $(srcdir)/Test/timetest $(distdir)/Test
- cp -p $(srcdir)/lib/testmul.c $(distdir)/lib
- cp -p $(srcdir)/FAQ $(distdir)
-
-timetest:
- (cd lib; $(MAKE) specialnumber)
diff --git a/contrib/bc/Makefile.in b/contrib/bc/Makefile.in
deleted file mode 100644
index b57eae5..0000000
--- a/contrib/bc/Makefile.in
+++ /dev/null
@@ -1,368 +0,0 @@
-# Makefile.in generated automatically by automake 1.4 from Makefile.am
-
-# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-
-SHELL = @SHELL@
-
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
-VPATH = @srcdir@
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-
-bindir = @bindir@
-sbindir = @sbindir@
-libexecdir = @libexecdir@
-datadir = @datadir@
-sysconfdir = @sysconfdir@
-sharedstatedir = @sharedstatedir@
-localstatedir = @localstatedir@
-libdir = @libdir@
-infodir = @infodir@
-mandir = @mandir@
-includedir = @includedir@
-oldincludedir = /usr/include
-
-DESTDIR =
-
-pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-
-top_builddir = .
-
-ACLOCAL = @ACLOCAL@
-AUTOCONF = @AUTOCONF@
-AUTOMAKE = @AUTOMAKE@
-AUTOHEADER = @AUTOHEADER@
-
-INSTALL = @INSTALL@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-transform = @program_transform_name@
-
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-CC = @CC@
-LEX = @LEX@
-MAKEINFO = @MAKEINFO@
-PACKAGE = @PACKAGE@
-RANLIB = @RANLIB@
-READLINELIB = @READLINELIB@
-VERSION = @VERSION@
-YACC = @YACC@
-
-SUBDIRS = lib bc dc doc
-
-MAINTAINERCLEANFILES = aclocal.m4 config.h.in configure Makefile.in $(distdir).tar.gz h/number.h
-
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
-CONFIG_HEADER = config.h
-CONFIG_CLEAN_FILES =
-DIST_COMMON = README ./stamp-h.in AUTHORS COPYING COPYING.LIB ChangeLog \
-INSTALL Makefile.am Makefile.in NEWS acconfig.h aclocal.m4 config.h.in \
-configure configure.in install-sh missing mkinstalldirs
-
-
-DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-
-TAR = tar
-GZIP_ENV = --best
-all: all-redirect
-.SUFFIXES:
-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
- cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps Makefile
-
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
- cd $(top_builddir) \
- && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
-
-$(ACLOCAL_M4): configure.in
- cd $(srcdir) && $(ACLOCAL)
-
-config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
- $(SHELL) ./config.status --recheck
-$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
- cd $(srcdir) && $(AUTOCONF)
-
-config.h: stamp-h
- @if test ! -f $@; then \
- rm -f stamp-h; \
- $(MAKE) stamp-h; \
- else :; fi
-stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status
- cd $(top_builddir) \
- && CONFIG_FILES= CONFIG_HEADERS=config.h \
- $(SHELL) ./config.status
- @echo timestamp > stamp-h 2> /dev/null
-$(srcdir)/config.h.in: $(srcdir)/stamp-h.in
- @if test ! -f $@; then \
- rm -f $(srcdir)/stamp-h.in; \
- $(MAKE) $(srcdir)/stamp-h.in; \
- else :; fi
-$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h
- cd $(top_srcdir) && $(AUTOHEADER)
- @echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null
-
-mostlyclean-hdr:
-
-clean-hdr:
-
-distclean-hdr:
- -rm -f config.h
-
-maintainer-clean-hdr:
-
-# This directory's subdirectories are mostly independent; you can cd
-# into them and run `make' without going through this Makefile.
-# To change the values of `make' variables: instead of editing Makefiles,
-# (1) if the variable is set in `config.status', edit `config.status'
-# (which will cause the Makefiles to be regenerated when you run `make');
-# (2) otherwise, pass the desired values on the `make' command line.
-
-@SET_MAKE@
-
-all-recursive install-data-recursive install-exec-recursive \
-installdirs-recursive install-recursive uninstall-recursive \
-check-recursive installcheck-recursive info-recursive dvi-recursive:
- @set fnord $(MAKEFLAGS); amf=$$2; \
- dot_seen=no; \
- target=`echo $@ | sed s/-recursive//`; \
- list='$(SUBDIRS)'; for subdir in $$list; do \
- echo "Making $$target in $$subdir"; \
- if test "$$subdir" = "."; then \
- dot_seen=yes; \
- local_target="$$target-am"; \
- else \
- local_target="$$target"; \
- fi; \
- (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
- || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
- done; \
- if test "$$dot_seen" = "no"; then \
- $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
- fi; test -z "$$fail"
-
-mostlyclean-recursive clean-recursive distclean-recursive \
-maintainer-clean-recursive:
- @set fnord $(MAKEFLAGS); amf=$$2; \
- dot_seen=no; \
- rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
- rev="$$subdir $$rev"; \
- test "$$subdir" = "." && dot_seen=yes; \
- done; \
- test "$$dot_seen" = "no" && rev=". $$rev"; \
- target=`echo $@ | sed s/-recursive//`; \
- for subdir in $$rev; do \
- echo "Making $$target in $$subdir"; \
- if test "$$subdir" = "."; then \
- local_target="$$target-am"; \
- else \
- local_target="$$target"; \
- fi; \
- (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
- || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
- done && test -z "$$fail"
-tags-recursive:
- list='$(SUBDIRS)'; for subdir in $$list; do \
- test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
- done
-
-tags: TAGS
-
-ID: $(HEADERS) $(SOURCES) $(LISP)
- list='$(SOURCES) $(HEADERS)'; \
- unique=`for i in $$list; do echo $$i; done | \
- awk ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
- here=`pwd` && cd $(srcdir) \
- && mkid -f$$here/ID $$unique $(LISP)
-
-TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP)
- tags=; \
- here=`pwd`; \
- list='$(SUBDIRS)'; for subdir in $$list; do \
- if test "$$subdir" = .; then :; else \
- test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
- fi; \
- done; \
- list='$(SOURCES) $(HEADERS)'; \
- unique=`for i in $$list; do echo $$i; done | \
- awk ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
- test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \
- || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS)
-
-mostlyclean-tags:
-
-clean-tags:
-
-distclean-tags:
- -rm -f TAGS ID
-
-maintainer-clean-tags:
-
-distdir = $(PACKAGE)-$(VERSION)
-top_distdir = $(distdir)
-
-# This target untars the dist file and tries a VPATH configuration. Then
-# it guarantees that the distribution is self-contained by making another
-# tarfile.
-distcheck: dist
- -rm -rf $(distdir)
- GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
- mkdir $(distdir)/=build
- mkdir $(distdir)/=inst
- dc_install_base=`cd $(distdir)/=inst && pwd`; \
- cd $(distdir)/=build \
- && ../configure --srcdir=.. --prefix=$$dc_install_base \
- && $(MAKE) $(AM_MAKEFLAGS) \
- && $(MAKE) $(AM_MAKEFLAGS) dvi \
- && $(MAKE) $(AM_MAKEFLAGS) check \
- && $(MAKE) $(AM_MAKEFLAGS) install \
- && $(MAKE) $(AM_MAKEFLAGS) installcheck \
- && $(MAKE) $(AM_MAKEFLAGS) dist
- -rm -rf $(distdir)
- @banner="$(distdir).tar.gz is ready for distribution"; \
- dashes=`echo "$$banner" | sed s/./=/g`; \
- echo "$$dashes"; \
- echo "$$banner"; \
- echo "$$dashes"
-dist: distdir
- -chmod -R a+r $(distdir)
- GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
- -rm -rf $(distdir)
-dist-all: distdir
- -chmod -R a+r $(distdir)
- GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
- -rm -rf $(distdir)
-distdir: $(DISTFILES)
- -rm -rf $(distdir)
- mkdir $(distdir)
- -chmod 777 $(distdir)
- @for file in $(DISTFILES); do \
- d=$(srcdir); \
- if test -d $$d/$$file; then \
- cp -pr $$/$$file $(distdir)/$$file; \
- else \
- test -f $(distdir)/$$file \
- || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
- || cp -p $$d/$$file $(distdir)/$$file || :; \
- fi; \
- done
- for subdir in $(SUBDIRS); do \
- if test "$$subdir" = .; then :; else \
- test -d $(distdir)/$$subdir \
- || mkdir $(distdir)/$$subdir \
- || exit 1; \
- chmod 777 $(distdir)/$$subdir; \
- (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \
- || exit 1; \
- fi; \
- done
- $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook
-info-am:
-info: info-recursive
-dvi-am:
-dvi: dvi-recursive
-check-am: all-am
-check: check-recursive
-installcheck-am:
-installcheck: installcheck-recursive
-all-recursive-am: config.h
- $(MAKE) $(AM_MAKEFLAGS) all-recursive
-
-install-exec-am:
-install-exec: install-exec-recursive
-
-install-data-am:
-install-data: install-data-recursive
-
-install-am: all-am
- @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-install: install-recursive
-uninstall-am:
-uninstall: uninstall-recursive
-all-am: Makefile config.h
-all-redirect: all-recursive-am
-install-strip:
- $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
-installdirs: installdirs-recursive
-installdirs-am:
-
-
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
- -rm -f Makefile $(CONFIG_CLEAN_FILES)
- -rm -f config.cache config.log stamp-h stamp-h[0-9]*
-
-maintainer-clean-generic:
- -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
-mostlyclean-am: mostlyclean-hdr mostlyclean-tags mostlyclean-generic
-
-mostlyclean: mostlyclean-recursive
-
-clean-am: clean-hdr clean-tags clean-generic mostlyclean-am
-
-clean: clean-recursive
-
-distclean-am: distclean-hdr distclean-tags distclean-generic clean-am
-
-distclean: distclean-recursive
- -rm -f config.status
-
-maintainer-clean-am: maintainer-clean-hdr maintainer-clean-tags \
- maintainer-clean-generic distclean-am
- @echo "This command is intended for maintainers to use;"
- @echo "it deletes files that may require special tools to rebuild."
-
-maintainer-clean: maintainer-clean-recursive
- -rm -f config.status
-
-.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
-install-data-recursive uninstall-data-recursive install-exec-recursive \
-uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
-all-recursive check-recursive installcheck-recursive info-recursive \
-dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
-maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
-distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
-dvi-am dvi check check-am installcheck-am installcheck all-recursive-am \
-install-exec-am install-exec install-data-am install-data install-am \
-install uninstall-am uninstall all-redirect all-am all installdirs-am \
-installdirs mostlyclean-generic distclean-generic clean-generic \
-maintainer-clean-generic clean mostlyclean distclean maintainer-clean
-
-
-dist-hook:
- mkdir $(distdir)/h $(distdir)/Examples $(distdir)/Test
- cp -p $(srcdir)/h/*.h $(distdir)/h
- cp -p $(srcdir)/Examples/*.b $(distdir)/Examples
- cp -p $(srcdir)/Test/*.b $(srcdir)/Test/*.bc $(distdir)/Test
- cp -p $(srcdir)/Test/signum $(srcdir)/Test/timetest $(distdir)/Test
- cp -p $(srcdir)/lib/testmul.c $(distdir)/lib
- cp -p $(srcdir)/FAQ $(distdir)
-
-timetest:
- (cd lib; $(MAKE) specialnumber)
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/contrib/bc/NEWS b/contrib/bc/NEWS
deleted file mode 100644
index fc02a0d..0000000
--- a/contrib/bc/NEWS
+++ /dev/null
@@ -1,68 +0,0 @@
-This is GNU bc version 1.06. (And dc version 1.2)
-
-Changes in dc from 1.2 to 1.3:
- Minor bug fixes.
- New multiply algorithm of bc.
-
-Changes in bc from 1.05 to 1.06:
- New multiply algoirthm and many other changes in lib/number.c
- Function size now done dynamically.
- Function syntax in non-posix mode allows newlines in more places.
- Bug fixes:
- improved computation of j(n,x).
- enables readline only if interactive.
- for statment bug fixed.
- use int instead of char for readline char counts.
- improved cosine accuracy.
-
-Changes in dc from 1.1 to 1.2:
- added !< != !> commands
- arrays now stack
- output is now line buffered, provided setvbuf() is available
- fixed known bugs in 'q', 'Q', 'a' commands, '-f' command-line option,
- and documentation
- changed the 'P' command's behavior on a numeric argument:
- due to popular demand it now does the equivalent of 'aP'
- (for small values)
- added new 'n' command to do what the old 'P' command did
-
-Changes in bc from 1.04 to 1.05:
- Solaris makes work better.
- bug fixes
- stdout now always does line buffering.
- sqrt bug fixed for small numbers.
- readline (if support is compiled in) is enabled only for
- interactive executions of bc.
-
-
-This is GNU bc version 1.04. (And dc version 1.1)
-
-Changes from 1.03
-
- reorganization of source tree
- use of automake
-
- new commands for dc (|, ~, r, a)
- new command line options for dc
-
- fixed infinite loop in sqrt in bc
- fixed an I/O bug in bc
- made bc conform to POSIX for array parameters
- added long option support for bc
- new commandline options for bc (-q)
- added support for readline to bc (use configure --with-readline)
- command line argumens can now be taken from an environment variable
-
-
-Changes from 1.02
-
- minor bug fixes in bc.
-
- addition of Ken Pizzini's dc program that uses the GNU bc
- arbitrary precision arithmetic routines.
-
-Changes from 1.01
-
- minor bug fixes.
-
-
diff --git a/contrib/bc/README b/contrib/bc/README
deleted file mode 100644
index 2813fb8..0000000
--- a/contrib/bc/README
+++ /dev/null
@@ -1,86 +0,0 @@
-GNU bc version 1.06:
-
-Extra configuration options:
-
- --with-readline tells bc to use the readline package that allows
- for editing input lines when run interactive.
-
- --with-editline tells bc to use the BSD editline package that
- allows for editing input lines when run interactive.
-
-Extra make steps:
-
- The simple make compiles a version of bc with fixed parameters
- for the recursive multiplication algorithm. The fixed parameter
- is the number of digits where a sequential algorithm is used
- instead of the recursive algorithm. It is set to a value that
- is known good on a couple of machines. (Sparc Ultra 10, Pentium
- II, 450.) I'm calling this point the crossover point.
-
- To make a version of bc with a custom crossover point for your
- machine, do the following steps:
-
- make timetest
- make
-
- The timetest step takes a minimum of 10 minutes to complete.
-
-
--------- Original comp.sources.reviewed README --------
-
-Program: GNU bc
-Author: Philip A. Nelson
-E-mail: phil@cs.wwu.edu
-OS: UNIX (BSD, System V, MINIX, POSIX)
-Copying: GNU GPL version 2
-Copyright holder: Free Software Foundation, Inc.
-Version: bc version 1.01
-Required: vsprintf and vfprintf routines.
-Machines: It has been compiled and run on the following environments:
- BSD4.3 (VAX 11)
- MINIX 1.5 (IBM PC, both K&R and ANSI compilers)
- MINIX 1.5 (pc532)
- SUN-OS 4.1 (SUN 3 and SUN 4)
- SVR3V5 (Motorola 68K)
- SVR3.2 (3B2)
- SVR4.0.2 (a 386 box)
- ULTRIX 4.1 (DEC 5000)
- UTS (Amdahl)
-
-bc is an arbitrary precision numeric processing language. Syntax is
-similar to C, but differs in many substantial areas. It supports
-interactive execution of statements. bc is a utility included in the
-POSIX P1003.2/D11 draft standard.
-
-This version was written to be a POSIX compliant bc processor with
-several extensions to the draft standard. Option flags are available
-to cause warning or rejection of the extensions to the POSIX standard.
-For those who want only POSIX bc with no extensions, a grammar is
-provided for exactly the language described in the POSIX document.
-The grammar (sbc.y) comes from the POSIX document. The Makefile
-contains rules to make sbc. (for Standard BC)
-
-Since the POSIX document does not specify how bc must be implemented,
-this version does not use the historical method of having bc be a
-compiler for the dc calculator. This version has a single executable
-that both compiles the language and runs the a resulting "byte code".
-The "byte code" is NOT the dc language.
-
-Also, included in the initial distribution is the library file
-vfprintf.c for MINIX systems. My minix 1.5 did not have this file.
-Also, you should verify that vsprintf.c works correctly on your
-system.
-
-The extensions add some features I think are missing. The major
-changes and additions for bc are (a) names are allowed to be full
-identifiers ([a-z][a-z0-9_]*), (b) addition of the &&, ||, and !
-operators, (c) allowing comparison and boolean operations in any
-expression, (d) addition of an else clause to the if statement, (e)
-addition of a new standard function "read()" that reads a number from
-the standard input under program control, (f) passing of arrays as
-parameters by variable, (g) addition of the "halt" statement that is
-an executable statement unlike the quit (i.e. "if (1 == 0) quit" will
-halt bc but "if (1 == 0) halt" will not halt bc.), and (h) the
-addition of the special variable "last" that is assigned the value of
-each print as the number is printed.
------------------------------------------------------------------------
diff --git a/contrib/bc/Test/BUG.bc b/contrib/bc/Test/BUG.bc
deleted file mode 100644
index 254eefe..0000000
--- a/contrib/bc/Test/BUG.bc
+++ /dev/null
@@ -1,40 +0,0 @@
-/* <--- bug.bc ---><--- bug.bc ---><--- bug.bc ---><--- bug.bc ---> */
-
-/*
- * See the file "signum" for a description and reference for this
- * program.
- *
- * THIS BUG IS *NOT* IN GNU BC!!!
- *
- */
-
-obase=16
-ibase=16
-x=1A8F5C99605AE52 /* dividend */
-y=BB0B404 /* divisor */
-q=245A07AD /* (correct) quotient */
-r=147EB9E /* (correct) remainder */
-"Base 16
-"
-"x = "; x /* output numbers just to be sure... */
-"y = "; y
-"quo = "; q
-"rem = "; r
-"x/y = "; x/y /* watch this result! */
-"x%y = "; x%y /* watch this result! */
-"y*q+r= "; y*q+r /* check quotient & remainder */
-/*
- * Do the same thing in base 10:
- */
-"
-Base 10
-"
-ibase=A
-obase=10
-"x = "; x /* output numbers just to be sure... */
-"y = "; y
-"q = "; q
-"r = "; r
-"x/y = "; x/y /* watch this result! */
-"x%y = "; x%y /* watch this result! */
-"y*q+r= "; y*q+r /* check quotient & remainder */
diff --git a/contrib/bc/Test/array.b b/contrib/bc/Test/array.b
deleted file mode 100644
index a0341ec..0000000
--- a/contrib/bc/Test/array.b
+++ /dev/null
@@ -1,14 +0,0 @@
-"This tests arrays!
-"
-define p(x,y) {
- auto i;
- for (i=x; i<y; i++) a[i];
-}
-
-for (i=0; i<10; i++) a[i] = i;
-j = p(0,10);
-
-for (i=1000; i<1030; i++) a[i] = i;
-j = p(1000,1030);
-j = p(0,10);
-
diff --git a/contrib/bc/Test/arrayp.b b/contrib/bc/Test/arrayp.b
deleted file mode 100644
index 3f3ca50..0000000
--- a/contrib/bc/Test/arrayp.b
+++ /dev/null
@@ -1,30 +0,0 @@
-"This tests arrays!
-"
-define p(a[],x,y) {
- auto i;
- for (i=x; i<y; i++) a[i];
-}
-
-define m(a[],x,y) {
- auto i;
- for (i=x; i<y; i++) a[i] = i;
-}
-
-define m1(*a[],x,y) {
- auto i;
- print "m1\n"
- for (i=x; i<y; i++) a[i] = i;
-}
-
-for (i=0; i<10; i++) a[i] = i;
-j = p(a[],0,10);
-
-j = m(b[],0,10);
-j = p(b[],0,10);
-
-print "---\n";
-j = m1(b[],0,10);
-j = p(b[],0,10);
-
-quit
-
diff --git a/contrib/bc/Test/aryprm.b b/contrib/bc/Test/aryprm.b
deleted file mode 100644
index 9d3f95b..0000000
--- a/contrib/bc/Test/aryprm.b
+++ /dev/null
@@ -1,16 +0,0 @@
-define p ( x[] ) {
- auto i;
- for (i=0; i<10; i++) x[i];
-}
-
-define m ( x[] ) {
- auto i;
- for (i=0; i<10; i++) x[i] *= 2;
-}
-
-scale = 20;
-for (i=0; i<10; i++) a[i] = sqrt(i);
-
-p(a[]);
-m(a[]);
-p(a[]);
diff --git a/contrib/bc/Test/atan.b b/contrib/bc/Test/atan.b
deleted file mode 100644
index e742279..0000000
--- a/contrib/bc/Test/atan.b
+++ /dev/null
@@ -1,5 +0,0 @@
-for (a=0; a<1000; a+=2) x=a(a)
-x
-for (a=0; a<2; a+=.01) x=a(a)
-x
-quit
diff --git a/contrib/bc/Test/checklib.b b/contrib/bc/Test/checklib.b
deleted file mode 100644
index 44c1fac..0000000
--- a/contrib/bc/Test/checklib.b
+++ /dev/null
@@ -1,109 +0,0 @@
-define t (x,y,d,s,t) {
- auto u, v, w, i, b, c;
-
- if (s >= t) {
- "Bad Scales. Try again.
-"; return;
- }
-
- for (i = x; i < y; i += d) {
- scale = s;
- u = f(i);
- scale = t;
- v = f(i);
- scale = s;
- w = v / 1;
- b += 1;
- if (u != w) {
- c += 1;
-"
-Failed:
-"
- " index = "; i;
- " val1 = "; u;
- " val2 = "; v;
-"
-"
- }
- }
-
-"
-Total tests: "; b;
-"
-Total failures: "; c;
-"
-Percent failed: "; scale = 2; c*100/b;
-
-}
-
-/*
- b = begining scale value,
- l = limit scale value,
- i = increment scale value.
-
- if b is set to a non-zero value before this file is executed,
- b, l and i are not reset.
-*/
-
-if (b == 0) { b = 10; l = 61; i = 10; }
-
-"
-Checking e(x)"
-define f(x) {
- return (e(x))
-}
-for (s=10; s<l; s=s+i) {
-"
-scale = "; s
-j = t(0,200,1,s,s+4)
-}
-
-"
-Checking l(x)"
-define f(x) {
- return (l(x))
-}
-for (s=10; s<l; s=s+i) {
-"
-scale = "; s
-j = t(1,10000,25,s,s+4)
-}
-
-"
-Checking s(x)"
-define f(x) {
- return (s(x))
-}
-for (s=10; s<l; s=s+i) {
-"
-scale = "; s
-j = t(0,8*a(1),.01,s,s+4)
-}
-
-"
-Checking a(x)"
-define f(x) {
- return (a(x))
-}
-for (s=10; s<l; s=s+i) {
-"
-scale = "; s
-j = t(-1000,1000,10,s,s+4)
-}
-
-"
-Checking j(n,x)"
-define f(x) {
- return (j(n,x))
-}
-for (s=10; s<l; s=s+i) {
-"
-n=0, scale = "; s
-n=0
-j = t(0,30,.1,s,s+4)
-"
-n=1, scale = "; s
-n=1
-j = t(0,30,.1,s,s+4)
-}
-
diff --git a/contrib/bc/Test/div.b b/contrib/bc/Test/div.b
deleted file mode 100644
index 3c7d377..0000000
--- a/contrib/bc/Test/div.b
+++ /dev/null
@@ -1,8 +0,0 @@
-scale = 20
-a=2/3
-for (i=0; i<1000; i++) {
- for (j=1; j<100; j++) b=a/j
-}
-b
-quit
-
diff --git a/contrib/bc/Test/exp.b b/contrib/bc/Test/exp.b
deleted file mode 100644
index 92c482c..0000000
--- a/contrib/bc/Test/exp.b
+++ /dev/null
@@ -1,3 +0,0 @@
-for (a=0; a<180; a+=.4) x=e(a)
-x
-quit
diff --git a/contrib/bc/Test/fact.b b/contrib/bc/Test/fact.b
deleted file mode 100644
index 995a26d..0000000
--- a/contrib/bc/Test/fact.b
+++ /dev/null
@@ -1,12 +0,0 @@
-define f (x) {
-
- if (x<=1) return(1)
- return (f(x-1)*x)
-}
-
-for (a=1; a<600; a++) b=f(a)
-"
-"
-"b=";b
-quit
-
diff --git a/contrib/bc/Test/jn.b b/contrib/bc/Test/jn.b
deleted file mode 100644
index a4e0624..0000000
--- a/contrib/bc/Test/jn.b
+++ /dev/null
@@ -1,6 +0,0 @@
-scale = 50
-for (a=0; a<=100; a += 20) {
- for (b=0; b<=300; b += 20) x=j(a,b)
- x
-}
-quit
diff --git a/contrib/bc/Test/ln.b b/contrib/bc/Test/ln.b
deleted file mode 100644
index cd00232..0000000
--- a/contrib/bc/Test/ln.b
+++ /dev/null
@@ -1,4 +0,0 @@
-scale = 60
-for (a=1; a<100000000000000000000000000000000000000; a = a*2) x=l(a)
-x
-quit
diff --git a/contrib/bc/Test/mul.b b/contrib/bc/Test/mul.b
deleted file mode 100644
index 722086f..0000000
--- a/contrib/bc/Test/mul.b
+++ /dev/null
@@ -1,13 +0,0 @@
-scale = 20
-for (i=0; i<10000; i++) {
- for (j=1; j<100; j++) b=i*j
-}
-b
-for (i=0; i<10000; i++) {
- for (j=1000000000000000000000000000000000000000000000000000000000000000000; \
- j<1000000000000000000000000000000000000000000000000000000000000000100; \
- j++) b=i*j
-}
-b
-quit
-
diff --git a/contrib/bc/Test/raise.b b/contrib/bc/Test/raise.b
deleted file mode 100644
index ec6929d..0000000
--- a/contrib/bc/Test/raise.b
+++ /dev/null
@@ -1,7 +0,0 @@
-for (i=0; i<1000; i++) a = 2^i;
-a
-for (i=3000; i<3100; i++) a = 3^i;
-a
-for (i=200; i<220; i++) a = (4^100)^i;
-a
-quit
diff --git a/contrib/bc/Test/signum b/contrib/bc/Test/signum
deleted file mode 100644
index 9e27d2d..0000000
--- a/contrib/bc/Test/signum
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
-
-/* From gnu@cygnus.com Wed Jul 14 13:46:44 1993
-Return-Path: <gnu@cygnus.com>
-To: phil@cs.wwu.edu, gnu@cygnus.com
-Subject: bc/dc - no rest for the wicked
-Date: Tue, 06 Jul 93 19:12:40 -0700
-From: gnu@cygnus.com
-
-GNU bc 1.02 passes all these tests. Can you add the test to the distribution?
-Putting it into a DejaGnu test case for GNU bc would be a great thing, too.
-(I haven't seen the Signum paper, maybe you can dig it out.)
-
- John Gilmore
- Cygnus Support
-
-------- Forwarded Message
-
-Date: Tue, 6 Jul 93 08:45:48 PDT
-From: uunet!Eng.Sun.COM!David.Hough@uunet.UU.NET (David Hough)
-Message-Id: <9307061545.AA14477@dgh.Eng.Sun.COM>
-To: numeric-interest@validgh.com
-Subject: bc/dc - no rest for the wicked
-
-Steve Sommars sent me a bc script which reproduces ALL the test cases from
-Dittmer's paper. Neither SunOS 5.2 on SPARC nor 5.1 on x86 come out clean.
-Anybody else who has fixed all the bugs would be justified in
-bragging about it here. */
-
-
-/*Ingo Dittmer, ACM Signum, April 1993, page 8-11*/
-define g(x,y,z){
- auto a
- a=x%y
- if(a!=z){
-"
-x=";x
- "y=";y
- "Should be ";z
- "was ";a
- }
-}
-
-/*Table 1*/
-g=g(53894380494284,9980035577,2188378484)
-g=g(47907874973121,9980035577,3704203521)
-g=g(76850276401922,9980035577,4002459022)
-g=g(85830854846664,9980035577,2548884464)
-g=g(43915353970066,9980035577,3197431266)
-g=g(35930746212825,9980035577,2618135625)
-g=g(51900604524715,9980035577,4419524315)
-g=g(87827018005068,9980035577,2704927468)
-g=g(57887902441764,9980035577,3696095164)
-g=g(96810941031110,9980035577,4595934210)
-
-/*Table 2*/
-g=g(86833646827370,9980035577,7337307470)
-g=g(77850880592435,9980035577,6603091835)
-g=g(84836601050323,9980035577,6298645823)
-g=g(85835110016211,9980035577,6804054011)
-g=g(94817143459192,9980035577,6805477692)
-g=g(94818870293481,9980035577,8532311981)
-g=g(91823235571154,9980035577,6908262754)
-g=g(59885451951796,9980035577,5238489796)
-g=g(80844460893239,9980035577,6172719539)
-g=g(67869195894693,9980035577,4953971093)
-g=g(95813990985202,9980035577,5649446002)
-
-/*Skip Table 3, duplicate of line 1, table 1*/
-
-/*Table 4*/
-g=g(28420950579078013018256253301,17987947258,16619542243)
-g=g(12015118977201790601658257234,16687885701,8697335297)
-g=g(14349070374946789715188912007,13712994561,3605141129)
-g=g(61984050238512905451986475027,13337935089,5296182558)
-g=g(86189707791214681859449918641,17837971389,14435206830)
-g=g(66747908181102582528134773954,19462997965,8615839889)
-
-/*Table 6*/
-g=g(4999253,9998,253)
-g=g(8996373,9995,873)
-
-
-/* Added by Phil Nelson..... */
-"end of tests
-"
diff --git a/contrib/bc/Test/sine.b b/contrib/bc/Test/sine.b
deleted file mode 100644
index 18c4b57..0000000
--- a/contrib/bc/Test/sine.b
+++ /dev/null
@@ -1,5 +0,0 @@
-for (i=0; i<8*a(1); i=i+.01) x=s(i)
-x
-for (i=i; i<16*a(1); i=i+.01) x=s(i+.1234123412341234)
-x
-quit
diff --git a/contrib/bc/Test/sqrt.b b/contrib/bc/Test/sqrt.b
deleted file mode 100644
index 3fb548c..0000000
--- a/contrib/bc/Test/sqrt.b
+++ /dev/null
@@ -1,13 +0,0 @@
-scale = 5
-for (a=1; a<500; a++) r=sqrt(a)
-r
-scale = 10
-for (a=1; a<500; a++) r=sqrt(a)
-r
-scale = 25
-for (a=1; a<500; a++) r=sqrt(a)
-r
-scale = 40
-for (a=1; a<500; a++) r=sqrt(a)
-r
-quit
diff --git a/contrib/bc/Test/sqrt1.b b/contrib/bc/Test/sqrt1.b
deleted file mode 100644
index c3ca269..0000000
--- a/contrib/bc/Test/sqrt1.b
+++ /dev/null
@@ -1,13 +0,0 @@
-for (j=0; j<10; j++) {
- a = .9;
- b = .9+j;
- scale = 2;
- for (i=0; i<90; i++) {
- scale += 1;
- a /= 10;
- b += a;
- x = sqrt(b);
- }
- x;
-}
-quit
diff --git a/contrib/bc/Test/sqrt2.b b/contrib/bc/Test/sqrt2.b
deleted file mode 100644
index bd0eaad..0000000
--- a/contrib/bc/Test/sqrt2.b
+++ /dev/null
@@ -1,10 +0,0 @@
-scale = 20
-for (a=1; a<5000; a += 1) r=sqrt(a)
-r
-for (a=1; a<50000; a += 100) r=sqrt(a)
-r
-for (a=1; a<500000; a+=1000) r=sqrt(a)
-r
-for (a=1; a<5000000; a+=10000) r=sqrt(a)
-r
-quit
diff --git a/contrib/bc/Test/testfn.b b/contrib/bc/Test/testfn.b
deleted file mode 100644
index 7578fc5..0000000
--- a/contrib/bc/Test/testfn.b
+++ /dev/null
@@ -1,47 +0,0 @@
-/* This function "t" tests the function "f" to see if computing at
- two different scales has much effect on the accuracy.
- test from f(x) to f(y) incrementing the index by d. f(i) is
- computed at two scales, scale s and then scale t, where t>s.
- the result from scale t is divided by 1 at scale s and the
- results are compared. If they are different, the function is
- said to have failed. It will then print out the value of i
- (called index) and the two original values val1 (scale s) and
- val2 (scale t) */
-
-define t (x,y,d,s,t) {
- auto u, v, w, i, b, c;
-
- if (s >= t) {
- "Bad Scales. Try again.
-"; return;
- }
-
- for (i = x; i < y; i += d) {
- scale = s;
- u = f(i);
- scale = t;
- v = f(i);
- scale = s;
- w = v / 1;
- b += 1;
- if (u != w) {
- c += 1;
-"
-Failed:
-"
- " index = "; i;
- " val1 = "; u;
- " val2 = "; v;
-"
-"
- }
- }
-
-"
-Total tests: "; b;
-"
-Total failures: "; c;
-"
-Percent failed: "; scale = 2; c*100/b;
-
-}
diff --git a/contrib/bc/Test/timetest b/contrib/bc/Test/timetest
deleted file mode 100755
index 1a4d0ea..0000000
--- a/contrib/bc/Test/timetest
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-#
-# Time the functions.
-#
-SYSBC=/usr/bin/bc
-if [ x$BC = x ] ; then
- BC=../bc/bc
-fi
-for file in exp.b ln.b sine.b atan.b jn.b mul.b div.b raise.b sqrt.b
-do
-for prog in $BC $SYSBC $OTHERBC
-do
-echo Timing $file with $prog
-time $prog -l $file
-done
-done
diff --git a/contrib/bc/acconfig.h b/contrib/bc/acconfig.h
deleted file mode 100644
index ff17f82..0000000
--- a/contrib/bc/acconfig.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* PACKAGE name */
-#undef PACKAGE
-
-/* Package VERSION number */
-#undef VERSION
-
-/* VERSION number for DC target*/
-#undef DC_VERSION
-
-/* COPYRIGHT notice for DC target */
-#undef DC_COPYRIGHT
-
-/* COPYRIGHT notice for BC target */
-#undef BC_COPYRIGHT
-
-/* Define to use the readline library. */
-#undef READLINE
-
-/* Define to use the BSD libedit library. */
-#undef LIBEDIT
-
-/* Define to `size_t' if <sys/types.h> and <stddef.h> don't define. */
-#undef ptrdiff_t
-
diff --git a/contrib/bc/aclocal.m4 b/contrib/bc/aclocal.m4
deleted file mode 100644
index 102dc3e..0000000
--- a/contrib/bc/aclocal.m4
+++ /dev/null
@@ -1,136 +0,0 @@
-dnl aclocal.m4 generated automatically by aclocal 1.4
-
-dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
-dnl This file is free software; the Free Software Foundation
-dnl gives unlimited permission to copy and/or distribute it,
-dnl with or without modifications, as long as this notice is preserved.
-
-dnl This program is distributed in the hope that it will be useful,
-dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-dnl PARTICULAR PURPOSE.
-
-# Do all the work for Automake. This macro actually does too much --
-# some checks are only needed if your package does certain things.
-# But this isn't really a big deal.
-
-# serial 1
-
-dnl Usage:
-dnl AM_INIT_AUTOMAKE(package,version, [no-define])
-
-AC_DEFUN(AM_INIT_AUTOMAKE,
-[AC_REQUIRE([AC_PROG_INSTALL])
-PACKAGE=[$1]
-AC_SUBST(PACKAGE)
-VERSION=[$2]
-AC_SUBST(VERSION)
-dnl test to see if srcdir already configured
-if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
- AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
-fi
-ifelse([$3],,
-AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
-AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package]))
-AC_REQUIRE([AM_SANITY_CHECK])
-AC_REQUIRE([AC_ARG_PROGRAM])
-dnl FIXME This is truly gross.
-missing_dir=`cd $ac_aux_dir && pwd`
-AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
-AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
-AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
-AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
-AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
-AC_REQUIRE([AC_PROG_MAKE_SET])])
-
-#
-# Check to make sure that the build environment is sane.
-#
-
-AC_DEFUN(AM_SANITY_CHECK,
-[AC_MSG_CHECKING([whether build environment is sane])
-# Just in case
-sleep 1
-echo timestamp > conftestfile
-# Do `set' in a subshell so we don't clobber the current shell's
-# arguments. Must try -L first in case configure is actually a
-# symlink; some systems play weird games with the mod time of symlinks
-# (eg FreeBSD returns the mod time of the symlink's containing
-# directory).
-if (
- set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
- if test "[$]*" = "X"; then
- # -L didn't work.
- set X `ls -t $srcdir/configure conftestfile`
- fi
- if test "[$]*" != "X $srcdir/configure conftestfile" \
- && test "[$]*" != "X conftestfile $srcdir/configure"; then
-
- # If neither matched, then we have a broken ls. This can happen
- # if, for instance, CONFIG_SHELL is bash and it inherits a
- # broken ls alias from the environment. This has actually
- # happened. Such a system could not be considered "sane".
- AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
-alias in your environment])
- fi
-
- test "[$]2" = conftestfile
- )
-then
- # Ok.
- :
-else
- AC_MSG_ERROR([newly created file is older than distributed files!
-Check your system clock])
-fi
-rm -f conftest*
-AC_MSG_RESULT(yes)])
-
-dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
-dnl The program must properly implement --version.
-AC_DEFUN(AM_MISSING_PROG,
-[AC_MSG_CHECKING(for working $2)
-# Run test in a subshell; some versions of sh will print an error if
-# an executable is not found, even if stderr is redirected.
-# Redirect stdin to placate older versions of autoconf. Sigh.
-if ($2 --version) < /dev/null > /dev/null 2>&1; then
- $1=$2
- AC_MSG_RESULT(found)
-else
- $1="$3/missing $2"
- AC_MSG_RESULT(missing)
-fi
-AC_SUBST($1)])
-
-# Like AC_CONFIG_HEADER, but automatically create stamp file.
-
-AC_DEFUN(AM_CONFIG_HEADER,
-[AC_PREREQ([2.12])
-AC_CONFIG_HEADER([$1])
-dnl When config.status generates a header, we must update the stamp-h file.
-dnl This file resides in the same directory as the config header
-dnl that is generated. We must strip everything past the first ":",
-dnl and everything past the last "/".
-AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl
-ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>,
-<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>,
-<<am_indx=1
-for am_file in <<$1>>; do
- case " <<$>>CONFIG_HEADERS " in
- *" <<$>>am_file "*<<)>>
- echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx
- ;;
- esac
- am_indx=`expr "<<$>>am_indx" + 1`
-done<<>>dnl>>)
-changequote([,]))])
-
-
-dnl AM_PROG_LEX
-dnl Look for flex, lex or missing, then run AC_PROG_LEX and AC_DECL_YYTEXT
-AC_DEFUN(AM_PROG_LEX,
-[missing_dir=ifelse([$1],,`cd $ac_aux_dir && pwd`,$1)
-AC_CHECK_PROGS(LEX, flex lex, "$missing_dir/missing flex")
-AC_PROG_LEX
-AC_DECL_YYTEXT])
-
diff --git a/contrib/bc/bc/Makefile.am b/contrib/bc/bc/Makefile.am
deleted file mode 100644
index 9187339..0000000
--- a/contrib/bc/bc/Makefile.am
+++ /dev/null
@@ -1,42 +0,0 @@
-## Process this file with automake to produce Makefile.in
-bin_PROGRAMS = bc
-
-bc_SOURCES = main.c bc.y scan.l execute.c load.c storage.c util.c global.c
-
-EXTRA_DIST = bc.h bcdefs.h const.h fix-libmath_h global.h libmath.b proto.h \
- sbc.y
-noinst_HEADERS = libmath.h
-
-DISTCLEANFILES = sbc sbc.c sbc.h
-
-MAINTAINERCLEANFILES = Makefile.in libmath.h bc.c bc.h scan.c
-
-INCLUDES = -I$(srcdir) -I$(srcdir)/../h
-LIBBC = ../lib/libbc.a
-LIBL = @LEXLIB@
-LDADD = $(LIBBC) $(LIBL) @READLINELIB@
-
-YFLAGS = -d
-
-CFLAGS = @CFLAGS@ -Wall -funsigned-char
-
-$(PROGRAMS): $(LIBBC)
-
-scan.o: bc.h
-global.o: libmath.h
-
-libmath.h: libmath.b
- echo '{0}' > libmath.h
- $(MAKE) fbc
- ./fbc -c $(srcdir)/libmath.b </dev/null >libmath.h
- $(srcdir)/fix-libmath_h
- rm -f ./fbc
-
-fbcOBJ = main.o bc.o scan.o execute.o global.o load.o storage.o util.o
-fbc: $(fbcOBJ)
- $(LINK) $(fbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS)
-
-sbcOBJ = main.o sbc.o scan.o execute.o global.o load.o storage.o util.o
-sbc.o: sbc.c
-sbc: $(sbcOBJ)
- $(LINK) $(sbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS)
diff --git a/contrib/bc/bc/Makefile.in b/contrib/bc/bc/Makefile.in
deleted file mode 100644
index 18ebce0..0000000
--- a/contrib/bc/bc/Makefile.in
+++ /dev/null
@@ -1,345 +0,0 @@
-# Makefile.in generated automatically by automake 1.4 from Makefile.am
-
-# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-
-SHELL = @SHELL@
-
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
-VPATH = @srcdir@
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-
-bindir = @bindir@
-sbindir = @sbindir@
-libexecdir = @libexecdir@
-datadir = @datadir@
-sysconfdir = @sysconfdir@
-sharedstatedir = @sharedstatedir@
-localstatedir = @localstatedir@
-libdir = @libdir@
-infodir = @infodir@
-mandir = @mandir@
-includedir = @includedir@
-oldincludedir = /usr/include
-
-DESTDIR =
-
-pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-
-top_builddir = ..
-
-ACLOCAL = @ACLOCAL@
-AUTOCONF = @AUTOCONF@
-AUTOMAKE = @AUTOMAKE@
-AUTOHEADER = @AUTOHEADER@
-
-INSTALL = @INSTALL@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-transform = @program_transform_name@
-
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-CC = @CC@
-LEX = @LEX@
-MAKEINFO = @MAKEINFO@
-PACKAGE = @PACKAGE@
-RANLIB = @RANLIB@
-READLINELIB = @READLINELIB@
-VERSION = @VERSION@
-YACC = @YACC@
-
-bin_PROGRAMS = bc
-
-bc_SOURCES = main.c bc.y scan.l execute.c load.c storage.c util.c global.c
-
-EXTRA_DIST = bc.h bcdefs.h const.h fix-libmath_h global.h libmath.b proto.h sbc.y
-
-noinst_HEADERS = libmath.h
-
-DISTCLEANFILES = sbc sbc.c sbc.h
-
-MAINTAINERCLEANFILES = Makefile.in libmath.h bc.c bc.h scan.c
-
-INCLUDES = -I$(srcdir) -I$(srcdir)/../h
-LIBBC = ../lib/libbc.a
-LIBL = @LEXLIB@
-LDADD = $(LIBBC) $(LIBL) @READLINELIB@
-
-YFLAGS = -d
-
-CFLAGS = @CFLAGS@ -Wall -funsigned-char
-
-fbcOBJ = main.o bc.o scan.o execute.o global.o load.o storage.o util.o
-
-sbcOBJ = main.o sbc.o scan.o execute.o global.o load.o storage.o util.o
-mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
-CONFIG_HEADER = ../config.h
-CONFIG_CLEAN_FILES =
-PROGRAMS = $(bin_PROGRAMS)
-
-
-DEFS = @DEFS@ -I. -I$(srcdir) -I..
-CPPFLAGS = @CPPFLAGS@
-LDFLAGS = @LDFLAGS@
-LIBS = @LIBS@
-bc_OBJECTS = main.o bc.o scan.o execute.o load.o storage.o util.o \
-global.o
-bc_LDADD = $(LDADD)
-bc_DEPENDENCIES = ../lib/libbc.a
-bc_LDFLAGS =
-LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
-LEXLIB = @LEXLIB@
-COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-CCLD = $(CC)
-LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
-HEADERS = $(noinst_HEADERS)
-
-DIST_COMMON = Makefile.am Makefile.in bc.c scan.c
-
-
-DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-
-TAR = tar
-GZIP_ENV = --best
-SOURCES = $(bc_SOURCES)
-OBJECTS = $(bc_OBJECTS)
-
-all: all-redirect
-.SUFFIXES:
-.SUFFIXES: .S .c .l .o .s .y
-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
- cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps bc/Makefile
-
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
- cd $(top_builddir) \
- && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
-
-
-mostlyclean-binPROGRAMS:
-
-clean-binPROGRAMS:
- -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
-
-distclean-binPROGRAMS:
-
-maintainer-clean-binPROGRAMS:
-
-install-binPROGRAMS: $(bin_PROGRAMS)
- @$(NORMAL_INSTALL)
- $(mkinstalldirs) $(DESTDIR)$(bindir)
- @list='$(bin_PROGRAMS)'; for p in $$list; do \
- if test -f $$p; then \
- echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
- $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
- else :; fi; \
- done
-
-uninstall-binPROGRAMS:
- @$(NORMAL_UNINSTALL)
- list='$(bin_PROGRAMS)'; for p in $$list; do \
- rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
- done
-
-.c.o:
- $(COMPILE) -c $<
-
-.s.o:
- $(COMPILE) -c $<
-
-.S.o:
- $(COMPILE) -c $<
-
-mostlyclean-compile:
- -rm -f *.o core *.core
-
-clean-compile:
-
-distclean-compile:
- -rm -f *.tab.c
-
-maintainer-clean-compile:
-
-bc: $(bc_OBJECTS) $(bc_DEPENDENCIES)
- @rm -f bc
- $(LINK) $(bc_LDFLAGS) $(bc_OBJECTS) $(bc_LDADD) $(LIBS)
-.l.c:
- $(LEX) $(AM_LFLAGS) $(LFLAGS) $< && mv $(LEX_OUTPUT_ROOT).c $@
-.y.c:
- $(YACC) $(AM_YFLAGS) $(YFLAGS) $< && mv y.tab.c $*.c
- if test -f y.tab.h; then \
- if cmp -s y.tab.h $*.h; then rm -f y.tab.h; else mv y.tab.h $*.h; fi; \
- else :; fi
-bc.h: bc.c
-
-
-tags: TAGS
-
-ID: $(HEADERS) $(SOURCES) $(LISP)
- list='$(SOURCES) $(HEADERS)'; \
- unique=`for i in $$list; do echo $$i; done | \
- awk ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
- here=`pwd` && cd $(srcdir) \
- && mkid -f$$here/ID $$unique $(LISP)
-
-TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
- tags=; \
- here=`pwd`; \
- list='$(SOURCES) $(HEADERS)'; \
- unique=`for i in $$list; do echo $$i; done | \
- awk ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
- test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
- || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
-
-mostlyclean-tags:
-
-clean-tags:
-
-distclean-tags:
- -rm -f TAGS ID
-
-maintainer-clean-tags:
-
-distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
-
-subdir = bc
-
-distdir: $(DISTFILES)
- @for file in $(DISTFILES); do \
- d=$(srcdir); \
- if test -d $$d/$$file; then \
- cp -pr $$/$$file $(distdir)/$$file; \
- else \
- test -f $(distdir)/$$file \
- || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
- || cp -p $$d/$$file $(distdir)/$$file || :; \
- fi; \
- done
-bc.o: bc.c bcdefs.h ../config.h const.h ../h/number.h global.h proto.h
-execute.o: execute.c bcdefs.h ../config.h const.h ../h/number.h global.h \
- proto.h
-global.o: global.c bcdefs.h ../config.h const.h ../h/number.h global.h \
- libmath.h
-load.o: load.c bcdefs.h ../config.h const.h ../h/number.h global.h \
- proto.h
-main.o: main.c bcdefs.h ../config.h const.h ../h/number.h global.h \
- proto.h ../h/getopt.h
-scan.o: scan.c bcdefs.h ../config.h const.h ../h/number.h bc.h global.h \
- proto.h
-storage.o: storage.c bcdefs.h ../config.h const.h ../h/number.h global.h \
- proto.h
-util.o: util.c bcdefs.h ../config.h const.h ../h/number.h global.h \
- proto.h
-
-info-am:
-info: info-am
-dvi-am:
-dvi: dvi-am
-check-am: all-am
-check: check-am
-installcheck-am:
-installcheck: installcheck-am
-install-exec-am: install-binPROGRAMS
-install-exec: install-exec-am
-
-install-data-am:
-install-data: install-data-am
-
-install-am: all-am
- @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-install: install-am
-uninstall-am: uninstall-binPROGRAMS
-uninstall: uninstall-am
-all-am: Makefile $(PROGRAMS) $(HEADERS)
-all-redirect: all-am
-install-strip:
- $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
-installdirs:
- $(mkinstalldirs) $(DESTDIR)$(bindir)
-
-
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
- -rm -f Makefile $(CONFIG_CLEAN_FILES)
- -rm -f config.cache config.log stamp-h stamp-h[0-9]*
- -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
-
-maintainer-clean-generic:
- -test -z "scanlbchbcc$(MAINTAINERCLEANFILES)" || rm -f scanl bch bcc $(MAINTAINERCLEANFILES)
-mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \
- mostlyclean-tags mostlyclean-generic
-
-mostlyclean: mostlyclean-am
-
-clean-am: clean-binPROGRAMS clean-compile clean-tags clean-generic \
- mostlyclean-am
-
-clean: clean-am
-
-distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \
- distclean-generic clean-am
-
-distclean: distclean-am
-
-maintainer-clean-am: maintainer-clean-binPROGRAMS \
- maintainer-clean-compile maintainer-clean-tags \
- maintainer-clean-generic distclean-am
- @echo "This command is intended for maintainers to use;"
- @echo "it deletes files that may require special tools to rebuild."
-
-maintainer-clean: maintainer-clean-am
-
-.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
-maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
-mostlyclean-compile distclean-compile clean-compile \
-maintainer-clean-compile tags mostlyclean-tags distclean-tags \
-clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
-check-am installcheck-am installcheck install-exec-am install-exec \
-install-data-am install-data install-am install uninstall-am uninstall \
-all-redirect all-am all installdirs mostlyclean-generic \
-distclean-generic clean-generic maintainer-clean-generic clean \
-mostlyclean distclean maintainer-clean
-
-
-$(PROGRAMS): $(LIBBC)
-
-scan.o: bc.h
-global.o: libmath.h
-
-libmath.h: libmath.b
- echo '{0}' > libmath.h
- $(MAKE) fbc
- ./fbc -c $(srcdir)/libmath.b </dev/null >libmath.h
- $(srcdir)/fix-libmath_h
- rm -f ./fbc
-fbc: $(fbcOBJ)
- $(LINK) $(fbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS)
-sbc.o: sbc.c
-sbc: $(sbcOBJ)
- $(LINK) $(sbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS)
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/contrib/bc/bc/bc.y b/contrib/bc/bc/bc.y
deleted file mode 100644
index 403e326..0000000
--- a/contrib/bc/bc/bc.y
+++ /dev/null
@@ -1,654 +0,0 @@
-%{
-/* bc.y: The grammar for a POSIX compatable bc processor with some
- extensions to the language. */
-
-/* This file is part of GNU bc.
- Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to:
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111 USA
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-#include "bcdefs.h"
-#include "global.h"
-#include "proto.h"
-%}
-
-%start program
-
-%union {
- char *s_value;
- char c_value;
- int i_value;
- arg_list *a_value;
- }
-
-/* Extensions over POSIX bc.
- a) NAME was LETTER. This grammar allows longer names.
- Single letter names will still work.
- b) Relational_expression allowed only one comparison.
- This grammar has added boolean expressions with
- && (and) || (or) and ! (not) and allowed all of them in
- full expressions.
- c) Added an else to the if.
- d) Call by variable array parameters
- e) read() procedure that reads a number under program control from stdin.
- f) halt statement that halts the the program under program control. It
- is an executed statement.
- g) continue statement for for loops.
- h) optional expressions in the for loop.
- i) print statement to print multiple numbers per line.
- j) warranty statement to print an extended warranty notice.
- j) limits statement to print the processor's limits.
-*/
-
-%token <i_value> ENDOFLINE AND OR NOT
-%token <s_value> STRING NAME NUMBER
-/* '-', '+' are tokens themselves */
-/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */
-%token <c_value> ASSIGN_OP
-/* '==', '<=', '>=', '!=', '<', '>' */
-%token <s_value> REL_OP
-/* '++', '--' */
-%token <c_value> INCR_DECR
-/* 'define', 'break', 'quit', 'length' */
-%token <i_value> Define Break Quit Length
-/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */
-%token <i_value> Return For If While Sqrt Else
-/* 'scale', 'ibase', 'obase', 'auto', 'read' */
-%token <i_value> Scale Ibase Obase Auto Read
-/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */
-%token <i_value> Warranty, Halt, Last, Continue, Print, Limits
-/* 'history' */
-%token <i_value> UNARY_MINUS HistoryVar
-
-/* Types of all other things. */
-%type <i_value> expression return_expression named_expression opt_expression
-%type <c_value> '+' '-' '*' '/' '%'
-%type <a_value> opt_parameter_list opt_auto_define_list define_list
-%type <a_value> opt_argument_list argument_list
-%type <i_value> program input_item semicolon_list statement_list
-%type <i_value> statement function statement_or_error required_eol
-
-/* precedence */
-%left OR
-%left AND
-%nonassoc NOT
-%left REL_OP
-%right ASSIGN_OP
-%left '+' '-'
-%left '*' '/' '%'
-%right '^'
-%nonassoc UNARY_MINUS
-%nonassoc INCR_DECR
-
-%%
-program : /* empty */
- {
- $$ = 0;
- if (interactive && !quiet)
- {
- show_bc_version ();
- welcome ();
- }
- }
- | program input_item
- ;
-input_item : semicolon_list ENDOFLINE
- { run_code (); }
- | function
- { run_code (); }
- | error ENDOFLINE
- {
- yyerrok;
- init_gen ();
- }
- ;
-opt_newline : /* empty */
- | ENDOFLINE
- { warn ("newline not allowed"); }
- ;
-semicolon_list : /* empty */
- { $$ = 0; }
- | statement_or_error
- | semicolon_list ';' statement_or_error
- | semicolon_list ';'
- ;
-statement_list : /* empty */
- { $$ = 0; }
- | statement_or_error
- | statement_list ENDOFLINE
- | statement_list ENDOFLINE statement_or_error
- | statement_list ';'
- | statement_list ';' statement
- ;
-statement_or_error : statement
- | error statement
- { $$ = $2; }
- ;
-statement : Warranty
- { warranty (""); }
- | Limits
- { limits (); }
- | expression
- {
- if ($1 & 2)
- warn ("comparison in expression");
- if ($1 & 1)
- generate ("W");
- else
- generate ("p");
- }
- | STRING
- {
- $$ = 0;
- generate ("w");
- generate ($1);
- free ($1);
- }
- | Break
- {
- if (break_label == 0)
- yyerror ("Break outside a for/while");
- else
- {
- sprintf (genstr, "J%1d:", break_label);
- generate (genstr);
- }
- }
- | Continue
- {
- warn ("Continue statement");
- if (continue_label == 0)
- yyerror ("Continue outside a for");
- else
- {
- sprintf (genstr, "J%1d:", continue_label);
- generate (genstr);
- }
- }
- | Quit
- { exit (0); }
- | Halt
- { generate ("h"); }
- | Return return_expression
- { generate ("R"); }
- | For
- {
- $1 = break_label;
- break_label = next_label++;
- }
- '(' opt_expression ';'
- {
- if ($4 & 2)
- warn ("Comparison in first for expression");
- if ($4 >= 0)
- generate ("p");
- $4 = next_label++;
- sprintf (genstr, "N%1d:", $4);
- generate (genstr);
- }
- opt_expression ';'
- {
- if ($7 < 0) generate ("1");
- $7 = next_label++;
- sprintf (genstr, "B%1d:J%1d:", $7, break_label);
- generate (genstr);
- $<i_value>$ = continue_label;
- continue_label = next_label++;
- sprintf (genstr, "N%1d:", continue_label);
- generate (genstr);
- }
- opt_expression ')'
- {
- if ($10 & 2 )
- warn ("Comparison in third for expression");
- if ($10 & 16)
- sprintf (genstr, "J%1d:N%1d:", $4, $7);
- else
- sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
- generate (genstr);
- }
- opt_newline statement
- {
- sprintf (genstr, "J%1d:N%1d:",
- continue_label, break_label);
- generate (genstr);
- break_label = $1;
- continue_label = $<i_value>9;
- }
- | If '(' expression ')'
- {
- $3 = if_label;
- if_label = next_label++;
- sprintf (genstr, "Z%1d:", if_label);
- generate (genstr);
- }
- opt_newline statement opt_else
- {
- sprintf (genstr, "N%1d:", if_label);
- generate (genstr);
- if_label = $3;
- }
- | While
- {
- $1 = next_label++;
- sprintf (genstr, "N%1d:", $1);
- generate (genstr);
- }
- '(' expression
- {
- $4 = break_label;
- break_label = next_label++;
- sprintf (genstr, "Z%1d:", break_label);
- generate (genstr);
- }
- ')' opt_newline statement
- {
- sprintf (genstr, "J%1d:N%1d:", $1, break_label);
- generate (genstr);
- break_label = $4;
- }
- | '{' statement_list '}'
- { $$ = 0; }
- | Print
- { warn ("print statement"); }
- print_list
- ;
-print_list : print_element
- | print_element ',' print_list
- ;
-print_element : STRING
- {
- generate ("O");
- generate ($1);
- free ($1);
- }
- | expression
- { generate ("P"); }
- ;
-opt_else : /* nothing */
- | Else
- {
- warn ("else clause in if statement");
- $1 = next_label++;
- sprintf (genstr, "J%d:N%1d:", $1, if_label);
- generate (genstr);
- if_label = $1;
- }
- opt_newline statement
-function : Define NAME '(' opt_parameter_list ')' opt_newline
- '{' required_eol opt_auto_define_list
- {
- /* Check auto list against parameter list? */
- check_params ($4,$9);
- sprintf (genstr, "F%d,%s.%s[",
- lookup($2,FUNCTDEF),
- arg_str ($4), arg_str ($9));
- generate (genstr);
- free_args ($4);
- free_args ($9);
- $1 = next_label;
- next_label = 1;
- }
- statement_list /* ENDOFLINE */ '}'
- {
- generate ("0R]");
- next_label = $1;
- }
- ;
-opt_parameter_list : /* empty */
- { $$ = NULL; }
- | define_list
- ;
-opt_auto_define_list : /* empty */
- { $$ = NULL; }
- | Auto define_list ENDOFLINE
- { $$ = $2; }
- | Auto define_list ';'
- { $$ = $2; }
- ;
-define_list : NAME
- { $$ = nextarg (NULL, lookup ($1,SIMPLE), FALSE);}
- | NAME '[' ']'
- { $$ = nextarg (NULL, lookup ($1,ARRAY), FALSE); }
- | '*' NAME '[' ']'
- { $$ = nextarg (NULL, lookup ($2,ARRAY), TRUE); }
- | define_list ',' NAME
- { $$ = nextarg ($1, lookup ($3,SIMPLE), FALSE); }
- | define_list ',' NAME '[' ']'
- { $$ = nextarg ($1, lookup ($3,ARRAY), FALSE); }
- | define_list ',' '*' NAME '[' ']'
- { $$ = nextarg ($1, lookup ($4,ARRAY), TRUE); }
- ;
-opt_argument_list : /* empty */
- { $$ = NULL; }
- | argument_list
- ;
-argument_list : expression
- {
- if ($1 & 2) warn ("comparison in argument");
- $$ = nextarg (NULL,0,FALSE);
- }
- | NAME '[' ']'
- {
- sprintf (genstr, "K%d:", -lookup ($1,ARRAY));
- generate (genstr);
- $$ = nextarg (NULL,1,FALSE);
- }
- | argument_list ',' expression
- {
- if ($3 & 2) warn ("comparison in argument");
- $$ = nextarg ($1,0,FALSE);
- }
- | argument_list ',' NAME '[' ']'
- {
- sprintf (genstr, "K%d:", -lookup ($3,ARRAY));
- generate (genstr);
- $$ = nextarg ($1,1,FALSE);
- }
- ;
-
-/* Expression lval meanings! (Bits mean something!)
- * 0 => Top op is assignment.
- * 1 => Top op is not assignment.
- * 2 => Comparison is somewhere in expression.
- * 4 => Expression is in parenthesis.
- * 16 => Empty optional expression.
- */
-
-opt_expression : /* empty */
- {
- $$ = 16;
- warn ("Missing expression in for statement");
- }
- | expression
- ;
-return_expression : /* empty */
- {
- $$ = 0;
- generate ("0");
- }
- | expression
- {
- if ($1 & 2)
- warn ("comparison in return expresion");
- if (!($1 & 4))
- warn ("return expression requires parenthesis");
- }
- ;
-expression : named_expression ASSIGN_OP
- {
- if ($2 != '=')
- {
- if ($1 < 0)
- sprintf (genstr, "DL%d:", -$1);
- else
- sprintf (genstr, "l%d:", $1);
- generate (genstr);
- }
- }
- expression
- {
- if ($4 & 2) warn("comparison in assignment");
- if ($2 != '=')
- {
- sprintf (genstr, "%c", $2);
- generate (genstr);
- }
- if ($1 < 0)
- sprintf (genstr, "S%d:", -$1);
- else
- sprintf (genstr, "s%d:", $1);
- generate (genstr);
- $$ = 0;
- }
- ;
- | expression AND
- {
- warn("&& operator");
- $2 = next_label++;
- sprintf (genstr, "DZ%d:p", $2);
- generate (genstr);
- }
- expression
- {
- sprintf (genstr, "DZ%d:p1N%d:", $2, $2);
- generate (genstr);
- $$ = ($1 | $4) & ~4;
- }
- | expression OR
- {
- warn("|| operator");
- $2 = next_label++;
- sprintf (genstr, "B%d:", $2);
- generate (genstr);
- }
- expression
- {
- int tmplab;
- tmplab = next_label++;
- sprintf (genstr, "B%d:0J%d:N%d:1N%d:",
- $2, tmplab, $2, tmplab);
- generate (genstr);
- $$ = ($1 | $4) & ~4;
- }
- | NOT expression
- {
- $$ = $2 & ~4;
- warn("! operator");
- generate ("!");
- }
- | expression REL_OP expression
- {
- $$ = 3;
- switch (*($2))
- {
- case '=':
- generate ("=");
- break;
-
- case '!':
- generate ("#");
- break;
-
- case '<':
- if ($2[1] == '=')
- generate ("{");
- else
- generate ("<");
- break;
-
- case '>':
- if ($2[1] == '=')
- generate ("}");
- else
- generate (">");
- break;
- }
- }
- | expression '+' expression
- {
- generate ("+");
- $$ = ($1 | $3) & ~4;
- }
- | expression '-' expression
- {
- generate ("-");
- $$ = ($1 | $3) & ~4;
- }
- | expression '*' expression
- {
- generate ("*");
- $$ = ($1 | $3) & ~4;
- }
- | expression '/' expression
- {
- generate ("/");
- $$ = ($1 | $3) & ~4;
- }
- | expression '%' expression
- {
- generate ("%");
- $$ = ($1 | $3) & ~4;
- }
- | expression '^' expression
- {
- generate ("^");
- $$ = ($1 | $3) & ~4;
- }
- | '-' expression %prec UNARY_MINUS
- {
- generate ("n");
- $$ = $2 & ~4;
- }
- | named_expression
- {
- $$ = 1;
- if ($1 < 0)
- sprintf (genstr, "L%d:", -$1);
- else
- sprintf (genstr, "l%d:", $1);
- generate (genstr);
- }
- | NUMBER
- {
- int len = strlen($1);
- $$ = 1;
- if (len == 1 && *$1 == '0')
- generate ("0");
- else if (len == 1 && *$1 == '1')
- generate ("1");
- else
- {
- generate ("K");
- generate ($1);
- generate (":");
- }
- free ($1);
- }
- | '(' expression ')'
- { $$ = $2 | 5; }
- | NAME '(' opt_argument_list ')'
- {
- $$ = 1;
- if ($3 != NULL)
- {
- sprintf (genstr, "C%d,%s:",
- lookup ($1,FUNCT),
- call_str ($3));
- free_args ($3);
- }
- else
- {
- sprintf (genstr, "C%d:", lookup ($1,FUNCT));
- }
- generate (genstr);
- }
- | INCR_DECR named_expression
- {
- $$ = 1;
- if ($2 < 0)
- {
- if ($1 == '+')
- sprintf (genstr, "DA%d:L%d:", -$2, -$2);
- else
- sprintf (genstr, "DM%d:L%d:", -$2, -$2);
- }
- else
- {
- if ($1 == '+')
- sprintf (genstr, "i%d:l%d:", $2, $2);
- else
- sprintf (genstr, "d%d:l%d:", $2, $2);
- }
- generate (genstr);
- }
- | named_expression INCR_DECR
- {
- $$ = 1;
- if ($1 < 0)
- {
- sprintf (genstr, "DL%d:x", -$1);
- generate (genstr);
- if ($2 == '+')
- sprintf (genstr, "A%d:", -$1);
- else
- sprintf (genstr, "M%d:", -$1);
- }
- else
- {
- sprintf (genstr, "l%d:", $1);
- generate (genstr);
- if ($2 == '+')
- sprintf (genstr, "i%d:", $1);
- else
- sprintf (genstr, "d%d:", $1);
- }
- generate (genstr);
- }
- | Length '(' expression ')'
- { generate ("cL"); $$ = 1;}
- | Sqrt '(' expression ')'
- { generate ("cR"); $$ = 1;}
- | Scale '(' expression ')'
- { generate ("cS"); $$ = 1;}
- | Read '(' ')'
- {
- warn ("read function");
- generate ("cI"); $$ = 1;
- }
- ;
-named_expression : NAME
- { $$ = lookup($1,SIMPLE); }
- | NAME '[' expression ']'
- {
- if ($3 > 1) warn("comparison in subscript");
- $$ = lookup($1,ARRAY);
- }
- | Ibase
- { $$ = 0; }
- | Obase
- { $$ = 1; }
- | Scale
- { $$ = 2; }
- | HistoryVar
- { $$ = 3;
- warn ("History variable");
- }
- | Last
- { $$ = 4;
- warn ("Last variable");
- }
- ;
-
-
-required_eol : { warn ("End of line required"); }
- | ENDOFLINE
- | required_eol ENDOFLINE
- { warn ("Too many end of lines"); }
- ;
-
-%%
-
diff --git a/contrib/bc/bc/bcdefs.h b/contrib/bc/bc/bcdefs.h
deleted file mode 100644
index 260cd12..0000000
--- a/contrib/bc/bc/bcdefs.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/* bcdefs.h: The single file to include all constants and type definitions. */
-
-/* This file is part of GNU bc.
- Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111 USA
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-/* Include the configuration file. */
-#include "config.h"
-
-/* Standard includes for all files. */
-#include <stdio.h>
-#include <sys/types.h>
-#include <ctype.h>
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#else
-#include <string.h>
-#endif
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-
-#if defined(LIBEDIT)
-#include <histedit.h>
-#endif
-
-#if defined(READLINE)
-#include <readline/readline.h>
-#include <readline/history.h>
-#endif
-
-/* Include the other definitions. */
-#include "const.h"
-#include "number.h"
-
-/* These definitions define all the structures used in
- code and data storage. This includes the representation of
- labels. The "guiding" principle is to make structures that
- take a minimum of space when unused but can be built to contain
- the full structures. */
-
-/* Labels are first. Labels are generated sequentially in functions
- and full code. They just "point" to a single bye in the code. The
- "address" is the byte number. The byte number is used to get an
- actual character pointer. */
-
-typedef struct bc_label_group
- {
- long l_adrs [ BC_LABEL_GROUP ];
- struct bc_label_group *l_next;
- } bc_label_group;
-
-/* Argument list. Recorded in the function so arguments can
- be checked at call time. */
-
-typedef struct arg_list
- {
- int av_name;
- int arg_is_var; /* Extension ... variable parameters. */
- struct arg_list *next;
- } arg_list;
-
-/* Each function has its own code segments and labels. There can be
- no jumps between functions so labels are unique to a function. */
-
-typedef struct
- {
- char f_defined; /* Is this function defined yet. */
- char *f_body;
- int f_body_size; /* Size of body. Power of 2. */
- int f_code_size;
- bc_label_group *f_label;
- arg_list *f_params;
- arg_list *f_autos;
- } bc_function;
-
-/* Code addresses. */
-typedef struct {
- int pc_func;
- int pc_addr;
- } program_counter;
-
-
-/* Variables are "pushable" (auto) and thus we need a stack mechanism.
- This is built into the variable record. */
-
-typedef struct bc_var
- {
- bc_num v_value;
- struct bc_var *v_next;
- } bc_var;
-
-
-/* bc arrays can also be "auto" variables and thus need the same
- kind of stacking mechanisms. */
-
-typedef struct bc_array_node
- {
- union
- {
- bc_num n_num [NODE_SIZE];
- struct bc_array_node *n_down [NODE_SIZE];
- } n_items;
- } bc_array_node;
-
-typedef struct bc_array
- {
- bc_array_node *a_tree;
- short a_depth;
- } bc_array;
-
-typedef struct bc_var_array
- {
- bc_array *a_value;
- char a_param;
- struct bc_var_array *a_next;
- } bc_var_array;
-
-
-/* For the stacks, execution and function, we need records to allow
- for arbitrary size. */
-
-typedef struct estack_rec {
- bc_num s_num;
- struct estack_rec *s_next;
-} estack_rec;
-
-typedef struct fstack_rec {
- int s_val;
- struct fstack_rec *s_next;
-} fstack_rec;
-
-
-/* The following are for the name tree. */
-
-typedef struct id_rec {
- char *id; /* The program name. */
- /* A name == 0 => nothing assigned yet. */
- int a_name; /* The array variable name (number). */
- int f_name; /* The function name (number). */
- int v_name; /* The variable name (number). */
- short balance; /* For the balanced tree. */
- struct id_rec *left, *right; /* Tree pointers. */
-} id_rec;
-
-
-/* A list of files to process. */
-
-typedef struct file_node {
- char *name;
- struct file_node *next;
-} file_node;
-
-/* Macro Definitions */
-
-#if defined(LIBEDIT)
-#define HISTORY_SIZE(n) history(hist, &histev, H_SETSIZE, n)
-#define UNLIMIT_HISTORY history(hist, &histev, H_SETSIZE, INT_MAX)
-#endif
-
-#if defined(READLINE)
-#define HISTORY_SIZE(n) stifle_history(n)
-#define UNLIMIT_HISTORY unstifle_history()
-#endif
diff --git a/contrib/bc/bc/const.h b/contrib/bc/bc/const.h
deleted file mode 100644
index 1a7c5b8..0000000
--- a/contrib/bc/bc/const.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/* const.h: Constants for bc. */
-
-/* This file is part of GNU bc.
- Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111 USA
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-
-/* Define INT_MAX and LONG_MAX if not defined. Assuming 32 bits... */
-
-#ifndef INT_MAX
-#define INT_MAX 0x7FFFFFFF
-#endif
-#ifndef LONG_MAX
-#define LONG_MAX 0x7FFFFFFF
-#endif
-
-
-/* Define constants in some reasonable size. The next 4 constants are
- POSIX constants. */
-
-#ifdef BC_BASE_MAX
- /* <limits.h> on a POSIX.2 system may have defined these. Override. */
-# undef BC_BASE_MAX
-# undef BC_SCALE_MAX
-# undef BC_STRING_MAX
-# undef BC_DIM_MAX
-#endif
-
-#define BC_BASE_MAX INT_MAX
-#define BC_SCALE_MAX INT_MAX
-#define BC_STRING_MAX INT_MAX
-
-
-/* Definitions for arrays. */
-
-#define BC_DIM_MAX 65535 /* this should be NODE_SIZE^NODE_DEPTH-1 */
-
-#define NODE_SIZE 16 /* Must be a power of 2. */
-#define NODE_MASK 0xf /* Must be NODE_SIZE-1. */
-#define NODE_SHIFT 4 /* Number of 1 bits in NODE_MASK. */
-#define NODE_DEPTH 4
-
-
-/* Other BC limits defined but not part of POSIX. */
-
-#define BC_LABEL_GROUP 64
-#define BC_LABEL_LOG 6
-#define BC_START_SIZE 1024 /* Initial code body size. */
-
-/* Maximum number of variables, arrays and functions and the
- allocation increment for the dynamic arrays. */
-
-#define MAX_STORE 32767
-#define STORE_INCR 32
-
-/* Other interesting constants. */
-
-#define FALSE 0
-#define TRUE 1
-
-/* for use with lookup (). */
-#define SIMPLE 0
-#define ARRAY 1
-#define FUNCT 2
-#define FUNCTDEF 3
-
-#define EXTERN extern
-#ifdef __STDC__
-#define CONST const
-#define VOID void
-#else
-#define CONST
-#define VOID
-#endif
diff --git a/contrib/bc/bc/execute.c b/contrib/bc/bc/execute.c
deleted file mode 100644
index d2864d11..0000000
--- a/contrib/bc/bc/execute.c
+++ /dev/null
@@ -1,788 +0,0 @@
-/* execute.c - run a bc program. */
-
-/* This file is part of GNU bc.
- Copyright (C) 1991-1994, 1997, 2000 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111 USA
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-#include "bcdefs.h"
-#include <signal.h>
-#include "global.h"
-#include "proto.h"
-
-
-/* The SIGINT interrupt handling routine. */
-
-int had_sigint;
-
-void
-stop_execution (sig)
- int sig;
-{
- had_sigint = TRUE;
- printf ("\n");
- rt_error ("interrupted execution");
-}
-
-
-/* Get the current byte and advance the PC counter. */
-
-unsigned char
-byte (pc)
- program_counter *pc;
-{
- return (functions[pc->pc_func].f_body[pc->pc_addr++]);
-}
-
-
-/* The routine that actually runs the machine. */
-
-void
-execute ()
-{
- int label_num, l_gp, l_off;
- bc_label_group *gp;
-
- char inst, ch;
- int new_func;
- int var_name;
-
- int const_base;
-
- bc_num temp_num;
- arg_list *auto_list;
-
- /* Initialize this run... */
- pc.pc_func = 0;
- pc.pc_addr = 0;
- runtime_error = FALSE;
- bc_init_num (&temp_num);
-
- /* Set up the interrupt mechanism for an interactive session. */
- if (interactive)
- {
- signal (SIGINT, stop_execution);
- had_sigint = FALSE;
- }
-
- while (pc.pc_addr < functions[pc.pc_func].f_code_size && !runtime_error)
- {
- inst = byte(&pc);
-
-#if DEBUG > 3
- { /* Print out address and the stack before each instruction.*/
- int depth; estack_rec *temp = ex_stack;
-
- printf ("func=%d addr=%d inst=%c\n",pc.pc_func, pc.pc_addr, inst);
- if (temp == NULL) printf ("empty stack.\n", inst);
- else
- {
- depth = 1;
- while (temp != NULL)
- {
- printf (" %d = ", depth);
- bc_out_num (temp->s_num, 10, out_char, std_only);
- depth++;
- temp = temp->s_next;
- }
- out_char ('\n');
- }
- }
-#endif
-
- switch ( inst )
- {
-
- case 'A' : /* increment array variable (Add one). */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name & 0x7f) << 8) + byte(&pc);
- incr_array (var_name);
- break;
-
- case 'B' : /* Branch to a label if TOS != 0. Remove value on TOS. */
- case 'Z' : /* Branch to a label if TOS == 0. Remove value on TOS. */
- c_code = !bc_is_zero (ex_stack->s_num);
- pop ();
- case 'J' : /* Jump to a label. */
- label_num = byte(&pc); /* Low order bits first. */
- label_num += byte(&pc) << 8;
- if (inst == 'J' || (inst == 'B' && c_code)
- || (inst == 'Z' && !c_code)) {
- gp = functions[pc.pc_func].f_label;
- l_gp = label_num >> BC_LABEL_LOG;
- l_off = label_num % BC_LABEL_GROUP;
- while (l_gp-- > 0) gp = gp->l_next;
- pc.pc_addr = gp->l_adrs[l_off];
- }
- break;
-
- case 'C' : /* Call a function. */
- /* Get the function number. */
- new_func = byte(&pc);
- if ((new_func & 0x80) != 0)
- new_func = ((new_func & 0x7f) << 8) + byte(&pc);
-
- /* Check to make sure it is defined. */
- if (!functions[new_func].f_defined)
- {
- rt_error ("Function %s not defined.", f_names[new_func]);
- break;
- }
-
- /* Check and push parameters. */
- process_params (&pc, new_func);
-
- /* Push auto variables. */
- for (auto_list = functions[new_func].f_autos;
- auto_list != NULL;
- auto_list = auto_list->next)
- auto_var (auto_list->av_name);
-
- /* Push pc and ibase. */
- fpush (pc.pc_func);
- fpush (pc.pc_addr);
- fpush (i_base);
-
- /* Reset pc to start of function. */
- pc.pc_func = new_func;
- pc.pc_addr = 0;
- break;
-
- case 'D' : /* Duplicate top of stack */
- push_copy (ex_stack->s_num);
- break;
-
- case 'K' : /* Push a constant */
- /* Get the input base and convert it to a bc number. */
- if (pc.pc_func == 0)
- const_base = i_base;
- else
- const_base = fn_stack->s_val;
- if (const_base == 10)
- push_b10_const (&pc);
- else
- push_constant (prog_char, const_base);
- break;
-
- case 'L' : /* load array variable */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name & 0x7f) << 8) + byte(&pc);
- load_array (var_name);
- break;
-
- case 'M' : /* decrement array variable (Minus!) */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name & 0x7f) << 8) + byte(&pc);
- decr_array (var_name);
- break;
-
- case 'O' : /* Write a string to the output with processing. */
- while ((ch = byte(&pc)) != '"')
- if (ch != '\\')
- out_schar (ch);
- else
- {
- ch = byte(&pc);
- if (ch == '"') break;
- switch (ch)
- {
- case 'a': out_schar (007); break;
- case 'b': out_schar ('\b'); break;
- case 'f': out_schar ('\f'); break;
- case 'n': out_schar ('\n'); break;
- case 'q': out_schar ('"'); break;
- case 'r': out_schar ('\r'); break;
- case 't': out_schar ('\t'); break;
- case '\\': out_schar ('\\'); break;
- default: break;
- }
- }
- fflush (stdout);
- break;
-
- case 'R' : /* Return from function */
- if (pc.pc_func != 0)
- {
- /* "Pop" autos and parameters. */
- pop_vars(functions[pc.pc_func].f_autos);
- pop_vars(functions[pc.pc_func].f_params);
- /* reset the pc. */
- fpop ();
- pc.pc_addr = fpop ();
- pc.pc_func = fpop ();
- }
- else
- rt_error ("Return from main program.");
- break;
-
- case 'S' : /* store array variable */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name & 0x7f ) << 8) + byte(&pc);
- store_array (var_name);
- break;
-
- case 'T' : /* Test tos for zero */
- c_code = bc_is_zero (ex_stack->s_num);
- assign (c_code);
- break;
-
- case 'W' : /* Write the value on the top of the stack. */
- case 'P' : /* Write the value on the top of the stack. No newline. */
- bc_out_num (ex_stack->s_num, o_base, out_char, std_only);
- if (inst == 'W') out_char ('\n');
- store_var (4); /* Special variable "last". */
- fflush (stdout);
- pop ();
- break;
-
- case 'c' : /* Call special function. */
- new_func = byte(&pc);
-
- switch (new_func)
- {
- case 'L': /* Length function. */
- /* For the number 0.xxxx, 0 is not significant. */
- if (ex_stack->s_num->n_len == 1 &&
- ex_stack->s_num->n_scale != 0 &&
- ex_stack->s_num->n_value[0] == 0 )
- bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
- else
- bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_len
- + ex_stack->s_num->n_scale);
- break;
-
- case 'S': /* Scale function. */
- bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
- break;
-
- case 'R': /* Square Root function. */
- if (!bc_sqrt (&ex_stack->s_num, scale))
- rt_error ("Square root of a negative number");
- break;
-
- case 'I': /* Read function. */
- push_constant (input_char, i_base);
- break;
- }
- break;
-
- case 'd' : /* Decrement number */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name & 0x7f) << 8) + byte(&pc);
- decr_var (var_name);
- break;
-
- case 'h' : /* Halt the machine. */
- exit (0);
-
- case 'i' : /* increment number */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name & 0x7f) << 8) + byte(&pc);
- incr_var (var_name);
- break;
-
- case 'l' : /* load variable */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name & 0x7f) << 8) + byte(&pc);
- load_var (var_name);
- break;
-
- case 'n' : /* Negate top of stack. */
- bc_sub (_zero_, ex_stack->s_num, &ex_stack->s_num, 0);
- break;
-
- case 'p' : /* Pop the execution stack. */
- pop ();
- break;
-
- case 's' : /* store variable */
- var_name = byte(&pc);
- if ((var_name & 0x80) != 0)
- var_name = ((var_name & 0x7f) << 8) + byte(&pc);
- store_var (var_name);
- break;
-
- case 'w' : /* Write a string to the output. */
- while ((ch = byte(&pc)) != '"') out_schar (ch);
- fflush (stdout);
- break;
-
- case 'x' : /* Exchange Top of Stack with the one under the tos. */
- if (check_stack(2)) {
- bc_num temp = ex_stack->s_num;
- ex_stack->s_num = ex_stack->s_next->s_num;
- ex_stack->s_next->s_num = temp;
- }
- break;
-
- case '0' : /* Load Constant 0. */
- push_copy (_zero_);
- break;
-
- case '1' : /* Load Constant 0. */
- push_copy (_one_);
- break;
-
- case '!' : /* Negate the boolean value on top of the stack. */
- c_code = bc_is_zero (ex_stack->s_num);
- assign (c_code);
- break;
-
- case '&' : /* compare greater than */
- if (check_stack(2))
- {
- c_code = !bc_is_zero (ex_stack->s_next->s_num)
- && !bc_is_zero (ex_stack->s_num);
- pop ();
- assign (c_code);
- }
- break;
-
- case '|' : /* compare greater than */
- if (check_stack(2))
- {
- c_code = !bc_is_zero (ex_stack->s_next->s_num)
- || !bc_is_zero (ex_stack->s_num);
- pop ();
- assign (c_code);
- }
- break;
-
- case '+' : /* add */
- if (check_stack(2))
- {
- bc_add (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0);
- pop();
- pop();
- push_num (temp_num);
- bc_init_num (&temp_num);
- }
- break;
-
- case '-' : /* subtract */
- if (check_stack(2))
- {
- bc_sub (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0);
- pop();
- pop();
- push_num (temp_num);
- bc_init_num (&temp_num);
- }
- break;
-
- case '*' : /* multiply */
- if (check_stack(2))
- {
- bc_multiply (ex_stack->s_next->s_num, ex_stack->s_num,
- &temp_num, scale);
- pop();
- pop();
- push_num (temp_num);
- bc_init_num (&temp_num);
- }
- break;
-
- case '/' : /* divide */
- if (check_stack(2))
- {
- if (bc_divide (ex_stack->s_next->s_num,
- ex_stack->s_num, &temp_num, scale) == 0)
- {
- pop();
- pop();
- push_num (temp_num);
- bc_init_num (&temp_num);
- }
- else
- rt_error ("Divide by zero");
- }
- break;
-
- case '%' : /* remainder */
- if (check_stack(2))
- {
- if (bc_is_zero (ex_stack->s_num))
- rt_error ("Modulo by zero");
- else
- {
- bc_modulo (ex_stack->s_next->s_num,
- ex_stack->s_num, &temp_num, scale);
- pop();
- pop();
- push_num (temp_num);
- bc_init_num (&temp_num);
- }
- }
- break;
-
- case '^' : /* raise */
- if (check_stack(2))
- {
- bc_raise (ex_stack->s_next->s_num,
- ex_stack->s_num, &temp_num, scale);
- if (bc_is_zero (ex_stack->s_next->s_num) && bc_is_neg (ex_stack->s_num))
- rt_error ("divide by zero");
- pop();
- pop();
- push_num (temp_num);
- bc_init_num (&temp_num);
- }
- break;
-
- case '=' : /* compare equal */
- if (check_stack(2))
- {
- c_code = bc_compare (ex_stack->s_next->s_num,
- ex_stack->s_num) == 0;
- pop ();
- assign (c_code);
- }
- break;
-
- case '#' : /* compare not equal */
- if (check_stack(2))
- {
- c_code = bc_compare (ex_stack->s_next->s_num,
- ex_stack->s_num) != 0;
- pop ();
- assign (c_code);
- }
- break;
-
- case '<' : /* compare less than */
- if (check_stack(2))
- {
- c_code = bc_compare (ex_stack->s_next->s_num,
- ex_stack->s_num) == -1;
- pop ();
- assign (c_code);
- }
- break;
-
- case '{' : /* compare less than or equal */
- if (check_stack(2))
- {
- c_code = bc_compare (ex_stack->s_next->s_num,
- ex_stack->s_num) <= 0;
- pop ();
- assign (c_code);
- }
- break;
-
- case '>' : /* compare greater than */
- if (check_stack(2))
- {
- c_code = bc_compare (ex_stack->s_next->s_num,
- ex_stack->s_num) == 1;
- pop ();
- assign (c_code);
- }
- break;
-
- case '}' : /* compare greater than or equal */
- if (check_stack(2))
- {
- c_code = bc_compare (ex_stack->s_next->s_num,
- ex_stack->s_num) >= 0;
- pop ();
- assign (c_code);
- }
- break;
-
- default : /* error! */
- rt_error ("bad instruction: inst=%c", inst);
- }
- }
-
- /* Clean up the function stack and pop all autos/parameters. */
- while (pc.pc_func != 0)
- {
- pop_vars(functions[pc.pc_func].f_autos);
- pop_vars(functions[pc.pc_func].f_params);
- fpop ();
- pc.pc_addr = fpop ();
- pc.pc_func = fpop ();
- }
-
- /* Clean up the execution stack. */
- while (ex_stack != NULL) pop();
-
- /* Clean up the interrupt stuff. */
- if (interactive)
- {
- signal (SIGINT, use_quit);
- if (had_sigint)
- printf ("Interruption completed.\n");
- }
-}
-
-
-/* Prog_char gets another byte from the program. It is used for
- conversion of text constants in the code to numbers. */
-
-char
-prog_char ()
-{
- return byte(&pc);
-}
-
-
-/* Read a character from the standard input. This function is used
- by the "read" function. */
-
-char
-input_char ()
-{
- char in_ch;
-
- /* Get a character from the standard input for the read function. */
- in_ch = getchar();
-
- /* Check for a \ quoted newline. */
- if (in_ch == '\\')
- {
- in_ch = getchar();
- if (in_ch == '\n')
- in_ch = getchar();
- }
-
- /* Classify and preprocess the input character. */
- if (isdigit((int)in_ch))
- return (in_ch - '0');
- if (in_ch >= 'A' && in_ch <= 'F')
- return (in_ch + 10 - 'A');
- if (in_ch >= 'a' && in_ch <= 'f')
- return (in_ch + 10 - 'a');
- if (in_ch == '.' || in_ch == '+' || in_ch == '-')
- return (in_ch);
- if (in_ch <= ' ')
- return (' ');
-
- return (':');
-}
-
-
-/* Push_constant converts a sequence of input characters as returned
- by IN_CHAR into a number. The number is pushed onto the execution
- stack. The number is converted as a number in base CONV_BASE. */
-
-void
-push_constant (in_char, conv_base)
- char (*in_char)(VOID);
- int conv_base;
-{
- int digits;
- bc_num build, temp, result, mult, divisor;
- char in_ch, first_ch;
- char negative;
-
- /* Initialize all bc numbers */
- bc_init_num (&temp);
- bc_init_num (&result);
- bc_init_num (&mult);
- build = bc_copy_num (_zero_);
- negative = FALSE;
-
- /* The conversion base. */
- bc_int2num (&mult, conv_base);
-
- /* Get things ready. */
- in_ch = in_char();
- while (in_ch == ' ')
- in_ch = in_char();
-
- if (in_ch == '+')
- in_ch = in_char();
- else
- if (in_ch == '-')
- {
- negative = TRUE;
- in_ch = in_char();
- }
-
- /* Check for the special case of a single digit. */
- if (in_ch < 16)
- {
- first_ch = in_ch;
- in_ch = in_char();
- if (in_ch < 16 && first_ch >= conv_base)
- first_ch = conv_base - 1;
- bc_int2num (&build, (int) first_ch);
- }
-
- /* Convert the integer part. */
- while (in_ch < 16)
- {
- if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1;
- bc_multiply (build, mult, &result, 0);
- bc_int2num (&temp, (int) in_ch);
- bc_add (result, temp, &build, 0);
- in_ch = in_char();
- }
- if (in_ch == '.')
- {
- in_ch = in_char();
- if (in_ch >= conv_base) in_ch = conv_base-1;
- bc_free_num (&result);
- bc_free_num (&temp);
- divisor = bc_copy_num (_one_);
- result = bc_copy_num (_zero_);
- digits = 0;
- while (in_ch < 16)
- {
- bc_multiply (result, mult, &result, 0);
- bc_int2num (&temp, (int) in_ch);
- bc_add (result, temp, &result, 0);
- bc_multiply (divisor, mult, &divisor, 0);
- digits++;
- in_ch = in_char();
- if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1;
- }
- bc_divide (result, divisor, &result, digits);
- bc_add (build, result, &build, 0);
- }
-
- /* Final work. */
- if (negative)
- bc_sub (_zero_, build, &build, 0);
-
- push_num (build);
- bc_free_num (&temp);
- bc_free_num (&result);
- bc_free_num (&mult);
-}
-
-
-/* When converting base 10 constants from the program, we use this
- more efficient way to convert them to numbers. PC tells where
- the constant starts and is expected to be advanced to after
- the constant. */
-
-void
-push_b10_const (pc)
- program_counter *pc;
-{
- bc_num build;
- program_counter look_pc;
- int kdigits, kscale;
- char inchar;
- char *ptr;
-
- /* Count the digits and get things ready. */
- look_pc = *pc;
- kdigits = 0;
- kscale = 0;
- inchar = byte (&look_pc);
- while (inchar != '.' && inchar != ':')
- {
- kdigits++;
- inchar = byte(&look_pc);
- }
- if (inchar == '.' )
- {
- inchar = byte(&look_pc);
- while (inchar != ':')
- {
- kscale++;
- inchar = byte(&look_pc);
- }
- }
-
- /* Get the first character again and move the pc. */
- inchar = byte(pc);
-
- /* Secial cases of 0, 1, and A-F single inputs. */
- if (kdigits == 1 && kscale == 0)
- {
- if (inchar == 0)
- {
- push_copy (_zero_);
- inchar = byte(pc);
- return;
- }
- if (inchar == 1) {
- push_copy (_one_);
- inchar = byte(pc);
- return;
- }
- if (inchar > 9)
- {
- bc_init_num (&build);
- bc_int2num (&build, inchar);
- push_num (build);
- inchar = byte(pc);
- return;
- }
- }
-
- /* Build the new number. */
- if (kdigits == 0)
- {
- build = bc_new_num (1,kscale);
- ptr = build->n_value;
- *ptr++ = 0;
- }
- else
- {
- build = bc_new_num (kdigits,kscale);
- ptr = build->n_value;
- }
-
- while (inchar != ':')
- {
- if (inchar != '.')
- {
- if (inchar > 9)
- *ptr++ = 9;
- else
- *ptr++ = inchar;
- }
- inchar = byte(pc);
- }
- push_num (build);
-}
-
-
-/* Put the correct value on the stack for C_CODE. Frees TOS num. */
-
-void
-assign (c_code)
- char c_code;
-{
- bc_free_num (&ex_stack->s_num);
- if (c_code)
- ex_stack->s_num = bc_copy_num (_one_);
- else
- ex_stack->s_num = bc_copy_num (_zero_);
-}
-
diff --git a/contrib/bc/bc/fix-libmath_h b/contrib/bc/bc/fix-libmath_h
deleted file mode 100755
index f973a8c..0000000
--- a/contrib/bc/bc/fix-libmath_h
+++ /dev/null
@@ -1,9 +0,0 @@
-ed libmath.h <<EOS-EOS
-1,1s/^/{"/
-1,\$s/\$/",/
-2,\$s/^/"/
-\$,\$d
-\$,\$s/,\$/,0}/
-w
-q
-EOS-EOS
diff --git a/contrib/bc/bc/global.c b/contrib/bc/bc/global.c
deleted file mode 100644
index 5d1205c..0000000
--- a/contrib/bc/bc/global.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/* global.c: This defines the global variables. */
-
-/* This file is part of GNU bc.
- Copyright (C) 1991-1994, 1997, 2000 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111 USA
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-#include "bcdefs.h"
-
-/* Since we want to define them here, we use the following define. */
-#undef EXTERN
-#define EXTERN
-
-/* Define all the global variables for bc. */
-#include "global.h"
-
-CONST char *libmath[] =
-#include "libmath.h"
-;
diff --git a/contrib/bc/bc/global.h b/contrib/bc/bc/global.h
deleted file mode 100644
index cf6945c..0000000
--- a/contrib/bc/bc/global.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/* global.h: The global variables for bc. */
-
-/* This file is part of GNU bc.
- Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111 USA
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-
-/* The current break level's lable. */
-EXTERN int break_label;
-
-/* The current if statement's else label or label after else. */
-EXTERN int if_label;
-
-/* The current for statement label for continuing the loop. */
-EXTERN int continue_label;
-
-/* Next available label number. */
-EXTERN int next_label;
-
-/* Byte code character storage. Used in many places for generation of code. */
-EXTERN char genstr[80];
-
-/* Count of characters printed to the output in compile_only mode. */
-EXTERN int out_count;
-
-/* Have we generated any code since the last initialization of the code
- generator. */
-EXTERN char did_gen;
-
-/* Is this run an interactive execution. (Is stdin a terminal?) */
-EXTERN char interactive;
-
-/* Just generate the byte code. -c flag. */
-EXTERN int compile_only;
-
-/* Load the standard math functions. -l flag. */
-EXTERN int use_math;
-
-/* Give a warning on use of any non-standard feature (non-POSIX). -w flag. */
-EXTERN int warn_not_std;
-
-/* Accept POSIX bc only! -s flag. */
-EXTERN int std_only;
-
-/* Don't print the banner at start up. -q flag. */
-EXTERN int quiet;
-
-/* The list of file names to process. */
-EXTERN file_node *file_names;
-
-/* The name of the current file being processed. */
-EXTERN char *file_name;
-
-/* Is the current file a named file or standard input? */
-EXTERN char is_std_in;
-
-/* global variables for the bc machine. All will be dynamic in size.*/
-/* Function storage. main is (0) and functions (1-f_count) */
-
-EXTERN bc_function *functions;
-EXTERN char **f_names;
-EXTERN int f_count;
-
-/* Variable stoarge and reverse names. */
-
-EXTERN bc_var **variables;
-EXTERN char **v_names;
-EXTERN int v_count;
-
-/* Array Variable storage and reverse names. */
-
-EXTERN bc_var_array **arrays;
-EXTERN char **a_names;
-EXTERN int a_count;
-
-/* Execution stack. */
-EXTERN estack_rec *ex_stack;
-
-/* Function return stack. */
-EXTERN fstack_rec *fn_stack;
-
-/* Current ibase, obase, scale, and n_history (if needed). */
-EXTERN int i_base;
-EXTERN int o_base;
-EXTERN int scale;
-#if defined(READLINE) || defined(LIBEDIT)
-EXTERN int n_history;
-#endif
-
-#if defined(LIBEDIT)
-/* LIBEDIT data */
-EditLine *edit;
-History *hist;
-HistEvent histev;
-#endif
-
-/* "Condition code" -- false (0) or true (1) */
-EXTERN char c_code;
-
-/* Records the number of the runtime error. */
-EXTERN char runtime_error;
-
-/* Holds the current location of execution. */
-EXTERN program_counter pc;
-
-/* For POSIX bc, this is just for number output, not strings. */
-EXTERN int out_col;
-
-/* Keeps track of the current number of characters per output line.
- This includes the \n at the end of the line. */
-EXTERN int line_size;
-
-/* Input Line numbers and other error information. */
-EXTERN int line_no;
-EXTERN int had_error;
-
-/* For larger identifiers, a tree, and how many "storage" locations
- have been allocated. */
-
-EXTERN int next_array;
-EXTERN int next_func;
-EXTERN int next_var;
-
-EXTERN id_rec *name_tree;
-
-/* For use with getopt. Do not declare them here.*/
-extern int optind;
-
-/* Access to the yy input file. Defined in scan.c. */
-extern FILE *yyin;
diff --git a/contrib/bc/bc/libmath.b b/contrib/bc/bc/libmath.b
deleted file mode 100644
index 7bb6405..0000000
--- a/contrib/bc/bc/libmath.b
+++ /dev/null
@@ -1,287 +0,0 @@
-/* libmath.b for GNU bc. */
-
-/* This file is part of GNU bc.
- Copyright (C) 1991, 1992, 1993, 1997 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111 USA
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-
-scale = 20
-
-/* Uses the fact that e^x = (e^(x/2))^2
- When x is small enough, we use the series:
- e^x = 1 + x + x^2/2! + x^3/3! + ...
-*/
-
-define e(x) {
- auto a, d, e, f, i, m, n, v, z
-
- /* a - holds x^y of x^y/y! */
- /* d - holds y! */
- /* e - is the value x^y/y! */
- /* v - is the sum of the e's */
- /* f - number of times x was divided by 2. */
- /* m - is 1 if x was minus. */
- /* i - iteration count. */
- /* n - the scale to compute the sum. */
- /* z - orignal scale. */
-
- /* Check the sign of x. */
- if (x<0) {
- m = 1
- x = -x
- }
-
- /* Precondition x. */
- z = scale;
- n = 6 + z + .44*x;
- scale = scale(x)+1;
- while (x > 1) {
- f += 1;
- x /= 2;
- scale += 1;
- }
-
- /* Initialize the variables. */
- scale = n;
- v = 1+x
- a = x
- d = 1
-
- for (i=2; 1; i++) {
- e = (a *= x) / (d *= i)
- if (e == 0) {
- if (f>0) while (f--) v = v*v;
- scale = z
- if (m) return (1/v);
- return (v/1);
- }
- v += e
- }
-}
-
-/* Natural log. Uses the fact that ln(x^2) = 2*ln(x)
- The series used is:
- ln(x) = 2(a+a^3/3+a^5/5+...) where a=(x-1)/(x+1)
-*/
-
-define l(x) {
- auto e, f, i, m, n, v, z
-
- /* return something for the special case. */
- if (x <= 0) return ((1 - 10^scale)/1)
-
- /* Precondition x to make .5 < x < 2.0. */
- z = scale;
- scale = 6 + scale;
- f = 2;
- i=0
- while (x >= 2) { /* for large numbers */
- f *= 2;
- x = sqrt(x);
- }
- while (x <= .5) { /* for small numbers */
- f *= 2;
- x = sqrt(x);
- }
-
- /* Set up the loop. */
- v = n = (x-1)/(x+1)
- m = n*n
-
- /* Sum the series. */
- for (i=3; 1; i+=2) {
- e = (n *= m) / i
- if (e == 0) {
- v = f*v
- scale = z
- return (v/1)
- }
- v += e
- }
-}
-
-/* Sin(x) uses the standard series:
- sin(x) = x - x^3/3! + x^5/5! - x^7/7! ... */
-
-define s(x) {
- auto e, i, m, n, s, v, z
-
- /* precondition x. */
- z = scale
- scale = 1.1*z + 2;
- v = a(1)
- if (x < 0) {
- m = 1;
- x = -x;
- }
- scale = 0
- n = (x / v + 2 )/4
- x = x - 4*n*v
- if (n%2) x = -x
-
- /* Do the loop. */
- scale = z + 2;
- v = e = x
- s = -x*x
- for (i=3; 1; i+=2) {
- e *= s/(i*(i-1))
- if (e == 0) {
- scale = z
- if (m) return (-v/1);
- return (v/1);
- }
- v += e
- }
-}
-
-/* Cosine : cos(x) = sin(x+pi/2) */
-define c(x) {
- auto v, z;
- z = scale;
- scale = scale*1.2;
- v = s(x+a(1)*2);
- scale = z;
- return (v/1);
-}
-
-/* Arctan: Using the formula:
- atan(x) = atan(c) + atan((x-c)/(1+xc)) for a small c (.2 here)
- For under .2, use the series:
- atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... */
-
-define a(x) {
- auto a, e, f, i, m, n, s, v, z
-
- /* a is the value of a(.2) if it is needed. */
- /* f is the value to multiply by a in the return. */
- /* e is the value of the current term in the series. */
- /* v is the accumulated value of the series. */
- /* m is 1 or -1 depending on x (-x -> -1). results are divided by m. */
- /* i is the denominator value for series element. */
- /* n is the numerator value for the series element. */
- /* s is -x*x. */
- /* z is the saved user's scale. */
-
- /* Negative x? */
- m = 1;
- if (x<0) {
- m = -1;
- x = -x;
- }
-
- /* Special case and for fast answers */
- if (x==1) {
- if (scale <= 25) return (.7853981633974483096156608/m)
- if (scale <= 40) return (.7853981633974483096156608458198757210492/m)
- if (scale <= 60) \
- return (.785398163397448309615660845819875721049292349843776455243736/m)
- }
- if (x==.2) {
- if (scale <= 25) return (.1973955598498807583700497/m)
- if (scale <= 40) return (.1973955598498807583700497651947902934475/m)
- if (scale <= 60) \
- return (.197395559849880758370049765194790293447585103787852101517688/m)
- }
-
-
- /* Save the scale. */
- z = scale;
-
- /* Note: a and f are known to be zero due to being auto vars. */
- /* Calculate atan of a known number. */
- if (x > .2) {
- scale = z+5;
- a = a(.2);
- }
-
- /* Precondition x. */
- scale = z+3;
- while (x > .2) {
- f += 1;
- x = (x-.2) / (1+x*.2);
- }
-
- /* Initialize the series. */
- v = n = x;
- s = -x*x;
-
- /* Calculate the series. */
- for (i=3; 1; i+=2) {
- e = (n *= s) / i;
- if (e == 0) {
- scale = z;
- return ((f*a+v)/m);
- }
- v += e
- }
-}
-
-
-/* Bessel function of integer order. Uses the following:
- j(-n,x) = (-1)^n*j(n,x)
- j(n,x) = x^n/(2^n*n!) * (1 - x^2/(2^2*1!*(n+1)) + x^4/(2^4*2!*(n+1)*(n+2))
- - x^6/(2^6*3!*(n+1)*(n+2)*(n+3)) .... )
-*/
-define j(n,x) {
- auto a, b, d, e, f, i, m, s, v, z
-
- /* Make n an integer and check for negative n. */
- z = scale;
- scale = 0;
- n = n/1;
- if (n<0) {
- n = -n;
- if (n%2 == 1) m = 1;
- }
-
- /* save ibase */
- b = ibase;
- ibase = A;
-
- /* Compute the factor of x^n/(2^n*n!) */
- f = 1;
- for (i=2; i<=n; i++) f = f*i;
- scale = 1.5*z;
- f = x^n / 2^n / f;
-
- /* Initialize the loop .*/
- v = e = 1;
- s = -x*x/4
- scale = 1.5*z + length(f) - scale(f);
-
- /* The Loop.... */
- for (i=1; 1; i++) {
- e = e * s / i / (n+i);
- if (e == 0) {
- ibase = b;
- scale = z
- if (m) return (-f*v/1);
- return (f*v/1);
- }
- v += e;
- }
-}
diff --git a/contrib/bc/bc/libmath.h b/contrib/bc/bc/libmath.h
deleted file mode 100644
index bf48f4b..0000000
--- a/contrib/bc/bc/libmath.h
+++ /dev/null
@@ -1,40 +0,0 @@
-{"@iK20:s2:p@r",
-"@iF1,5.6,7,8,9,10,11,12,13,14[l5:0<Z1:1s11:pl5:ns5:pN1:l2:s14:",
-"pK6:l14:+K.44:l5:*+s12:pl5:cS1+s2:pN2:l5:1>Z3:l9:1+s9:pl5:K2:",
-"/s5:pl2:1+s2:pJ2:N3:l12:s2:p1l5:+s13:pl5:s6:p1s7:pK2:s10:pN5:",
-"1B6:J4:N7:l10:i10:pJ5:N6:l6:l5:*s6:l7:l10:*s7:/s8:pl8:0=Z8:l9:",
-"0>Z9:N10:l9:d9:Z11:l13:l13:*s13:pJ10:N11:N9:l14:s2:pl11:Z12:1",
-"l13:/RN12:l13:1/RN8:l13:l8:+s13:pJ7:N4:0R]@r",
-"@iF2,5.8,9,10,11,12,13,14[l5:0{Z1:1K10:l2:^-1/RN1:l2:s14:pK6:",
-"l2:+s2:pK2:s9:p0s10:pN2:l5:K2:}Z3:l9:K2:*s9:pl5:cRs5:pJ2:N3:N4:",
-"l5:K.5:{Z5:l9:K2:*s9:pl5:cRs5:pJ4:N5:l5:1-l5:1+/s12:s13:pl12:",
-"l12:*s11:pK3:s10:pN7:1B8:J6:N9:l10:K2:+s10:pJ7:N8:l12:l11:*s12:",
-"l10:/s8:pl8:0=Z10:l9:l13:*s13:pl14:s2:pl13:1/RN10:l13:l8:+s13:",
-"pJ9:N6:0R]@r",
-"@iF3,5.8,10,11,12,15,13,14[l2:s14:pK1.1:l14:*K2:+s2:p1C4,0:s13:",
-"pl5:0<Z1:1s11:pl5:ns5:pN1:0s2:pl5:l13:/K2:+K4:/s12:pl5:K4:l12:",
-"*l13:*-s5:pl12:K2:%Z2:l5:ns5:pN2:l14:K2:+s2:pl5:s8:s13:pl5:nl5:",
-"*s15:pK3:s10:pN4:1B5:J3:N6:l10:K2:+s10:pJ4:N5:l8:l15:l10:l10:",
-"1-*/*s8:pl8:0=Z7:l14:s2:pl11:Z8:l13:n1/RN8:l13:1/RN7:l13:l8:+",
-"s13:pJ6:N3:0R]@r",
-"@iF5,5.13,14[l2:s14:pl2:K1.2:*s2:pl5:1C4,0:K2:*+C3,0:s13:pl14:",
-"s2:pl13:1/R0R]@r",
-"@iF4,5.6,8,9,10,11,12,15,13,14[1s11:pl5:0<Z1:1ns11:pl5:ns5:pN1:",
-"l5:1=Z2:l2:K25:{Z3:K.7853981633974483096156608:l11:/RN3:l2:K40",
-":{Z4:K.7853981633974483096156608458198757210492:l11:/RN4:l2:K",
-"60:{Z5:K.785398163397448309615660845819875721049292349843776455243736",
-":l11:/RN5:N2:l5:K.2:=Z6:l2:K25:{Z7:K.1973955598498807583700497",
-":l11:/RN7:l2:K40:{Z8:K.1973955598498807583700497651947902934475",
-":l11:/RN8:l2:K60:{Z9:K.197395559849880758370049765194790293447585103787852101517688",
-":l11:/RN9:N6:l2:s14:pl5:K.2:>Z10:l14:K5:+s2:pK.2:C4,0:s6:pN10:",
-"l14:K3:+s2:pN11:l5:K.2:>Z12:l9:1+s9:pl5:K.2:-1l5:K.2:*+/s5:pJ11:N12:",
-"l5:s12:s13:pl5:nl5:*s15:pK3:s10:pN14:1B15:J13:N16:l10:K2:+s10:",
-"pJ14:N15:l12:l15:*s12:l10:/s8:pl8:0=Z17:l14:s2:pl9:l6:*l13:+l11:",
-"/RN17:l13:l8:+s13:pJ16:N13:0R]@r",
-"@iF6,12,5.6,16,7,8,9,10,11,15,13,14[l2:s14:p0s2:pl12:1/s12:pl12:",
-"0<Z1:l12:ns12:pl12:K2:%1=Z2:1s11:pN2:N1:l0:s16:pKA:s0:p1s9:pK",
-"2:s10:pN4:l10:l12:{B5:J3:N6:l10:i10:pJ4:N5:l9:l10:*s9:pJ6:N3:",
-"K1.5:l14:*s2:pl5:l12:^K2:l12:^/l9:/s9:p1s8:s13:pl5:nl5:*K4:/s15:",
-"pK1.5:l14:*l9:cL+l9:cS-s2:p1s10:pN8:1B9:J7:N10:l10:i10:pJ8:N9:",
-"l8:l15:*l10:/l12:l10:+/s8:pl8:0=Z11:l16:s0:pl14:s2:pl11:Z12:l9:",
-"nl13:*1/RN12:l9:l13:*1/RN11:l13:l8:+s13:pJ10:N7:0R]@r",0}
diff --git a/contrib/bc/bc/load.c b/contrib/bc/bc/load.c
deleted file mode 100644
index dd03435..0000000
--- a/contrib/bc/bc/load.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/* load.c: This code "loads" code into the code segments. */
-
-/* This file is part of GNU bc.
- Copyright (C) 1991-1994, 1997, 2000 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111 USA
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-#include "bcdefs.h"
-#include "global.h"
-#include "proto.h"
-
-/* Load variables. */
-
-program_counter load_adr;
-char load_str;
-char load_const;
-
-/* Initialize the load sequence. */
-void
-init_load ()
-{
- clear_func(0);
- load_adr.pc_func = 0;
- load_adr.pc_addr = 0;
- load_str = FALSE;
- load_const = FALSE;
-}
-
-/* addbyte adds one BYTE to the current code segment. */
-void
-addbyte (byte)
- char byte;
-{
- int pc;
- bc_function *f;
- char *new_body;
-
- /* If there was an error, don't continue. */
- if (had_error) return;
-
- /* Calculate the segment and offset. */
- pc = load_adr.pc_addr++;
- f = &functions[load_adr.pc_func];
-
- if (pc >= f->f_body_size)
- {
- f->f_body_size *= 2;
- new_body = (char *) bc_malloc (f->f_body_size);
- memcpy(new_body, f->f_body, f->f_body_size/2);
- free (f->f_body);
- f->f_body = new_body;
- }
-
- /* Store the byte. */
- f->f_body[pc] = byte;
- f->f_code_size++;
-}
-
-
-/* Define a label LAB to be the current program counter. */
-
-void
-def_label (lab)
- long lab;
-{
- bc_label_group *temp;
- int group, offset, func;
-
- /* Get things ready. */
- group = lab >> BC_LABEL_LOG;
- offset = lab % BC_LABEL_GROUP;
- func = load_adr.pc_func;
-
- /* Make sure there is at least one label group. */
- if (functions[func].f_label == NULL)
- {
- functions[func].f_label =
- (bc_label_group *) bc_malloc (sizeof(bc_label_group));
- functions[func].f_label->l_next = NULL;
- }
-
- /* Add the label group. */
- temp = functions[func].f_label;
- while (group > 0)
- {
- if (temp->l_next == NULL)
- {
- temp->l_next = (bc_label_group *) bc_malloc (sizeof(bc_label_group));
- temp->l_next->l_next = NULL;
- }
- temp = temp->l_next;
- group --;
- }
-
- /* Define it! */
- temp->l_adrs [offset] = load_adr.pc_addr;
-}
-
-/* Several instructions have integers in the code. They
- are all known to be legal longs. So, no error code
- is added. STR is the pointer to the load string and
- must be moved to the last non-digit character. */
-
-long
-long_val (str)
- char **str;
-{ int val = 0;
- char neg = FALSE;
-
- if (**str == '-')
- {
- neg = TRUE;
- (*str)++;
- }
- while (isdigit((int)(**str)))
- val = val*10 + *(*str)++ - '0';
-
- if (neg)
- return -val;
- else
- return val;
-}
-
-
-/* load_code loads the CODE into the machine. */
-
-void
-load_code (code)
- char *code;
-{
- char *str;
- long ap_name; /* auto or parameter name. */
- long label_no;
- long vaf_name; /* variable, array or function number. */
- long func;
- static program_counter save_adr;
-
- /* Initialize. */
- str = code;
-
- /* Scan the code. */
- while (*str != 0)
- {
- /* If there was an error, don't continue. */
- if (had_error) return;
-
- if (load_str)
- {
- if (*str == '"') load_str = FALSE;
- addbyte (*str++);
- }
- else
- if (load_const)
- {
- if (*str == '\n')
- str++;
- else
- {
- if (*str == ':')
- {
- load_const = FALSE;
- addbyte (*str++);
- }
- else
- if (*str == '.')
- addbyte (*str++);
- else
- if (*str >= 'A')
- addbyte (*str++ + 10 - 'A');
- else
- addbyte (*str++ - '0');
- }
- }
- else
- {
- switch (*str)
- {
-
- case '"': /* Starts a string. */
- load_str = TRUE;
- break;
-
- case 'N': /* A label */
- str++;
- label_no = long_val (&str);
- def_label (label_no);
- break;
-
- case 'B': /* Branch to label. */
- case 'J': /* Jump to label. */
- case 'Z': /* Branch Zero to label. */
- addbyte(*str++);
- label_no = long_val (&str);
- if (label_no > 65535L)
- { /* Better message? */
- fprintf (stderr,"Program too big.\n");
- exit(1);
- }
- addbyte ( (char) (label_no & 0xFF));
- addbyte ( (char) (label_no >> 8));
- break;
-
- case 'F': /* A function, get the name and initialize it. */
- str++;
- func = long_val (&str);
- clear_func (func);
-#if DEBUG > 2
- printf ("Loading function number %d\n", func);
-#endif
- /* get the parameters */
- while (*str++ != '.')
- {
- if (*str == '.')
- {
- str++;
- break;
- }
- if (*str == '*')
- {
- str++;
- ap_name = long_val (&str);
-#if DEBUG > 2
- printf ("var parameter number %d\n", ap_name);
-#endif
- functions[(int)func].f_params =
- nextarg (functions[(int)func].f_params, ap_name,
- TRUE);
- }
- else
- {
- ap_name = long_val (&str);
-#if DEBUG > 2
- printf ("parameter number %d\n", ap_name);
-#endif
- functions[(int)func].f_params =
- nextarg (functions[(int)func].f_params, ap_name,
- FALSE);
- }
- }
-
- /* get the auto vars */
- while (*str != '[')
- {
- if (*str == ',') str++;
- ap_name = long_val (&str);
-#if DEBUG > 2
- printf ("auto number %d\n", ap_name);
-#endif
- functions[(int)func].f_autos =
- nextarg (functions[(int)func].f_autos, ap_name, FALSE);
- }
- save_adr = load_adr;
- load_adr.pc_func = func;
- load_adr.pc_addr = 0;
- break;
-
- case ']': /* A function end */
- functions[load_adr.pc_func].f_defined = TRUE;
- load_adr = save_adr;
- break;
-
- case 'C': /* Call a function. */
- addbyte (*str++);
- func = long_val (&str);
- if (func < 128)
- addbyte ( (char) func);
- else
- {
- addbyte (((func >> 8) & 0xff) | 0x80);
- addbyte (func & 0xff);
- }
- if (*str == ',') str++;
- while (*str != ':')
- addbyte (*str++);
- addbyte (':');
- break;
-
- case 'c': /* Call a special function. */
- addbyte (*str++);
- addbyte (*str);
- break;
-
- case 'K': /* A constant.... may have an "F" in it. */
- addbyte (*str);
- load_const = TRUE;
- break;
-
- case 'd': /* Decrement. */
- case 'i': /* Increment. */
- case 'l': /* Load. */
- case 's': /* Store. */
- case 'A': /* Array Increment */
- case 'M': /* Array Decrement */
- case 'L': /* Array Load */
- case 'S': /* Array Store */
- addbyte (*str++);
- vaf_name = long_val (&str);
- if (vaf_name < 128)
- addbyte (vaf_name);
- else
- {
- addbyte (((vaf_name >> 8) & 0xff) | 0x80);
- addbyte (vaf_name & 0xff);
- }
- break;
-
- case '@': /* A command! */
- switch (*(++str))
- {
- case 'i':
- init_load ();
- break;
- case 'r':
- execute ();
- break;
- }
- break;
-
- case '\n': /* Ignore the newlines */
- break;
-
- default: /* Anything else */
- addbyte (*str);
- }
- str++;
- }
- }
-}
diff --git a/contrib/bc/bc/main.c b/contrib/bc/bc/main.c
deleted file mode 100644
index 8ac2981..0000000
--- a/contrib/bc/bc/main.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/* main.c: The main program for bc. */
-
-/* This file is part of GNU bc.
- Copyright (C) 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111 USA
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-$FreeBSD$
-
-*************************************************************************/
-
-#include "bcdefs.h"
-#include <signal.h>
-#include "global.h"
-#include "proto.h"
-#include "getopt.h"
-
-
-/* Variables for processing multiple files. */
-static char first_file;
-
-/* Points to the last node in the file name list for easy adding. */
-static file_node *last = NULL;
-
-/* long option support */
-static struct option long_options[] =
-{
- {"compile", 0, &compile_only, TRUE},
- {"help", 0, 0, 'h'},
- {"interactive", 0, 0, 'i'},
- {"mathlib", 0, &use_math, TRUE},
- {"quiet", 0, &quiet, TRUE},
- {"standard", 0, &std_only, TRUE},
- {"version", 0, 0, 'v'},
- {"warn", 0, &warn_not_std, TRUE},
-
- {0, 0, 0, 0}
-};
-
-
-void
-usage (char *progname)
-{
- printf ("usage: %s [options] [file ...]\n%s%s%s%s%s%s%s", progname,
- " -h --help print this usage and exit\n",
- " -i --interactive force interactive mode\n",
- " -l --mathlib use the predefined math routines\n",
- " -q --quiet don't print initial banner\n",
- " -s --standard non-standard bc constructs are errors\n",
- " -w --warn warn about non-standard bc constructs\n",
- " -v --version print version information and exit\n");
-}
-
-
-void
-parse_args (argc, argv)
- int argc;
- char **argv;
-{
- int optch;
- int long_index;
- file_node *temp;
-
- /* Force getopt to initialize. Depends on GNU getopt. */
- optind = 0;
-
- /* Parse the command line */
- while (1)
- {
- optch = getopt_long (argc, argv, "chilqswv", long_options, &long_index);
-
- if (optch == EOF) /* End of arguments. */
- break;
-
- switch (optch)
- {
- case 'c': /* compile only */
- compile_only = TRUE;
- break;
-
- case 'h': /* help */
- usage(argv[0]);
- exit (0);
- break;
-
- case 'i': /* force interactive */
- interactive = TRUE;
- break;
-
- case 'l': /* math lib */
- use_math = TRUE;
- break;
-
- case 'q': /* quiet mode */
- quiet = TRUE;
- break;
-
- case 's': /* Non standard features give errors. */
- std_only = TRUE;
- break;
-
- case 'v': /* Print the version. */
- show_bc_version ();
- exit (0);
- break;
-
- case 'w': /* Non standard features give warnings. */
- warn_not_std = TRUE;
- break;
-
- case 0:
- /* long options */
- break;
-
- default:
- usage(argv[0]);
- exit (1);
- }
- }
-
- /* Add file names to a list of files to process. */
- while (optind < argc)
- {
- temp = (file_node *) bc_malloc(sizeof(file_node));
- temp->name = argv[optind];
- temp->next = NULL;
- if (last == NULL)
- file_names = temp;
- else
- last->next = temp;
- last = temp;
- optind++;
- }
-}
-
-/* The main program for bc. */
-int
-main (argc, argv)
- int argc;
- char *argv[];
-{
- char *env_value;
- char *env_argv[30];
- int env_argc;
-
- /* Initialize many variables. */
- compile_only = FALSE;
- use_math = FALSE;
- warn_not_std = FALSE;
- std_only = FALSE;
- if (isatty(0) && isatty(1))
- interactive = TRUE;
- else
- interactive = FALSE;
- quiet = FALSE;
- file_names = NULL;
-
-#ifdef HAVE_SETVBUF
- /* attempt to simplify interaction with applications such as emacs */
- (void) setvbuf(stdout, NULL, _IOLBF, 0);
-#endif
-
- /* Environment arguments. */
- env_value = getenv ("BC_ENV_ARGS");
- if (env_value != NULL)
- {
- env_argc = 1;
- env_argv[0] = "BC_ENV_ARGS";
- while (*env_value != 0)
- {
- if (*env_value != ' ')
- {
- env_argv[env_argc++] = env_value;
- while (*env_value != ' ' && *env_value != 0)
- env_value++;
- if (*env_value != 0)
- {
- *env_value = 0;
- env_value++;
- }
- }
- else
- env_value++;
- }
- parse_args (env_argc, env_argv);
- }
-
- /* Command line arguments. */
- parse_args (argc, argv);
-
- /* Other environment processing. */
- if (getenv ("POSIXLY_CORRECT") != NULL)
- std_only = TRUE;
-
- env_value = getenv ("BC_LINE_LENGTH");
- if (env_value != NULL)
- {
- line_size = atoi (env_value);
- if (line_size < 2)
- line_size = 70;
- }
- else
- line_size = 70;
-
- /* Initialize the machine. */
- init_storage();
- init_load();
-
- /* Set up interrupts to print a message. */
- if (interactive)
- signal (SIGINT, use_quit);
-
- /* Initialize the front end. */
- init_tree();
- init_gen ();
- is_std_in = FALSE;
- first_file = TRUE;
- if (!open_new_file ())
- exit (1);
-
-#if defined(LIBEDIT)
- if (interactive) {
- /* Enable libedit support. */
- edit = el_init ("bc", stdin, stdout, stderr);
- hist = history_init();
- el_set (edit, EL_EDITOR, "emacs");
- el_set (edit, EL_HIST, history, hist);
- el_set (edit, EL_PROMPT, null_prompt);
- el_source (edit, NULL);
- history (hist, &histev, H_SETSIZE, INT_MAX);
- }
-#endif
-
-#if defined(READLINE)
- if (interactive) {
- /* Readline support. Set both application name and input file. */
- rl_readline_name = "bc";
- rl_instream = stdin;
- using_history ();
- }
-#endif
-
- /* Do the parse. */
- yyparse ();
-
- /* End the compile only output with a newline. */
- if (compile_only)
- printf ("\n");
-
- exit (0);
-}
-
-
-/* This is the function that opens all the files.
- It returns TRUE if the file was opened, otherwise
- it returns FALSE. */
-
-int
-open_new_file ()
-{
- FILE *new_file;
- file_node *temp;
-
- /* Set the line number. */
- line_no = 1;
-
- /* Check to see if we are done. */
- if (is_std_in) return (FALSE);
-
- /* Open the other files. */
- if (use_math && first_file)
- {
- /* Load the code from a precompiled version of the math libarary. */
- extern char *libmath[];
- char **mstr;
- char tmp;
- /* These MUST be in the order of first mention of each function.
- That is why "a" comes before "c" even though "a" is defined after
- after "c". "a" is used in "s"! */
- tmp = lookup ("e", FUNCT);
- tmp = lookup ("l", FUNCT);
- tmp = lookup ("s", FUNCT);
- tmp = lookup ("a", FUNCT);
- tmp = lookup ("c", FUNCT);
- tmp = lookup ("j", FUNCT);
- mstr = libmath;
- while (*mstr) {
- load_code (*mstr);
- mstr++;
- }
- }
-
- /* One of the argv values. */
- if (file_names != NULL)
- {
- new_file = fopen (file_names->name, "r");
- if (new_file != NULL)
- {
- new_yy_file (new_file);
- temp = file_names;
- file_name = temp->name;
- file_names = temp->next;
- free (temp);
- return TRUE;
- }
- fprintf (stderr, "File %s is unavailable.\n", file_names->name);
- exit (1);
- }
-
- /* If we fall through to here, we should return stdin. */
- new_yy_file (stdin);
- is_std_in = TRUE;
- return TRUE;
-}
-
-
-/* Set yyin to the new file. */
-
-void
-new_yy_file (file)
- FILE *file;
-{
- if (!first_file) fclose (yyin);
- yyin = file;
- first_file = FALSE;
-}
-
-
-/* Message to use quit. */
-
-void
-use_quit (sig)
- int sig;
-{
- printf ("\n(interrupt) use quit to exit.\n");
- signal (SIGINT, use_quit);
-}
diff --git a/contrib/bc/bc/proto.h b/contrib/bc/bc/proto.h
deleted file mode 100644
index 1e7311f..0000000
--- a/contrib/bc/bc/proto.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/* proto.h: Prototype function definitions for "external" functions. */
-
-/* This file is part of GNU bc.
- Copyright (C) 1991-1994, 1997, 2000 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111 USA
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-/* For the pc version using k&r ACK. (minix1.5 and earlier.) */
-#ifdef SHORTNAMES
-#define init_numbers i_numbers
-#define push_constant push__constant
-#define load_const in_load_const
-#define yy_get_next_buffer yyget_next_buffer
-#define yy_init_buffer yyinit_buffer
-#define yy_last_accepting_state yylast_accepting_state
-#define arglist1 arg1list
-#endif
-
-/* Include the standard library header files. */
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-/* Define the _PROTOTYPE macro if it is needed. */
-
-#ifndef _PROTOTYPE
-#ifdef __STDC__
-#define _PROTOTYPE(func, args) func args
-#else
-#define _PROTOTYPE(func, args) func()
-#endif
-#endif
-
-/* From execute.c */
-_PROTOTYPE(void stop_execution, (int));
-_PROTOTYPE(unsigned char byte, (program_counter *pc));
-_PROTOTYPE(void execute, (void));
-_PROTOTYPE(char prog_char, (void));
-_PROTOTYPE(char input_char, (void));
-_PROTOTYPE(void push_constant, (char (*in_char)(void), int conv_base));
-_PROTOTYPE(void push_b10_const, (program_counter *pc));
-_PROTOTYPE(void assign, (int c_code));
-
-/* From util.c */
-_PROTOTYPE(char *strcopyof, (char *str));
-_PROTOTYPE(arg_list *nextarg, (arg_list *args, int val, int is_var));
-_PROTOTYPE(char *arg_str, (arg_list *args));
-_PROTOTYPE(char *call_str, (arg_list *args));
-_PROTOTYPE(void free_args, (arg_list *args));
-_PROTOTYPE(void check_params, (arg_list *params, arg_list *autos));
-_PROTOTYPE(void init_gen, (void));
-_PROTOTYPE(void generate, (char *str));
-_PROTOTYPE(void run_code, (void));
-_PROTOTYPE(void out_char, (int ch));
-_PROTOTYPE(void out_schar, (int ch));
-_PROTOTYPE(id_rec *find_id, (id_rec *tree, char *id));
-_PROTOTYPE(int insert_id_rec, (id_rec **root, id_rec *new_id));
-_PROTOTYPE(void init_tree, (void));
-_PROTOTYPE(int lookup, (char *name, int namekind));
-_PROTOTYPE(char *bc_malloc, (int));
-_PROTOTYPE(void out_of_memory, (void));
-_PROTOTYPE(void welcome, (void));
-_PROTOTYPE(void warranty, (char *));
-_PROTOTYPE(void show_bc_version, (void));
-_PROTOTYPE(void limits, (void));
-_PROTOTYPE(void yyerror, (char *str ,...));
-_PROTOTYPE(void warn, (char *mesg ,...));
-_PROTOTYPE(void rt_error, (char *mesg ,...));
-_PROTOTYPE(void rt_warn, (char *mesg ,...));
-
-/* From load.c */
-_PROTOTYPE(void init_load, (void));
-_PROTOTYPE(void addbyte, (int byte));
-_PROTOTYPE(void def_label, (long lab));
-_PROTOTYPE(long long_val, (char **str));
-_PROTOTYPE(void load_code, (char *code));
-
-/* From main.c */
-_PROTOTYPE(int open_new_file, (void));
-_PROTOTYPE(void new_yy_file, (FILE *file));
-_PROTOTYPE(void use_quit, (int));
-
-/* From storage.c */
-_PROTOTYPE(void init_storage, (void));
-_PROTOTYPE(void more_functions, (void));
-_PROTOTYPE(void more_variables, (void));
-_PROTOTYPE(void more_arrays, (void));
-_PROTOTYPE(void clear_func, (int func ));
-_PROTOTYPE(int fpop, (void));
-_PROTOTYPE(void fpush, (int val ));
-_PROTOTYPE(void pop, (void));
-_PROTOTYPE(void push_copy, (bc_num num ));
-_PROTOTYPE(void push_num, (bc_num num ));
-_PROTOTYPE(char check_stack, (int depth ));
-_PROTOTYPE(bc_var *get_var, (int var_name ));
-_PROTOTYPE(bc_num *get_array_num, (int var_index, long index ));
-_PROTOTYPE(void store_var, (int var_name ));
-_PROTOTYPE(void store_array, (int var_name ));
-_PROTOTYPE(void load_var, (int var_name ));
-_PROTOTYPE(void load_array, (int var_name ));
-_PROTOTYPE(void decr_var, (int var_name ));
-_PROTOTYPE(void decr_array, (int var_name ));
-_PROTOTYPE(void incr_var, (int var_name ));
-_PROTOTYPE(void incr_array, (int var_name ));
-_PROTOTYPE(void auto_var, (int name ));
-_PROTOTYPE(void free_a_tree, (bc_array_node *root, int depth ));
-_PROTOTYPE(void pop_vars, (arg_list *list ));
-_PROTOTYPE(void process_params, (program_counter *pc, int func ));
-
-/* For the scanner and parser.... */
-_PROTOTYPE(int yyparse, (void));
-_PROTOTYPE(int yylex, (void));
-
-#if defined(LIBEDIT)
-/* The *?*&^ prompt function */
-_PROTOTYPE(char *null_prompt, (EditLine *));
-#endif
-
-/* Other things... */
-#ifndef HAVE_UNISTD_H
-_PROTOTYPE (int getopt, (int, char *[], CONST char *));
-#endif
diff --git a/contrib/bc/bc/sbc.y b/contrib/bc/bc/sbc.y
deleted file mode 100644
index b1ff1d1..0000000
--- a/contrib/bc/bc/sbc.y
+++ /dev/null
@@ -1,448 +0,0 @@
-%{
-/* sbc.y: A POSIX bc processor written for minix with no extensions. */
-
-/* This file is part of GNU bc.
- Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111 USA
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-#include "bcdefs.h"
-#include "global.h" /* To get the global variables. */
-#include "proto.h"
-%}
-
-%start program
-
-%union {
- char *s_value;
- char c_value;
- int i_value;
- arg_list *a_value;
- }
-
-%token <i_value> ENDOFLINE AND OR NOT
-%token <s_value> STRING NAME NUMBER
-/* '-', '+' are tokens themselves */
-%token <c_value> ASSIGN_OP
-/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */
-%token <s_value> REL_OP
-/* '==', '<=', '>=', '!=', '<', '>' */
-%token <c_value> INCR_DECR
-/* '++', '--' */
-%token <i_value> Define Break Quit Length
-/* 'define', 'break', 'quit', 'length' */
-%token <i_value> Return For If While Sqrt Else
-/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */
-%token <i_value> Scale Ibase Obase Auto Read
-/* 'scale', 'ibase', 'obase', 'auto', 'read' */
-%token <i_value> Warranty, Halt, Last, Continue, Print, Limits
-/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */
-
-/* The types of all other non-terminals. */
-%type <i_value> expression named_expression return_expression
-%type <a_value> opt_parameter_list parameter_list opt_auto_define_list
-%type <a_value> define_list opt_argument_list argument_list
-%type <i_value> program input_item semicolon_list statement_list
-%type <i_value> statement_or_error statement function relational_expression
-
-/* precedence */
-%nonassoc REL_OP
-%right ASSIGN_OP
-%left '+' '-'
-%left '*' '/' '%'
-%right '^'
-%nonassoc UNARY_MINUS
-%nonassoc INCR_DECR
-
-%%
-program : /* empty */
- {
- $$ = 0;
- std_only = TRUE;
- if (interactive)
- {
- printf ("s%s\n", BC_VERSION);
- welcome();
- }
- }
- | program input_item
- ;
-input_item : semicolon_list ENDOFLINE
- { run_code(); }
- | function
- { run_code(); }
- | error ENDOFLINE
- {
- yyerrok;
- init_gen() ;
- }
- ;
-semicolon_list : /* empty */
- { $$ = 0; }
- | statement_or_error
- | semicolon_list ';' statement_or_error
- | semicolon_list ';'
- ;
-statement_list : /* empty */
- { $$ = 0; }
- | statement
- | statement_list ENDOFLINE
- | statement_list ENDOFLINE statement
- | statement_list ';'
- | statement_list ';' statement
- ;
-statement_or_error : statement
- | error statement
- { $$ = $2; }
- ;
-statement : Warranty
- { warranty("s"); }
- | expression
- {
- if ($1 & 1)
- generate ("W");
- else
- generate ("p");
- }
- | STRING
- {
- $$ = 0;
- generate ("w");
- generate ($1);
- free ($1);
- }
- | Break
- {
- if (break_label == 0)
- yyerror ("Break outside a for/while");
- else
- {
- sprintf (genstr, "J%1d:", break_label);
- generate (genstr);
- }
- }
- | Quit
- { exit(0); }
- | Return
- { generate ("0R"); }
- | Return '(' return_expression ')'
- { generate ("R"); }
- | For
- {
- $1 = break_label;
- break_label = next_label++;
- }
- '(' expression ';'
- {
- $4 = next_label++;
- sprintf (genstr, "pN%1d:", $4);
- generate (genstr);
- }
- relational_expression ';'
- {
- $7 = next_label++;
- sprintf (genstr, "B%1d:J%1d:", $7, break_label);
- generate (genstr);
- $<i_value>$ = next_label++;
- sprintf (genstr, "N%1d:", $<i_value>$);
- generate (genstr);
- }
- expression ')'
- {
- sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
- generate (genstr);
- }
- statement
- {
- sprintf (genstr, "J%1d:N%1d:", $<i_value>9,
- break_label);
- generate (genstr);
- break_label = $1;
- }
- | If '(' relational_expression ')'
- {
- $3 = next_label++;
- sprintf (genstr, "Z%1d:", $3);
- generate (genstr);
- }
- statement
- {
- sprintf (genstr, "N%1d:", $3);
- generate (genstr);
- }
- | While
- {
- $1 = next_label++;
- sprintf (genstr, "N%1d:", $1);
- generate (genstr);
- }
- '(' relational_expression
- {
- $4 = break_label;
- break_label = next_label++;
- sprintf (genstr, "Z%1d:", break_label);
- generate (genstr);
- }
- ')' statement
- {
- sprintf (genstr, "J%1d:N%1d:", $1, break_label);
- generate (genstr);
- break_label = $4;
- }
- | '{' statement_list '}'
- { $$ = 0; }
- ;
-function : Define NAME '(' opt_parameter_list ')' '{'
- ENDOFLINE opt_auto_define_list
- {
- check_params ($4,$8);
- sprintf (genstr, "F%d,%s.%s[", lookup($2,FUNCT),
- arg_str ($4), arg_str ($8));
- generate (genstr);
- free_args ($4);
- free_args ($8);
- $1 = next_label;
- next_label = 0;
- }
- statement_list ENDOFLINE '}'
- {
- generate ("0R]");
- next_label = $1;
- }
- ;
-opt_parameter_list : /* empty */
- { $$ = NULL; }
- | parameter_list
- ;
-parameter_list : NAME
- { $$ = nextarg (NULL, lookup($1,SIMPLE), FALSE); }
- | define_list ',' NAME
- { $$ = nextarg ($1, lookup($3,SIMPLE), FALSE); }
- ;
-opt_auto_define_list : /* empty */
- { $$ = NULL; }
- | Auto define_list ENDOFLINE
- { $$ = $2; }
- | Auto define_list ';'
- { $$ = $2; }
- ;
-define_list : NAME
- { $$ = nextarg (NULL, lookup($1,SIMPLE), FALSE); }
- | NAME '[' ']'
- { $$ = nextarg (NULL, lookup($1,ARRAY), FALSE); }
- | define_list ',' NAME
- { $$ = nextarg ($1, lookup($3,SIMPLE), FALSE); }
- | define_list ',' NAME '[' ']'
- { $$ = nextarg ($1, lookup($3,ARRAY), FALSE); }
- ;
-opt_argument_list : /* empty */
- { $$ = NULL; }
- | argument_list
- ;
-argument_list : expression
- { $$ = nextarg (NULL,0, FALSE); }
- | argument_list ',' expression
- { $$ = nextarg ($1,0, FALSE); }
- ;
-relational_expression : expression
- { $$ = 0; }
- | expression REL_OP expression
- {
- $$ = 0;
- switch (*($2))
- {
- case '=':
- generate ("=");
- break;
- case '!':
- generate ("#");
- break;
- case '<':
- if ($2[1] == '=')
- generate ("{");
- else
- generate ("<");
- break;
- case '>':
- if ($2[1] == '=')
- generate ("}");
- else
- generate (">");
- break;
- }
- }
- ;
-return_expression : /* empty */
- {
- $$ = 0;
- generate ("0");
- }
- | expression
- ;
-expression : named_expression ASSIGN_OP
- {
- if ($2 != '=')
- {
- if ($1 < 0)
- sprintf (genstr, "DL%d:", -$1);
- else
- sprintf (genstr, "l%d:", $1);
- generate (genstr);
- }
- }
- expression
- {
- $$ = 0;
- if ($2 != '=')
- {
- sprintf (genstr, "%c", $2);
- generate (genstr);
- }
- if ($1 < 0)
- sprintf (genstr, "S%d:", -$1);
- else
- sprintf (genstr, "s%d:", $1);
- generate (genstr);
- }
- | expression '+' expression
- { generate ("+"); }
- | expression '-' expression
- { generate ("-"); }
- | expression '*' expression
- { generate ("*"); }
- | expression '/' expression
- { generate ("/"); }
- | expression '%' expression
- { generate ("%"); }
- | expression '^' expression
- { generate ("^"); }
- | '-' expression %prec UNARY_MINUS
- { generate ("n"); $$ = 1;}
- | named_expression
- {
- $$ = 1;
- if ($1 < 0)
- sprintf (genstr, "L%d:", -$1);
- else
- sprintf (genstr, "l%d:", $1);
- generate (genstr);
- }
- | NUMBER
- {
- int len = strlen($1);
- $$ = 1;
- if (len == 1 && *$1 == '0')
- generate ("0");
- else
- {
- if (len == 1 && *$1 == '1')
- generate ("1");
- else
- {
- generate ("K");
- generate ($1);
- generate (":");
- }
- free ($1);
- }
- }
- | '(' expression ')'
- { $$ = 1; }
- | NAME '(' opt_argument_list ')'
- {
- $$ = 1;
- if ($3 != NULL)
- {
- sprintf (genstr, "C%d,%s:", lookup($1,FUNCT),
- arg_str ($3));
- free_args ($3);
- }
- else
- sprintf (genstr, "C%d:", lookup($1,FUNCT));
- generate (genstr);
- }
- | INCR_DECR named_expression
- {
- $$ = 1;
- if ($2 < 0)
- {
- if ($1 == '+')
- sprintf (genstr, "DA%d:L%d:", -$2, -$2);
- else
- sprintf (genstr, "DM%d:L%d:", -$2, -$2);
- }
- else
- {
- if ($1 == '+')
- sprintf (genstr, "i%d:l%d:", $2, $2);
- else
- sprintf (genstr, "d%d:l%d:", $2, $2);
- }
- generate (genstr);
- }
- | named_expression INCR_DECR
- {
- $$ = 1;
- if ($1 < 0)
- {
- sprintf (genstr, "DL%d:x", -$1);
- generate (genstr);
- if ($2 == '+')
- sprintf (genstr, "A%d:", -$1);
- else
- sprintf (genstr, "M%d:", -$1);
- }
- else
- {
- sprintf (genstr, "l%d:", $1);
- generate (genstr);
- if ($2 == '+')
- sprintf (genstr, "i%d:", $1);
- else
- sprintf (genstr, "d%d:", $1);
- }
- generate (genstr);
- }
- | Length '(' expression ')'
- { generate ("cL"); $$ = 1;}
- | Sqrt '(' expression ')'
- { generate ("cR"); $$ = 1;}
- | Scale '(' expression ')'
- { generate ("cS"); $$ = 1;}
- ;
-named_expression : NAME
- { $$ = lookup($1,SIMPLE); }
- | NAME '[' expression ']'
- { $$ = lookup($1,ARRAY); }
- | Ibase
- { $$ = 0; }
- | Obase
- { $$ = 1; }
- | Scale
- { $$ = 2; }
- ;
-
-%%
diff --git a/contrib/bc/bc/scan.l b/contrib/bc/bc/scan.l
deleted file mode 100644
index 8910c66..0000000
--- a/contrib/bc/bc/scan.l
+++ /dev/null
@@ -1,374 +0,0 @@
-%{
-/* $FreeBSD$ */
-/* scan.l: the (f)lex description file for the scanner. */
-
-/* This file is part of GNU bc.
- Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111 USA
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-#include "bcdefs.h"
-#include "bc.h"
-#include "global.h"
-#include "proto.h"
-#include <errno.h>
-
-/* Using flex, we can ask for a smaller input buffer. With lex, this
- does nothing! */
-
-#ifdef SMALL_BUF
-#undef YY_READ_BUF_SIZE
-#define YY_READ_BUF_SIZE 512
-#endif
-
-/* Force . as last for now. */
-#define DOT_IS_LAST
-
-/* We want to define our own yywrap. */
-#undef yywrap
-_PROTOTYPE(int yywrap, (void));
-
-#if defined(LIBEDIT)
-/* Support for the BSD libedit with history for
- nicer input on the interactive part of input. */
-
-#include <histedit.h>
-
-/* Have input call the following function. */
-#undef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
- bcel_input((char *)buf, &result, max_size)
-
-/* Variables to help interface editline with bc. */
-static const char *bcel_line = (char *)NULL;
-static int bcel_len = 0;
-
-
-/* Required to get rid of that ugly ? default prompt! */
-char *
-null_prompt (EditLine *el)
-{
- return "";
-}
-
-
-/* bcel_input puts upto MAX characters into BUF with the number put in
- BUF placed in *RESULT. If the yy input file is the same as
- stdin, use editline. Otherwise, just read it.
-*/
-
-static void
-bcel_input (buf, result, max)
- char *buf;
- int *result;
- int max;
-{
- if (!edit || yyin != stdin)
- {
- while ( (*result = read( fileno(yyin), buf, max )) < 0 )
- if (errno != EINTR)
- {
- yyerror( "read() in flex scanner failed" );
- exit (1);
- }
- return;
- }
-
- /* Do we need a new string? */
- if (bcel_len == 0)
- {
- bcel_line = el_gets(edit, &bcel_len);
- if (bcel_line == NULL) {
- /* end of file */
- *result = 0;
- bcel_len = 0;
- return;
- }
- if (bcel_len != 0)
- history (hist, &histev, H_ENTER, bcel_line);
- fflush (stdout);
- }
-
- if (bcel_len <= max)
- {
- strncpy (buf, bcel_line, bcel_len);
- *result = bcel_len;
- bcel_len = 0;
- }
- else
- {
- strncpy (buf, bcel_line, max);
- *result = max;
- bcel_line += max;
- bcel_len -= max;
- }
-}
-#endif
-
-#ifdef READLINE
-/* Support for the readline and history libraries. This allows
- nicer input on the interactive part of input. */
-
-/* Have input call the following function. */
-#undef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
- rl_input((char *)buf, &result, max_size)
-
-/* Variables to help interface readline with bc. */
-static char *rl_line = (char *)NULL;
-static char *rl_start = (char *)NULL;
-static int rl_len = 0;
-
-/* Definitions for readline access. */
-extern FILE *rl_instream;
-
-/* rl_input puts upto MAX characters into BUF with the number put in
- BUF placed in *RESULT. If the yy input file is the same as
- rl_instream (stdin), use readline. Otherwise, just read it.
-*/
-
-static void
-rl_input (buf, result, max)
- char *buf;
- int *result;
- int max;
-{
- if (yyin != rl_instream)
- {
- while ( (*result = read( fileno(yyin), buf, max )) < 0 )
- if (errno != EINTR)
- {
- yyerror( "read() in flex scanner failed" );
- exit (1);
- }
- return;
- }
-
- /* Do we need a new string? */
- if (rl_len == 0)
- {
- if (rl_start)
- free(rl_start);
- rl_start = readline ("");
- if (rl_start == NULL) {
- /* end of file */
- *result = 0;
- rl_len = 0;
- return;
- }
- rl_line = rl_start;
- rl_len = strlen (rl_line)+1;
- if (rl_len != 1)
- add_history (rl_line);
- rl_line[rl_len-1] = '\n';
- fflush (stdout);
- }
-
- if (rl_len <= max)
- {
- strncpy (buf, rl_line, rl_len);
- *result = rl_len;
- rl_len = 0;
- }
- else
- {
- strncpy (buf, rl_line, max);
- *result = max;
- rl_line += max;
- rl_len -= max;
- }
-}
-#endif
-
-#if !defined(READLINE) && !defined(LIBEDIT)
-
-/* MINIX returns from read with < 0 if SIGINT is encountered.
- In flex, we can redefine YY_INPUT to the following. In lex, this
- does nothing! */
-#undef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
- while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \
- if (errno != EINTR) \
- YY_FATAL_ERROR( "read() in flex scanner failed" );
-#endif
-
-%}
-DIGIT [0-9A-F]
-LETTER [a-z]
-%s slcomment
-%%
-"#" {
- if (!std_only)
- BEGIN(slcomment);
- else
- yyerror ("illegal character: #");
- }
-<slcomment>[^\n]* { BEGIN(INITIAL); }
-<slcomment>"\n" { line_no++; BEGIN(INITIAL); return(ENDOFLINE); }
-define return(Define);
-break return(Break);
-quit return(Quit);
-length return(Length);
-return return(Return);
-for return(For);
-if return(If);
-while return(While);
-sqrt return(Sqrt);
-scale return(Scale);
-ibase return(Ibase);
-obase return(Obase);
-auto return(Auto);
-else return(Else);
-read return(Read);
-halt return(Halt);
-last return(Last);
-history {
-#if defined(READLINE) || defined(LIBEDIT)
- return(HistoryVar);
-#else
- yylval.s_value = strcopyof(yytext); return(NAME);
-#endif
- }
-
-warranty return(Warranty);
-continue return(Continue);
-print return(Print);
-limits return(Limits);
-"." {
-#ifdef DOT_IS_LAST
- return(Last);
-#else
- yyerror ("illegal character: %s",yytext);
-#endif
- }
-"+"|"-"|";"|"("|")"|"{"|"}"|"["|"]"|","|"^" { yylval.c_value = yytext[0];
- return((int)yytext[0]); }
-&& { return(AND); }
-\|\| { return(OR); }
-"!" { return(NOT); }
-"*"|"/"|"%" { yylval.c_value = yytext[0]; return((int)yytext[0]); }
-"="|\+=|-=|\*=|\/=|%=|\^= { yylval.c_value = yytext[0]; return(ASSIGN_OP); }
-=\+|=-|=\*|=\/|=%|=\^ {
-#ifdef OLD_EQ_OP
- char warn_save;
- warn_save = warn_not_std;
- warn_not_std = TRUE;
- warn ("Old fashioned =<op>");
- warn_not_std = warn_save;
- yylval.c_value = yytext[1];
-#else
- yylval.c_value = '=';
- yyless (1);
-#endif
- return(ASSIGN_OP);
- }
-==|\<=|\>=|\!=|"<"|">" { yylval.s_value = strcopyof(yytext); return(REL_OP); }
-\+\+|-- { yylval.c_value = yytext[0]; return(INCR_DECR); }
-"\n" { line_no++; return(ENDOFLINE); }
-\\\n { line_no++; /* ignore a "quoted" newline */ }
-[ \t]+ { /* ignore spaces and tabs */ }
-"/*" {
- int c;
-
- for (;;)
- {
- while ( ((c=input()) != '*') && (c != EOF))
- /* eat it */
- if (c == '\n') line_no++;
- if (c == '*')
- {
- while ( (c=input()) == '*') /* eat it*/;
- if (c == '/') break; /* at end of comment */
- if (c == '\n') line_no++;
- }
- if (c == EOF)
- {
- fprintf (stderr,"EOF encountered in a comment.\n");
- break;
- }
- }
- }
-[a-z][a-z0-9_]* { yylval.s_value = strcopyof(yytext); return(NAME); }
-\"[^\"]*\" {
- unsigned char *look;
- int count = 0;
- yylval.s_value = strcopyof(yytext);
- for (look = yytext; *look != 0; look++)
- {
- if (*look == '\n') line_no++;
- if (*look == '"') count++;
- }
- if (count != 2) yyerror ("NUL character in string.");
- return(STRING);
- }
-{DIGIT}({DIGIT}|\\\n)*("."({DIGIT}|\\\n)*)?|"."(\\\n)*{DIGIT}({DIGIT}|\\\n)* {
- unsigned char *src, *dst;
- int len;
- /* remove a trailing decimal point. */
- len = strlen(yytext);
- if (yytext[len-1] == '.')
- yytext[len-1] = 0;
- /* remove leading zeros. */
- src = yytext;
- dst = yytext;
- while (*src == '0') src++;
- if (*src == 0) src--;
- /* Copy strings removing the newlines. */
- while (*src != 0)
- {
- if (*src == '\\')
- {
- src++; src++;
- line_no++;
- }
- else
- *dst++ = *src++;
- }
- *dst = 0;
- yylval.s_value = strcopyof(yytext);
- return(NUMBER);
- }
-. {
- if (yytext[0] < ' ')
- yyerror ("illegal character: ^%c",yytext[0] + '@');
- else
- if (yytext[0] > '~')
- yyerror ("illegal character: \\%03o", (int) yytext[0]);
- else
- yyerror ("illegal character: %s",yytext);
- }
-%%
-
-
-
-/* This is the way to get multiple files input into lex. */
-
-int
-yywrap()
-{
- if (!open_new_file ()) return (1); /* EOF on standard in. */
- return (0); /* We have more input. */
-}
diff --git a/contrib/bc/bc/storage.c b/contrib/bc/bc/storage.c
deleted file mode 100644
index 10ebf5c..0000000
--- a/contrib/bc/bc/storage.c
+++ /dev/null
@@ -1,1067 +0,0 @@
-/* storage.c: Code and data storage manipulations. This includes labels. */
-
-/* This file is part of GNU bc.
- Copyright (C) 1991-1994, 1997, 2000 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111 USA
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-#include "bcdefs.h"
-#include "global.h"
-#include "proto.h"
-
-
-/* Initialize the storage at the beginning of the run. */
-
-void
-init_storage ()
-{
-
- /* Functions: we start with none and ask for more. */
- f_count = 0;
- more_functions ();
- f_names[0] = "(main)";
-
- /* Variables. */
- v_count = 0;
- more_variables ();
-
- /* Arrays. */
- a_count = 0;
- more_arrays ();
-
- /* Other things... */
- ex_stack = NULL;
- fn_stack = NULL;
- i_base = 10;
- o_base = 10;
- scale = 0;
-#if defined(READLINE) || defined(LIBEDIT)
- n_history = -1;
-#endif
- c_code = FALSE;
- bc_init_numbers();
-}
-
-/* Three functions for increasing the number of functions, variables, or
- arrays that are needed. This adds another 32 of the requested object. */
-
-void
-more_functions (VOID)
-{
- int old_count;
- int indx;
- bc_function *old_f;
- bc_function *f;
- char **old_names;
-
- /* Save old information. */
- old_count = f_count;
- old_f = functions;
- old_names = f_names;
-
- /* Add a fixed amount and allocate new space. */
- f_count += STORE_INCR;
- functions = (bc_function *) bc_malloc (f_count*sizeof (bc_function));
- f_names = (char **) bc_malloc (f_count*sizeof (char *));
-
- /* Copy old ones. */
- for (indx = 0; indx < old_count; indx++)
- {
- functions[indx] = old_f[indx];
- f_names[indx] = old_names[indx];
- }
-
- /* Initialize the new ones. */
- for (; indx < f_count; indx++)
- {
- f = &functions[indx];
- f->f_defined = FALSE;
- f->f_body = (char *) bc_malloc (BC_START_SIZE);
- f->f_body_size = BC_START_SIZE;
- f->f_code_size = 0;
- f->f_label = NULL;
- f->f_autos = NULL;
- f->f_params = NULL;
- }
-
- /* Free the old elements. */
- if (old_count != 0)
- {
- free (old_f);
- free (old_names);
- }
-}
-
-void
-more_variables ()
-{
- int indx;
- int old_count;
- bc_var **old_var;
- char **old_names;
-
- /* Save the old values. */
- old_count = v_count;
- old_var = variables;
- old_names = v_names;
-
- /* Increment by a fixed amount and allocate. */
- v_count += STORE_INCR;
- variables = (bc_var **) bc_malloc (v_count*sizeof(bc_var *));
- v_names = (char **) bc_malloc (v_count*sizeof(char *));
-
- /* Copy the old variables. */
- for (indx = 3; indx < old_count; indx++)
- variables[indx] = old_var[indx];
-
- /* Initialize the new elements. */
- for (; indx < v_count; indx++)
- variables[indx] = NULL;
-
- /* Free the old elements. */
- if (old_count != 0)
- {
- free (old_var);
- free (old_names);
- }
-}
-
-void
-more_arrays ()
-{
- int indx;
- int old_count;
- bc_var_array **old_ary;
- char **old_names;
-
- /* Save the old values. */
- old_count = a_count;
- old_ary = arrays;
- old_names = a_names;
-
- /* Increment by a fixed amount and allocate. */
- a_count += STORE_INCR;
- arrays = (bc_var_array **) bc_malloc (a_count*sizeof(bc_var_array *));
- a_names = (char **) bc_malloc (a_count*sizeof(char *));
-
- /* Copy the old arrays. */
- for (indx = 1; indx < old_count; indx++)
- arrays[indx] = old_ary[indx];
-
-
- /* Initialize the new elements. */
- for (; indx < v_count; indx++)
- arrays[indx] = NULL;
-
- /* Free the old elements. */
- if (old_count != 0)
- {
- free (old_ary);
- free (old_names);
- }
-}
-
-
-/* clear_func clears out function FUNC and makes it ready to redefine. */
-
-void
-clear_func (func)
- int func;
-{
- bc_function *f;
- bc_label_group *lg;
-
- /* Set the pointer to the function. */
- f = &functions[func];
- f->f_defined = FALSE;
- /* XXX restore f_body to initial size??? */
- f->f_code_size = 0;
- if (f->f_autos != NULL)
- {
- free_args (f->f_autos);
- f->f_autos = NULL;
- }
- if (f->f_params != NULL)
- {
- free_args (f->f_params);
- f->f_params = NULL;
- }
- while (f->f_label != NULL)
- {
- lg = f->f_label->l_next;
- free (f->f_label);
- f->f_label = lg;
- }
-}
-
-
-/* Pop the function execution stack and return the top. */
-
-int
-fpop()
-{
- fstack_rec *temp;
- int retval;
-
- if (fn_stack != NULL)
- {
- temp = fn_stack;
- fn_stack = temp->s_next;
- retval = temp->s_val;
- free (temp);
- }
- else
- {
- retval = 0;
- rt_error ("function stack underflow, contact maintainer.");
- }
- return (retval);
-}
-
-
-/* Push VAL on to the function stack. */
-
-void
-fpush (val)
- int val;
-{
- fstack_rec *temp;
-
- temp = (fstack_rec *) bc_malloc (sizeof (fstack_rec));
- temp->s_next = fn_stack;
- temp->s_val = val;
- fn_stack = temp;
-}
-
-
-/* Pop and discard the top element of the regular execution stack. */
-
-void
-pop ()
-{
- estack_rec *temp;
-
- if (ex_stack != NULL)
- {
- temp = ex_stack;
- ex_stack = temp->s_next;
- bc_free_num (&temp->s_num);
- free (temp);
- }
-}
-
-
-/* Push a copy of NUM on to the regular execution stack. */
-
-void
-push_copy (num)
- bc_num num;
-{
- estack_rec *temp;
-
- temp = (estack_rec *) bc_malloc (sizeof (estack_rec));
- temp->s_num = bc_copy_num (num);
- temp->s_next = ex_stack;
- ex_stack = temp;
-}
-
-
-/* Push NUM on to the regular execution stack. Do NOT push a copy. */
-
-void
-push_num (num)
- bc_num num;
-{
- estack_rec *temp;
-
- temp = (estack_rec *) bc_malloc (sizeof (estack_rec));
- temp->s_num = num;
- temp->s_next = ex_stack;
- ex_stack = temp;
-}
-
-
-/* Make sure the ex_stack has at least DEPTH elements on it.
- Return TRUE if it has at least DEPTH elements, otherwise
- return FALSE. */
-
-char
-check_stack (depth)
- int depth;
-{
- estack_rec *temp;
-
- temp = ex_stack;
- while ((temp != NULL) && (depth > 0))
- {
- temp = temp->s_next;
- depth--;
- }
- if (depth > 0)
- {
- rt_error ("Stack error.");
- return FALSE;
- }
- return TRUE;
-}
-
-
-/* The following routines manipulate simple variables and
- array variables. */
-
-/* get_var returns a pointer to the variable VAR_NAME. If one does not
- exist, one is created. */
-
-bc_var *
-get_var (var_name)
- int var_name;
-{
- bc_var *var_ptr;
-
- var_ptr = variables[var_name];
- if (var_ptr == NULL)
- {
- var_ptr = variables[var_name] = (bc_var *) bc_malloc (sizeof (bc_var));
- bc_init_num (&var_ptr->v_value);
- }
- return var_ptr;
-}
-
-
-/* get_array_num returns the address of the bc_num in the array
- structure. If more structure is requried to get to the index,
- this routine does the work to create that structure. VAR_INDEX
- is a zero based index into the arrays storage array. INDEX is
- the index into the bc array. */
-
-bc_num *
-get_array_num (var_index, index)
- int var_index;
- long index;
-{
- bc_var_array *ary_ptr;
- bc_array *a_var;
- bc_array_node *temp;
- int log, ix, ix1;
- int sub [NODE_DEPTH];
-
- /* Get the array entry. */
- ary_ptr = arrays[var_index];
- if (ary_ptr == NULL)
- {
- ary_ptr = arrays[var_index] =
- (bc_var_array *) bc_malloc (sizeof (bc_var_array));
- ary_ptr->a_value = NULL;
- ary_ptr->a_next = NULL;
- ary_ptr->a_param = FALSE;
- }
-
- a_var = ary_ptr->a_value;
- if (a_var == NULL) {
- a_var = ary_ptr->a_value = (bc_array *) bc_malloc (sizeof (bc_array));
- a_var->a_tree = NULL;
- a_var->a_depth = 0;
- }
-
- /* Get the index variable. */
- sub[0] = index & NODE_MASK;
- ix = index >> NODE_SHIFT;
- log = 1;
- while (ix > 0 || log < a_var->a_depth)
- {
- sub[log] = ix & NODE_MASK;
- ix >>= NODE_SHIFT;
- log++;
- }
-
- /* Build any tree that is necessary. */
- while (log > a_var->a_depth)
- {
- temp = (bc_array_node *) bc_malloc (sizeof(bc_array_node));
- if (a_var->a_depth != 0)
- {
- temp->n_items.n_down[0] = a_var->a_tree;
- for (ix=1; ix < NODE_SIZE; ix++)
- temp->n_items.n_down[ix] = NULL;
- }
- else
- {
- for (ix=0; ix < NODE_SIZE; ix++)
- temp->n_items.n_num[ix] = bc_copy_num(_zero_);
- }
- a_var->a_tree = temp;
- a_var->a_depth++;
- }
-
- /* Find the indexed variable. */
- temp = a_var->a_tree;
- while ( log-- > 1)
- {
- ix1 = sub[log];
- if (temp->n_items.n_down[ix1] == NULL)
- {
- temp->n_items.n_down[ix1] =
- (bc_array_node *) bc_malloc (sizeof(bc_array_node));
- temp = temp->n_items.n_down[ix1];
- if (log > 1)
- for (ix=0; ix < NODE_SIZE; ix++)
- temp->n_items.n_down[ix] = NULL;
- else
- for (ix=0; ix < NODE_SIZE; ix++)
- temp->n_items.n_num[ix] = bc_copy_num(_zero_);
- }
- else
- temp = temp->n_items.n_down[ix1];
- }
-
- /* Return the address of the indexed variable. */
- return &(temp->n_items.n_num[sub[0]]);
-}
-
-
-/* Store the top of the execution stack into VAR_NAME.
- This includes the special variables ibase, obase, and scale. */
-
-void
-store_var (var_name)
- int var_name;
-{
- bc_var *var_ptr;
- long temp;
- char toobig;
-
- if (var_name > 3)
- {
- /* It is a simple variable. */
- var_ptr = get_var (var_name);
- if (var_ptr != NULL)
- {
- bc_free_num(&var_ptr->v_value);
- var_ptr->v_value = bc_copy_num (ex_stack->s_num);
- }
- }
- else
- {
- /* It is a special variable... */
- toobig = FALSE;
- temp = 0;
- if (bc_is_neg (ex_stack->s_num))
- {
- switch (var_name)
- {
- case 0:
- rt_warn ("negative ibase, set to 2");
- temp = 2;
- break;
- case 1:
- rt_warn ("negative obase, set to 2");
- temp = 2;
- break;
- case 2:
- rt_warn ("negative scale, set to 0");
- temp = 0;
- break;
-#if defined(READLINE) || defined(LIBEDIT)
- case 3:
- temp = -1;
- break;
-#endif
- }
- }
- else
- {
- temp = bc_num2long (ex_stack->s_num);
- if (!bc_is_zero (ex_stack->s_num) && temp == 0)
- toobig = TRUE;
- }
- switch (var_name)
- {
- case 0:
- if (temp < 2 && !toobig)
- {
- i_base = 2;
- rt_warn ("ibase too small, set to 2");
- }
- else
- if (temp > 16 || toobig)
- {
- i_base = 16;
- rt_warn ("ibase too large, set to 16");
- }
- else
- i_base = (int) temp;
- break;
-
- case 1:
- if (temp < 2 && !toobig)
- {
- o_base = 2;
- rt_warn ("obase too small, set to 2");
- }
- else
- if (temp > BC_BASE_MAX || toobig)
- {
- o_base = BC_BASE_MAX;
- rt_warn ("obase too large, set to %d", BC_BASE_MAX);
- }
- else
- o_base = (int) temp;
- break;
-
- case 2:
- /* WARNING: The following if statement may generate a compiler
- warning if INT_MAX == LONG_MAX. This is NOT a problem. */
- if (temp > BC_SCALE_MAX || toobig )
- {
- scale = BC_SCALE_MAX;
- rt_warn ("scale too large, set to %d", BC_SCALE_MAX);
- }
- else
- scale = (int) temp;
- break;
-
-#if defined(READLINE) || defined(LIBEDIT)
- case 3:
- if (toobig)
- {
- temp = -1;
- rt_warn ("history too large, set to unlimited");
- UNLIMIT_HISTORY;
- }
- else
- {
- n_history = temp;
- if (temp < 0)
- UNLIMIT_HISTORY;
- else
- HISTORY_SIZE(n_history);
- }
-#endif
- }
- }
-}
-
-
-/* Store the top of the execution stack into array VAR_NAME.
- VAR_NAME is the name of an array, and the next to the top
- of stack for the index into the array. */
-
-void
-store_array (var_name)
- int var_name;
-{
- bc_num *num_ptr;
- long index;
-
- if (!check_stack(2)) return;
- index = bc_num2long (ex_stack->s_next->s_num);
- if (index < 0 || index > BC_DIM_MAX ||
- (index == 0 && !bc_is_zero(ex_stack->s_next->s_num)))
- rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
- else
- {
- num_ptr = get_array_num (var_name, index);
- if (num_ptr != NULL)
- {
- bc_free_num (num_ptr);
- *num_ptr = bc_copy_num (ex_stack->s_num);
- bc_free_num (&ex_stack->s_next->s_num);
- ex_stack->s_next->s_num = ex_stack->s_num;
- bc_init_num (&ex_stack->s_num);
- pop();
- }
- }
-}
-
-
-/* Load a copy of VAR_NAME on to the execution stack. This includes
- the special variables ibase, obase and scale. */
-
-void
-load_var (var_name)
- int var_name;
-{
- bc_var *var_ptr;
-
- switch (var_name)
- {
-
- case 0:
- /* Special variable ibase. */
- push_copy (_zero_);
- bc_int2num (&ex_stack->s_num, i_base);
- break;
-
- case 1:
- /* Special variable obase. */
- push_copy (_zero_);
- bc_int2num (&ex_stack->s_num, o_base);
- break;
-
- case 2:
- /* Special variable scale. */
- push_copy (_zero_);
- bc_int2num (&ex_stack->s_num, scale);
- break;
-
-#if defined(READLINE) || defined(LIBEDIT)
- case 3:
- /* Special variable history. */
- push_copy (_zero_);
- bc_int2num (&ex_stack->s_num, n_history);
- break;
-#endif
-
- default:
- /* It is a simple variable. */
- var_ptr = variables[var_name];
- if (var_ptr != NULL)
- push_copy (var_ptr->v_value);
- else
- push_copy (_zero_);
- }
-}
-
-
-/* Load a copy of VAR_NAME on to the execution stack. This includes
- the special variables ibase, obase and scale. */
-
-void
-load_array (var_name)
- int var_name;
-{
- bc_num *num_ptr;
- long index;
-
- if (!check_stack(1)) return;
- index = bc_num2long (ex_stack->s_num);
- if (index < 0 || index > BC_DIM_MAX ||
- (index == 0 && !bc_is_zero(ex_stack->s_num)))
- rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
- else
- {
- num_ptr = get_array_num (var_name, index);
- if (num_ptr != NULL)
- {
- pop();
- push_copy (*num_ptr);
- }
- }
-}
-
-
-/* Decrement VAR_NAME by one. This includes the special variables
- ibase, obase, and scale. */
-
-void
-decr_var (var_name)
- int var_name;
-{
- bc_var *var_ptr;
-
- switch (var_name)
- {
-
- case 0: /* ibase */
- if (i_base > 2)
- i_base--;
- else
- rt_warn ("ibase too small in --");
- break;
-
- case 1: /* obase */
- if (o_base > 2)
- o_base--;
- else
- rt_warn ("obase too small in --");
- break;
-
- case 2: /* scale */
- if (scale > 0)
- scale--;
- else
- rt_warn ("scale can not be negative in -- ");
- break;
-
-#if defined(READLINE) || defined(LIBEDIT)
- case 3: /* history */
- n_history--;
- if (n_history >= 0)
- HISTORY_SIZE(n_history);
- else
- {
- n_history = -1;
- rt_warn ("history is negative, set to unlimited");
- UNLIMIT_HISTORY;
- }
-#endif
-
- default: /* It is a simple variable. */
- var_ptr = get_var (var_name);
- if (var_ptr != NULL)
- bc_sub (var_ptr->v_value,_one_,&var_ptr->v_value, 0);
- }
-}
-
-
-/* Decrement VAR_NAME by one. VAR_NAME is an array, and the top of
- the execution stack is the index and it is popped off the stack. */
-
-void
-decr_array (var_name)
- int var_name;
-{
- bc_num *num_ptr;
- long index;
-
- /* It is an array variable. */
- if (!check_stack (1)) return;
- index = bc_num2long (ex_stack->s_num);
- if (index < 0 || index > BC_DIM_MAX ||
- (index == 0 && !bc_is_zero (ex_stack->s_num)))
- rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
- else
- {
- num_ptr = get_array_num (var_name, index);
- if (num_ptr != NULL)
- {
- pop ();
- bc_sub (*num_ptr, _one_, num_ptr, 0);
- }
- }
-}
-
-
-/* Increment VAR_NAME by one. This includes the special variables
- ibase, obase, and scale. */
-
-void
-incr_var (var_name)
- int var_name;
-{
- bc_var *var_ptr;
-
- switch (var_name)
- {
-
- case 0: /* ibase */
- if (i_base < 16)
- i_base++;
- else
- rt_warn ("ibase too big in ++");
- break;
-
- case 1: /* obase */
- if (o_base < BC_BASE_MAX)
- o_base++;
- else
- rt_warn ("obase too big in ++");
- break;
-
- case 2:
- if (scale < BC_SCALE_MAX)
- scale++;
- else
- rt_warn ("Scale too big in ++");
- break;
-
-#if defined(READLINE) || defined(LIBEDIT)
- case 3: /* history */
- n_history++;
- if (n_history > 0)
- HISTORY_SIZE(n_history);
- else
- {
- n_history = -1;
- rt_warn ("history set to unlimited");
- UNLIMIT_HISTORY;
- }
-#endif
-
- default: /* It is a simple variable. */
- var_ptr = get_var (var_name);
- if (var_ptr != NULL)
- bc_add (var_ptr->v_value, _one_, &var_ptr->v_value, 0);
-
- }
-}
-
-
-/* Increment VAR_NAME by one. VAR_NAME is an array and top of
- execution stack is the index and is popped off the stack. */
-
-void
-incr_array (var_name)
- int var_name;
-{
- bc_num *num_ptr;
- long index;
-
- if (!check_stack (1)) return;
- index = bc_num2long (ex_stack->s_num);
- if (index < 0 || index > BC_DIM_MAX ||
- (index == 0 && !bc_is_zero (ex_stack->s_num)))
- rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
- else
- {
- num_ptr = get_array_num (var_name, index);
- if (num_ptr != NULL)
- {
- pop ();
- bc_add (*num_ptr, _one_, num_ptr, 0);
- }
- }
-}
-
-
-/* Routines for processing autos variables and parameters. */
-
-/* NAME is an auto variable that needs to be pushed on its stack. */
-
-void
-auto_var (name)
- int name;
-{
- bc_var *v_temp;
- bc_var_array *a_temp;
- int ix;
-
- if (name > 0)
- {
- /* A simple variable. */
- ix = name;
- v_temp = (bc_var *) bc_malloc (sizeof (bc_var));
- v_temp->v_next = variables[ix];
- bc_init_num (&v_temp->v_value);
- variables[ix] = v_temp;
- }
- else
- {
- /* An array variable. */
- ix = -name;
- a_temp = (bc_var_array *) bc_malloc (sizeof (bc_var_array));
- a_temp->a_next = arrays[ix];
- a_temp->a_value = NULL;
- a_temp->a_param = FALSE;
- arrays[ix] = a_temp;
- }
-}
-
-
-/* Free_a_tree frees everything associated with an array variable tree.
- This is used when popping an array variable off its auto stack. */
-
-void
-free_a_tree ( root, depth )
- bc_array_node *root;
- int depth;
-{
- int ix;
-
- if (root != NULL)
- {
- if (depth > 1)
- for (ix = 0; ix < NODE_SIZE; ix++)
- free_a_tree (root->n_items.n_down[ix], depth-1);
- else
- for (ix = 0; ix < NODE_SIZE; ix++)
- bc_free_num ( &(root->n_items.n_num[ix]));
- free (root);
- }
-}
-
-
-/* LIST is an NULL terminated list of varible names that need to be
- popped off their auto stacks. */
-
-void
-pop_vars (list)
- arg_list *list;
-{
- bc_var *v_temp;
- bc_var_array *a_temp;
- int ix;
-
- while (list != NULL)
- {
- ix = list->av_name;
- if (ix > 0)
- {
- /* A simple variable. */
- v_temp = variables[ix];
- if (v_temp != NULL)
- {
- variables[ix] = v_temp->v_next;
- bc_free_num (&v_temp->v_value);
- free (v_temp);
- }
- }
- else
- {
- /* An array variable. */
- ix = -ix;
- a_temp = arrays[ix];
- if (a_temp != NULL)
- {
- arrays[ix] = a_temp->a_next;
- if (!a_temp->a_param && a_temp->a_value != NULL)
- {
- free_a_tree (a_temp->a_value->a_tree,
- a_temp->a_value->a_depth);
- free (a_temp->a_value);
- }
- free (a_temp);
- }
- }
- list = list->next;
- }
-}
-
-/* COPY_NODE: Copies an array node for a call by value parameter. */
-bc_array_node *
-copy_tree (ary_node, depth)
- bc_array_node *ary_node;
- int depth;
-{
- bc_array_node *res = (bc_array_node *) bc_malloc (sizeof(bc_array_node));
- int i;
-
- if (depth > 1)
- for (i=0; i<NODE_SIZE; i++)
- if (ary_node->n_items.n_down[i] != NULL)
- res->n_items.n_down[i] =
- copy_tree (ary_node->n_items.n_down[i], depth - 1);
- else
- res->n_items.n_down[i] = NULL;
- else
- for (i=0; i<NODE_SIZE; i++)
- if (ary_node->n_items.n_num[i] != NULL)
- res->n_items.n_num[i] = bc_copy_num (ary_node->n_items.n_num[i]);
- else
- res->n_items.n_num[i] = NULL;
- return res;
-}
-
-/* COPY_ARRAY: Copies an array for a call by value array parameter.
- ARY is the pointer to the bc_array structure. */
-
-bc_array *
-copy_array (ary)
- bc_array *ary;
-{
- bc_array *res = (bc_array *) bc_malloc (sizeof(bc_array));
- res->a_depth = ary->a_depth;
- res->a_tree = copy_tree (ary->a_tree, ary->a_depth);
- return (res);
-}
-
-
-/* A call is being made to FUNC. The call types are at PC. Process
- the parameters by doing an auto on the parameter variable and then
- store the value at the new variable or put a pointer the the array
- variable. */
-
-void
-process_params (pc, func)
- program_counter *pc;
- int func;
-{
- char ch;
- arg_list *params;
- int ix, ix1;
- bc_var *v_temp;
- bc_var_array *a_src, *a_dest;
- bc_num *n_temp;
-
- /* Get the parameter names from the function. */
- params = functions[func].f_params;
-
- while ((ch = byte(pc)) != ':')
- {
- if (params != NULL)
- {
- if ((ch == '0') && params->av_name > 0)
- {
- /* A simple variable. */
- ix = params->av_name;
- v_temp = (bc_var *) bc_malloc (sizeof(bc_var));
- v_temp->v_next = variables[ix];
- v_temp->v_value = ex_stack->s_num;
- bc_init_num (&ex_stack->s_num);
- variables[ix] = v_temp;
- }
- else
- if ((ch == '1') && (params->av_name < 0))
- {
- /* The variables is an array variable. */
-
- /* Compute source index and make sure some structure exists. */
- ix = (int) bc_num2long (ex_stack->s_num);
- n_temp = get_array_num (ix, 0);
-
- /* Push a new array and Compute Destination index */
- auto_var (params->av_name);
- ix1 = -params->av_name;
-
- /* Set up the correct pointers in the structure. */
- if (ix == ix1)
- a_src = arrays[ix]->a_next;
- else
- a_src = arrays[ix];
- a_dest = arrays[ix1];
- if (params->arg_is_var)
- {
- a_dest->a_param = TRUE;
- a_dest->a_value = a_src->a_value;
- }
- else
- {
- a_dest->a_param = FALSE;
- a_dest->a_value = copy_array (a_src->a_value);
- }
- }
- else
- {
- if (params->av_name < 0)
- rt_error ("Parameter type mismatch parameter %s.",
- a_names[-params->av_name]);
- else
- rt_error ("Parameter type mismatch, parameter %s.",
- v_names[params->av_name]);
- params++;
- }
- pop ();
- }
- else
- {
- rt_error ("Parameter number mismatch");
- return;
- }
- params = params->next;
- }
- if (params != NULL)
- rt_error ("Parameter number mismatch");
-}
diff --git a/contrib/bc/bc/util.c b/contrib/bc/bc/util.c
deleted file mode 100644
index c305c2e..0000000
--- a/contrib/bc/bc/util.c
+++ /dev/null
@@ -1,873 +0,0 @@
-/* util.c: Utility routines for bc. */
-
-/* This file is part of GNU bc.
- Copyright (C) 1991-1994, 1997, 2000 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111 USA
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-
-#include "bcdefs.h"
-#ifndef VARARGS
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-#include "global.h"
-#include "proto.h"
-
-
-/* strcopyof mallocs new memory and copies a string to to the new
- memory. */
-
-char *
-strcopyof (str)
- char *str;
-{
- char *temp;
-
- temp = (char *) bc_malloc (strlen (str)+1);
- return (strcpy (temp,str));
-}
-
-
-/* nextarg adds another value to the list of arguments. */
-
-arg_list *
-nextarg (args, val, is_var)
- arg_list *args;
- int val;
- int is_var;
-{ arg_list *temp;
-
- temp = (arg_list *) bc_malloc (sizeof (arg_list));
- temp->av_name = val;
- temp->arg_is_var = is_var;
- temp->next = args;
-
- return (temp);
-}
-
-
-/* For generate, we must produce a string in the form
- "val,val,...,val". We also need a couple of static variables
- for retaining old generated strings. It also uses a recursive
- function that builds the string. */
-
-static char *arglist1 = NULL, *arglist2 = NULL;
-
-
-/* make_arg_str does the actual construction of the argument string.
- ARGS is the pointer to the list and LEN is the maximum number of
- characters needed. 1 char is the minimum needed.
- */
-
-_PROTOTYPE (static char *make_arg_str, (arg_list *args, int len));
-
-static char *
-make_arg_str (args, len)
- arg_list *args;
- int len;
-{
- char *temp;
- char sval[20];
-
- /* Recursive call. */
- if (args != NULL)
- temp = make_arg_str (args->next, len+12);
- else
- {
- temp = (char *) bc_malloc (len);
- *temp = 0;
- return temp;
- }
-
- /* Add the current number to the end of the string. */
- if (args->arg_is_var)
- if (len != 1)
- sprintf (sval, "*%d,", args->av_name);
- else
- sprintf (sval, "*%d", args->av_name);
- else
- if (len != 1)
- sprintf (sval, "%d,", args->av_name);
- else
- sprintf (sval, "%d", args->av_name);
- temp = strcat (temp, sval);
- return (temp);
-}
-
-char *
-arg_str (args)
- arg_list *args;
-{
- if (arglist2 != NULL)
- free (arglist2);
- arglist2 = arglist1;
- arglist1 = make_arg_str (args, 1);
- return (arglist1);
-}
-
-char *
-call_str (args)
- arg_list *args;
-{
- arg_list *temp;
- int arg_count;
- int ix;
-
- if (arglist2 != NULL)
- free (arglist2);
- arglist2 = arglist1;
-
- /* Count the number of args and add the 0's and 1's. */
- for (temp = args, arg_count = 0; temp != NULL; temp = temp->next)
- arg_count++;
- arglist1 = (char *) bc_malloc(arg_count+1);
- for (temp = args, ix=0; temp != NULL; temp = temp->next)
- arglist1[ix++] = ( temp->av_name ? '1' : '0');
- arglist1[ix] = 0;
-
- return (arglist1);
-}
-
-/* free_args frees an argument list ARGS. */
-
-void
-free_args (args)
- arg_list *args;
-{
- arg_list *temp;
-
- temp = args;
- while (temp != NULL)
- {
- args = args->next;
- free (temp);
- temp = args;
- }
-}
-
-
-/* Check for valid parameter (PARAMS) and auto (AUTOS) lists.
- There must be no duplicates any where. Also, this is where
- warnings are generated for array parameters. */
-
-void
-check_params ( params, autos )
- arg_list *params, *autos;
-{
- arg_list *tmp1, *tmp2;
-
- /* Check for duplicate parameters. */
- if (params != NULL)
- {
- tmp1 = params;
- while (tmp1 != NULL)
- {
- tmp2 = tmp1->next;
- while (tmp2 != NULL)
- {
- if (tmp2->av_name == tmp1->av_name)
- yyerror ("duplicate parameter names");
- tmp2 = tmp2->next;
- }
- if (tmp1->arg_is_var)
- warn ("Variable array parameter");
- tmp1 = tmp1->next;
- }
- }
-
- /* Check for duplicate autos. */
- if (autos != NULL)
- {
- tmp1 = autos;
- while (tmp1 != NULL)
- {
- tmp2 = tmp1->next;
- while (tmp2 != NULL)
- {
- if (tmp2->av_name == tmp1->av_name)
- yyerror ("duplicate auto variable names");
- tmp2 = tmp2->next;
- }
- if (tmp1->arg_is_var)
- yyerror ("* not allowed here");
- tmp1 = tmp1->next;
- }
- }
-
- /* Check for duplicate between parameters and autos. */
- if ((params != NULL) && (autos != NULL))
- {
- tmp1 = params;
- while (tmp1 != NULL)
- {
- tmp2 = autos;
- while (tmp2 != NULL)
- {
- if (tmp2->av_name == tmp1->av_name)
- yyerror ("variable in both parameter and auto lists");
- tmp2 = tmp2->next;
- }
- tmp1 = tmp1->next;
- }
- }
-}
-
-
-/* Initialize the code generator the parser. */
-
-void
-init_gen ()
-{
- /* Get things ready. */
- break_label = 0;
- continue_label = 0;
- next_label = 1;
- out_count = 2;
- if (compile_only)
- printf ("@i");
- else
- init_load ();
- had_error = FALSE;
- did_gen = FALSE;
-}
-
-
-/* generate code STR for the machine. */
-
-void
-generate (str)
- char *str;
-{
- did_gen = TRUE;
- if (compile_only)
- {
- printf ("%s",str);
- out_count += strlen(str);
- if (out_count > 60)
- {
- printf ("\n");
- out_count = 0;
- }
- }
- else
- load_code (str);
-}
-
-
-/* Execute the current code as loaded. */
-
-void
-run_code()
-{
- /* If no compile errors run the current code. */
- if (!had_error && did_gen)
- {
- if (compile_only)
- {
- printf ("@r\n");
- out_count = 0;
- }
- else
- execute ();
- }
-
- /* Reinitialize the code generation and machine. */
- if (did_gen)
- init_gen();
- else
- had_error = FALSE;
-}
-
-
-/* Output routines: Write a character CH to the standard output.
- It keeps track of the number of characters output and may
- break the output with a "\<cr>". Always used for numbers. */
-
-void
-out_char (ch)
- int ch;
-{
- if (ch == '\n')
- {
- out_col = 0;
- putchar ('\n');
- }
- else
- {
- out_col++;
- if (out_col == line_size-1)
- {
- putchar ('\\');
- putchar ('\n');
- out_col = 1;
- }
- putchar (ch);
- }
-}
-
-/* Output routines: Write a character CH to the standard output.
- It keeps track of the number of characters output and may
- break the output with a "\<cr>". This one is for strings.
- In POSIX bc, strings are not broken across lines. */
-
-void
-out_schar (ch)
- int ch;
-{
- if (ch == '\n')
- {
- out_col = 0;
- putchar ('\n');
- }
- else
- {
- if (!std_only)
- {
- out_col++;
- if (out_col == line_size-1)
- {
- putchar ('\\');
- putchar ('\n');
- out_col = 1;
- }
- }
- putchar (ch);
- }
-}
-
-
-/* The following are "Symbol Table" routines for the parser. */
-
-/* find_id returns a pointer to node in TREE that has the correct
- ID. If there is no node in TREE with ID, NULL is returned. */
-
-id_rec *
-find_id (tree, id)
- id_rec *tree;
- char *id;
-{
- int cmp_result;
-
- /* Check for an empty tree. */
- if (tree == NULL)
- return NULL;
-
- /* Recursively search the tree. */
- cmp_result = strcmp (id, tree->id);
- if (cmp_result == 0)
- return tree; /* This is the item. */
- else if (cmp_result < 0)
- return find_id (tree->left, id);
- else
- return find_id (tree->right, id);
-}
-
-
-/* insert_id_rec inserts a NEW_ID rec into the tree whose ROOT is
- provided. insert_id_rec returns TRUE if the tree height from
- ROOT down is increased otherwise it returns FALSE. This is a
- recursive balanced binary tree insertion algorithm. */
-
-int insert_id_rec (root, new_id)
- id_rec **root;
- id_rec *new_id;
-{
- id_rec *A, *B;
-
- /* If root is NULL, this where it is to be inserted. */
- if (*root == NULL)
- {
- *root = new_id;
- new_id->left = NULL;
- new_id->right = NULL;
- new_id->balance = 0;
- return (TRUE);
- }
-
- /* We need to search for a leaf. */
- if (strcmp (new_id->id, (*root)->id) < 0)
- {
- /* Insert it on the left. */
- if (insert_id_rec (&((*root)->left), new_id))
- {
- /* The height increased. */
- (*root)->balance --;
-
- switch ((*root)->balance)
- {
- case 0: /* no height increase. */
- return (FALSE);
- case -1: /* height increase. */
- return (FALSE);
- case -2: /* we need to do a rebalancing act. */
- A = *root;
- B = (*root)->left;
- if (B->balance <= 0)
- {
- /* Single Rotate. */
- A->left = B->right;
- B->right = A;
- *root = B;
- A->balance = 0;
- B->balance = 0;
- }
- else
- {
- /* Double Rotate. */
- *root = B->right;
- B->right = (*root)->left;
- A->left = (*root)->right;
- (*root)->left = B;
- (*root)->right = A;
- switch ((*root)->balance)
- {
- case -1:
- A->balance = 1;
- B->balance = 0;
- break;
- case 0:
- A->balance = 0;
- B->balance = 0;
- break;
- case 1:
- A->balance = 0;
- B->balance = -1;
- break;
- }
- (*root)->balance = 0;
- }
- }
- }
- }
- else
- {
- /* Insert it on the right. */
- if (insert_id_rec (&((*root)->right), new_id))
- {
- /* The height increased. */
- (*root)->balance ++;
- switch ((*root)->balance)
- {
- case 0: /* no height increase. */
- return (FALSE);
- case 1: /* height increase. */
- return (FALSE);
- case 2: /* we need to do a rebalancing act. */
- A = *root;
- B = (*root)->right;
- if (B->balance >= 0)
- {
- /* Single Rotate. */
- A->right = B->left;
- B->left = A;
- *root = B;
- A->balance = 0;
- B->balance = 0;
- }
- else
- {
- /* Double Rotate. */
- *root = B->left;
- B->left = (*root)->right;
- A->right = (*root)->left;
- (*root)->left = A;
- (*root)->right = B;
- switch ((*root)->balance)
- {
- case -1:
- A->balance = 0;
- B->balance = 1;
- break;
- case 0:
- A->balance = 0;
- B->balance = 0;
- break;
- case 1:
- A->balance = -1;
- B->balance = 0;
- break;
- }
- (*root)->balance = 0;
- }
- }
- }
- }
-
- /* If we fall through to here, the tree did not grow in height. */
- return (FALSE);
-}
-
-
-/* Initialize variables for the symbol table tree. */
-
-void
-init_tree()
-{
- name_tree = NULL;
- next_array = 1;
- next_func = 1;
- /* 0 => ibase, 1 => obase, 2 => scale, 3 => history, 4 => last. */
- next_var = 5;
-}
-
-
-/* Lookup routines for symbol table names. */
-
-int
-lookup (name, namekind)
- char *name;
- int namekind;
-{
- id_rec *id;
-
- /* Warn about non-standard name. */
- if (strlen(name) != 1)
- warn ("multiple letter name - %s", name);
-
- /* Look for the id. */
- id = find_id (name_tree, name);
- if (id == NULL)
- {
- /* We need to make a new item. */
- id = (id_rec *) bc_malloc (sizeof (id_rec));
- id->id = strcopyof (name);
- id->a_name = 0;
- id->f_name = 0;
- id->v_name = 0;
- insert_id_rec (&name_tree, id);
- }
-
- /* Return the correct value. */
- switch (namekind)
- {
-
- case ARRAY:
- /* ARRAY variable numbers are returned as negative numbers. */
- if (id->a_name != 0)
- {
- free (name);
- return (-id->a_name);
- }
- id->a_name = next_array++;
- a_names[id->a_name] = name;
- if (id->a_name < MAX_STORE)
- {
- if (id->a_name >= a_count)
- more_arrays ();
- return (-id->a_name);
- }
- yyerror ("Too many array variables");
- exit (1);
-
- case FUNCT:
- case FUNCTDEF:
- if (id->f_name != 0)
- {
- free(name);
- /* Check to see if we are redefining a math lib function. */
- if (use_math && namekind == FUNCTDEF && id->f_name <= 6)
- id->f_name = next_func++;
- return (id->f_name);
- }
- id->f_name = next_func++;
- f_names[id->f_name] = name;
- if (id->f_name < MAX_STORE)
- {
- if (id->f_name >= f_count)
- more_functions ();
- return (id->f_name);
- }
- yyerror ("Too many functions");
- exit (1);
-
- case SIMPLE:
- if (id->v_name != 0)
- {
- free(name);
- return (id->v_name);
- }
- id->v_name = next_var++;
- v_names[id->v_name - 1] = name;
- if (id->v_name <= MAX_STORE)
- {
- if (id->v_name >= v_count)
- more_variables ();
- return (id->v_name);
- }
- yyerror ("Too many variables");
- exit (1);
- }
-
- yyerror ("End of util.c/lookup() reached. Please report this bug.");
- exit (1);
- /* not reached */
-}
-
-
-/* Print the welcome banner. */
-
-void
-welcome()
-{
- printf ("This is free software with ABSOLUTELY NO WARRANTY.\n");
- printf ("For details type `warranty'. \n");
-}
-
-/* Print out the version information. */
-void
-show_bc_version()
-{
- printf("%s %s\n%s\n", PACKAGE, VERSION, BC_COPYRIGHT);
-}
-
-
-/* Print out the warranty information. */
-
-void
-warranty(prefix)
- char *prefix;
-{
- printf ("\n%s", prefix);
- show_bc_version ();
- printf ("\n"
-" This program is free software; you can redistribute it and/or modify\n"
-" it under the terms of the GNU General Public License as published by\n"
-" the Free Software Foundation; either version 2 of the License , or\n"
-" (at your option) any later version.\n\n"
-" This program is distributed in the hope that it will be useful,\n"
-" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
-" GNU General Public License for more details.\n\n"
-" You should have received a copy of the GNU General Public License\n"
-" along with this program. If not, write to\n\n"
-" The Free Software Foundation, Inc.\n"
-" 59 Temple Place, Suite 330\n"
-" Boston, MA 02111, USA.\n\n");
-}
-
-/* Print out the limits of this program. */
-
-void
-limits()
-{
- printf ("BC_BASE_MAX = %d\n", BC_BASE_MAX);
- printf ("BC_DIM_MAX = %ld\n", (long) BC_DIM_MAX);
- printf ("BC_SCALE_MAX = %d\n", BC_SCALE_MAX);
- printf ("BC_STRING_MAX = %d\n", BC_STRING_MAX);
- printf ("MAX Exponent = %ld\n", (long) LONG_MAX);
- printf ("Number of vars = %ld\n", (long) MAX_STORE);
-#ifdef OLD_EQ_OP
- printf ("Old assignment operatiors are valid. (=-, =+, ...)\n");
-#endif
-}
-
-/* bc_malloc will check the return value so all other places do not
- have to do it! SIZE is the number of bytes to allocate. */
-
-char *
-bc_malloc (size)
- int size;
-{
- char *ptr;
-
- ptr = (char *) malloc (size);
- if (ptr == NULL)
- out_of_memory ();
-
- return ptr;
-}
-
-
-/* The following routines are error routines for various problems. */
-
-/* Malloc could not get enought memory. */
-
-void
-out_of_memory()
-{
- fprintf (stderr, "Fatal error: Out of memory for malloc.\n");
- exit (1);
-}
-
-
-
-/* The standard yyerror routine. Built with variable number of argumnets. */
-
-#ifndef VARARGS
-#ifdef __STDC__
-void
-yyerror (char *str, ...)
-#else
-void
-yyerror (str)
- char *str;
-#endif
-#else
-void
-yyerror (str, va_alist)
- char *str;
-#endif
-{
- char *name;
- va_list args;
-
-#ifndef VARARGS
- va_start (args, str);
-#else
- va_start (args);
-#endif
- if (is_std_in)
- name = "(standard_in)";
- else
- name = file_name;
- fprintf (stderr,"%s %d: ",name,line_no);
- vfprintf (stderr, str, args);
- fprintf (stderr, "\n");
- had_error = TRUE;
- va_end (args);
-}
-
-
-/* The routine to produce warnings about non-standard features
- found during parsing. */
-
-#ifndef VARARGS
-#ifdef __STDC__
-void
-warn (char *mesg, ...)
-#else
-void
-warn (mesg)
- char *mesg;
-#endif
-#else
-void
-warn (mesg, va_alist)
- char *mesg;
-#endif
-{
- char *name;
- va_list args;
-
-#ifndef VARARGS
- va_start (args, mesg);
-#else
- va_start (args);
-#endif
- if (std_only)
- {
- if (is_std_in)
- name = "(standard_in)";
- else
- name = file_name;
- fprintf (stderr,"%s %d: ",name,line_no);
- vfprintf (stderr, mesg, args);
- fprintf (stderr, "\n");
- had_error = TRUE;
- }
- else
- if (warn_not_std)
- {
- if (is_std_in)
- name = "(standard_in)";
- else
- name = file_name;
- fprintf (stderr,"%s %d: (Warning) ",name,line_no);
- vfprintf (stderr, mesg, args);
- fprintf (stderr, "\n");
- }
- va_end (args);
-}
-
-/* Runtime error will print a message and stop the machine. */
-
-#ifndef VARARGS
-#ifdef __STDC__
-void
-rt_error (char *mesg, ...)
-#else
-void
-rt_error (mesg)
- char *mesg;
-#endif
-#else
-void
-rt_error (mesg, va_alist)
- char *mesg;
-#endif
-{
- va_list args;
-
- fprintf (stderr, "Runtime error (func=%s, adr=%d): ",
- f_names[pc.pc_func], pc.pc_addr);
-#ifndef VARARGS
- va_start (args, mesg);
-#else
- va_start (args);
-#endif
- vfprintf (stderr, mesg, args);
- va_end (args);
-
- fprintf (stderr, "\n");
- runtime_error = TRUE;
-}
-
-
-/* A runtime warning tells of some action taken by the processor that
- may change the program execution but was not enough of a problem
- to stop the execution. */
-
-#ifndef VARARGS
-#ifdef __STDC__
-void
-rt_warn (char *mesg, ...)
-#else
-void
-rt_warn (mesg)
- char *mesg;
-#endif
-#else
-void
-rt_warn (mesg, va_alist)
- char *mesg;
-#endif
-{
- va_list args;
-
- fprintf (stderr, "Runtime warning (func=%s, adr=%d): ",
- f_names[pc.pc_func], pc.pc_addr);
-#ifndef VARARGS
- va_start (args, mesg);
-#else
- va_start (args);
-#endif
- vfprintf (stderr, mesg, args);
- va_end (args);
-
- fprintf (stderr, "\n");
-}
diff --git a/contrib/bc/config.h.in b/contrib/bc/config.h.in
deleted file mode 100644
index ebb9e34..0000000
--- a/contrib/bc/config.h.in
+++ /dev/null
@@ -1,81 +0,0 @@
-/* config.h.in. Generated automatically from configure.in by autoheader. */
-
-/* Define to empty if the keyword does not work. */
-#undef const
-
-/* Define if you don't have vprintf but do have _doprnt. */
-#undef HAVE_DOPRNT
-
-/* Define if you have the vprintf function. */
-#undef HAVE_VPRINTF
-
-/* Define if on MINIX. */
-#undef _MINIX
-
-/* Define if the system does not provide POSIX.1 features except
- with this defined. */
-#undef _POSIX_1_SOURCE
-
-/* Define if you need to in order for stat and other things to work. */
-#undef _POSIX_SOURCE
-
-/* Define to `unsigned' if <sys/types.h> doesn't define. */
-#undef size_t
-
-/* Define if you have the ANSI C header files. */
-#undef STDC_HEADERS
-
-/* Define if lex declares yytext as a char * by default, not a char[]. */
-#undef YYTEXT_POINTER
-
-/* VERSION number for DC target*/
-#undef DC_VERSION
-
-/* COPYRIGHT notice for DC target */
-#undef DC_COPYRIGHT
-
-/* COPYRIGHT notice for BC target */
-#undef BC_COPYRIGHT
-
-/* Define to use the readline library. */
-#undef READLINE
-
-/* Define to use the BSD libedit library. */
-#undef LIBEDIT
-
-/* Define to `size_t' if <sys/types.h> and <stddef.h> don't define. */
-#undef ptrdiff_t
-
-/* Define if you have the isgraph function. */
-#undef HAVE_ISGRAPH
-
-/* Define if you have the setvbuf function. */
-#undef HAVE_SETVBUF
-
-/* Define if you have the <lib.h> header file. */
-#undef HAVE_LIB_H
-
-/* Define if you have the <limits.h> header file. */
-#undef HAVE_LIMITS_H
-
-/* Define if you have the <stdarg.h> header file. */
-#undef HAVE_STDARG_H
-
-/* Define if you have the <stddef.h> header file. */
-#undef HAVE_STDDEF_H
-
-/* Define if you have the <stdlib.h> header file. */
-#undef HAVE_STDLIB_H
-
-/* Define if you have the <string.h> header file. */
-#undef HAVE_STRING_H
-
-/* Define if you have the <unistd.h> header file. */
-#undef HAVE_UNISTD_H
-
-/* Name of package */
-#undef PACKAGE
-
-/* Version number of package */
-#undef VERSION
-
diff --git a/contrib/bc/configure b/contrib/bc/configure
deleted file mode 100755
index e5fc7d9..0000000
--- a/contrib/bc/configure
+++ /dev/null
@@ -1,2656 +0,0 @@
-#! /bin/sh
-
-# Guess values for system-dependent variables and create Makefiles.
-# Generated automatically using autoconf version 2.13
-# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
-#
-# This configure script is free software; the Free Software Foundation
-# gives unlimited permission to copy, distribute and modify it.
-
-# Defaults:
-ac_help=
-ac_default_prefix=/usr/local
-# Any additions from configure.in:
-ac_help="$ac_help
- --with-pkg use software installed in /usr/pkg tree"
-ac_help="$ac_help
- --with-libedit support fancy BSD command input
-editing"
-ac_help="$ac_help
- --with-readline support fancy command input editing"
-
-# Initialize some variables set by options.
-# The variables have the same names as the options, with
-# dashes changed to underlines.
-build=NONE
-cache_file=./config.cache
-exec_prefix=NONE
-host=NONE
-no_create=
-nonopt=NONE
-no_recursion=
-prefix=NONE
-program_prefix=NONE
-program_suffix=NONE
-program_transform_name=s,x,x,
-silent=
-site=
-srcdir=
-target=NONE
-verbose=
-x_includes=NONE
-x_libraries=NONE
-bindir='${exec_prefix}/bin'
-sbindir='${exec_prefix}/sbin'
-libexecdir='${exec_prefix}/libexec'
-datadir='${prefix}/share'
-sysconfdir='${prefix}/etc'
-sharedstatedir='${prefix}/com'
-localstatedir='${prefix}/var'
-libdir='${exec_prefix}/lib'
-includedir='${prefix}/include'
-oldincludedir='/usr/include'
-infodir='${prefix}/info'
-mandir='${prefix}/man'
-
-# Initialize some other variables.
-subdirs=
-MFLAGS= MAKEFLAGS=
-SHELL=${CONFIG_SHELL-/bin/sh}
-# Maximum number of lines to put in a shell here document.
-ac_max_here_lines=12
-
-ac_prev=
-for ac_option
-do
-
- # If the previous option needs an argument, assign it.
- if test -n "$ac_prev"; then
- eval "$ac_prev=\$ac_option"
- ac_prev=
- continue
- fi
-
- case "$ac_option" in
- -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
- *) ac_optarg= ;;
- esac
-
- # Accept the important Cygnus configure options, so we can diagnose typos.
-
- case "$ac_option" in
-
- -bindir | --bindir | --bindi | --bind | --bin | --bi)
- ac_prev=bindir ;;
- -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
- bindir="$ac_optarg" ;;
-
- -build | --build | --buil | --bui | --bu)
- ac_prev=build ;;
- -build=* | --build=* | --buil=* | --bui=* | --bu=*)
- build="$ac_optarg" ;;
-
- -cache-file | --cache-file | --cache-fil | --cache-fi \
- | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
- ac_prev=cache_file ;;
- -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
- | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
- cache_file="$ac_optarg" ;;
-
- -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
- ac_prev=datadir ;;
- -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
- | --da=*)
- datadir="$ac_optarg" ;;
-
- -disable-* | --disable-*)
- ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
- # Reject names that are not valid shell variable names.
- if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
- { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
- fi
- ac_feature=`echo $ac_feature| sed 's/-/_/g'`
- eval "enable_${ac_feature}=no" ;;
-
- -enable-* | --enable-*)
- ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
- # Reject names that are not valid shell variable names.
- if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
- { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
- fi
- ac_feature=`echo $ac_feature| sed 's/-/_/g'`
- case "$ac_option" in
- *=*) ;;
- *) ac_optarg=yes ;;
- esac
- eval "enable_${ac_feature}='$ac_optarg'" ;;
-
- -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
- | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
- | --exec | --exe | --ex)
- ac_prev=exec_prefix ;;
- -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
- | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
- | --exec=* | --exe=* | --ex=*)
- exec_prefix="$ac_optarg" ;;
-
- -gas | --gas | --ga | --g)
- # Obsolete; use --with-gas.
- with_gas=yes ;;
-
- -help | --help | --hel | --he)
- # Omit some internal or obsolete options to make the list less imposing.
- # This message is too long to be a string in the A/UX 3.1 sh.
- cat << EOF
-Usage: configure [options] [host]
-Options: [defaults in brackets after descriptions]
-Configuration:
- --cache-file=FILE cache test results in FILE
- --help print this message
- --no-create do not create output files
- --quiet, --silent do not print \`checking...' messages
- --version print the version of autoconf that created configure
-Directory and file names:
- --prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
- --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [same as prefix]
- --bindir=DIR user executables in DIR [EPREFIX/bin]
- --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
- --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
- --datadir=DIR read-only architecture-independent data in DIR
- [PREFIX/share]
- --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
- --sharedstatedir=DIR modifiable architecture-independent data in DIR
- [PREFIX/com]
- --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
- --libdir=DIR object code libraries in DIR [EPREFIX/lib]
- --includedir=DIR C header files in DIR [PREFIX/include]
- --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
- --infodir=DIR info documentation in DIR [PREFIX/info]
- --mandir=DIR man documentation in DIR [PREFIX/man]
- --srcdir=DIR find the sources in DIR [configure dir or ..]
- --program-prefix=PREFIX prepend PREFIX to installed program names
- --program-suffix=SUFFIX append SUFFIX to installed program names
- --program-transform-name=PROGRAM
- run sed PROGRAM on installed program names
-EOF
- cat << EOF
-Host type:
- --build=BUILD configure for building on BUILD [BUILD=HOST]
- --host=HOST configure for HOST [guessed]
- --target=TARGET configure for TARGET [TARGET=HOST]
-Features and packages:
- --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
- --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
- --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
- --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
- --x-includes=DIR X include files are in DIR
- --x-libraries=DIR X library files are in DIR
-EOF
- if test -n "$ac_help"; then
- echo "--enable and --with options recognized:$ac_help"
- fi
- exit 0 ;;
-
- -host | --host | --hos | --ho)
- ac_prev=host ;;
- -host=* | --host=* | --hos=* | --ho=*)
- host="$ac_optarg" ;;
-
- -includedir | --includedir | --includedi | --included | --include \
- | --includ | --inclu | --incl | --inc)
- ac_prev=includedir ;;
- -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
- | --includ=* | --inclu=* | --incl=* | --inc=*)
- includedir="$ac_optarg" ;;
-
- -infodir | --infodir | --infodi | --infod | --info | --inf)
- ac_prev=infodir ;;
- -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
- infodir="$ac_optarg" ;;
-
- -libdir | --libdir | --libdi | --libd)
- ac_prev=libdir ;;
- -libdir=* | --libdir=* | --libdi=* | --libd=*)
- libdir="$ac_optarg" ;;
-
- -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
- | --libexe | --libex | --libe)
- ac_prev=libexecdir ;;
- -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
- | --libexe=* | --libex=* | --libe=*)
- libexecdir="$ac_optarg" ;;
-
- -localstatedir | --localstatedir | --localstatedi | --localstated \
- | --localstate | --localstat | --localsta | --localst \
- | --locals | --local | --loca | --loc | --lo)
- ac_prev=localstatedir ;;
- -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
- | --localstate=* | --localstat=* | --localsta=* | --localst=* \
- | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
- localstatedir="$ac_optarg" ;;
-
- -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
- ac_prev=mandir ;;
- -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
- mandir="$ac_optarg" ;;
-
- -nfp | --nfp | --nf)
- # Obsolete; use --without-fp.
- with_fp=no ;;
-
- -no-create | --no-create | --no-creat | --no-crea | --no-cre \
- | --no-cr | --no-c)
- no_create=yes ;;
-
- -no-recursion | --no-recursion | --no-recursio | --no-recursi \
- | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
- no_recursion=yes ;;
-
- -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
- | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
- | --oldin | --oldi | --old | --ol | --o)
- ac_prev=oldincludedir ;;
- -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
- | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
- | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
- oldincludedir="$ac_optarg" ;;
-
- -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
- ac_prev=prefix ;;
- -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
- prefix="$ac_optarg" ;;
-
- -program-prefix | --program-prefix | --program-prefi | --program-pref \
- | --program-pre | --program-pr | --program-p)
- ac_prev=program_prefix ;;
- -program-prefix=* | --program-prefix=* | --program-prefi=* \
- | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
- program_prefix="$ac_optarg" ;;
-
- -program-suffix | --program-suffix | --program-suffi | --program-suff \
- | --program-suf | --program-su | --program-s)
- ac_prev=program_suffix ;;
- -program-suffix=* | --program-suffix=* | --program-suffi=* \
- | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
- program_suffix="$ac_optarg" ;;
-
- -program-transform-name | --program-transform-name \
- | --program-transform-nam | --program-transform-na \
- | --program-transform-n | --program-transform- \
- | --program-transform | --program-transfor \
- | --program-transfo | --program-transf \
- | --program-trans | --program-tran \
- | --progr-tra | --program-tr | --program-t)
- ac_prev=program_transform_name ;;
- -program-transform-name=* | --program-transform-name=* \
- | --program-transform-nam=* | --program-transform-na=* \
- | --program-transform-n=* | --program-transform-=* \
- | --program-transform=* | --program-transfor=* \
- | --program-transfo=* | --program-transf=* \
- | --program-trans=* | --program-tran=* \
- | --progr-tra=* | --program-tr=* | --program-t=*)
- program_transform_name="$ac_optarg" ;;
-
- -q | -quiet | --quiet | --quie | --qui | --qu | --q \
- | -silent | --silent | --silen | --sile | --sil)
- silent=yes ;;
-
- -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
- ac_prev=sbindir ;;
- -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
- | --sbi=* | --sb=*)
- sbindir="$ac_optarg" ;;
-
- -sharedstatedir | --sharedstatedir | --sharedstatedi \
- | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
- | --sharedst | --shareds | --shared | --share | --shar \
- | --sha | --sh)
- ac_prev=sharedstatedir ;;
- -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
- | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
- | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
- | --sha=* | --sh=*)
- sharedstatedir="$ac_optarg" ;;
-
- -site | --site | --sit)
- ac_prev=site ;;
- -site=* | --site=* | --sit=*)
- site="$ac_optarg" ;;
-
- -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
- ac_prev=srcdir ;;
- -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
- srcdir="$ac_optarg" ;;
-
- -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
- | --syscon | --sysco | --sysc | --sys | --sy)
- ac_prev=sysconfdir ;;
- -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
- | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
- sysconfdir="$ac_optarg" ;;
-
- -target | --target | --targe | --targ | --tar | --ta | --t)
- ac_prev=target ;;
- -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
- target="$ac_optarg" ;;
-
- -v | -verbose | --verbose | --verbos | --verbo | --verb)
- verbose=yes ;;
-
- -version | --version | --versio | --versi | --vers)
- echo "configure generated by autoconf version 2.13"
- exit 0 ;;
-
- -with-* | --with-*)
- ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
- # Reject names that are not valid shell variable names.
- if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
- { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
- fi
- ac_package=`echo $ac_package| sed 's/-/_/g'`
- case "$ac_option" in
- *=*) ;;
- *) ac_optarg=yes ;;
- esac
- eval "with_${ac_package}='$ac_optarg'" ;;
-
- -without-* | --without-*)
- ac_package=`echo $ac_option|sed -e 's/-*without-//'`
- # Reject names that are not valid shell variable names.
- if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
- { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
- fi
- ac_package=`echo $ac_package| sed 's/-/_/g'`
- eval "with_${ac_package}=no" ;;
-
- --x)
- # Obsolete; use --with-x.
- with_x=yes ;;
-
- -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
- | --x-incl | --x-inc | --x-in | --x-i)
- ac_prev=x_includes ;;
- -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
- | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
- x_includes="$ac_optarg" ;;
-
- -x-libraries | --x-libraries | --x-librarie | --x-librari \
- | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
- ac_prev=x_libraries ;;
- -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
- | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
- x_libraries="$ac_optarg" ;;
-
- -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
- ;;
-
- *)
- if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
- echo "configure: warning: $ac_option: invalid host type" 1>&2
- fi
- if test "x$nonopt" != xNONE; then
- { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
- fi
- nonopt="$ac_option"
- ;;
-
- esac
-done
-
-if test -n "$ac_prev"; then
- { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
-fi
-
-trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
-
-# File descriptor usage:
-# 0 standard input
-# 1 file creation
-# 2 errors and warnings
-# 3 some systems may open it to /dev/tty
-# 4 used on the Kubota Titan
-# 6 checking for... messages and results
-# 5 compiler messages saved in config.log
-if test "$silent" = yes; then
- exec 6>/dev/null
-else
- exec 6>&1
-fi
-exec 5>./config.log
-
-echo "\
-This file contains any messages produced by compilers while
-running configure, to aid debugging if configure makes a mistake.
-" 1>&5
-
-# Strip out --no-create and --no-recursion so they do not pile up.
-# Also quote any args containing shell metacharacters.
-ac_configure_args=
-for ac_arg
-do
- case "$ac_arg" in
- -no-create | --no-create | --no-creat | --no-crea | --no-cre \
- | --no-cr | --no-c) ;;
- -no-recursion | --no-recursion | --no-recursio | --no-recursi \
- | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
- *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
- ac_configure_args="$ac_configure_args '$ac_arg'" ;;
- *) ac_configure_args="$ac_configure_args $ac_arg" ;;
- esac
-done
-
-# NLS nuisances.
-# Only set these to C if already set. These must not be set unconditionally
-# because not all systems understand e.g. LANG=C (notably SCO).
-# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
-# Non-C LC_CTYPE values break the ctype check.
-if test "${LANG+set}" = set; then LANG=C; export LANG; fi
-if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
-if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
-if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
-
-# confdefs.h avoids OS command line length limits that DEFS can exceed.
-rm -rf conftest* confdefs.h
-# AIX cpp loses on an empty file, so make sure it contains at least a newline.
-echo > confdefs.h
-
-# A filename unique to this package, relative to the directory that
-# configure is in, which we can look for to find out if srcdir is correct.
-ac_unique_file=doc/bc.1
-
-# Find the source files, if location was not specified.
-if test -z "$srcdir"; then
- ac_srcdir_defaulted=yes
- # Try the directory containing this script, then its parent.
- ac_prog=$0
- ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
- test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
- srcdir=$ac_confdir
- if test ! -r $srcdir/$ac_unique_file; then
- srcdir=..
- fi
-else
- ac_srcdir_defaulted=no
-fi
-if test ! -r $srcdir/$ac_unique_file; then
- if test "$ac_srcdir_defaulted" = yes; then
- { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
- else
- { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
- fi
-fi
-srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
-
-# Prefer explicitly selected file to automatically selected ones.
-if test -z "$CONFIG_SITE"; then
- if test "x$prefix" != xNONE; then
- CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
- else
- CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
- fi
-fi
-for ac_site_file in $CONFIG_SITE; do
- if test -r "$ac_site_file"; then
- echo "loading site script $ac_site_file"
- . "$ac_site_file"
- fi
-done
-
-if test -r "$cache_file"; then
- echo "loading cache $cache_file"
- . $cache_file
-else
- echo "creating cache $cache_file"
- > $cache_file
-fi
-
-ac_ext=c
-# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
-cross_compiling=$ac_cv_prog_cc_cross
-
-ac_exeext=
-ac_objext=o
-if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
- # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
- if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
- ac_n= ac_c='
-' ac_t=' '
- else
- ac_n=-n ac_c= ac_t=
- fi
-else
- ac_n= ac_c='\c' ac_t=
-fi
-
-
-ac_aux_dir=
-for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
- if test -f $ac_dir/install-sh; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install-sh -c"
- break
- elif test -f $ac_dir/install.sh; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install.sh -c"
- break
- fi
-done
-if test -z "$ac_aux_dir"; then
- { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
-fi
-ac_config_guess=$ac_aux_dir/config.guess
-ac_config_sub=$ac_aux_dir/config.sub
-ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
-
-# Find a good install program. We prefer a C program (faster),
-# so one script is as good as another. But avoid the broken or
-# incompatible versions:
-# SysV /etc/install, /usr/sbin/install
-# SunOS /usr/etc/install
-# IRIX /sbin/install
-# AIX /bin/install
-# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
-# AFS /usr/afsws/bin/install, which mishandles nonexistent args
-# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
-# ./install, which can be erroneously created by make from ./install.sh.
-echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:563: checking for a BSD compatible install" >&5
-if test -z "$INSTALL"; then
-if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
- for ac_dir in $PATH; do
- # Account for people who put trailing slashes in PATH elements.
- case "$ac_dir/" in
- /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
- *)
- # OSF1 and SCO ODT 3.0 have their own names for install.
- # Don't use installbsd from OSF since it installs stuff as root
- # by default.
- for ac_prog in ginstall scoinst install; do
- if test -f $ac_dir/$ac_prog; then
- if test $ac_prog = install &&
- grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
- # AIX install. It has an incompatible calling convention.
- :
- else
- ac_cv_path_install="$ac_dir/$ac_prog -c"
- break 2
- fi
- fi
- done
- ;;
- esac
- done
- IFS="$ac_save_IFS"
-
-fi
- if test "${ac_cv_path_install+set}" = set; then
- INSTALL="$ac_cv_path_install"
- else
- # As a last resort, use the slow shell script. We don't cache a
- # path for INSTALL within a source directory, because that will
- # break other packages using the cache if that directory is
- # removed, or if the path is relative.
- INSTALL="$ac_install_sh"
- fi
-fi
-echo "$ac_t""$INSTALL" 1>&6
-
-# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
-# It thinks the first close brace ends the variable substitution.
-test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
-
-test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
-
-test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
-
-echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6
-echo "configure:616: checking whether build environment is sane" >&5
-# Just in case
-sleep 1
-echo timestamp > conftestfile
-# Do `set' in a subshell so we don't clobber the current shell's
-# arguments. Must try -L first in case configure is actually a
-# symlink; some systems play weird games with the mod time of symlinks
-# (eg FreeBSD returns the mod time of the symlink's containing
-# directory).
-if (
- set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
- if test "$*" = "X"; then
- # -L didn't work.
- set X `ls -t $srcdir/configure conftestfile`
- fi
- if test "$*" != "X $srcdir/configure conftestfile" \
- && test "$*" != "X conftestfile $srcdir/configure"; then
-
- # If neither matched, then we have a broken ls. This can happen
- # if, for instance, CONFIG_SHELL is bash and it inherits a
- # broken ls alias from the environment. This has actually
- # happened. Such a system could not be considered "sane".
- { echo "configure: error: ls -t appears to fail. Make sure there is not a broken
-alias in your environment" 1>&2; exit 1; }
- fi
-
- test "$2" = conftestfile
- )
-then
- # Ok.
- :
-else
- { echo "configure: error: newly created file is older than distributed files!
-Check your system clock" 1>&2; exit 1; }
-fi
-rm -f conftest*
-echo "$ac_t""yes" 1>&6
-if test "$program_transform_name" = s,x,x,; then
- program_transform_name=
-else
- # Double any \ or $. echo might interpret backslashes.
- cat <<\EOF_SED > conftestsed
-s,\\,\\\\,g; s,\$,$$,g
-EOF_SED
- program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
- rm -f conftestsed
-fi
-test "$program_prefix" != NONE &&
- program_transform_name="s,^,${program_prefix},; $program_transform_name"
-# Use a double $ so make ignores it.
-test "$program_suffix" != NONE &&
- program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
-
-# sed with no file args requires a program.
-test "$program_transform_name" = "" && program_transform_name="s,x,x,"
-
-echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
-echo "configure:673: checking whether ${MAKE-make} sets \${MAKE}" >&5
-set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftestmake <<\EOF
-all:
- @echo 'ac_maketemp="${MAKE}"'
-EOF
-# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
-eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
-if test -n "$ac_maketemp"; then
- eval ac_cv_prog_make_${ac_make}_set=yes
-else
- eval ac_cv_prog_make_${ac_make}_set=no
-fi
-rm -f conftestmake
-fi
-if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- SET_MAKE=
-else
- echo "$ac_t""no" 1>&6
- SET_MAKE="MAKE=${MAKE-make}"
-fi
-
-
-PACKAGE="bc"
-
-VERSION="1.06"
-
-if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
- { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
-fi
-cat >> confdefs.h <<EOF
-#define PACKAGE "$PACKAGE"
-EOF
-
-cat >> confdefs.h <<EOF
-#define VERSION "$VERSION"
-EOF
-
-
-
-missing_dir=`cd $ac_aux_dir && pwd`
-echo $ac_n "checking for working aclocal""... $ac_c" 1>&6
-echo "configure:719: checking for working aclocal" >&5
-# Run test in a subshell; some versions of sh will print an error if
-# an executable is not found, even if stderr is redirected.
-# Redirect stdin to placate older versions of autoconf. Sigh.
-if (aclocal --version) < /dev/null > /dev/null 2>&1; then
- ACLOCAL=aclocal
- echo "$ac_t""found" 1>&6
-else
- ACLOCAL="$missing_dir/missing aclocal"
- echo "$ac_t""missing" 1>&6
-fi
-
-echo $ac_n "checking for working autoconf""... $ac_c" 1>&6
-echo "configure:732: checking for working autoconf" >&5
-# Run test in a subshell; some versions of sh will print an error if
-# an executable is not found, even if stderr is redirected.
-# Redirect stdin to placate older versions of autoconf. Sigh.
-if (autoconf --version) < /dev/null > /dev/null 2>&1; then
- AUTOCONF=autoconf
- echo "$ac_t""found" 1>&6
-else
- AUTOCONF="$missing_dir/missing autoconf"
- echo "$ac_t""missing" 1>&6
-fi
-
-echo $ac_n "checking for working automake""... $ac_c" 1>&6
-echo "configure:745: checking for working automake" >&5
-# Run test in a subshell; some versions of sh will print an error if
-# an executable is not found, even if stderr is redirected.
-# Redirect stdin to placate older versions of autoconf. Sigh.
-if (automake --version) < /dev/null > /dev/null 2>&1; then
- AUTOMAKE=automake
- echo "$ac_t""found" 1>&6
-else
- AUTOMAKE="$missing_dir/missing automake"
- echo "$ac_t""missing" 1>&6
-fi
-
-echo $ac_n "checking for working autoheader""... $ac_c" 1>&6
-echo "configure:758: checking for working autoheader" >&5
-# Run test in a subshell; some versions of sh will print an error if
-# an executable is not found, even if stderr is redirected.
-# Redirect stdin to placate older versions of autoconf. Sigh.
-if (autoheader --version) < /dev/null > /dev/null 2>&1; then
- AUTOHEADER=autoheader
- echo "$ac_t""found" 1>&6
-else
- AUTOHEADER="$missing_dir/missing autoheader"
- echo "$ac_t""missing" 1>&6
-fi
-
-echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6
-echo "configure:771: checking for working makeinfo" >&5
-# Run test in a subshell; some versions of sh will print an error if
-# an executable is not found, even if stderr is redirected.
-# Redirect stdin to placate older versions of autoconf. Sigh.
-if (makeinfo --version) < /dev/null > /dev/null 2>&1; then
- MAKEINFO=makeinfo
- echo "$ac_t""found" 1>&6
-else
- MAKEINFO="$missing_dir/missing makeinfo"
- echo "$ac_t""missing" 1>&6
-fi
-
-
-
-
-
-
-cat >> confdefs.h <<\EOF
-#define DC_VERSION "1.3"
-EOF
-
-cat >> confdefs.h <<EOF
-#define BC_COPYRIGHT "Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc."
-EOF
-
-cat >> confdefs.h <<EOF
-#define DC_COPYRIGHT "Copyright 1994, 1997, 1998, 2000 Free Software Foundation, Inc."
-EOF
-
-
-# Extract the first word of "gcc", so it can be a program name with args.
-set dummy gcc; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:804: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_word; then
- ac_cv_prog_CC="gcc"
- break
- fi
- done
- IFS="$ac_save_ifs"
-fi
-fi
-CC="$ac_cv_prog_CC"
-if test -n "$CC"; then
- echo "$ac_t""$CC" 1>&6
-else
- echo "$ac_t""no" 1>&6
-fi
-
-if test -z "$CC"; then
- # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:834: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_prog_rejected=no
- ac_dummy="$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_word; then
- if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
- ac_prog_rejected=yes
- continue
- fi
- ac_cv_prog_CC="cc"
- break
- fi
- done
- IFS="$ac_save_ifs"
-if test $ac_prog_rejected = yes; then
- # We found a bogon in the path, so make sure we never use it.
- set dummy $ac_cv_prog_CC
- shift
- if test $# -gt 0; then
- # We chose a different compiler from the bogus one.
- # However, it has the same basename, so the bogon will be chosen
- # first if we set CC to just the basename; use the full file name.
- shift
- set dummy "$ac_dir/$ac_word" "$@"
- shift
- ac_cv_prog_CC="$@"
- fi
-fi
-fi
-fi
-CC="$ac_cv_prog_CC"
-if test -n "$CC"; then
- echo "$ac_t""$CC" 1>&6
-else
- echo "$ac_t""no" 1>&6
-fi
-
- if test -z "$CC"; then
- case "`uname -s`" in
- *win32* | *WIN32*)
- # Extract the first word of "cl", so it can be a program name with args.
-set dummy cl; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:885: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_word; then
- ac_cv_prog_CC="cl"
- break
- fi
- done
- IFS="$ac_save_ifs"
-fi
-fi
-CC="$ac_cv_prog_CC"
-if test -n "$CC"; then
- echo "$ac_t""$CC" 1>&6
-else
- echo "$ac_t""no" 1>&6
-fi
- ;;
- esac
- fi
- test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
-fi
-
-echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
-echo "configure:917: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
-
-ac_ext=c
-# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
-cross_compiling=$ac_cv_prog_cc_cross
-
-cat > conftest.$ac_ext << EOF
-
-#line 928 "configure"
-#include "confdefs.h"
-
-main(){return(0);}
-EOF
-if { (eval echo configure:933: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- ac_cv_prog_cc_works=yes
- # If we can't run a trivial program, we are probably using a cross compiler.
- if (./conftest; exit) 2>/dev/null; then
- ac_cv_prog_cc_cross=no
- else
- ac_cv_prog_cc_cross=yes
- fi
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- ac_cv_prog_cc_works=no
-fi
-rm -fr conftest*
-ac_ext=c
-# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
-cross_compiling=$ac_cv_prog_cc_cross
-
-echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
-if test $ac_cv_prog_cc_works = no; then
- { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
-fi
-echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
-echo "configure:959: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
-echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
-cross_compiling=$ac_cv_prog_cc_cross
-
-echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
-echo "configure:964: checking whether we are using GNU C" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.c <<EOF
-#ifdef __GNUC__
- yes;
-#endif
-EOF
-if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:973: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
- ac_cv_prog_gcc=yes
-else
- ac_cv_prog_gcc=no
-fi
-fi
-
-echo "$ac_t""$ac_cv_prog_gcc" 1>&6
-
-if test $ac_cv_prog_gcc = yes; then
- GCC=yes
-else
- GCC=
-fi
-
-ac_test_CFLAGS="${CFLAGS+set}"
-ac_save_CFLAGS="$CFLAGS"
-CFLAGS=
-echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
-echo "configure:992: checking whether ${CC-cc} accepts -g" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- echo 'void f(){}' > conftest.c
-if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
- ac_cv_prog_cc_g=yes
-else
- ac_cv_prog_cc_g=no
-fi
-rm -f conftest*
-
-fi
-
-echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
-if test "$ac_test_CFLAGS" = set; then
- CFLAGS="$ac_save_CFLAGS"
-elif test $ac_cv_prog_cc_g = yes; then
- if test "$GCC" = yes; then
- CFLAGS="-g -O2"
- else
- CFLAGS="-g"
- fi
-else
- if test "$GCC" = yes; then
- CFLAGS="-O2"
- else
- CFLAGS=
- fi
-fi
-
-echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:1024: checking how to run the C preprocessor" >&5
-# On Suns, sometimes $CPP names a directory.
-if test -n "$CPP" && test -d "$CPP"; then
- CPP=
-fi
-if test -z "$CPP"; then
-if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- # This must be in double quotes, not single quotes, because CPP may get
- # substituted into the Makefile and "${CC-cc}" will confuse make.
- CPP="${CC-cc} -E"
- # On the NeXT, cc -E runs the code through the compiler's parser,
- # not just through cpp.
- cat > conftest.$ac_ext <<EOF
-#line 1039 "configure"
-#include "confdefs.h"
-#include <assert.h>
-Syntax Error
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1045: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- :
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- CPP="${CC-cc} -E -traditional-cpp"
- cat > conftest.$ac_ext <<EOF
-#line 1056 "configure"
-#include "confdefs.h"
-#include <assert.h>
-Syntax Error
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1062: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- :
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- CPP="${CC-cc} -nologo -E"
- cat > conftest.$ac_ext <<EOF
-#line 1073 "configure"
-#include "confdefs.h"
-#include <assert.h>
-Syntax Error
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1079: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- :
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- CPP=/lib/cpp
-fi
-rm -f conftest*
-fi
-rm -f conftest*
-fi
-rm -f conftest*
- ac_cv_prog_CPP="$CPP"
-fi
- CPP="$ac_cv_prog_CPP"
-else
- ac_cv_prog_CPP="$CPP"
-fi
-echo "$ac_t""$CPP" 1>&6
-
-ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
-echo "configure:1105: checking for minix/config.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1110 "configure"
-#include "confdefs.h"
-#include <minix/config.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1115: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- MINIX=yes
-else
- echo "$ac_t""no" 1>&6
-MINIX=
-fi
-
-if test "$MINIX" = yes; then
- cat >> confdefs.h <<\EOF
-#define _POSIX_SOURCE 1
-EOF
-
- cat >> confdefs.h <<\EOF
-#define _POSIX_1_SOURCE 2
-EOF
-
- cat >> confdefs.h <<\EOF
-#define _MINIX 1
-EOF
-
-fi
-
-
-missing_dir=`cd $ac_aux_dir && pwd`
-for ac_prog in flex lex
-do
-# Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1159: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- if test -n "$LEX"; then
- ac_cv_prog_LEX="$LEX" # Let the user override the test.
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_word; then
- ac_cv_prog_LEX="$ac_prog"
- break
- fi
- done
- IFS="$ac_save_ifs"
-fi
-fi
-LEX="$ac_cv_prog_LEX"
-if test -n "$LEX"; then
- echo "$ac_t""$LEX" 1>&6
-else
- echo "$ac_t""no" 1>&6
-fi
-
-test -n "$LEX" && break
-done
-test -n "$LEX" || LEX=""$missing_dir/missing flex""
-
-# Extract the first word of "flex", so it can be a program name with args.
-set dummy flex; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1192: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- if test -n "$LEX"; then
- ac_cv_prog_LEX="$LEX" # Let the user override the test.
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_word; then
- ac_cv_prog_LEX="flex"
- break
- fi
- done
- IFS="$ac_save_ifs"
- test -z "$ac_cv_prog_LEX" && ac_cv_prog_LEX="lex"
-fi
-fi
-LEX="$ac_cv_prog_LEX"
-if test -n "$LEX"; then
- echo "$ac_t""$LEX" 1>&6
-else
- echo "$ac_t""no" 1>&6
-fi
-
-if test -z "$LEXLIB"
-then
- case "$LEX" in
- flex*) ac_lib=fl ;;
- *) ac_lib=l ;;
- esac
- echo $ac_n "checking for yywrap in -l$ac_lib""... $ac_c" 1>&6
-echo "configure:1226: checking for yywrap in -l$ac_lib" >&5
-ac_lib_var=`echo $ac_lib'_'yywrap | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- ac_save_LIBS="$LIBS"
-LIBS="-l$ac_lib $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1234 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char yywrap();
-
-int main() {
-yywrap()
-; return 0; }
-EOF
-if { (eval echo configure:1245: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- LEXLIB="-l$ac_lib"
-else
- echo "$ac_t""no" 1>&6
-fi
-
-fi
-
-echo $ac_n "checking lex output file root""... $ac_c" 1>&6
-echo "configure:1268: checking lex output file root" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_lex_root'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- # The minimal lex program is just a single line: %%. But some broken lexes
-# (Solaris, I think it was) want two %% lines, so accommodate them.
-echo '%%
-%%' | $LEX
-if test -f lex.yy.c; then
- ac_cv_prog_lex_root=lex.yy
-elif test -f lexyy.c; then
- ac_cv_prog_lex_root=lexyy
-else
- { echo "configure: error: cannot find output from $LEX; giving up" 1>&2; exit 1; }
-fi
-fi
-
-echo "$ac_t""$ac_cv_prog_lex_root" 1>&6
-LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
-
-echo $ac_n "checking whether yytext is a pointer""... $ac_c" 1>&6
-echo "configure:1289: checking whether yytext is a pointer" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_lex_yytext_pointer'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- # POSIX says lex can declare yytext either as a pointer or an array; the
-# default is implementation-dependent. Figure out which it is, since
-# not all implementations provide the %pointer and %array declarations.
-ac_cv_prog_lex_yytext_pointer=no
-echo 'extern char *yytext;' >>$LEX_OUTPUT_ROOT.c
-ac_save_LIBS="$LIBS"
-LIBS="$LIBS $LEXLIB"
-cat > conftest.$ac_ext <<EOF
-#line 1301 "configure"
-#include "confdefs.h"
-`cat $LEX_OUTPUT_ROOT.c`
-int main() {
-
-; return 0; }
-EOF
-if { (eval echo configure:1308: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- ac_cv_prog_lex_yytext_pointer=yes
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-rm -f "${LEX_OUTPUT_ROOT}.c"
-
-fi
-
-echo "$ac_t""$ac_cv_prog_lex_yytext_pointer" 1>&6
-if test $ac_cv_prog_lex_yytext_pointer = yes; then
- cat >> confdefs.h <<\EOF
-#define YYTEXT_POINTER 1
-EOF
-
-fi
-
-for ac_prog in 'bison -y' byacc
-do
-# Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1334: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- if test -n "$YACC"; then
- ac_cv_prog_YACC="$YACC" # Let the user override the test.
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_word; then
- ac_cv_prog_YACC="$ac_prog"
- break
- fi
- done
- IFS="$ac_save_ifs"
-fi
-fi
-YACC="$ac_cv_prog_YACC"
-if test -n "$YACC"; then
- echo "$ac_t""$YACC" 1>&6
-else
- echo "$ac_t""no" 1>&6
-fi
-
-test -n "$YACC" && break
-done
-test -n "$YACC" || YACC="yacc"
-
-# Find a good install program. We prefer a C program (faster),
-# so one script is as good as another. But avoid the broken or
-# incompatible versions:
-# SysV /etc/install, /usr/sbin/install
-# SunOS /usr/etc/install
-# IRIX /sbin/install
-# AIX /bin/install
-# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
-# AFS /usr/afsws/bin/install, which mishandles nonexistent args
-# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
-# ./install, which can be erroneously created by make from ./install.sh.
-echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:1376: checking for a BSD compatible install" >&5
-if test -z "$INSTALL"; then
-if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
- for ac_dir in $PATH; do
- # Account for people who put trailing slashes in PATH elements.
- case "$ac_dir/" in
- /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
- *)
- # OSF1 and SCO ODT 3.0 have their own names for install.
- # Don't use installbsd from OSF since it installs stuff as root
- # by default.
- for ac_prog in ginstall scoinst install; do
- if test -f $ac_dir/$ac_prog; then
- if test $ac_prog = install &&
- grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
- # AIX install. It has an incompatible calling convention.
- :
- else
- ac_cv_path_install="$ac_dir/$ac_prog -c"
- break 2
- fi
- fi
- done
- ;;
- esac
- done
- IFS="$ac_save_IFS"
-
-fi
- if test "${ac_cv_path_install+set}" = set; then
- INSTALL="$ac_cv_path_install"
- else
- # As a last resort, use the slow shell script. We don't cache a
- # path for INSTALL within a source directory, because that will
- # break other packages using the cache if that directory is
- # removed, or if the path is relative.
- INSTALL="$ac_install_sh"
- fi
-fi
-echo "$ac_t""$INSTALL" 1>&6
-
-# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
-# It thinks the first close brace ends the variable substitution.
-test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
-
-test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
-
-test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
-
-# Extract the first word of "ranlib", so it can be a program name with args.
-set dummy ranlib; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1431: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- if test -n "$RANLIB"; then
- ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_word; then
- ac_cv_prog_RANLIB="ranlib"
- break
- fi
- done
- IFS="$ac_save_ifs"
- test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
-fi
-fi
-RANLIB="$ac_cv_prog_RANLIB"
-if test -n "$RANLIB"; then
- echo "$ac_t""$RANLIB" 1>&6
-else
- echo "$ac_t""no" 1>&6
-fi
-
-echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
-echo "configure:1459: checking whether ${MAKE-make} sets \${MAKE}" >&5
-set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftestmake <<\EOF
-all:
- @echo 'ac_maketemp="${MAKE}"'
-EOF
-# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
-eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
-if test -n "$ac_maketemp"; then
- eval ac_cv_prog_make_${ac_make}_set=yes
-else
- eval ac_cv_prog_make_${ac_make}_set=no
-fi
-rm -f conftestmake
-fi
-if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- SET_MAKE=
-else
- echo "$ac_t""no" 1>&6
- SET_MAKE="MAKE=${MAKE-make}"
-fi
-
-
-for ac_hdr in stdarg.h stddef.h stdlib.h string.h limits.h unistd.h lib.h
-do
-ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1490: checking for $ac_hdr" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1495 "configure"
-#include "confdefs.h"
-#include <$ac_hdr>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1500: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_hdr 1
-EOF
-
-else
- echo "$ac_t""no" 1>&6
-fi
-done
-
-echo $ac_n "checking for working const""... $ac_c" 1>&6
-echo "configure:1527: checking for working const" >&5
-if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1532 "configure"
-#include "confdefs.h"
-
-int main() {
-
-/* Ultrix mips cc rejects this. */
-typedef int charset[2]; const charset x;
-/* SunOS 4.1.1 cc rejects this. */
-char const *const *ccp;
-char **p;
-/* NEC SVR4.0.2 mips cc rejects this. */
-struct point {int x, y;};
-static struct point const zero = {0,0};
-/* AIX XL C 1.02.0.0 rejects this.
- It does not let you subtract one const X* pointer from another in an arm
- of an if-expression whose if-part is not a constant expression */
-const char *g = "string";
-ccp = &g + (g ? g-g : 0);
-/* HPUX 7.0 cc rejects these. */
-++ccp;
-p = (char**) ccp;
-ccp = (char const *const *) p;
-{ /* SCO 3.2v4 cc rejects this. */
- char *t;
- char const *s = 0 ? (char *) 0 : (char const *) 0;
-
- *t++ = 0;
-}
-{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
- int x[] = {25, 17};
- const int *foo = &x[0];
- ++foo;
-}
-{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
- typedef const int *iptr;
- iptr p = 0;
- ++p;
-}
-{ /* AIX XL C 1.02.0.0 rejects this saying
- "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
- struct s { int j; const int *ap[3]; };
- struct s *b; b->j = 5;
-}
-{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
- const int foo = 10;
-}
-
-; return 0; }
-EOF
-if { (eval echo configure:1581: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
- rm -rf conftest*
- ac_cv_c_const=yes
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- ac_cv_c_const=no
-fi
-rm -f conftest*
-fi
-
-echo "$ac_t""$ac_cv_c_const" 1>&6
-if test $ac_cv_c_const = no; then
- cat >> confdefs.h <<\EOF
-#define const
-EOF
-
-fi
-
-echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:1602: checking for ANSI C header files" >&5
-if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1607 "configure"
-#include "confdefs.h"
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <float.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1615: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- ac_cv_header_stdc=yes
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-if test $ac_cv_header_stdc = yes; then
- # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
-cat > conftest.$ac_ext <<EOF
-#line 1632 "configure"
-#include "confdefs.h"
-#include <string.h>
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- egrep "memchr" >/dev/null 2>&1; then
- :
-else
- rm -rf conftest*
- ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
- # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
-cat > conftest.$ac_ext <<EOF
-#line 1650 "configure"
-#include "confdefs.h"
-#include <stdlib.h>
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- egrep "free" >/dev/null 2>&1; then
- :
-else
- rm -rf conftest*
- ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
- # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
-if test "$cross_compiling" = yes; then
- :
-else
- cat > conftest.$ac_ext <<EOF
-#line 1671 "configure"
-#include "confdefs.h"
-#include <ctype.h>
-#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int main () { int i; for (i = 0; i < 256; i++)
-if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
-exit (0); }
-
-EOF
-if { (eval echo configure:1682: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
-then
- :
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -fr conftest*
- ac_cv_header_stdc=no
-fi
-rm -fr conftest*
-fi
-
-fi
-fi
-
-echo "$ac_t""$ac_cv_header_stdc" 1>&6
-if test $ac_cv_header_stdc = yes; then
- cat >> confdefs.h <<\EOF
-#define STDC_HEADERS 1
-EOF
-
-fi
-
-echo $ac_n "checking for size_t""... $ac_c" 1>&6
-echo "configure:1706: checking for size_t" >&5
-if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1711 "configure"
-#include "confdefs.h"
-#include <sys/types.h>
-#if STDC_HEADERS
-#include <stdlib.h>
-#include <stddef.h>
-#endif
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
- rm -rf conftest*
- ac_cv_type_size_t=yes
-else
- rm -rf conftest*
- ac_cv_type_size_t=no
-fi
-rm -f conftest*
-
-fi
-echo "$ac_t""$ac_cv_type_size_t" 1>&6
-if test $ac_cv_type_size_t = no; then
- cat >> confdefs.h <<\EOF
-#define size_t unsigned
-EOF
-
-fi
-
-echo $ac_n "checking for ptrdiff_t""... $ac_c" 1>&6
-echo "configure:1739: checking for ptrdiff_t" >&5
-if eval "test \"`echo '$''{'ac_cv_type_ptrdiff_t'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1744 "configure"
-#include "confdefs.h"
-#include <sys/types.h>
-#if STDC_HEADERS
-#include <stdlib.h>
-#include <stddef.h>
-#endif
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- egrep "(^|[^a-zA-Z_0-9])ptrdiff_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
- rm -rf conftest*
- ac_cv_type_ptrdiff_t=yes
-else
- rm -rf conftest*
- ac_cv_type_ptrdiff_t=no
-fi
-rm -f conftest*
-
-fi
-echo "$ac_t""$ac_cv_type_ptrdiff_t" 1>&6
-if test $ac_cv_type_ptrdiff_t = no; then
- cat >> confdefs.h <<\EOF
-#define ptrdiff_t size_t
-EOF
-
-fi
-
-
-echo $ac_n "checking for vprintf""... $ac_c" 1>&6
-echo "configure:1773: checking for vprintf" >&5
-if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1778 "configure"
-#include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char vprintf(); below. */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char vprintf();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
- to always fail with ENOSYS. Some functions are actually named
- something starting with __ and the normal name is an alias. */
-#if defined (__stub_vprintf) || defined (__stub___vprintf)
-choke me
-#else
-vprintf();
-#endif
-
-; return 0; }
-EOF
-if { (eval echo configure:1801: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_func_vprintf=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_func_vprintf=no"
-fi
-rm -f conftest*
-fi
-
-if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- cat >> confdefs.h <<\EOF
-#define HAVE_VPRINTF 1
-EOF
-
-else
- echo "$ac_t""no" 1>&6
-fi
-
-if test "$ac_cv_func_vprintf" != yes; then
-echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
-echo "configure:1825: checking for _doprnt" >&5
-if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1830 "configure"
-#include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char _doprnt(); below. */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char _doprnt();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
- to always fail with ENOSYS. Some functions are actually named
- something starting with __ and the normal name is an alias. */
-#if defined (__stub__doprnt) || defined (__stub____doprnt)
-choke me
-#else
-_doprnt();
-#endif
-
-; return 0; }
-EOF
-if { (eval echo configure:1853: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_func__doprnt=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_func__doprnt=no"
-fi
-rm -f conftest*
-fi
-
-if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- cat >> confdefs.h <<\EOF
-#define HAVE_DOPRNT 1
-EOF
-
-else
- echo "$ac_t""no" 1>&6
-fi
-
-fi
-
-for ac_func in isgraph setvbuf
-do
-echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1880: checking for $ac_func" >&5
-if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1885 "configure"
-#include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char $ac_func(); below. */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char $ac_func();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
- to always fail with ENOSYS. Some functions are actually named
- something starting with __ and the normal name is an alias. */
-#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
-choke me
-#else
-$ac_func();
-#endif
-
-; return 0; }
-EOF
-if { (eval echo configure:1908: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_func_$ac_func=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_func_$ac_func=no"
-fi
-rm -f conftest*
-fi
-
-if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_func 1
-EOF
-
-else
- echo "$ac_t""no" 1>&6
-fi
-done
-
-
-# Check whether --with-pkg or --without-pkg was given.
-if test "${with_pkg+set}" = set; then
- withval="$with_pkg"
-
- CPPFLAGS="$CPPFLAGS -I/usr/pkg/include"
- LDFLAGS="$LDFLAGS -L/usr/pkg/lib"
- echo Using /usr/pkg/include and /usr/pkg/lib
-
-fi
-
-
-bcle=n
-# Check whether --with-libedit or --without-libedit was given.
-if test "${with_libedit+set}" = set; then
- withval="$with_libedit"
-
- echo $ac_n "checking for tgetent in -ltermcap""... $ac_c" 1>&6
-echo "configure:1950: checking for tgetent in -ltermcap" >&5
-ac_lib_var=`echo termcap'_'tgetent | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- ac_save_LIBS="$LIBS"
-LIBS="-ltermcap $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1958 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char tgetent();
-
-int main() {
-tgetent()
-; return 0; }
-EOF
-if { (eval echo configure:1969: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- TERMLIB=-ltermcap
-else
- echo "$ac_t""no" 1>&6
-fi
-
- LDSAVE=$LDFLAGS
- LDFLAGS="$LDFLAGS $TERMLIB"
- echo $ac_n "checking for el_gets in -ledit""... $ac_c" 1>&6
-echo "configure:1992: checking for el_gets in -ledit" >&5
-ac_lib_var=`echo edit'_'el_gets | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- ac_save_LIBS="$LIBS"
-LIBS="-ledit $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2000 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char el_gets();
-
-int main() {
-el_gets()
-; return 0; }
-EOF
-if { (eval echo configure:2011: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_safe=`echo "histedit.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for histedit.h""... $ac_c" 1>&6
-echo "configure:2028: checking for histedit.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 2033 "configure"
-#include "confdefs.h"
-#include <histedit.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2038: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- READLINELIB="-ledit $TERMLIB";bcle=y
-else
- echo "$ac_t""no" 1>&6
-fi
-
-else
- echo "$ac_t""no" 1>&6
-READLINELIB=""
-fi
-
- if test "$bcle" = "y"; then
- echo Using the libedit library.
- cat >> confdefs.h <<\EOF
-#define LIBEDIT 1
-EOF
-
- fi
- LDFLAGS=$LDSAVE
-
-fi
-
-
-bcrl=n
-# Check whether --with-readline or --without-readline was given.
-if test "${with_readline+set}" = set; then
- withval="$with_readline"
-
- echo $ac_n "checking for tparm in -lncurses""... $ac_c" 1>&6
-echo "configure:2082: checking for tparm in -lncurses" >&5
-ac_lib_var=`echo ncurses'_'tparm | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- ac_save_LIBS="$LIBS"
-LIBS="-lncurses $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2090 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char tparm();
-
-int main() {
-tparm()
-; return 0; }
-EOF
-if { (eval echo configure:2101: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- TERMLIB=-lncurses
-else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for tgetent in -ltermcap""... $ac_c" 1>&6
-echo "configure:2120: checking for tgetent in -ltermcap" >&5
-ac_lib_var=`echo termcap'_'tgetent | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- ac_save_LIBS="$LIBS"
-LIBS="-ltermcap $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2128 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char tgetent();
-
-int main() {
-tgetent()
-; return 0; }
-EOF
-if { (eval echo configure:2139: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- TERMLIB=-ltermcap
-else
- echo "$ac_t""no" 1>&6
-fi
-
-fi
-
- LDSAVE=$LDFLAGS
- LDFLAGS="$LDFLAGS $TERMLIB"
- echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6
-echo "configure:2164: checking for readline in -lreadline" >&5
-ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- ac_save_LIBS="$LIBS"
-LIBS="-lreadline $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2172 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char readline();
-
-int main() {
-readline()
-; return 0; }
-EOF
-if { (eval echo configure:2183: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_safe=`echo "readline/readline.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for readline/readline.h""... $ac_c" 1>&6
-echo "configure:2200: checking for readline/readline.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 2205 "configure"
-#include "confdefs.h"
-#include <readline/readline.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2210: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- READLINELIB="-lreadline $TERMLIB";bcrl=y
-else
- echo "$ac_t""no" 1>&6
-fi
-
-else
- echo "$ac_t""no" 1>&6
-READLINELIB=""
-fi
-
- if test "$bcrl" = "y" ; then
- echo Using the readline library.
- cat >> confdefs.h <<\EOF
-#define READLINE 1
-EOF
-
- fi
- LDFLAGS=$LDSAVE
-
-fi
-
-
-if test "$LEX" = "flex" ; then
- LEX="flex -I8"
-else
- if test "$bcrl" = "y" ; then
- echo "configure: warning: readline works only with flex." 1>&2
- fi
-fi
-
-if test "$bcrl" = "y" -a "$bcle" = "y" ; then
- { echo "configure: error: Can not use both readline and libedit. Aborting." 1>&2; exit 1; }
-fi
-
-if test "$LEX" = "lex" -a `uname -s` = "SunOS" ; then
- LEXLIB=""
- echo "SunOS using lex does not have a -ll."
-fi
-
-
-if test "$program_transform_name" = s,x,x,; then
- program_transform_name=
-else
- # Double any \ or $. echo might interpret backslashes.
- cat <<\EOF_SED > conftestsed
-s,\\,\\\\,g; s,\$,$$,g
-EOF_SED
- program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
- rm -f conftestsed
-fi
-test "$program_prefix" != NONE &&
- program_transform_name="s,^,${program_prefix},; $program_transform_name"
-# Use a double $ so make ignores it.
-test "$program_suffix" != NONE &&
- program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
-
-# sed with no file args requires a program.
-test "$program_transform_name" = "" && program_transform_name="s,x,x,"
-
-trap '' 1 2 15
-cat > confcache <<\EOF
-# This file is a shell script that caches the results of configure
-# tests run on this system so they can be shared between configure
-# scripts and configure runs. It is not useful on other systems.
-# If it contains results you don't want to keep, you may remove or edit it.
-#
-# By default, configure uses ./config.cache as the cache file,
-# creating it if it does not exist already. You can give configure
-# the --cache-file=FILE option to use a different cache file; that is
-# what configure does when it calls configure scripts in
-# subdirectories, so they share the cache.
-# Giving --cache-file=/dev/null disables caching, for debugging configure.
-# config.status only pays attention to the cache file if you give it the
-# --recheck option to rerun configure.
-#
-EOF
-# The following way of writing the cache mishandles newlines in values,
-# but we know of no workaround that is simple, portable, and efficient.
-# So, don't put newlines in cache variables' values.
-# Ultrix sh set writes to stderr and can't be redirected directly,
-# and sets the high bit in the cache file unless we assign to the vars.
-(set) 2>&1 |
- case `(ac_space=' '; set | grep ac_space) 2>&1` in
- *ac_space=\ *)
- # `set' does not quote correctly, so add quotes (double-quote substitution
- # turns \\\\ into \\, and sed turns \\ into \).
- sed -n \
- -e "s/'/'\\\\''/g" \
- -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
- ;;
- *)
- # `set' quotes correctly as required by POSIX, so do not add quotes.
- sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
- ;;
- esac >> confcache
-if cmp -s $cache_file confcache; then
- :
-else
- if test -w $cache_file; then
- echo "updating cache $cache_file"
- cat confcache > $cache_file
- else
- echo "not updating unwritable cache $cache_file"
- fi
-fi
-rm -f confcache
-
-trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
-
-test "x$prefix" = xNONE && prefix=$ac_default_prefix
-# Let make expand exec_prefix.
-test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
-
-# Any assignment to VPATH causes Sun make to only execute
-# the first set of double-colon rules, so remove it if not needed.
-# If there is a colon in the path, we need to keep it.
-if test "x$srcdir" = x.; then
- ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
-fi
-
-trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
-
-DEFS=-DHAVE_CONFIG_H
-
-# Without the "./", some shells look in PATH for config.status.
-: ${CONFIG_STATUS=./config.status}
-
-echo creating $CONFIG_STATUS
-rm -f $CONFIG_STATUS
-cat > $CONFIG_STATUS <<EOF
-#! /bin/sh
-# Generated automatically by configure.
-# Run this file to recreate the current configuration.
-# This directory was configured as follows,
-# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
-#
-# $0 $ac_configure_args
-#
-# Compiler output produced by configure, useful for debugging
-# configure, is in ./config.log if it exists.
-
-ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
-for ac_option
-do
- case "\$ac_option" in
- -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
- echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
- exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
- -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
- echo "$CONFIG_STATUS generated by autoconf version 2.13"
- exit 0 ;;
- -help | --help | --hel | --he | --h)
- echo "\$ac_cs_usage"; exit 0 ;;
- *) echo "\$ac_cs_usage"; exit 1 ;;
- esac
-done
-
-ac_given_srcdir=$srcdir
-ac_given_INSTALL="$INSTALL"
-
-trap 'rm -fr `echo "Makefile bc/Makefile dc/Makefile doc/Makefile lib/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
-EOF
-cat >> $CONFIG_STATUS <<EOF
-
-# Protect against being on the right side of a sed subst in config.status.
-sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
- s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
-$ac_vpsub
-$extrasub
-s%@SHELL@%$SHELL%g
-s%@CFLAGS@%$CFLAGS%g
-s%@CPPFLAGS@%$CPPFLAGS%g
-s%@CXXFLAGS@%$CXXFLAGS%g
-s%@FFLAGS@%$FFLAGS%g
-s%@DEFS@%$DEFS%g
-s%@LDFLAGS@%$LDFLAGS%g
-s%@LIBS@%$LIBS%g
-s%@exec_prefix@%$exec_prefix%g
-s%@prefix@%$prefix%g
-s%@program_transform_name@%$program_transform_name%g
-s%@bindir@%$bindir%g
-s%@sbindir@%$sbindir%g
-s%@libexecdir@%$libexecdir%g
-s%@datadir@%$datadir%g
-s%@sysconfdir@%$sysconfdir%g
-s%@sharedstatedir@%$sharedstatedir%g
-s%@localstatedir@%$localstatedir%g
-s%@libdir@%$libdir%g
-s%@includedir@%$includedir%g
-s%@oldincludedir@%$oldincludedir%g
-s%@infodir@%$infodir%g
-s%@mandir@%$mandir%g
-s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
-s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
-s%@INSTALL_DATA@%$INSTALL_DATA%g
-s%@PACKAGE@%$PACKAGE%g
-s%@VERSION@%$VERSION%g
-s%@ACLOCAL@%$ACLOCAL%g
-s%@AUTOCONF@%$AUTOCONF%g
-s%@AUTOMAKE@%$AUTOMAKE%g
-s%@AUTOHEADER@%$AUTOHEADER%g
-s%@MAKEINFO@%$MAKEINFO%g
-s%@SET_MAKE@%$SET_MAKE%g
-s%@CC@%$CC%g
-s%@CPP@%$CPP%g
-s%@LEX@%$LEX%g
-s%@LEXLIB@%$LEXLIB%g
-s%@LEX_OUTPUT_ROOT@%$LEX_OUTPUT_ROOT%g
-s%@YACC@%$YACC%g
-s%@RANLIB@%$RANLIB%g
-s%@READLINELIB@%$READLINELIB%g
-
-CEOF
-EOF
-
-cat >> $CONFIG_STATUS <<\EOF
-
-# Split the substitutions into bite-sized pieces for seds with
-# small command number limits, like on Digital OSF/1 and HP-UX.
-ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
-ac_file=1 # Number of current file.
-ac_beg=1 # First line for current file.
-ac_end=$ac_max_sed_cmds # Line after last line for current file.
-ac_more_lines=:
-ac_sed_cmds=""
-while $ac_more_lines; do
- if test $ac_beg -gt 1; then
- sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
- else
- sed "${ac_end}q" conftest.subs > conftest.s$ac_file
- fi
- if test ! -s conftest.s$ac_file; then
- ac_more_lines=false
- rm -f conftest.s$ac_file
- else
- if test -z "$ac_sed_cmds"; then
- ac_sed_cmds="sed -f conftest.s$ac_file"
- else
- ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
- fi
- ac_file=`expr $ac_file + 1`
- ac_beg=$ac_end
- ac_end=`expr $ac_end + $ac_max_sed_cmds`
- fi
-done
-if test -z "$ac_sed_cmds"; then
- ac_sed_cmds=cat
-fi
-EOF
-
-cat >> $CONFIG_STATUS <<EOF
-
-CONFIG_FILES=\${CONFIG_FILES-"Makefile bc/Makefile dc/Makefile doc/Makefile lib/Makefile"}
-EOF
-cat >> $CONFIG_STATUS <<\EOF
-for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
- # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
- case "$ac_file" in
- *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
- ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
- *) ac_file_in="${ac_file}.in" ;;
- esac
-
- # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
-
- # Remove last slash and all that follows it. Not all systems have dirname.
- ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
- if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
- # The file is in a subdirectory.
- test ! -d "$ac_dir" && mkdir "$ac_dir"
- ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
- # A "../" for each directory in $ac_dir_suffix.
- ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
- else
- ac_dir_suffix= ac_dots=
- fi
-
- case "$ac_given_srcdir" in
- .) srcdir=.
- if test -z "$ac_dots"; then top_srcdir=.
- else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
- /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
- *) # Relative path.
- srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
- top_srcdir="$ac_dots$ac_given_srcdir" ;;
- esac
-
- case "$ac_given_INSTALL" in
- [/$]*) INSTALL="$ac_given_INSTALL" ;;
- *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
- esac
-
- echo creating "$ac_file"
- rm -f "$ac_file"
- configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
- case "$ac_file" in
- *Makefile*) ac_comsub="1i\\
-# $configure_input" ;;
- *) ac_comsub= ;;
- esac
-
- ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
- sed -e "$ac_comsub
-s%@configure_input@%$configure_input%g
-s%@srcdir@%$srcdir%g
-s%@top_srcdir@%$top_srcdir%g
-s%@INSTALL@%$INSTALL%g
-" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
-fi; done
-rm -f conftest.s*
-
-# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
-# NAME is the cpp macro being defined and VALUE is the value it is being given.
-#
-# ac_d sets the value in "#define NAME VALUE" lines.
-ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
-ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
-ac_dC='\3'
-ac_dD='%g'
-# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
-ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
-ac_uB='\([ ]\)%\1#\2define\3'
-ac_uC=' '
-ac_uD='\4%g'
-# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
-ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
-ac_eB='$%\1#\2define\3'
-ac_eC=' '
-ac_eD='%g'
-
-if test "${CONFIG_HEADERS+set}" != set; then
-EOF
-cat >> $CONFIG_STATUS <<EOF
- CONFIG_HEADERS="config.h"
-EOF
-cat >> $CONFIG_STATUS <<\EOF
-fi
-for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
- # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
- case "$ac_file" in
- *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
- ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
- *) ac_file_in="${ac_file}.in" ;;
- esac
-
- echo creating $ac_file
-
- rm -f conftest.frag conftest.in conftest.out
- ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
- cat $ac_file_inputs > conftest.in
-
-EOF
-
-# Transform confdefs.h into a sed script conftest.vals that substitutes
-# the proper values into config.h.in to produce config.h. And first:
-# Protect against being on the right side of a sed subst in config.status.
-# Protect against being in an unquoted here document in config.status.
-rm -f conftest.vals
-cat > conftest.hdr <<\EOF
-s/[\\&%]/\\&/g
-s%[\\$`]%\\&%g
-s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
-s%ac_d%ac_u%gp
-s%ac_u%ac_e%gp
-EOF
-sed -n -f conftest.hdr confdefs.h > conftest.vals
-rm -f conftest.hdr
-
-# This sed command replaces #undef with comments. This is necessary, for
-# example, in the case of _POSIX_SOURCE, which is predefined and required
-# on some systems where configure will not decide to define it.
-cat >> conftest.vals <<\EOF
-s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
-EOF
-
-# Break up conftest.vals because some shells have a limit on
-# the size of here documents, and old seds have small limits too.
-
-rm -f conftest.tail
-while :
-do
- ac_lines=`grep -c . conftest.vals`
- # grep -c gives empty output for an empty file on some AIX systems.
- if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
- # Write a limited-size here document to conftest.frag.
- echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
- sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
- echo 'CEOF
- sed -f conftest.frag conftest.in > conftest.out
- rm -f conftest.in
- mv conftest.out conftest.in
-' >> $CONFIG_STATUS
- sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
- rm -f conftest.vals
- mv conftest.tail conftest.vals
-done
-rm -f conftest.vals
-
-cat >> $CONFIG_STATUS <<\EOF
- rm -f conftest.frag conftest.h
- echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
- cat conftest.in >> conftest.h
- rm -f conftest.in
- if cmp -s $ac_file conftest.h 2>/dev/null; then
- echo "$ac_file is unchanged"
- rm -f conftest.h
- else
- # Remove last slash and all that follows it. Not all systems have dirname.
- ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
- if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
- # The file is in a subdirectory.
- test ! -d "$ac_dir" && mkdir "$ac_dir"
- fi
- rm -f $ac_file
- mv conftest.h $ac_file
- fi
-fi; done
-
-EOF
-cat >> $CONFIG_STATUS <<EOF
-
-
-EOF
-cat >> $CONFIG_STATUS <<\EOF
-test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
-
-exit 0
-EOF
-chmod +x $CONFIG_STATUS
-rm -fr confdefs* $ac_clean_files
-test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
-
diff --git a/contrib/bc/configure.in b/contrib/bc/configure.in
deleted file mode 100644
index 5f982d3..0000000
--- a/contrib/bc/configure.in
+++ /dev/null
@@ -1,89 +0,0 @@
-dnl Process this file with autoconf to produce a configure script.
-AC_INIT(doc/bc.1)
-AM_INIT_AUTOMAKE("bc", "1.06")
-AM_CONFIG_HEADER(config.h)
-
-AC_DEFINE(DC_VERSION,"1.3")
-AC_DEFINE_UNQUOTED(BC_COPYRIGHT, dnl
- ["Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc."])
-AC_DEFINE_UNQUOTED(DC_COPYRIGHT, dnl
- ["Copyright 1994, 1997, 1998, 2000 Free Software Foundation, Inc."])
-
-AC_PROG_CC
-AC_MINIX
-dnl AC_ISC_POSIX
-
-AM_PROG_LEX
-AC_PROG_YACC
-AC_PROG_INSTALL
-AC_PROG_RANLIB
-AC_PROG_MAKE_SET
-
-AC_CHECK_HEADERS(stdarg.h stddef.h stdlib.h string.h limits.h unistd.h lib.h)
-AC_C_CONST
-AC_TYPE_SIZE_T
-AC_CHECK_TYPE(ptrdiff_t, size_t)
-
-AC_FUNC_VPRINTF
-AC_CHECK_FUNCS(isgraph setvbuf)
-
-AC_ARG_WITH(pkg,[ --with-pkg use software installed in /usr/pkg tree], [
- CPPFLAGS="$CPPFLAGS -I/usr/pkg/include"
- LDFLAGS="$LDFLAGS -L/usr/pkg/lib"
- echo Using /usr/pkg/include and /usr/pkg/lib
-])
-
-bcle=n
-AC_ARG_WITH(libedit,[ --with-libedit support fancy BSD command input
-editing], [
- AC_CHECK_LIB(termcap,tgetent,TERMLIB=-ltermcap)
- LDSAVE=$LDFLAGS
- LDFLAGS="$LDFLAGS $TERMLIB"
- AC_CHECK_LIB(edit,el_gets,
- [AC_CHECK_HEADER(histedit.h,
- READLINELIB="-ledit $TERMLIB";bcle=y)],
- READLINELIB="")
- if test "$bcle" = "y"; then
- echo Using the libedit library.
- AC_DEFINE(LIBEDIT,1)
- fi
- LDFLAGS=$LDSAVE
-])
-
-bcrl=n
-AC_ARG_WITH(readline,[ --with-readline support fancy command input editing], [
- AC_CHECK_LIB(ncurses,tparm,TERMLIB=-lncurses,
- AC_CHECK_LIB(termcap,tgetent,TERMLIB=-ltermcap))
- LDSAVE=$LDFLAGS
- LDFLAGS="$LDFLAGS $TERMLIB"
- AC_CHECK_LIB(readline,readline,
- [AC_CHECK_HEADER(readline/readline.h,
- READLINELIB="-lreadline $TERMLIB";bcrl=y)],
- READLINELIB="")
- if test "$bcrl" = "y" ; then
- echo Using the readline library.
- AC_DEFINE(READLINE,1)
- fi
- LDFLAGS=$LDSAVE
-])
-
-if test "$LEX" = "flex" ; then
- LEX="flex -I8"
-else
- if test "$bcrl" = "y" ; then
- AC_MSG_WARN(readline works only with flex.)
- fi
-fi
-
-if test "$bcrl" = "y" -a "$bcle" = "y" ; then
- AC_MSG_ERROR(Can not use both readline and libedit. Aborting.)
-fi
-
-if test "$LEX" = "lex" -a `uname -s` = "SunOS" ; then
- LEXLIB=""
- echo "SunOS using lex does not have a -ll."
-fi
-
-AC_SUBST(READLINELIB)
-AC_ARG_PROGRAM
-AC_OUTPUT(Makefile bc/Makefile dc/Makefile doc/Makefile lib/Makefile)
diff --git a/contrib/bc/dc/Makefile.am b/contrib/bc/dc/Makefile.am
deleted file mode 100644
index 99164ba..0000000
--- a/contrib/bc/dc/Makefile.am
+++ /dev/null
@@ -1,14 +0,0 @@
-## Process this file with automake to produce Makefile.in
-bin_PROGRAMS = dc
-
-dc_SOURCES = dc.c misc.c eval.c stack.c array.c numeric.c string.c
-noinst_HEADERS = dc.h dc-proto.h dc-regdef.h
-
-INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../h
-LDADD = ../lib/libbc.a
-
-MAINTAINERCLEANFILES = Makefile.in
-
-CFLAGS = @CFLAGS@ -Wall -funsigned-char
-
-$(PROGRAMS): $(LDADD)
diff --git a/contrib/bc/dc/Makefile.in b/contrib/bc/dc/Makefile.in
deleted file mode 100644
index 0772dd6..0000000
--- a/contrib/bc/dc/Makefile.in
+++ /dev/null
@@ -1,296 +0,0 @@
-# Makefile.in generated automatically by automake 1.4 from Makefile.am
-
-# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-
-SHELL = @SHELL@
-
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
-VPATH = @srcdir@
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-
-bindir = @bindir@
-sbindir = @sbindir@
-libexecdir = @libexecdir@
-datadir = @datadir@
-sysconfdir = @sysconfdir@
-sharedstatedir = @sharedstatedir@
-localstatedir = @localstatedir@
-libdir = @libdir@
-infodir = @infodir@
-mandir = @mandir@
-includedir = @includedir@
-oldincludedir = /usr/include
-
-DESTDIR =
-
-pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-
-top_builddir = ..
-
-ACLOCAL = @ACLOCAL@
-AUTOCONF = @AUTOCONF@
-AUTOMAKE = @AUTOMAKE@
-AUTOHEADER = @AUTOHEADER@
-
-INSTALL = @INSTALL@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-transform = @program_transform_name@
-
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-CC = @CC@
-LEX = @LEX@
-MAKEINFO = @MAKEINFO@
-PACKAGE = @PACKAGE@
-RANLIB = @RANLIB@
-READLINELIB = @READLINELIB@
-VERSION = @VERSION@
-YACC = @YACC@
-
-bin_PROGRAMS = dc
-
-dc_SOURCES = dc.c misc.c eval.c stack.c array.c numeric.c string.c
-noinst_HEADERS = dc.h dc-proto.h dc-regdef.h
-
-INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../h
-LDADD = ../lib/libbc.a
-
-MAINTAINERCLEANFILES = Makefile.in
-
-CFLAGS = @CFLAGS@ -Wall -funsigned-char
-mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
-CONFIG_HEADER = ../config.h
-CONFIG_CLEAN_FILES =
-PROGRAMS = $(bin_PROGRAMS)
-
-
-DEFS = @DEFS@ -I. -I$(srcdir) -I..
-CPPFLAGS = @CPPFLAGS@
-LDFLAGS = @LDFLAGS@
-LIBS = @LIBS@
-dc_OBJECTS = dc.o misc.o eval.o stack.o array.o numeric.o string.o
-dc_LDADD = $(LDADD)
-dc_DEPENDENCIES = ../lib/libbc.a
-dc_LDFLAGS =
-COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-CCLD = $(CC)
-LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
-HEADERS = $(noinst_HEADERS)
-
-DIST_COMMON = Makefile.am Makefile.in
-
-
-DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-
-TAR = tar
-GZIP_ENV = --best
-SOURCES = $(dc_SOURCES)
-OBJECTS = $(dc_OBJECTS)
-
-all: all-redirect
-.SUFFIXES:
-.SUFFIXES: .S .c .o .s
-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
- cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps dc/Makefile
-
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
- cd $(top_builddir) \
- && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
-
-
-mostlyclean-binPROGRAMS:
-
-clean-binPROGRAMS:
- -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
-
-distclean-binPROGRAMS:
-
-maintainer-clean-binPROGRAMS:
-
-install-binPROGRAMS: $(bin_PROGRAMS)
- @$(NORMAL_INSTALL)
- $(mkinstalldirs) $(DESTDIR)$(bindir)
- @list='$(bin_PROGRAMS)'; for p in $$list; do \
- if test -f $$p; then \
- echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
- $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
- else :; fi; \
- done
-
-uninstall-binPROGRAMS:
- @$(NORMAL_UNINSTALL)
- list='$(bin_PROGRAMS)'; for p in $$list; do \
- rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
- done
-
-.c.o:
- $(COMPILE) -c $<
-
-.s.o:
- $(COMPILE) -c $<
-
-.S.o:
- $(COMPILE) -c $<
-
-mostlyclean-compile:
- -rm -f *.o core *.core
-
-clean-compile:
-
-distclean-compile:
- -rm -f *.tab.c
-
-maintainer-clean-compile:
-
-dc: $(dc_OBJECTS) $(dc_DEPENDENCIES)
- @rm -f dc
- $(LINK) $(dc_LDFLAGS) $(dc_OBJECTS) $(dc_LDADD) $(LIBS)
-
-tags: TAGS
-
-ID: $(HEADERS) $(SOURCES) $(LISP)
- list='$(SOURCES) $(HEADERS)'; \
- unique=`for i in $$list; do echo $$i; done | \
- awk ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
- here=`pwd` && cd $(srcdir) \
- && mkid -f$$here/ID $$unique $(LISP)
-
-TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
- tags=; \
- here=`pwd`; \
- list='$(SOURCES) $(HEADERS)'; \
- unique=`for i in $$list; do echo $$i; done | \
- awk ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
- test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
- || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
-
-mostlyclean-tags:
-
-clean-tags:
-
-distclean-tags:
- -rm -f TAGS ID
-
-maintainer-clean-tags:
-
-distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
-
-subdir = dc
-
-distdir: $(DISTFILES)
- @for file in $(DISTFILES); do \
- d=$(srcdir); \
- if test -d $$d/$$file; then \
- cp -pr $$/$$file $(distdir)/$$file; \
- else \
- test -f $(distdir)/$$file \
- || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
- || cp -p $$d/$$file $(distdir)/$$file || :; \
- fi; \
- done
-array.o: array.c ../config.h dc.h dc-proto.h dc-regdef.h
-dc.o: dc.c ../config.h ../h/getopt.h dc.h dc-proto.h
-eval.o: eval.c ../config.h dc.h dc-proto.h
-misc.o: misc.c ../config.h ../h/getopt.h dc.h dc-proto.h
-numeric.o: numeric.c ../config.h ../h/number.h dc.h dc-proto.h
-stack.o: stack.c ../config.h dc.h dc-proto.h dc-regdef.h
-string.o: string.c ../config.h dc.h dc-proto.h
-
-info-am:
-info: info-am
-dvi-am:
-dvi: dvi-am
-check-am: all-am
-check: check-am
-installcheck-am:
-installcheck: installcheck-am
-install-exec-am: install-binPROGRAMS
-install-exec: install-exec-am
-
-install-data-am:
-install-data: install-data-am
-
-install-am: all-am
- @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-install: install-am
-uninstall-am: uninstall-binPROGRAMS
-uninstall: uninstall-am
-all-am: Makefile $(PROGRAMS) $(HEADERS)
-all-redirect: all-am
-install-strip:
- $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
-installdirs:
- $(mkinstalldirs) $(DESTDIR)$(bindir)
-
-
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
- -rm -f Makefile $(CONFIG_CLEAN_FILES)
- -rm -f config.cache config.log stamp-h stamp-h[0-9]*
-
-maintainer-clean-generic:
- -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
-mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \
- mostlyclean-tags mostlyclean-generic
-
-mostlyclean: mostlyclean-am
-
-clean-am: clean-binPROGRAMS clean-compile clean-tags clean-generic \
- mostlyclean-am
-
-clean: clean-am
-
-distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \
- distclean-generic clean-am
-
-distclean: distclean-am
-
-maintainer-clean-am: maintainer-clean-binPROGRAMS \
- maintainer-clean-compile maintainer-clean-tags \
- maintainer-clean-generic distclean-am
- @echo "This command is intended for maintainers to use;"
- @echo "it deletes files that may require special tools to rebuild."
-
-maintainer-clean: maintainer-clean-am
-
-.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
-maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
-mostlyclean-compile distclean-compile clean-compile \
-maintainer-clean-compile tags mostlyclean-tags distclean-tags \
-clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
-check-am installcheck-am installcheck install-exec-am install-exec \
-install-data-am install-data install-am install uninstall-am uninstall \
-all-redirect all-am all installdirs mostlyclean-generic \
-distclean-generic clean-generic maintainer-clean-generic clean \
-mostlyclean distclean maintainer-clean
-
-
-$(PROGRAMS): $(LDADD)
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/contrib/bc/dc/array.c b/contrib/bc/dc/array.c
deleted file mode 100644
index d97f716..0000000
--- a/contrib/bc/dc/array.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * implement arrays for dc
- *
- * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you can either send email to this
- * program's author (see below) or write to:
- *
- * The Free Software Foundation, Inc.
- * 59 Temple Place, Suite 330
- * Boston, MA 02111 USA
- */
-
-/* This module is the only one that knows what arrays look like. */
-
-#include "config.h"
-
-#include <stdio.h> /* "dc-proto.h" wants this */
-#ifdef HAVE_STDLIB_H
-/* get size_t definition from "almost ANSI" compiling environments. */
-#include <stdlib.h>
-#endif
-#include "dc.h"
-#include "dc-proto.h"
-#include "dc-regdef.h"
-
-/* what's most useful: quick access or sparse arrays? */
-/* I'll go with sparse arrays for now */
-struct dc_array {
- int Index;
- dc_data value;
- struct dc_array *next;
-};
-
-
-/* initialize the arrays */
-void
-dc_array_init DC_DECLVOID()
-{
-}
-
-/* store value into array_id[Index] */
-void
-dc_array_set DC_DECLARG((array_id, Index, value))
- int array_id DC_DECLSEP
- int Index DC_DECLSEP
- dc_data value DC_DECLEND
-{
- struct dc_array *cur;
- struct dc_array *prev=NULL;
- struct dc_array *newentry;
-
- cur = dc_get_stacked_array(array_id);
- while (cur && cur->Index < Index){
- prev = cur;
- cur = cur->next;
- }
- if (cur && cur->Index == Index){
- if (cur->value.dc_type == DC_NUMBER)
- dc_free_num(&cur->value.v.number);
- else if (cur->value.dc_type == DC_STRING)
- dc_free_str(&cur->value.v.string);
- else
- dc_garbage(" in array", array_id);
- cur->value = value;
- }else{
- newentry = dc_malloc(sizeof *newentry);
- newentry->Index = Index;
- newentry->value = value;
- newentry->next = cur;
- if (prev)
- prev->next = newentry;
- else
- dc_set_stacked_array(array_id, newentry);
- }
-}
-
-/* retrieve a dup of a value from array_id[Index] */
-/* A zero value is returned if the specified value is unintialized. */
-dc_data
-dc_array_get DC_DECLARG((array_id, Index))
- int array_id DC_DECLSEP
- int Index DC_DECLEND
-{
- struct dc_array *cur;
-
- for (cur=dc_get_stacked_array(array_id); cur; cur=cur->next)
- if (cur->Index == Index)
- return dc_dup(cur->value);
- return dc_int2data(0);
-}
-
-/* free an array chain */
-void
-dc_array_free DC_DECLARG((a_head))
- struct dc_array *a_head DC_DECLEND
-{
- struct dc_array *cur;
- struct dc_array *next;
-
- for (cur=a_head; cur; cur=next) {
- next = cur->next;
- if (cur->value.dc_type == DC_NUMBER)
- dc_free_num(&cur->value.v.number);
- else if (cur->value.dc_type == DC_STRING)
- dc_free_str(&cur->value.v.string);
- else
- dc_garbage("in stack", -1);
- free(cur);
- }
-}
diff --git a/contrib/bc/dc/dc-proto.h b/contrib/bc/dc/dc-proto.h
deleted file mode 100644
index f0ac28b..0000000
--- a/contrib/bc/dc/dc-proto.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * prototypes of all externally visible dc functions
- *
- * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you can either send email to this
- * program's author (see below) or write to:
- *
- * The Free Software Foundation, Inc.
- * 59 Temple Place, Suite 330
- * Boston, MA 02111 USA
- */
-
-extern const char *dc_str2charp DC_PROTO((dc_str));
-extern const char *dc_system DC_PROTO((const char *));
-extern void *dc_malloc DC_PROTO((size_t));
-extern struct dc_array *dc_get_stacked_array DC_PROTO((int));
-
-extern void dc_array_set DC_PROTO((int, int, dc_data));
-extern void dc_array_free DC_PROTO((struct dc_array *));
-extern void dc_array_init DC_PROTO((void));
-extern void dc_binop DC_PROTO((int (*)(dc_num, dc_num, int, dc_num *), int));
-extern void dc_binop2 DC_PROTO((int (*)(dc_num, dc_num, int,
- dc_num *, dc_num *), int));
-extern void dc_triop DC_PROTO((int (*)(dc_num, dc_num, dc_num, int,
- dc_num *), int));
-extern void dc_clear_stack DC_PROTO((void));
-extern void dc_dump_num(dc_num, dc_discard);
-extern void dc_free_num DC_PROTO((dc_num *));
-extern void dc_free_str DC_PROTO((dc_str *));
-extern void dc_garbage DC_PROTO((const char *, int));
-extern void dc_math_init DC_PROTO((void));
-extern void dc_memfail DC_PROTO((void));
-extern void dc_out_num DC_PROTO((dc_num, int, dc_newline, dc_discard));
-extern void dc_out_str DC_PROTO((dc_str, dc_newline, dc_discard));
-extern void dc_print DC_PROTO((dc_data, int, dc_newline, dc_discard));
-extern void dc_printall DC_PROTO((int));
-extern void dc_push DC_PROTO((dc_data));
-extern void dc_register_init DC_PROTO((void));
-extern void dc_register_push DC_PROTO((int, dc_data));
-extern void dc_register_set DC_PROTO((int, dc_data));
-extern void dc_set_stacked_array DC_PROTO((int, struct dc_array *));
-extern void dc_show_id DC_PROTO((FILE *, int, const char *));
-extern void dc_string_init DC_PROTO((void));
-
-extern int dc_cmpop DC_PROTO((void));
-extern int dc_compare DC_PROTO((dc_num, dc_num));
-extern int dc_evalfile DC_PROTO((FILE *));
-extern int dc_evalstr DC_PROTO((dc_data));
-extern int dc_num2int DC_PROTO((dc_num, dc_discard));
-extern int dc_numlen DC_PROTO((dc_num));
-extern int dc_pop DC_PROTO((dc_data *));
-extern int dc_register_get DC_PROTO((int, dc_data *));
-extern int dc_register_pop DC_PROTO((int, dc_data *));
-extern int dc_tell_length DC_PROTO((dc_data, dc_discard));
-extern int dc_tell_scale DC_PROTO((dc_num, dc_discard));
-extern int dc_tell_stackdepth DC_PROTO((void));
-extern int dc_top_of_stack DC_PROTO((dc_data *));
-
-extern size_t dc_strlen DC_PROTO((dc_str));
-
-extern dc_data dc_array_get DC_PROTO((int, int));
-extern dc_data dc_dup DC_PROTO((dc_data));
-extern dc_data dc_dup_num DC_PROTO((dc_num));
-extern dc_data dc_dup_str DC_PROTO((dc_str));
-extern dc_data dc_getnum DC_PROTO((int (*)(void), int, int *));
-extern dc_data dc_int2data DC_PROTO((int));
-extern dc_data dc_makestring DC_PROTO((const char *, size_t));
-extern dc_data dc_readstring DC_PROTO((FILE *, int , int));
-
-extern int dc_add DC_PROTO((dc_num, dc_num, int, dc_num *));
-extern int dc_div DC_PROTO((dc_num, dc_num, int, dc_num *));
-extern int dc_divrem DC_PROTO((dc_num, dc_num, int, dc_num *, dc_num *));
-extern int dc_exp DC_PROTO((dc_num, dc_num, int, dc_num *));
-extern int dc_modexp DC_PROTO((dc_num, dc_num, dc_num, int, dc_num *));
-extern int dc_mul DC_PROTO((dc_num, dc_num, int, dc_num *));
-extern int dc_rem DC_PROTO((dc_num, dc_num, int, dc_num *));
-extern int dc_sub DC_PROTO((dc_num, dc_num, int, dc_num *));
-extern int dc_sqrt DC_PROTO((dc_num, int, dc_num *));
diff --git a/contrib/bc/dc/dc-regdef.h b/contrib/bc/dc/dc-regdef.h
deleted file mode 100644
index 540268c..0000000
--- a/contrib/bc/dc/dc-regdef.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * definitions for dc's "register" declarations
- *
- * Copyright (C) 1994 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you can either send email to this
- * program's author (see below) or write to:
- *
- * The Free Software Foundation, Inc.
- * 59 Temple Place, Suite 330
- * Boston, MA 02111 USA
- */
-
-#ifdef HAVE_LIMITS_H
-# include <limits.h> /* UCHAR_MAX */
-#endif
-
-/* determine how many register stacks there are */
-#ifndef DC_REGCOUNT
-# ifndef UCHAR_MAX
-# define DC_REGCOUNT 256
-# else
-# define DC_REGCOUNT (UCHAR_MAX+1)
-# endif
-#endif /* not DC_REGCOUNT */
-
-/* efficiency hack for masking arbritrary integers to 0..(DC_REGCOUNT-1) */
-#if (DC_REGCOUNT & (DC_REGCOUNT-1)) == 0 /* DC_REGCOUNT is power of 2 */
-# define regmap(r) ((r) & (DC_REGCOUNT-1))
-#else
-# define regmap(r) ((r) % DC_REGCOUNT)
-#endif
diff --git a/contrib/bc/dc/dc.c b/contrib/bc/dc/dc.c
deleted file mode 100644
index a72644c..0000000
--- a/contrib/bc/dc/dc.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * implement the "dc" Desk Calculator language.
- *
- * Copyright (C) 1994, 1997, 1998, 2000 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you can either send email to this
- * program's author (see below) or write to:
- * The Free Software Foundation, Inc.
- * 59 Temple Place, Suite 330
- * Boston, MA 02111 USA
- */
-
-/* Written with strong hiding of implementation details
- * in their own specialized modules.
- */
-/* This module contains the argument processing/main functions.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# ifdef HAVE_STRINGS_H
-# include <strings.h>
-# endif
-#endif
-#include <getopt.h>
-#include "dc.h"
-#include "dc-proto.h"
-
-#ifndef EXIT_SUCCESS /* C89 <stdlib.h> */
-# define EXIT_SUCCESS 0
-#endif
-#ifndef EXIT_FAILURE /* C89 <stdlib.h> */
-# define EXIT_FAILURE 1
-#endif
-
-const char *progname; /* basename of program invocation */
-
-static void
-bug_report_info DC_DECLVOID()
-{
- printf("Email bug reports to: bug-dc@gnu.org .\n");
-}
-
-static void
-show_version DC_DECLVOID()
-{
- printf("dc (GNU %s %s) %s\n", PACKAGE, VERSION, DC_VERSION);
- printf("\n%s\n\
-This is free software; see the source for copying conditions. There is NO\n\
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,\n\
-to the extent permitted by law.\n", DC_COPYRIGHT);
-}
-
-/* your generic usage function */
-static void
-usage DC_DECLARG((f))
- FILE *f DC_DECLEND
-{
- fprintf(f, "\
-Usage: %s [OPTION] [file ...]\n\
- -e, --expression=EXPR evaluate expression\n\
- -f, --file=FILE evaluate contents of file\n\
- -h, --help display this help and exit\n\
- -V, --version output version information and exit\n\
-\n\
-", progname);
- bug_report_info();
-}
-
-/* returns a pointer to one past the last occurance of c in s,
- * or s if c does not occur in s.
- */
-static char *
-r1bindex DC_DECLARG((s, c))
- char *s DC_DECLSEP
- int c DC_DECLEND
-{
- char *p = strrchr(s, c);
-
- if (!p)
- return s;
- return p + 1;
-}
-
-static void
-try_file(const char *filename)
-{
- FILE *input;
-
- if (strcmp(filename, "-") == 0) {
- input = stdin;
- } else if ( !(input=fopen(filename, "r")) ) {
- fprintf(stderr, "Could not open file ");
- perror(filename);
- exit(EXIT_FAILURE);
- }
- if (dc_evalfile(input))
- exit(EXIT_FAILURE);
- if (input != stdin)
- fclose(input);
-}
-
-
-int
-main DC_DECLARG((argc, argv))
- int argc DC_DECLSEP
- char **argv DC_DECLEND
-{
- static struct option const long_opts[] = {
- {"expression", required_argument, NULL, 'e'},
- {"file", required_argument, NULL, 'f'},
- {"help", no_argument, NULL, 'h'},
- {"version", no_argument, NULL, 'V'},
- {NULL, 0, NULL, 0}
- };
- int did_eval = 0;
- int c;
-
- progname = r1bindex(*argv, '/');
-#ifdef HAVE_SETVBUF
- /* attempt to simplify interaction with applications such as emacs */
- (void) setvbuf(stdout, NULL, _IOLBF, 0);
-#endif
- dc_math_init();
- dc_string_init();
- dc_register_init();
- dc_array_init();
-
- while ((c = getopt_long(argc, argv, "hVe:f:", long_opts, (int *)0)) != EOF) {
- switch (c) {
- case 'e':
- { dc_data string = dc_makestring(optarg, strlen(optarg));
- if (dc_evalstr(string))
- return EXIT_SUCCESS;
- dc_free_str(&string.v.string);
- did_eval = 1;
- }
- break;
- case 'f':
- try_file(optarg);
- did_eval = 1;
- break;
- case 'h':
- usage(stdout);
- return EXIT_SUCCESS;
- case 'V':
- show_version();
- return EXIT_SUCCESS;
- default:
- usage(stderr);
- return EXIT_FAILURE;
- }
- }
-
- for (; optind < argc; ++optind) {
- try_file(argv[optind]);
- did_eval = 1;
- }
- if (!did_eval) {
- /* if no -e commands and no command files, then eval stdin */
- if (dc_evalfile(stdin))
- return EXIT_FAILURE;
- }
- return EXIT_SUCCESS;
-}
diff --git a/contrib/bc/dc/dc.h b/contrib/bc/dc/dc.h
deleted file mode 100644
index 3300f44..0000000
--- a/contrib/bc/dc/dc.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Header file for dc routines
- *
- * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you can either send email to this
- * program's author (see below) or write to:
- *
- * The Free Software Foundation, Inc.
- * 59 Temple Place, Suite 330
- * Boston, MA 02111 USA
- */
-
-#ifndef DC_DEFS_H
-#define DC_DEFS_H
-
-/* 'I' is a command, and bases 17 and 18 are quite
- * unusual, so we limit ourselves to bases 2 to 16
- */
-#define DC_IBASE_MAX 16
-
-#define DC_SUCCESS 0
-#define DC_DOMAIN_ERROR 1
-#define DC_FAIL 2 /* generic failure */
-
-
-#ifndef __STDC__
-# define DC_PROTO(x) ()
-# define DC_DECLVOID() ()
-# define DC_DECLARG(arglist) arglist
-# define DC_DECLSEP ;
-# define DC_DECLEND ;
-#else /* __STDC__ */
-# define DC_PROTO(x) x
-# define DC_DECLVOID() (void)
-# define DC_DECLARG(arglist) (
-# define DC_DECLSEP ,
-# define DC_DECLEND )
-#endif /* __STDC__ */
-
-
-typedef enum {DC_TOSS, DC_KEEP} dc_discard;
-typedef enum {DC_NONL, DC_WITHNL} dc_newline;
-
-
-/* type discriminant for dc_data */
-typedef enum {DC_UNINITIALIZED, DC_NUMBER, DC_STRING} dc_value_type;
-
-/* only numeric.c knows what dc_num's *really* look like */
-typedef struct dc_number *dc_num;
-
-/* only string.c knows what dc_str's *really* look like */
-typedef struct dc_string *dc_str;
-
-
-/* except for the two implementation-specific modules, all
- * dc functions only know of this one generic type of object
- */
-typedef struct {
- dc_value_type dc_type; /* discriminant for union */
- union {
- dc_num number;
- dc_str string;
- } v;
-} dc_data;
-
-
-/* This is dc's only global variable: */
-extern const char *progname; /* basename of program invocation */
-
-#endif /* not DC_DEFS_H */
diff --git a/contrib/bc/dc/eval.c b/contrib/bc/dc/eval.c
deleted file mode 100644
index 21592d9..0000000
--- a/contrib/bc/dc/eval.c
+++ /dev/null
@@ -1,682 +0,0 @@
-/*
- * evaluate the dc language, from a FILE* or a string
- *
- * Copyright (C) 1994, 1997, 1998, 2000 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you can either send email to this
- * program's author (see below) or write to:
- * The Free Software Foundation, Inc.
- * 59 Temple Place, Suite 330
- * Boston, MA 02111 USA
- */
-
-/* This is the only module which knows about the dc input language */
-
-#include "config.h"
-
-#include <stdio.h>
-#ifdef HAVE_STRING_H
-# include <string.h> /* memchr */
-#else
-# ifdef HAVE_MEMORY_H
-# include <memory.h> /* memchr, maybe */
-# else
-# ifdef HAVE_STRINGS_H
-# include <strings.h> /* memchr, maybe */
-# endif
-#endif
-#endif
-#include "dc.h"
-#include "dc-proto.h"
-
-typedef enum {DC_FALSE, DC_TRUE} dc_boolean;
-
-typedef enum {
- DC_OKAY = DC_SUCCESS, /* no further intervention needed for this command */
- DC_EATONE, /* caller needs to eat the lookahead char */
- DC_QUIT, /* quit out of unwind_depth levels of evaluation */
-
- /* with the following return values, the caller does not have to
- * fret about stdin_lookahead's value
- */
- DC_INT, /* caller needs to parse a dc_num from input stream */
- DC_STR, /* caller needs to parse a dc_str from input stream */
- DC_SYSTEM, /* caller needs to run a system() on next input line */
- DC_COMMENT, /* caller needs to skip to the next input line */
- DC_NEGCMP, /* caller needs to re-call dc_func() with `negcmp' set */
-
- DC_EOF_ERROR /* unexpected end of input; abort current eval */
-} dc_status;
-
-static int dc_ibase=10; /* input base, 2 <= dc_ibase <= DC_IBASE_MAX */
-static int dc_obase=10; /* output base, 2 <= dc_obase */
-static int dc_scale=0; /* scale (see user documentaton) */
-
-/* for Quitting evaluations */
-static int unwind_depth=0;
-
-/* if true, active Quit will not exit program */
-static dc_boolean unwind_noexit=DC_FALSE;
-
-/*
- * Used to synchronize lookahead on stdin for '?' command.
- * If set to EOF then lookahead is used up.
- */
-static int stdin_lookahead=EOF;
-
-
-/* input_fil and input_str are passed as arguments to dc_getnum */
-
-/* used by the input_* functions: */
-static FILE *input_fil_fp;
-static const char *input_str_string;
-
-/* Since we have a need for two characters of pushback, and
- * ungetc() only guarantees one, we place the second pushback here
- */
-static int input_pushback;
-
-/* passed as an argument to dc_getnum */
-static int
-input_fil DC_DECLVOID()
-{
- if (input_pushback != EOF){
- int c = input_pushback;
- input_pushback = EOF;
- return c;
- }
- return getc(input_fil_fp);
-}
-
-/* passed as an argument to dc_getnum */
-static int
-input_str DC_DECLVOID()
-{
- if (!*input_str_string)
- return EOF;
- return *input_str_string++;
-}
-
-
-
-/* takes a string and evals it; frees the string when done */
-/* Wrapper around dc_evalstr to avoid duplicating the free call
- * at all possible return points.
- */
-static int
-dc_eval_and_free_str DC_DECLARG((string))
- dc_data string DC_DECLEND
-{
- dc_status status;
-
- status = dc_evalstr(string);
- if (string.dc_type == DC_STRING)
- dc_free_str(&string.v.string);
- return status;
-}
-
-
-/* dc_func does the grunt work of figuring out what each input
- * character means; used by both dc_evalstr and dc_evalfile
- *
- * c -> the "current" input character under consideration
- * peekc -> the lookahead input character
- * negcmp -> negate comparison test (for <,=,> commands)
- */
-static dc_status
-dc_func DC_DECLARG((c, peekc, negcmp))
- int c DC_DECLSEP
- int peekc DC_DECLSEP
- int negcmp DC_DECLEND
-{
- /* we occasionally need these for temporary data */
- /* Despite the GNU coding standards, it is much easier
- * to have these declared once here, since this function
- * is just one big switch statement.
- */
- dc_data datum;
- int tmpint;
-
- switch (c){
- case '_': case '.':
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- case '8': case '9': case 'A': case 'B':
- case 'C': case 'D': case 'E': case 'F':
- return DC_INT;
- case ' ':
- case '\t':
- case '\n':
- /* standard command separators */
- break;
-
- case '+': /* add top two stack elements */
- dc_binop(dc_add, dc_scale);
- break;
- case '-': /* subtract top two stack elements */
- dc_binop(dc_sub, dc_scale);
- break;
- case '*': /* multiply top two stack elements */
- dc_binop(dc_mul, dc_scale);
- break;
- case '/': /* divide top two stack elements */
- dc_binop(dc_div, dc_scale);
- break;
- case '%':
- /* take the remainder from division of the top two stack elements */
- dc_binop(dc_rem, dc_scale);
- break;
- case '~':
- /* Do division on the top two stack elements. Return the
- * quotient as next-to-top of stack and the remainder as
- * top-of-stack.
- */
- dc_binop2(dc_divrem, dc_scale);
- break;
- case '|':
- /* Consider the top three elements of the stack as (base, exp, mod),
- * where mod is top-of-stack, exp is next-to-top, and base is
- * second-from-top. Mod must be non-zero, exp must be non-negative,
- * and all three must be integers. Push the result of raising
- * base to the exp power, reduced modulo mod. If we had base in
- * register b, exp in register e, and mod in register m then this
- * is conceptually equivalent to "lble^lm%", but it is implemented
- * in a more efficient manner, and can handle arbritrarily large
- * values for exp.
- */
- dc_triop(dc_modexp, dc_scale);
- break;
- case '^': /* exponientiation of the top two stack elements */
- dc_binop(dc_exp, dc_scale);
- break;
- case '<':
- /* eval register named by peekc if
- * less-than holds for top two stack elements
- */
- if (peekc == EOF)
- return DC_EOF_ERROR;
- if ( (dc_cmpop() < 0) == !negcmp )
- if (dc_register_get(peekc, &datum) == DC_SUCCESS)
- if (dc_eval_and_free_str(datum) == DC_QUIT)
- return DC_QUIT;
- return DC_EATONE;
- case '=':
- /* eval register named by peekc if
- * equal-to holds for top two stack elements
- */
- if (peekc == EOF)
- return DC_EOF_ERROR;
- if ( (dc_cmpop() == 0) == !negcmp )
- if (dc_register_get(peekc, &datum) == DC_SUCCESS)
- if (dc_eval_and_free_str(datum) == DC_QUIT)
- return DC_QUIT;
- return DC_EATONE;
- case '>':
- /* eval register named by peekc if
- * greater-than holds for top two stack elements
- */
- if (peekc == EOF)
- return DC_EOF_ERROR;
- if ( (dc_cmpop() > 0) == !negcmp )
- if (dc_register_get(peekc, &datum) == DC_SUCCESS)
- if (dc_eval_and_free_str(datum) == DC_QUIT)
- return DC_QUIT;
- return DC_EATONE;
- case '?': /* read a line from standard-input and eval it */
- if (stdin_lookahead != EOF){
- ungetc(stdin_lookahead, stdin);
- stdin_lookahead = EOF;
- }
- if (dc_eval_and_free_str(dc_readstring(stdin, '\n', '\n')) == DC_QUIT)
- return DC_QUIT;
- return DC_OKAY;
- case '[': /* read to balancing ']' into a dc_str */
- return DC_STR;
- case '!': /* read to newline and call system() on resulting string */
- if (peekc == '<' || peekc == '=' || peekc == '>')
- return DC_NEGCMP;
- return DC_SYSTEM;
- case '#': /* comment; skip remainder of current line */
- return DC_COMMENT;
-
- case 'a': /* Convert top of stack to an ascii character. */
- if (dc_pop(&datum) == DC_SUCCESS){
- char tmps;
- if (datum.dc_type == DC_NUMBER){
- tmps = (char) dc_num2int(datum.v.number, DC_TOSS);
- }else if (datum.dc_type == DC_STRING){
- tmps = *dc_str2charp(datum.v.string);
- dc_free_str(&datum.v.string);
- }else{
- dc_garbage("at top of stack", -1);
- }
- dc_push(dc_makestring(&tmps, 1));
- }
- break;
- case 'c': /* clear whole stack */
- dc_clear_stack();
- break;
- case 'd': /* duplicate the datum on the top of stack */
- if (dc_top_of_stack(&datum) == DC_SUCCESS)
- dc_push(dc_dup(datum));
- break;
- case 'f': /* print list of all stack items */
- dc_printall(dc_obase);
- break;
- case 'i': /* set input base to value on top of stack */
- if (dc_pop(&datum) == DC_SUCCESS){
- tmpint = 0;
- if (datum.dc_type == DC_NUMBER)
- tmpint = dc_num2int(datum.v.number, DC_TOSS);
- if ( ! (2 <= tmpint && tmpint <= DC_IBASE_MAX) )
- fprintf(stderr,
- "%s: input base must be a number \
-between 2 and %d (inclusive)\n",
- progname, DC_IBASE_MAX);
- else
- dc_ibase = tmpint;
- }
- break;
- case 'k': /* set scale to value on top of stack */
- if (dc_pop(&datum) == DC_SUCCESS){
- tmpint = -1;
- if (datum.dc_type == DC_NUMBER)
- tmpint = dc_num2int(datum.v.number, DC_TOSS);
- if ( ! (tmpint >= 0) )
- fprintf(stderr,
- "%s: scale must be a nonnegative number\n",
- progname);
- else
- dc_scale = tmpint;
- }
- break;
- case 'l': /* "load" -- push value on top of register stack named
- * by peekc onto top of evaluation stack; does not
- * modify the register stack
- */
- if (peekc == EOF)
- return DC_EOF_ERROR;
- if (dc_register_get(peekc, &datum) == DC_SUCCESS)
- dc_push(datum);
- return DC_EATONE;
- case 'n': /* print the value popped off of top-of-stack;
- * do not add a trailing newline
- */
- if (dc_pop(&datum) == DC_SUCCESS)
- dc_print(datum, dc_obase, DC_NONL, DC_TOSS);
- break;
- case 'o': /* set output base to value on top of stack */
- if (dc_pop(&datum) == DC_SUCCESS){
- tmpint = 0;
- if (datum.dc_type == DC_NUMBER)
- tmpint = dc_num2int(datum.v.number, DC_TOSS);
- if ( ! (tmpint > 1) )
- fprintf(stderr,
- "%s: output base must be a number greater than 1\n",
- progname);
- else
- dc_obase = tmpint;
- }
- break;
- case 'p': /* print the datum on the top of stack,
- * with a trailing newline
- */
- if (dc_top_of_stack(&datum) == DC_SUCCESS)
- dc_print(datum, dc_obase, DC_WITHNL, DC_KEEP);
- break;
- case 'q': /* quit two levels of evaluation, posibly exiting program */
- unwind_depth = 1; /* the return below is the first level of returns */
- unwind_noexit = DC_FALSE;
- return DC_QUIT;
- case 'r': /* rotate (swap) the top two elements on the stack
- */
- if (dc_pop(&datum) == DC_SUCCESS) {
- dc_data datum2;
- int two_status;
- two_status = dc_pop(&datum2);
- dc_push(datum);
- if (two_status == DC_SUCCESS)
- dc_push(datum2);
- }
- break;
- case 's': /* "store" -- replace top of register stack named
- * by peekc with the value popped from the top
- * of the evaluation stack
- */
- if (peekc == EOF)
- return DC_EOF_ERROR;
- if (dc_pop(&datum) == DC_SUCCESS)
- dc_register_set(peekc, datum);
- return DC_EATONE;
- case 'v': /* replace top of stack with its square root */
- if (dc_pop(&datum) == DC_SUCCESS){
- dc_num tmpnum;
- if (datum.dc_type != DC_NUMBER){
- fprintf(stderr,
- "%s: square root of nonnumeric attempted\n",
- progname);
- }else if (dc_sqrt(datum.v.number, dc_scale, &tmpnum) == DC_SUCCESS){
- dc_free_num(&datum.v.number);
- datum.v.number = tmpnum;
- dc_push(datum);
- }
- }
- break;
- case 'x': /* eval the datum popped from top of stack */
- if (dc_pop(&datum) == DC_SUCCESS){
- if (datum.dc_type == DC_STRING){
- if (dc_eval_and_free_str(datum) == DC_QUIT)
- return DC_QUIT;
- }else if (datum.dc_type == DC_NUMBER){
- dc_push(datum);
- }else{
- dc_garbage("at top of stack", -1);
- }
- }
- break;
- case 'z': /* push the current stack depth onto the top of stack */
- dc_push(dc_int2data(dc_tell_stackdepth()));
- break;
-
- case 'I': /* push the current input base onto the stack */
- dc_push(dc_int2data(dc_ibase));
- break;
- case 'K': /* push the current scale onto the stack */
- dc_push(dc_int2data(dc_scale));
- break;
- case 'L': /* pop a value off of register stack named by peekc
- * and push it onto the evaluation stack
- */
- if (peekc == EOF)
- return DC_EOF_ERROR;
- if (dc_register_pop(peekc, &datum) == DC_SUCCESS)
- dc_push(datum);
- return DC_EATONE;
- case 'O': /* push the current output base onto the stack */
- dc_push(dc_int2data(dc_obase));
- break;
- case 'P':
- /* Pop the value off the top of a stack. If it is
- * a number, dump out the integer portion of its
- * absolute value as a "base UCHAR_MAX+1" byte stream;
- * if it is a string, just print it.
- * In either case, do not append a trailing newline.
- */
- if (dc_pop(&datum) == DC_SUCCESS){
- if (datum.dc_type == DC_NUMBER)
- dc_dump_num(datum.v.number, DC_TOSS);
- else if (datum.dc_type == DC_STRING)
- dc_out_str(datum.v.string, DC_NONL, DC_TOSS);
- else
- dc_garbage("at top of stack", -1);
- }
- break;
- case 'Q': /* quit out of top-of-stack nested evals;
- * pops value from stack;
- * does not exit program (stops short if necessary)
- */
- if (dc_pop(&datum) == DC_SUCCESS){
- unwind_depth = 0;
- unwind_noexit = DC_TRUE;
- if (datum.dc_type == DC_NUMBER)
- unwind_depth = dc_num2int(datum.v.number, DC_TOSS);
- if (unwind_depth-- > 0)
- return DC_QUIT;
- unwind_depth = 0; /* paranoia */
- fprintf(stderr,
- "%s: Q command requires a number >= 1\n",
- progname);
- }
- break;
-#if 0
- case 'R': /* pop a value off of the evaluation stack,;
- * rotate the top
- remaining stack elements that many
- * places forward (negative numbers mean rotate
- * backward).
- */
- if (dc_pop(&datum) == DC_SUCCESS){
- tmpint = 0;
- if (datum.dc_type == DC_NUMBER)
- tmpint = dc_num2int(datum.v.number, DC_TOSS);
- dc_stack_rotate(tmpint);
- }
- break;
-#endif
- case 'S': /* pop a value off of the evaluation stack
- * and push it onto the register stack named by peekc
- */
- if (peekc == EOF)
- return DC_EOF_ERROR;
- if (dc_pop(&datum) == DC_SUCCESS)
- dc_register_push(peekc, datum);
- return DC_EATONE;
- case 'X': /* replace the number on top-of-stack with its scale factor */
- if (dc_pop(&datum) == DC_SUCCESS){
- tmpint = 0;
- if (datum.dc_type == DC_NUMBER)
- tmpint = dc_tell_scale(datum.v.number, DC_TOSS);
- dc_push(dc_int2data(tmpint));
- }
- break;
- case 'Z': /* replace the datum on the top-of-stack with its length */
- if (dc_pop(&datum) == DC_SUCCESS)
- dc_push(dc_int2data(dc_tell_length(datum, DC_TOSS)));
- break;
-
- case ':': /* store into array */
- if (peekc == EOF)
- return DC_EOF_ERROR;
- if (dc_pop(&datum) == DC_SUCCESS){
- tmpint = -1;
- if (datum.dc_type == DC_NUMBER)
- tmpint = dc_num2int(datum.v.number, DC_TOSS);
- if (dc_pop(&datum) == DC_SUCCESS){
- if (tmpint < 0)
- fprintf(stderr,
- "%s: array index must be a nonnegative integer\n",
- progname);
- else
- dc_array_set(peekc, tmpint, datum);
- }
- }
- return DC_EATONE;
- case ';': /* retreive from array */
- if (peekc == EOF)
- return DC_EOF_ERROR;
- if (dc_pop(&datum) == DC_SUCCESS){
- tmpint = -1;
- if (datum.dc_type == DC_NUMBER)
- tmpint = dc_num2int(datum.v.number, DC_TOSS);
- if (tmpint < 0)
- fprintf(stderr,
- "%s: array index must be a nonnegative integer\n",
- progname);
- else
- dc_push(dc_array_get(peekc, tmpint));
- }
- return DC_EATONE;
-
- default: /* What did that user mean? */
- fprintf(stderr, "%s: ", progname);
- dc_show_id(stdout, c, " unimplemented\n");
- break;
- }
- return DC_OKAY;
-}
-
-
-/* takes a string and evals it */
-int
-dc_evalstr DC_DECLARG((string))
- dc_data string DC_DECLEND
-{
- const char *s;
- const char *end;
- const char *p;
- size_t len;
- int c;
- int peekc;
- int count;
- int negcmp;
- int next_negcmp = 0;
-
- if (string.dc_type != DC_STRING){
- fprintf(stderr,
- "%s: eval called with non-string argument\n",
- progname);
- return DC_OKAY;
- }
- s = dc_str2charp(string.v.string);
- end = s + dc_strlen(string.v.string);
- while (s < end){
- c = *(const unsigned char *)s++;
- peekc = EOF;
- if (s < end)
- peekc = *(const unsigned char *)s;
- negcmp = next_negcmp;
- next_negcmp = 0;
- switch (dc_func(c, peekc, negcmp)){
- case DC_OKAY:
- break;
- case DC_EATONE:
- if (peekc != EOF)
- ++s;
- break;
- case DC_QUIT:
- if (unwind_depth > 0){
- --unwind_depth;
- return DC_QUIT;
- }
- return DC_OKAY;
-
- case DC_INT:
- input_str_string = s - 1;
- dc_push(dc_getnum(input_str, dc_ibase, &peekc));
- s = input_str_string;
- if (peekc != EOF)
- --s;
- break;
- case DC_STR:
- count = 1;
- for (p=s; p<end && count>0; ++p)
- if (*p == ']')
- --count;
- else if (*p == '[')
- ++count;
- len = p - s;
- dc_push(dc_makestring(s, len-1));
- s = p;
- break;
- case DC_SYSTEM:
- s = dc_system(s);
- case DC_COMMENT:
- s = memchr(s, '\n', (size_t)(end-s));
- if (!s)
- s = end;
- else
- ++s;
- break;
- case DC_NEGCMP:
- next_negcmp = 1;
- break;
-
- case DC_EOF_ERROR:
- fprintf(stderr, "%s: unexpected EOS\n", progname);
- return DC_OKAY;
- }
- }
- return DC_OKAY;
-}
-
-
-/* This is the main function of the whole DC program.
- * Reads the file described by fp, calls dc_func to do
- * the dirty work, and takes care of dc_func's shortcomings.
- */
-int
-dc_evalfile DC_DECLARG((fp))
- FILE *fp DC_DECLEND
-{
- int c;
- int peekc;
- int negcmp;
- int next_negcmp = 0;
- dc_data datum;
-
- stdin_lookahead = EOF;
- for (c=getc(fp); c!=EOF; c=peekc){
- peekc = getc(fp);
- /*
- * The following if() is the only place where ``stdin_lookahead''
- * might be set to other than EOF:
- */
- if (fp == stdin)
- stdin_lookahead = peekc;
- negcmp = next_negcmp;
- next_negcmp = 0;
- switch (dc_func(c, peekc, negcmp)){
- case DC_OKAY:
- if (stdin_lookahead != peekc && fp == stdin)
- peekc = getc(fp);
- break;
- case DC_EATONE:
- peekc = getc(fp);
- break;
- case DC_QUIT:
- if (unwind_noexit != DC_TRUE)
- return DC_SUCCESS;
- fprintf(stderr,
- "%s: Q command argument exceeded string execution depth\n",
- progname);
- if (stdin_lookahead != peekc && fp == stdin)
- peekc = getc(fp);
- break;
-
- case DC_INT:
- input_fil_fp = fp;
- input_pushback = c;
- ungetc(peekc, fp);
- dc_push(dc_getnum(input_fil, dc_ibase, &peekc));
- break;
- case DC_STR:
- ungetc(peekc, fp);
- datum = dc_readstring(fp, '[', ']');
- dc_push(datum);
- peekc = getc(fp);
- break;
- case DC_SYSTEM:
- ungetc(peekc, fp);
- datum = dc_readstring(stdin, '\n', '\n');
- (void)dc_system(dc_str2charp(datum.v.string));
- dc_free_str(&datum.v.string);
- peekc = getc(fp);
- break;
- case DC_COMMENT:
- while (peekc!=EOF && peekc!='\n')
- peekc = getc(fp);
- if (peekc != EOF)
- peekc = getc(fp);
- break;
- case DC_NEGCMP:
- next_negcmp = 1;
- break;
-
- case DC_EOF_ERROR:
- fprintf(stderr, "%s: unexpected EOF\n", progname);
- return DC_FAIL;
- }
- }
- return DC_SUCCESS;
-}
diff --git a/contrib/bc/dc/misc.c b/contrib/bc/dc/misc.c
deleted file mode 100644
index fa94de1..0000000
--- a/contrib/bc/dc/misc.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * misc. functions for the "dc" Desk Calculator language.
- *
- * Copyright (C) 1994, 1997, 1998, 2000 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you can either send email to this
- * program's author (see below) or write to:
- * The Free Software Foundation, Inc.
- * 59 Temple Place, Suite 330
- * Boston, MA 02111 USA
- */
-
-/* This module contains miscelaneous functions that have no
- * special knowledge of any private data structures.
- * They could all be moved to their own separate modules, but
- * are agglomerated here for convenience.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# ifdef HAVE_STRINGS_H
-# include <strings.h>
-# endif
-#endif
-#include <ctype.h>
-#ifndef isgraph
-# ifndef HAVE_ISGRAPH
-# define isgraph isprint
-# endif
-#endif
-#include <getopt.h>
-#include "dc.h"
-#include "dc-proto.h"
-
-#ifndef EXIT_FAILURE /* C89 <stdlib.h> */
-# define EXIT_FAILURE 1
-#endif
-
-
-/* print an "out of memory" diagnostic and exit program */
-void
-dc_memfail DC_DECLVOID()
-{
- fprintf(stderr, "%s: out of memory\n", progname);
- exit(EXIT_FAILURE);
-}
-
-/* malloc or die */
-void *
-dc_malloc DC_DECLARG((len))
- size_t len DC_DECLEND
-{
- void *result = malloc(len);
-
- if (!result)
- dc_memfail();
- return result;
-}
-
-
-/* print the id in a human-understandable form
- * fp is the output stream to place the output on
- * id is the name of the register (or command) to be printed
- * suffix is a modifier (such as "stack") to be printed
- */
-void
-dc_show_id DC_DECLARG((fp, id, suffix))
- FILE *fp DC_DECLSEP
- int id DC_DECLSEP
- const char *suffix DC_DECLEND
-{
- if (isgraph(id))
- fprintf(fp, "'%c' (%#o)%s", id, id, suffix);
- else
- fprintf(fp, "%#o%s", id, suffix);
-}
-
-
-/* report that corrupt data has been detected;
- * use the msg and regid (if nonnegative) to give information
- * about where the garbage was found,
- *
- * will abort() so that a debugger might be used to help find
- * the bug
- */
-/* If this routine is called, then there is a bug in the code;
- * i.e. it is _not_ a data or user error
- */
-void
-dc_garbage DC_DECLARG((msg, regid))
- const char *msg DC_DECLSEP
- int regid DC_DECLEND
-{
- if (regid < 0) {
- fprintf(stderr, "%s: garbage %s\n", progname, msg);
- } else {
- fprintf(stderr, "%s:%s register ", progname, msg);
- dc_show_id(stderr, regid, " is garbage\n");
- }
- abort();
-}
-
-
-/* call system() with the passed string;
- * if the string contains a newline, terminate the string
- * there before calling system.
- * Return a pointer to the first unused character in the string
- * (i.e. past the '\n' if there was one, to the '\0' otherwise).
- */
-const char *
-dc_system DC_DECLARG((s))
- const char *s DC_DECLEND
-{
- const char *p;
- char *tmpstr;
- size_t len;
-
- p = strchr(s, '\n');
- if (p) {
- len = p - s;
- tmpstr = dc_malloc(len + 1);
- strncpy(tmpstr, s, len);
- tmpstr[len] = '\0';
- system(tmpstr);
- free(tmpstr);
- return p + 1;
- }
- system(s);
- return s + strlen(s);
-}
-
-
-/* print out the indicated value */
-void
-dc_print DC_DECLARG((value, obase, newline_p, discard_p))
- dc_data value DC_DECLSEP
- int obase DC_DECLSEP
- dc_newline newline_p DC_DECLSEP
- dc_discard discard_p DC_DECLEND
-{
- if (value.dc_type == DC_NUMBER) {
- dc_out_num(value.v.number, obase, newline_p, discard_p);
- } else if (value.dc_type == DC_STRING) {
- dc_out_str(value.v.string, newline_p, discard_p);
- } else {
- dc_garbage("in data being printed", -1);
- }
-}
-
-/* return a duplicate of the passed value, regardless of type */
-dc_data
-dc_dup DC_DECLARG((value))
- dc_data value DC_DECLEND
-{
- if (value.dc_type!=DC_NUMBER && value.dc_type!=DC_STRING)
- dc_garbage("in value being duplicated", -1);
- if (value.dc_type == DC_NUMBER)
- return dc_dup_num(value.v.number);
- /*else*/
- return dc_dup_str(value.v.string);
-}
diff --git a/contrib/bc/dc/numeric.c b/contrib/bc/dc/numeric.c
deleted file mode 100644
index 6086be5..0000000
--- a/contrib/bc/dc/numeric.c
+++ /dev/null
@@ -1,600 +0,0 @@
-/*
- * interface dc to the bc numeric routines
- *
- * Copyright (C) 1994, 1997, 1998, 2000 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you can either send email to this
- * program's author (see below) or write to:
- * The Free Software Foundation, Inc.
- * 59 Temple Place, Suite 330
- * Boston, MA 02111 USA
- */
-
-/* This should be the only module that knows the internals of type dc_num */
-/* In this particular implementation we just slather out some glue and
- * make use of bc's numeric routines.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <ctype.h>
-#ifdef HAVE_LIMITS_H
-# include <limits.h>
-#else
-# define UCHAR_MAX ((unsigned char)~0)
-#endif
-#include <stdlib.h>
-#include "number.h"
-#include "dc.h"
-#include "dc-proto.h"
-
-#ifdef __GNUC__
-# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__-0 >= 7)
-# define ATTRIB(x) __attribute__(x)
-# endif
-#endif
-#ifndef ATTRIB
-# define ATTRIB(x)
-#endif
-
-/* Forward prototype */
-static void out_char (int);
-
-/* there is no POSIX standard for dc, so we'll take the GNU definitions */
-int std_only = FALSE;
-
-/* convert an opaque dc_num into a real bc_num */
-#define CastNum(x) ((bc_num)(x))
-
-/* add two dc_nums, place into *result;
- * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
- */
-int
-dc_add DC_DECLARG((a, b, kscale, result))
- dc_num a DC_DECLSEP
- dc_num b DC_DECLSEP
- int kscale ATTRIB((unused)) DC_DECLSEP
- dc_num *result DC_DECLEND
-{
- bc_init_num((bc_num *)result);
- bc_add(CastNum(a), CastNum(b), (bc_num *)result, 0);
- return DC_SUCCESS;
-}
-
-/* subtract two dc_nums, place into *result;
- * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
- */
-int
-dc_sub DC_DECLARG((a, b, kscale, result))
- dc_num a DC_DECLSEP
- dc_num b DC_DECLSEP
- int kscale ATTRIB((unused)) DC_DECLSEP
- dc_num *result DC_DECLEND
-{
- bc_init_num((bc_num *)result);
- bc_sub(CastNum(a), CastNum(b), (bc_num *)result, 0);
- return DC_SUCCESS;
-}
-
-/* multiply two dc_nums, place into *result;
- * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
- */
-int
-dc_mul DC_DECLARG((a, b, kscale, result))
- dc_num a DC_DECLSEP
- dc_num b DC_DECLSEP
- int kscale DC_DECLSEP
- dc_num *result DC_DECLEND
-{
- bc_init_num((bc_num *)result);
- bc_multiply(CastNum(a), CastNum(b), (bc_num *)result, kscale);
- return DC_SUCCESS;
-}
-
-/* divide two dc_nums, place into *result;
- * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
- */
-int
-dc_div DC_DECLARG((a, b, kscale, result))
- dc_num a DC_DECLSEP
- dc_num b DC_DECLSEP
- int kscale DC_DECLSEP
- dc_num *result DC_DECLEND
-{
- bc_init_num((bc_num *)result);
- if (bc_divide(CastNum(a), CastNum(b), (bc_num *)result, kscale)){
- fprintf(stderr, "%s: divide by zero\n", progname);
- return DC_DOMAIN_ERROR;
- }
- return DC_SUCCESS;
-}
-
-/* divide two dc_nums, place quotient into *quotient and remainder
- * into *remainder;
- * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
- */
-int
-dc_divrem DC_DECLARG((a, b, kscale, quotient, remainder))
- dc_num a DC_DECLSEP
- dc_num b DC_DECLSEP
- int kscale DC_DECLSEP
- dc_num *quotient DC_DECLSEP
- dc_num *remainder DC_DECLEND
-{
- bc_init_num((bc_num *)quotient);
- bc_init_num((bc_num *)remainder);
- if (bc_divmod(CastNum(a), CastNum(b),
- (bc_num *)quotient, (bc_num *)remainder, kscale)){
- fprintf(stderr, "%s: divide by zero\n", progname);
- return DC_DOMAIN_ERROR;
- }
- return DC_SUCCESS;
-}
-
-/* place the reminder of dividing a by b into *result;
- * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
- */
-int
-dc_rem DC_DECLARG((a, b, kscale, result))
- dc_num a DC_DECLSEP
- dc_num b DC_DECLSEP
- int kscale DC_DECLSEP
- dc_num *result DC_DECLEND
-{
- bc_init_num((bc_num *)result);
- if (bc_modulo(CastNum(a), CastNum(b), (bc_num *)result, kscale)){
- fprintf(stderr, "%s: remainder by zero\n", progname);
- return DC_DOMAIN_ERROR;
- }
- return DC_SUCCESS;
-}
-
-int
-dc_modexp DC_DECLARG((base, expo, mod, kscale, result))
- dc_num base DC_DECLSEP
- dc_num expo DC_DECLSEP
- dc_num mod DC_DECLSEP
- int kscale DC_DECLSEP
- dc_num *result DC_DECLEND
-{
- bc_init_num((bc_num *)result);
- if (bc_raisemod(CastNum(base), CastNum(expo), CastNum(mod),
- (bc_num *)result, kscale)){
- if (bc_is_zero(CastNum(mod)))
- fprintf(stderr, "%s: remainder by zero\n", progname);
- return DC_DOMAIN_ERROR;
- }
- return DC_SUCCESS;
-}
-
-/* place the result of exponentiationg a by b into *result;
- * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
- */
-int
-dc_exp DC_DECLARG((a, b, kscale, result))
- dc_num a DC_DECLSEP
- dc_num b DC_DECLSEP
- int kscale DC_DECLSEP
- dc_num *result DC_DECLEND
-{
- bc_init_num((bc_num *)result);
- bc_raise(CastNum(a), CastNum(b), (bc_num *)result, kscale);
- return DC_SUCCESS;
-}
-
-/* take the square root of the value, place into *result;
- * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
- */
-int
-dc_sqrt DC_DECLARG((value, kscale, result))
- dc_num value DC_DECLSEP
- int kscale DC_DECLSEP
- dc_num *result DC_DECLEND
-{
- bc_num tmp;
-
- tmp = bc_copy_num(CastNum(value));
- if (!bc_sqrt(&tmp, kscale)){
- fprintf(stderr, "%s: square root of negative number\n", progname);
- bc_free_num(&tmp);
- return DC_DOMAIN_ERROR;
- }
- *((bc_num *)result) = tmp;
- return DC_SUCCESS;
-}
-
-/* compare dc_nums a and b;
- * return a negative value if a < b;
- * return a positive value if a > b;
- * return zero value if a == b
- */
-int
-dc_compare DC_DECLARG((a, b))
- dc_num a DC_DECLSEP
- dc_num b DC_DECLEND
-{
- return bc_compare(CastNum(a), CastNum(b));
-}
-
-/* attempt to convert a dc_num to its corresponding int value
- * If discard_p is DC_TOSS then deallocate the value after use.
- */
-int
-dc_num2int DC_DECLARG((value, discard_p))
- dc_num value DC_DECLSEP
- dc_discard discard_p DC_DECLEND
-{
- long result;
-
- result = bc_num2long(CastNum(value));
- if (discard_p == DC_TOSS)
- dc_free_num(&value);
- return (int)result;
-}
-
-/* convert a C integer value into a dc_num */
-/* For convenience of the caller, package the dc_num
- * into a dc_data result.
- */
-dc_data
-dc_int2data DC_DECLARG((value))
- int value DC_DECLEND
-{
- dc_data result;
-
- bc_init_num((bc_num *)&result.v.number);
- bc_int2num((bc_num *)&result.v.number, value);
- result.dc_type = DC_NUMBER;
- return result;
-}
-
-/* get a dc_num from some input stream;
- * input is a function which knows how to read the desired input stream
- * ibase is the input base (2<=ibase<=DC_IBASE_MAX)
- * *readahead will be set to the readahead character consumed while
- * looking for the end-of-number
- */
-/* For convenience of the caller, package the dc_num
- * into a dc_data result.
- */
-dc_data
-dc_getnum DC_DECLARG((input, ibase, readahead))
- int (*input) DC_PROTO((void)) DC_DECLSEP
- int ibase DC_DECLSEP
- int *readahead DC_DECLEND
-{
- bc_num base;
- bc_num result;
- bc_num build;
- bc_num tmp;
- bc_num divisor;
- dc_data full_result;
- int negative = 0;
- int digit;
- int decimal;
- int c;
-
- bc_init_num(&tmp);
- bc_init_num(&build);
- bc_init_num(&base);
- result = bc_copy_num(_zero_);
- bc_int2num(&base, ibase);
- c = (*input)();
- while (isspace(c))
- c = (*input)();
- if (c == '_' || c == '-'){
- negative = c;
- c = (*input)();
- }else if (c == '+'){
- c = (*input)();
- }
- while (isspace(c))
- c = (*input)();
- for (;;){
- if (isdigit(c))
- digit = c - '0';
- else if ('A' <= c && c <= 'F')
- digit = 10 + c - 'A';
- else
- break;
- c = (*input)();
- bc_int2num(&tmp, digit);
- bc_multiply(result, base, &result, 0);
- bc_add(result, tmp, &result, 0);
- }
- if (c == '.'){
- bc_free_num(&build);
- bc_free_num(&tmp);
- divisor = bc_copy_num(_one_);
- build = bc_copy_num(_zero_);
- decimal = 0;
- for (;;){
- c = (*input)();
- if (isdigit(c))
- digit = c - '0';
- else if ('A' <= c && c <= 'F')
- digit = 10 + c - 'A';
- else
- break;
- bc_int2num(&tmp, digit);
- bc_multiply(build, base, &build, 0);
- bc_add(build, tmp, &build, 0);
- bc_multiply(divisor, base, &divisor, 0);
- ++decimal;
- }
- bc_divide(build, divisor, &build, decimal);
- bc_add(result, build, &result, 0);
- }
- /* Final work. */
- if (negative)
- bc_sub(_zero_, result, &result, 0);
-
- bc_free_num(&tmp);
- bc_free_num(&build);
- bc_free_num(&base);
- if (readahead)
- *readahead = c;
- full_result.v.number = (dc_num)result;
- full_result.dc_type = DC_NUMBER;
- return full_result;
-}
-
-
-/* return the "length" of the number */
-int
-dc_numlen DC_DECLARG((value))
- dc_num value DC_DECLEND
-{
- bc_num num = CastNum(value);
-
- /* is this right??? */
- return num->n_len + num->n_scale - (*num->n_value == '\0');
-}
-
-/* return the scale factor of the passed dc_num
- * If discard_p is DC_TOSS then deallocate the value after use.
- */
-int
-dc_tell_scale DC_DECLARG((value, discard_p))
- dc_num value DC_DECLSEP
- dc_discard discard_p DC_DECLEND
-{
- int kscale;
-
- kscale = CastNum(value)->n_scale;
- if (discard_p == DC_TOSS)
- dc_free_num(&value);
- return kscale;
-}
-
-
-/* initialize the math subsystem */
-void
-dc_math_init DC_DECLVOID()
-{
- bc_init_numbers();
-}
-
-/* print out a dc_num in output base obase to stdout;
- * if newline_p is DC_WITHNL, terminate output with a '\n';
- * if discard_p is DC_TOSS then deallocate the value after use
- */
-void
-dc_out_num DC_DECLARG((value, obase, newline_p, discard_p))
- dc_num value DC_DECLSEP
- int obase DC_DECLSEP
- dc_newline newline_p DC_DECLSEP
- dc_discard discard_p DC_DECLEND
-{
- out_char('\0'); /* clear the column counter */
- bc_out_num(CastNum(value), obase, out_char, 0);
- if (newline_p == DC_WITHNL)
- putchar ('\n');
- if (discard_p == DC_TOSS)
- dc_free_num(&value);
-}
-
-/* dump out the absolute value of the integer part of a
- * dc_num as a byte stream, without any line wrapping;
- * if discard_p is DC_TOSS then deallocate the value after use
- */
-void
-dc_dump_num DC_DECLARG((dcvalue, discard_p))
- dc_num dcvalue DC_DECLSEP
- dc_discard discard_p DC_DECLEND
-{
- struct digit_stack { int digit; struct digit_stack *link;};
- struct digit_stack *top_of_stack = NULL;
- struct digit_stack *cur;
- struct digit_stack *next;
- bc_num value;
- bc_num obase;
- bc_num digit;
-
- bc_init_num(&value);
- bc_init_num(&obase);
- bc_init_num(&digit);
-
- /* we only handle the integer portion: */
- bc_divide(CastNum(dcvalue), _one_, &value, 0);
- /* we only handle the absolute value: */
- value->n_sign = PLUS;
- /* we're done with the dcvalue parameter: */
- if (discard_p == DC_TOSS)
- dc_free_num(&dcvalue);
-
- bc_int2num(&obase, 1+UCHAR_MAX);
- do {
- (void) bc_divmod(value, obase, &value, &digit, 0);
- cur = dc_malloc(sizeof *cur);
- cur->digit = (int)bc_num2long(digit);
- cur->link = top_of_stack;
- top_of_stack = cur;
- } while (!bc_is_zero(value));
-
- for (cur=top_of_stack; cur; cur=next) {
- putchar(cur->digit);
- next = cur->link;
- free(cur);
- }
-
- bc_free_num(&digit);
- bc_free_num(&obase);
- bc_free_num(&value);
-}
-
-/* deallocate an instance of a dc_num */
-void
-dc_free_num DC_DECLARG((value))
- dc_num *value DC_DECLEND
-{
- bc_free_num((bc_num *)value);
-}
-
-/* return a duplicate of the number in the passed value */
-/* The mismatched data types forces the caller to deal with
- * bad dc_type'd dc_data values, and makes it more convenient
- * for the caller to not have to do the grunge work of setting
- * up a dc_type result.
- */
-dc_data
-dc_dup_num DC_DECLARG((value))
- dc_num value DC_DECLEND
-{
- dc_data result;
-
- ++CastNum(value)->n_refs;
- result.v.number = value;
- result.dc_type = DC_NUMBER;
- return result;
-}
-
-
-
-/*---------------------------------------------------------------------------\
-| The rest of this file consists of stubs for bc routines called by numeric.c|
-| so as to minimize the amount of bc code needed to build dc. |
-| The bulk of the code was just lifted straight out of the bc source. |
-\---------------------------------------------------------------------------*/
-
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-
-#ifdef HAVE_STDARG_H
-# include <stdarg.h>
-#else
-# include <varargs.h>
-#endif
-
-
-int out_col = 0;
-
-/* Output routines: Write a character CH to the standard output.
- It keeps track of the number of characters output and may
- break the output with a "\<cr>". */
-
-static void
-out_char (ch)
- int ch;
-{
-
- if (ch == '\0')
- {
- out_col = 0;
- }
- else
- {
- out_col++;
- if (out_col == 70)
- {
- putchar ('\\');
- putchar ('\n');
- out_col = 1;
- }
- putchar (ch);
- }
-}
-
-/* Malloc could not get enough memory. */
-
-void
-out_of_memory()
-{
- dc_memfail();
-}
-
-/* Runtime error will print a message and stop the machine. */
-
-#ifdef HAVE_STDARG_H
-#ifdef __STDC__
-void
-rt_error (char *mesg, ...)
-#else
-void
-rt_error (mesg)
- char *mesg;
-#endif
-#else
-void
-rt_error (mesg, va_alist)
- char *mesg;
-#endif
-{
- va_list args;
-
- fprintf (stderr, "Runtime error: ");
-#ifdef HAVE_STDARG_H
- va_start (args, mesg);
-#else
- va_start (args);
-#endif
- vfprintf (stderr, mesg, args);
- va_end (args);
- fprintf (stderr, "\n");
-}
-
-
-/* A runtime warning tells of some action taken by the processor that
- may change the program execution but was not enough of a problem
- to stop the execution. */
-
-#ifdef HAVE_STDARG_H
-#ifdef __STDC__
-void
-rt_warn (char *mesg, ...)
-#else
-void
-rt_warn (mesg)
- char *mesg;
-#endif
-#else
-void
-rt_warn (mesg, va_alist)
- char *mesg;
-#endif
-{
- va_list args;
-
- fprintf (stderr, "Runtime warning: ");
-#ifdef HAVE_STDARG_H
- va_start (args, mesg);
-#else
- va_start (args);
-#endif
- vfprintf (stderr, mesg, args);
- va_end (args);
- fprintf (stderr, "\n");
-}
diff --git a/contrib/bc/dc/stack.c b/contrib/bc/dc/stack.c
deleted file mode 100644
index 1d8a9bf..0000000
--- a/contrib/bc/dc/stack.c
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
- * implement stack functions for dc
- *
- * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you can either send email to this
- * program's author (see below) or write to:
- *
- * The Free Software Foundation, Inc.
- * 59 Temple Place, Suite 330
- * Boston, MA 02111 USA
- */
-
-/* This module is the only one that knows what stacks (both the
- * regular evaluation stack and the named register stacks)
- * look like.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-#include "dc.h"
-#include "dc-proto.h"
-#include "dc-regdef.h"
-
-/* an oft-used error message: */
-#define Empty_Stack fprintf(stderr, "%s: stack empty\n", progname)
-
-
-/* simple linked-list implementaion suffices: */
-struct dc_list {
- dc_data value;
- struct dc_array *array; /* opaque */
- struct dc_list *link;
-};
-typedef struct dc_list dc_list;
-
-/* the anonymous evaluation stack */
-static dc_list *dc_stack=NULL;
-
-/* the named register stacks */
-static dc_list *dc_register[DC_REGCOUNT];
-
-
-/* allocate a new dc_list item */
-static dc_list *
-dc_alloc DC_DECLVOID()
-{
- dc_list *result;
-
- result = dc_malloc(sizeof *result);
- result->value.dc_type = DC_UNINITIALIZED;
- result->array = NULL;
- result->link = NULL;
- return result;
-}
-
-
-/* check that there are two numbers on top of the stack,
- * then call op with the popped numbers. Construct a dc_data
- * value from the dc_num returned by op and push it
- * on the stack.
- * If the op call doesn't return DC_SUCCESS, then leave the stack
- * unmodified.
- */
-void
-dc_binop DC_DECLARG((op, kscale))
- int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *)) DC_DECLSEP
- int kscale DC_DECLEND
-{
- dc_data a;
- dc_data b;
- dc_data r;
-
- if (!dc_stack || !dc_stack->link){
- Empty_Stack;
- return;
- }
- if (dc_stack->value.dc_type!=DC_NUMBER
- || dc_stack->link->value.dc_type!=DC_NUMBER){
- fprintf(stderr, "%s: non-numeric value\n", progname);
- return;
- }
- (void)dc_pop(&b);
- (void)dc_pop(&a);
- if ((*op)(a.v.number, b.v.number, kscale, &r.v.number) == DC_SUCCESS){
- r.dc_type = DC_NUMBER;
- dc_push(r);
- dc_free_num(&a.v.number);
- dc_free_num(&b.v.number);
- }else{
- /* op failed; restore the stack */
- dc_push(a);
- dc_push(b);
- }
-}
-
-/* check that there are two numbers on top of the stack,
- * then call op with the popped numbers. Construct two dc_data
- * values from the dc_num's returned by op and push them
- * on the stack.
- * If the op call doesn't return DC_SUCCESS, then leave the stack
- * unmodified.
- */
-void
-dc_binop2 DC_DECLARG((op, kscale))
- int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *, dc_num *)) DC_DECLSEP
- int kscale DC_DECLEND
-{
- dc_data a;
- dc_data b;
- dc_data r1;
- dc_data r2;
-
- if (!dc_stack || !dc_stack->link){
- Empty_Stack;
- return;
- }
- if (dc_stack->value.dc_type!=DC_NUMBER
- || dc_stack->link->value.dc_type!=DC_NUMBER){
- fprintf(stderr, "%s: non-numeric value\n", progname);
- return;
- }
- (void)dc_pop(&b);
- (void)dc_pop(&a);
- if ((*op)(a.v.number, b.v.number, kscale,
- &r1.v.number, &r2.v.number) == DC_SUCCESS){
- r1.dc_type = DC_NUMBER;
- dc_push(r1);
- r2.dc_type = DC_NUMBER;
- dc_push(r2);
- dc_free_num(&a.v.number);
- dc_free_num(&b.v.number);
- }else{
- /* op failed; restore the stack */
- dc_push(a);
- dc_push(b);
- }
-}
-
-/* check that there are two numbers on top of the stack,
- * then call dc_compare with the popped numbers.
- * Return negative, zero, or positive based on the ordering
- * of the two numbers.
- */
-int
-dc_cmpop DC_DECLVOID()
-{
- int result;
- dc_data a;
- dc_data b;
-
- if (!dc_stack || !dc_stack->link){
- Empty_Stack;
- return 0;
- }
- if (dc_stack->value.dc_type!=DC_NUMBER
- || dc_stack->link->value.dc_type!=DC_NUMBER){
- fprintf(stderr, "%s: non-numeric value\n", progname);
- return 0;
- }
- (void)dc_pop(&b);
- (void)dc_pop(&a);
- result = dc_compare(b.v.number, a.v.number);
- dc_free_num(&a.v.number);
- dc_free_num(&b.v.number);
- return result;
-}
-
-/* check that there are three numbers on top of the stack,
- * then call op with the popped numbers. Construct a dc_data
- * value from the dc_num returned by op and push it
- * on the stack.
- * If the op call doesn't return DC_SUCCESS, then leave the stack
- * unmodified.
- */
-void
-dc_triop DC_DECLARG((op, kscale))
- int (*op)DC_PROTO((dc_num, dc_num, dc_num, int, dc_num *)) DC_DECLSEP
- int kscale DC_DECLEND
-{
- dc_data a;
- dc_data b;
- dc_data c;
- dc_data r;
-
- if (!dc_stack || !dc_stack->link || !dc_stack->link->link){
- Empty_Stack;
- return;
- }
- if (dc_stack->value.dc_type!=DC_NUMBER
- || dc_stack->link->value.dc_type!=DC_NUMBER
- || dc_stack->link->link->value.dc_type!=DC_NUMBER){
- fprintf(stderr, "%s: non-numeric value\n", progname);
- return;
- }
- (void)dc_pop(&c);
- (void)dc_pop(&b);
- (void)dc_pop(&a);
- if ((*op)(a.v.number, b.v.number, c.v.number,
- kscale, &r.v.number) == DC_SUCCESS){
- r.dc_type = DC_NUMBER;
- dc_push(r);
- dc_free_num(&a.v.number);
- dc_free_num(&b.v.number);
- dc_free_num(&c.v.number);
- }else{
- /* op failed; restore the stack */
- dc_push(a);
- dc_push(b);
- dc_push(c);
- }
-}
-
-
-/* initialize the register stacks to their initial values */
-void
-dc_register_init DC_DECLVOID()
-{
- int i;
-
- for (i=0; i<DC_REGCOUNT; ++i)
- dc_register[i] = NULL;
-}
-
-/* clear the evaluation stack */
-void
-dc_clear_stack DC_DECLVOID()
-{
- dc_list *n;
- dc_list *t;
-
- for (n=dc_stack; n; n=t){
- t = n->link;
- if (n->value.dc_type == DC_NUMBER)
- dc_free_num(&n->value.v.number);
- else if (n->value.dc_type == DC_STRING)
- dc_free_str(&n->value.v.string);
- else
- dc_garbage("in stack", -1);
- dc_array_free(n->array);
- free(n);
- }
- dc_stack = NULL;
-}
-
-/* push a value onto the evaluation stack */
-void
-dc_push DC_DECLARG((value))
- dc_data value DC_DECLEND
-{
- dc_list *n = dc_alloc();
-
- if (value.dc_type!=DC_NUMBER && value.dc_type!=DC_STRING)
- dc_garbage("in data being pushed", -1);
- n->value = value;
- n->link = dc_stack;
- dc_stack = n;
-}
-
-/* push a value onto the named register stack */
-void
-dc_register_push DC_DECLARG((stackid, value))
- int stackid DC_DECLSEP
- dc_data value DC_DECLEND
-{
- dc_list *n = dc_alloc();
-
- stackid = regmap(stackid);
- n->value = value;
- n->link = dc_register[stackid];
- dc_register[stackid] = n;
-}
-
-/* set *result to the value on the top of the evaluation stack */
-/* The caller is responsible for duplicating the value if it
- * is to be maintained as anything more than a transient identity.
- *
- * DC_FAIL is returned if the stack is empty (and *result unchanged),
- * DC_SUCCESS is returned otherwise
- */
-int
-dc_top_of_stack DC_DECLARG((result))
- dc_data *result DC_DECLEND
-{
- if (!dc_stack){
- Empty_Stack;
- return DC_FAIL;
- }
- if (dc_stack->value.dc_type!=DC_NUMBER
- && dc_stack->value.dc_type!=DC_STRING)
- dc_garbage("at top of stack", -1);
- *result = dc_stack->value;
- return DC_SUCCESS;
-}
-
-/* set *result to a dup of the value on the top of the named register stack */
-/*
- * DC_FAIL is returned if the named stack is empty (and *result unchanged),
- * DC_SUCCESS is returned otherwise
- */
-int
-dc_register_get DC_DECLARG((regid, result))
- int regid DC_DECLSEP
- dc_data *result DC_DECLEND
-{
- dc_list *r;
-
- regid = regmap(regid);
- r = dc_register[regid];
- if ( ! r ){
- fprintf(stderr, "%s: register ", progname);
- dc_show_id(stderr, regid, " is empty\n");
- return DC_FAIL;
- }
- *result = dc_dup(r->value);
- return DC_SUCCESS;
-}
-
-/* set the top of the named register stack to the indicated value */
-/* If the named stack is empty, craft a stack entry to enter the
- * value into.
- */
-void
-dc_register_set DC_DECLARG((regid, value))
- int regid DC_DECLSEP
- dc_data value DC_DECLEND
-{
- dc_list *r;
-
- regid = regmap(regid);
- r = dc_register[regid];
- if ( ! r )
- dc_register[regid] = dc_alloc();
- else if (r->value.dc_type == DC_NUMBER)
- dc_free_num(&r->value.v.number);
- else if (r->value.dc_type == DC_STRING)
- dc_free_str(&r->value.v.string);
- else if (r->value.dc_type == DC_UNINITIALIZED)
- ;
- else
- dc_garbage("", regid);
- dc_register[regid]->value = value;
-}
-
-/* pop from the evaluation stack
- *
- * DC_FAIL is returned if the stack is empty (and *result unchanged),
- * DC_SUCCESS is returned otherwise
- */
-int
-dc_pop DC_DECLARG((result))
- dc_data *result DC_DECLEND
-{
- dc_list *r;
-
- r = dc_stack;
- if (!r){
- Empty_Stack;
- return DC_FAIL;
- }
- if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING)
- dc_garbage("at top of stack", -1);
- *result = r->value;
- dc_stack = r->link;
- dc_array_free(r->array);
- free(r);
- return DC_SUCCESS;
-}
-
-/* pop from the named register stack
- *
- * DC_FAIL is returned if the named stack is empty (and *result unchanged),
- * DC_SUCCESS is returned otherwise
- */
-int
-dc_register_pop DC_DECLARG((stackid, result))
- int stackid DC_DECLSEP
- dc_data *result DC_DECLEND
-{
- dc_list *r;
-
- stackid = regmap(stackid);
- r = dc_register[stackid];
- if (!r){
- fprintf(stderr, "%s: stack register ", progname);
- dc_show_id(stderr, stackid, " is empty\n");
- return DC_FAIL;
- }
- if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING)
- dc_garbage(" stack", stackid);
- *result = r->value;
- dc_register[stackid] = r->link;
- dc_array_free(r->array);
- free(r);
- return DC_SUCCESS;
-}
-
-
-/* tell how many entries are currently on the evaluation stack */
-int
-dc_tell_stackdepth DC_DECLVOID()
-{
- dc_list *n;
- int depth=0;
-
- for (n=dc_stack; n; n=n->link)
- ++depth;
- return depth;
-}
-
-
-/* return the length of the indicated data value;
- * if discard_p is DC_TOSS, the deallocate the value when done
- *
- * The definition of a datum's length is deligated to the
- * appropriate module.
- */
-int
-dc_tell_length DC_DECLARG((value, discard_p))
- dc_data value DC_DECLSEP
- dc_discard discard_p DC_DECLEND
-{
- int length;
-
- if (value.dc_type == DC_NUMBER){
- length = dc_numlen(value.v.number);
- if (discard_p == DC_TOSS)
- dc_free_num(&value.v.number);
- } else if (value.dc_type == DC_STRING) {
- length = dc_strlen(value.v.string);
- if (discard_p == DC_TOSS)
- dc_free_str(&value.v.string);
- } else {
- dc_garbage("in tell_length", -1);
- /*NOTREACHED*/
- length = 0; /*just to suppress spurious compiler warnings*/
- }
- return length;
-}
-
-
-
-/* print out all of the values on the evaluation stack */
-void
-dc_printall DC_DECLARG((obase))
- int obase DC_DECLEND
-{
- dc_list *n;
-
- for (n=dc_stack; n; n=n->link)
- dc_print(n->value, obase, DC_WITHNL, DC_KEEP);
-}
-
-
-
-
-/* get the current array head for the named array */
-struct dc_array *
-dc_get_stacked_array DC_DECLARG((array_id))
- int array_id DC_DECLEND
-{
- dc_list *r = dc_register[regmap(array_id)];
- return r ? r->array : NULL;
-}
-
-/* set the current array head for the named array */
-void
-dc_set_stacked_array DC_DECLARG((array_id, new_head))
- int array_id DC_DECLSEP
- struct dc_array *new_head DC_DECLEND
-{
- dc_list *r;
-
- array_id = regmap(array_id);
- r = dc_register[array_id];
- if ( ! r )
- r = dc_register[array_id] = dc_alloc();
- r->array = new_head;
-}
diff --git a/contrib/bc/dc/string.c b/contrib/bc/dc/string.c
deleted file mode 100644
index a7f79a4..0000000
--- a/contrib/bc/dc/string.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * implement string functions for dc
- *
- * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you can either send email to this
- * program's author (see below) or write to:
- *
- * The Free Software Foundation, Inc.
- * 59 Temple Place, Suite 330
- * Boston, MA 02111 USA
- */
-
-/* This should be the only module that knows the internals of type dc_string */
-
-#include "config.h"
-
-#include <stdio.h>
-#ifdef HAVE_STDDEF_H
-# include <stddef.h> /* ptrdiff_t */
-#else
-# define ptrdiff_t size_t
-#endif
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-# include <string.h> /* memcpy */
-#else
-# ifdef HAVE_MEMORY_H
-# include <memory.h> /* memcpy, maybe */
-# else
-# ifdef HAVE_STRINGS_H
-# include <strings.h> /* memcpy, maybe */
-# endif
-# endif
-#endif
-#include "dc.h"
-#include "dc-proto.h"
-
-/* here is the completion of the dc_string type: */
-struct dc_string {
- char *s_ptr; /* pointer to base of string */
- size_t s_len; /* length of counted string */
- int s_refs; /* reference count to cut down on memory use by duplicates */
-};
-
-
-/* return a duplicate of the string in the passed value */
-/* The mismatched data types forces the caller to deal with
- * bad dc_type'd dc_data values, and makes it more convenient
- * for the caller to not have to do the grunge work of setting
- * up a dc_type result.
- */
-dc_data
-dc_dup_str DC_DECLARG((value))
- dc_str value DC_DECLEND
-{
- dc_data result;
-
- ++value->s_refs;
- result.v.string = value;
- result.dc_type = DC_STRING;
- return result;
-}
-
-/* free an instance of a dc_str value */
-void
-dc_free_str DC_DECLARG((value))
- dc_str *value DC_DECLEND
-{
- struct dc_string *string = *value;
-
- if (--string->s_refs < 1){
- free(string->s_ptr);
- free(string);
- }
-}
-
-/* Output a dc_str value.
- * Add a trailing newline if "newline" is set.
- * Free the value after use if discard_flag is set.
- */
-void
-dc_out_str DC_DECLARG((value, newline, discard_flag))
- dc_str value DC_DECLSEP
- dc_newline newline DC_DECLSEP
- dc_discard discard_flag DC_DECLEND
-{
- fwrite(value->s_ptr, value->s_len, sizeof *value->s_ptr, stdout);
- if (newline == DC_WITHNL)
- putchar('\n');
- if (discard_flag == DC_TOSS)
- dc_free_str(&value);
-}
-
-/* make a copy of a string (base s, length len)
- * into a dc_str value; return a dc_data result
- * with this value
- */
-dc_data
-dc_makestring DC_DECLARG((s, len))
- const char *s DC_DECLSEP
- size_t len DC_DECLEND
-{
- dc_data result;
- struct dc_string *string;
-
- string = dc_malloc(sizeof *string);
- string->s_ptr = dc_malloc(len+1);
- memcpy(string->s_ptr, s, len);
- string->s_ptr[len] = '\0'; /* nul terminated for those who need it */
- string->s_len = len;
- string->s_refs = 1;
- result.v.string = string;
- result.dc_type = DC_STRING;
- return result;
-}
-
-/* read a dc_str value from FILE *fp;
- * if ldelim == rdelim, then read until a ldelim char or EOF is reached;
- * if ldelim != rdelim, then read until a matching rdelim for the
- * (already eaten) first ldelim is read.
- * Return a dc_data result with the dc_str value as its contents.
- */
-dc_data
-dc_readstring DC_DECLARG((fp, ldelim, rdelim))
- FILE *fp DC_DECLSEP
- int ldelim DC_DECLSEP
- int rdelim DC_DECLEND
-{
- static char *line_buf = NULL; /* a buffer to build the string in */
- static size_t buflen = 0; /* the current size of line_buf */
- int depth=1;
- int c;
- char *p;
- const char *end;
-
- if (!line_buf){
- /* initial buflen should be large enough to handle most cases */
- buflen = 2016;
- line_buf = dc_malloc(buflen);
- }
- p = line_buf;
- end = line_buf + buflen;
- for (;;){
- c = getc(fp);
- if (c == EOF)
- break;
- else if (c == rdelim && --depth < 1)
- break;
- else if (c == ldelim)
- ++depth;
- if (p >= end){
- ptrdiff_t offset = p - line_buf;
- /* buflen increment should be big enough
- * to avoid execessive reallocs:
- */
- buflen += 2048;
- line_buf = realloc(line_buf, buflen);
- if (!line_buf)
- dc_memfail();
- p = line_buf + offset;
- end = line_buf + buflen;
- }
- *p++ = c;
- }
- return dc_makestring(line_buf, (size_t)(p-line_buf));
-}
-
-/* return the base pointer of the dc_str value;
- * This function is needed because no one else knows what dc_str
- * looks like.
- */
-const char *
-dc_str2charp DC_DECLARG((value))
- dc_str value DC_DECLEND
-{
- return value->s_ptr;
-}
-
-/* return the length of the dc_str value;
- * This function is needed because no one else knows what dc_str
- * looks like, and strlen(dc_str2charp(value)) won't work
- * if there's an embedded '\0'.
- */
-size_t
-dc_strlen DC_DECLARG((value))
- dc_str value DC_DECLEND
-{
- return value->s_len;
-}
-
-
-/* initialize the strings subsystem */
-void
-dc_string_init DC_DECLVOID()
-{
- /* nothing to do for this implementation */
-}
diff --git a/contrib/bc/doc/Makefile.am b/contrib/bc/doc/Makefile.am
deleted file mode 100644
index a729cee..0000000
--- a/contrib/bc/doc/Makefile.am
+++ /dev/null
@@ -1,12 +0,0 @@
-## Process this file with automake to produce Makefile.in
-
-info_TEXINFOS = bc.texi dc.texi
-MAKEINFO = makeinfo --no-split
-
-MAINTAINERCLEANFILES = Makefile.in
-
-# FIXME: remove this when automake has been fixed to include these
-# files automatically
-EXTRA_DIST = bc.1 dc.1
-
-man_MANS = bc.1 dc.1
diff --git a/contrib/bc/doc/Makefile.in b/contrib/bc/doc/Makefile.in
deleted file mode 100644
index 840d007..0000000
--- a/contrib/bc/doc/Makefile.in
+++ /dev/null
@@ -1,355 +0,0 @@
-# Makefile.in generated automatically by automake 1.4 from Makefile.am
-
-# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-
-SHELL = @SHELL@
-
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
-VPATH = @srcdir@
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-
-bindir = @bindir@
-sbindir = @sbindir@
-libexecdir = @libexecdir@
-datadir = @datadir@
-sysconfdir = @sysconfdir@
-sharedstatedir = @sharedstatedir@
-localstatedir = @localstatedir@
-libdir = @libdir@
-infodir = @infodir@
-mandir = @mandir@
-includedir = @includedir@
-oldincludedir = /usr/include
-
-DESTDIR =
-
-pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-
-top_builddir = ..
-
-ACLOCAL = @ACLOCAL@
-AUTOCONF = @AUTOCONF@
-AUTOMAKE = @AUTOMAKE@
-AUTOHEADER = @AUTOHEADER@
-
-INSTALL = @INSTALL@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-transform = @program_transform_name@
-
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-CC = @CC@
-LEX = @LEX@
-PACKAGE = @PACKAGE@
-RANLIB = @RANLIB@
-READLINELIB = @READLINELIB@
-VERSION = @VERSION@
-YACC = @YACC@
-
-info_TEXINFOS = bc.texi dc.texi
-MAKEINFO = makeinfo --no-split
-
-MAINTAINERCLEANFILES = Makefile.in
-
-# FIXME: remove this when automake has been fixed to include these
-# files automatically
-EXTRA_DIST = bc.1 dc.1
-
-man_MANS = bc.1 dc.1
-mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
-CONFIG_HEADER = ../config.h
-CONFIG_CLEAN_FILES =
-TEXI2DVI = texi2dvi
-INFO_DEPS = bc.info dc.info
-DVIS = bc.dvi dc.dvi
-TEXINFOS = bc.texi dc.texi
-man1dir = $(mandir)/man1
-MANS = $(man_MANS)
-
-NROFF = nroff
-DIST_COMMON = Makefile.am Makefile.in texinfo.tex
-
-
-DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-
-TAR = tar
-GZIP_ENV = --best
-all: all-redirect
-.SUFFIXES:
-.SUFFIXES: .dvi .info .ps .texi .texinfo .txi
-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
- cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps doc/Makefile
-
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
- cd $(top_builddir) \
- && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
-
-
-bc.info: bc.texi
-bc.dvi: bc.texi
-
-
-dc.info: dc.texi
-dc.dvi: dc.texi
-
-
-DVIPS = dvips
-
-.texi.info:
- @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9]
- cd $(srcdir) \
- && $(MAKEINFO) `echo $< | sed 's,.*/,,'`
-
-.texi.dvi:
- TEXINPUTS=.:$$TEXINPUTS \
- MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $<
-
-.texi:
- @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9]
- cd $(srcdir) \
- && $(MAKEINFO) `echo $< | sed 's,.*/,,'`
-
-.texinfo.info:
- @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9]
- cd $(srcdir) \
- && $(MAKEINFO) `echo $< | sed 's,.*/,,'`
-
-.texinfo:
- @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9]
- cd $(srcdir) \
- && $(MAKEINFO) `echo $< | sed 's,.*/,,'`
-
-.texinfo.dvi:
- TEXINPUTS=.:$$TEXINPUTS \
- MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $<
-
-.txi.info:
- @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9]
- cd $(srcdir) \
- && $(MAKEINFO) `echo $< | sed 's,.*/,,'`
-
-.txi.dvi:
- TEXINPUTS=.:$$TEXINPUTS \
- MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $<
-
-.txi:
- @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9]
- cd $(srcdir) \
- && $(MAKEINFO) `echo $< | sed 's,.*/,,'`
-.dvi.ps:
- $(DVIPS) $< -o $@
-
-install-info-am: $(INFO_DEPS)
- @$(NORMAL_INSTALL)
- $(mkinstalldirs) $(DESTDIR)$(infodir)
- @list='$(INFO_DEPS)'; \
- for file in $$list; do \
- d=$(srcdir); \
- for ifile in `cd $$d && echo $$file $$file-[0-9] $$file-[0-9][0-9]`; do \
- if test -f $$d/$$ifile; then \
- echo " $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile"; \
- $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile; \
- else : ; fi; \
- done; \
- done
- @$(POST_INSTALL)
- @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \
- list='$(INFO_DEPS)'; \
- for file in $$list; do \
- echo " install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file";\
- install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file || :;\
- done; \
- else : ; fi
-
-uninstall-info:
- $(PRE_UNINSTALL)
- @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \
- ii=yes; \
- else ii=; fi; \
- list='$(INFO_DEPS)'; \
- for file in $$list; do \
- test -z "$ii" \
- || install-info --info-dir=$(DESTDIR)$(infodir) --remove $$file; \
- done
- @$(NORMAL_UNINSTALL)
- list='$(INFO_DEPS)'; \
- for file in $$list; do \
- (cd $(DESTDIR)$(infodir) && rm -f $$file $$file-[0-9] $$file-[0-9][0-9]); \
- done
-
-dist-info: $(INFO_DEPS)
- list='$(INFO_DEPS)'; \
- for base in $$list; do \
- d=$(srcdir); \
- for file in `cd $$d && eval echo $$base*`; do \
- test -f $(distdir)/$$file \
- || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
- || cp -p $$d/$$file $(distdir)/$$file; \
- done; \
- done
-
-mostlyclean-aminfo:
- -rm -f bc.aux bc.cp bc.cps bc.dvi bc.fn bc.fns bc.ky bc.kys bc.ps \
- bc.log bc.pg bc.toc bc.tp bc.tps bc.vr bc.vrs bc.op bc.tr \
- bc.cv bc.cn dc.aux dc.cp dc.cps dc.dvi dc.fn dc.fns dc.ky \
- dc.kys dc.ps dc.log dc.pg dc.toc dc.tp dc.tps dc.vr dc.vrs \
- dc.op dc.tr dc.cv dc.cn
-
-clean-aminfo:
-
-distclean-aminfo:
-
-maintainer-clean-aminfo:
- cd $(srcdir) && for i in $(INFO_DEPS); do \
- rm -f $$i; \
- if test "`echo $$i-[0-9]*`" != "$$i-[0-9]*"; then \
- rm -f $$i-[0-9]*; \
- fi; \
- done
-
-install-man1:
- $(mkinstalldirs) $(DESTDIR)$(man1dir)
- @list='$(man1_MANS)'; \
- l2='$(man_MANS)'; for i in $$l2; do \
- case "$$i" in \
- *.1*) list="$$list $$i" ;; \
- esac; \
- done; \
- for i in $$list; do \
- if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
- else file=$$i; fi; \
- ext=`echo $$i | sed -e 's/^.*\\.//'`; \
- inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
- inst=`echo $$inst | sed '$(transform)'`.$$ext; \
- echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \
- $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \
- done
-
-uninstall-man1:
- @list='$(man1_MANS)'; \
- l2='$(man_MANS)'; for i in $$l2; do \
- case "$$i" in \
- *.1*) list="$$list $$i" ;; \
- esac; \
- done; \
- for i in $$list; do \
- ext=`echo $$i | sed -e 's/^.*\\.//'`; \
- inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
- inst=`echo $$inst | sed '$(transform)'`.$$ext; \
- echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \
- rm -f $(DESTDIR)$(man1dir)/$$inst; \
- done
-install-man: $(MANS)
- @$(NORMAL_INSTALL)
- $(MAKE) $(AM_MAKEFLAGS) install-man1
-uninstall-man:
- @$(NORMAL_UNINSTALL)
- $(MAKE) $(AM_MAKEFLAGS) uninstall-man1
-tags: TAGS
-TAGS:
-
-
-distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
-
-subdir = doc
-
-distdir: $(DISTFILES)
- @for file in $(DISTFILES); do \
- d=$(srcdir); \
- if test -d $$d/$$file; then \
- cp -pr $$/$$file $(distdir)/$$file; \
- else \
- test -f $(distdir)/$$file \
- || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
- || cp -p $$d/$$file $(distdir)/$$file || :; \
- fi; \
- done
- $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-info
-info-am: $(INFO_DEPS)
-info: info-am
-dvi-am: $(DVIS)
-dvi: dvi-am
-check-am: all-am
-check: check-am
-installcheck-am:
-installcheck: installcheck-am
-install-exec-am:
-install-exec: install-exec-am
-
-install-data-am: install-info-am install-man
-install-data: install-data-am
-
-install-am: all-am
- @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-install: install-am
-uninstall-am: uninstall-info uninstall-man
-uninstall: uninstall-am
-all-am: Makefile $(INFO_DEPS) $(MANS)
-all-redirect: all-am
-install-strip:
- $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
-installdirs:
- $(mkinstalldirs) $(DESTDIR)$(infodir) $(DESTDIR)$(mandir)/man1
-
-
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
- -rm -f Makefile $(CONFIG_CLEAN_FILES)
- -rm -f config.cache config.log stamp-h stamp-h[0-9]*
-
-maintainer-clean-generic:
- -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
-mostlyclean-am: mostlyclean-aminfo mostlyclean-generic
-
-mostlyclean: mostlyclean-am
-
-clean-am: clean-aminfo clean-generic mostlyclean-am
-
-clean: clean-am
-
-distclean-am: distclean-aminfo distclean-generic clean-am
-
-distclean: distclean-am
-
-maintainer-clean-am: maintainer-clean-aminfo maintainer-clean-generic \
- distclean-am
- @echo "This command is intended for maintainers to use;"
- @echo "it deletes files that may require special tools to rebuild."
-
-maintainer-clean: maintainer-clean-am
-
-.PHONY: install-info-am uninstall-info mostlyclean-aminfo \
-distclean-aminfo clean-aminfo maintainer-clean-aminfo install-man1 \
-uninstall-man1 install-man uninstall-man tags distdir info-am info \
-dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
-install-exec install-data-am install-data install-am install \
-uninstall-am uninstall all-redirect all-am all installdirs \
-mostlyclean-generic distclean-generic clean-generic \
-maintainer-clean-generic clean mostlyclean distclean maintainer-clean
-
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/contrib/bc/doc/bc.1 b/contrib/bc/doc/bc.1
deleted file mode 100644
index bb19594..0000000
--- a/contrib/bc/doc/bc.1
+++ /dev/null
@@ -1,793 +0,0 @@
-.\"
-.\" bc.1 - the *roff document processor source for the bc manual
-.\"
-.\" This file is part of GNU bc.
-.\" Copyright (C) 1991-1994, 1997, 2000 Free Software Foundation, Inc.
-.\"
-.\" This program is free software; you can redistribute it and/or modify
-.\" it under the terms of the GNU General Public License as published by
-.\" the Free Software Foundation; either version 2 of the License , or
-.\" (at your option) any later version.
-.\"
-.\" This program is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public License
-.\" along with this program; see the file COPYING. If not, write to:
-.\" The Free Software Foundation, Inc.
-.\" 59 Temple Place, Suite 330
-.\" Boston, MA 02111 USA
-.\"
-.\" You may contact the author by:
-.\" e-mail: philnelson@acm.org
-.\" us-mail: Philip A. Nelson
-.\" Computer Science Department, 9062
-.\" Western Washington University
-.\" Bellingham, WA 98226-9062
-.\"
-.\" $FreeBSD$
-.\"
-.TH bc 1 .\" "Command Manual" v1.06 "Sept 12, 2000"
-.SH NAME
-bc - An arbitrary precision calculator language
-.SH SYNTAX
-\fBbc\fR [ \fB-hlwsqv\fR ] [long-options] [ \fI file ...\fR ]
-.SH VERSION
-This man page documents GNU bc version 1.06.
-.SH DESCRIPTION
-\fBbc\fR is a language that supports arbitrary precision numbers
-with interactive execution of statements. There are some similarities
-in the syntax to the C programming language.
-A standard math library is available by command line option.
-If requested, the math library is defined before processing any files.
-\fBbc\fR starts by processing code from all the files listed
-on the command line in the order listed. After all files have been
-processed, \fBbc\fR reads from the standard input. All code is
-executed as it is read. (If a file contains a command to halt the
-processor, \fBbc\fR will never read from the standard input.)
-.PP
-This version of \fBbc\fR contains several extensions beyond
-traditional \fBbc\fR implementations and the POSIX draft standard.
-Command line options can cause these extensions to print a warning
-or to be rejected. This
-document describes the language accepted by this processor.
-Extensions will be identified as such.
-.SS OPTIONS
-.IP "-h, --help"
-Print the usage and exit.
-.IP "-i, --interactive"
-Force interactive mode.
-.IP "-l, --mathlib"
-Define the standard math library.
-.IP "-w, --warn"
-Give warnings for extensions to POSIX \fBbc\fR.
-.IP "-s, --standard"
-Process exactly the POSIX \fBbc\fR language.
-.IP "-q, --quiet"
-Do not print the normal GNU bc welcome.
-.IP "-v, --version"
-Print the version number and copyright and quit.
-.SS NUMBERS
-The most basic element in \fBbc\fR is the number. Numbers are
-arbitrary precision numbers. This precision is both in the integer
-part and the fractional part. All numbers are represented internally
-in decimal and all computation is done in decimal. (This version
-truncates results from divide and multiply operations.) There are two
-attributes of numbers, the length and the scale. The length is the
-total number of significant decimal digits in a number and the scale
-is the total number of decimal digits after the decimal point. For
-example:
-.nf
-.RS
- .000001 has a length of 6 and scale of 6.
- 1935.000 has a length of 7 and a scale of 3.
-.RE
-.fi
-.SS VARIABLES
-Numbers are stored in two types of variables, simple variables and
-arrays. Both simple variables and array variables are named. Names
-begin with a letter followed by any number of letters, digits and
-underscores. All letters must be lower case. (Full alpha-numeric
-names are an extension. In POSIX \fBbc\fR all names are a single
-lower case letter.) The type of variable is clear by the context
-because all array variable names will be followed by brackets ([]).
-.PP
-There are four special variables, \fBscale, ibase, obase,\fR and
-\fBlast\fR. \fBscale\fR defines how some operations use digits after the
-decimal point. The default value of \fBscale\fR is 0. \fBibase\fR
-and \fBobase\fR define the conversion base for input and output
-numbers. The default for both input and output is base 10.
-\fBlast\fR (an extension) is a variable that has the value of the last
-printed number. These will be discussed in further detail where
-appropriate. All of these variables may have values assigned to them
-as well as used in expressions.
-.SS COMMENTS
-Comments in \fBbc\fR start with the characters \fB/*\fR and end with
-the characters \fB*/\fR. Comments may start anywhere and appear as a
-single space in the input. (This causes comments to delimit other
-input items. For example, a comment can not be found in the middle of
-a variable name.) Comments include any newlines (end of line) between
-the start and the end of the comment.
-.PP
-To support the use of scripts for \fBbc\fR, a single line comment has been
-added as an extension. A single line comment starts at a \fB#\fR
-character and continues to the next end of the line. The end of line
-character is not part of the comment and is processed normally.
-.SS EXPRESSIONS
-The numbers are manipulated by expressions and statements. Since
-the language was designed to be interactive, statements and expressions
-are executed as soon as possible. There is no "main" program. Instead,
-code is executed as it is encountered. (Functions, discussed in
-detail later, are defined when encountered.)
-.PP
-A simple expression is just a constant. \fBbc\fR converts constants
-into internal decimal numbers using the current input base, specified
-by the variable \fBibase\fR. (There is an exception in functions.)
-The legal values of \fBibase\fR are 2 through 16. Assigning a
-value outside this range to \fBibase\fR will result in a value of 2
-or 16. Input numbers may contain the characters 0-9 and A-F. (Note:
-They must be capitals. Lower case letters are variable names.)
-Single digit numbers always have the value of the digit regardless of
-the value of \fBibase\fR. (i.e. A = 10.) For multi-digit numbers,
-\fBbc\fR changes all input digits greater or equal to ibase to the
-value of \fBibase\fR-1. This makes the number \fBFFF\fR always be
-the largest 3 digit number of the input base.
-.PP
-Full expressions are similar to many other high level languages.
-Since there is only one kind of number, there are no rules for mixing
-types. Instead, there are rules on the scale of expressions. Every
-expression has a scale. This is derived from the scale of original
-numbers, the operation performed and in many cases, the value of the
-variable \fBscale\fR. Legal values of the variable \fBscale\fR are
-0 to the maximum number representable by a C integer.
-.PP
-In the following descriptions of legal expressions, "expr" refers to a
-complete expression and "var" refers to a simple or an array variable.
-A simple variable is just a
-.RS
-\fIname\fR
-.RE
-and an array variable is specified as
-.RS
-\fIname\fR[\fIexpr\fR]
-.RE
-Unless specifically
-mentioned the scale of the result is the maximum scale of the
-expressions involved.
-.IP "- expr"
-The result is the negation of the expression.
-.IP "++ var"
-The variable is incremented by one and the new value is the result of
-the expression.
-.IP "-- var"
-The variable
-is decremented by one and the new value is the result of the
-expression.
-.IP "var ++"
- The result of the expression is the value of
-the variable and then the variable is incremented by one.
-.IP "var --"
-The result of the expression is the value of the variable and then
-the variable is decremented by one.
-.IP "expr + expr"
-The result of the expression is the sum of the two expressions.
-.IP "expr - expr"
-The result of the expression is the difference of the two expressions.
-.IP "expr * expr"
-The result of the expression is the product of the two expressions.
-.IP "expr / expr"
-The result of the expression is the quotient of the two expressions.
-The scale of the result is the value of the variable \fBscale\fR.
-.IP "expr % expr"
-The result of the expression is the "remainder" and it is computed in the
-following way. To compute a%b, first a/b is computed to \fBscale\fR
-digits. That result is used to compute a-(a/b)*b to the scale of the
-maximum of \fBscale\fR+scale(b) and scale(a). If \fBscale\fR is set
-to zero and both expressions are integers this expression is the
-integer remainder function.
-.IP "expr ^ expr"
-The result of the expression is the value of the first raised to the
-second. The second expression must be an integer. (If the second
-expression is not an integer, a warning is generated and the
-expression is truncated to get an integer value.) The scale of the
-result is \fBscale\fR if the exponent is negative. If the exponent
-is positive the scale of the result is the minimum of the scale of the
-first expression times the value of the exponent and the maximum of
-\fBscale\fR and the scale of the first expression. (e.g. scale(a^b)
-= min(scale(a)*b, max( \fBscale,\fR scale(a))).) It should be noted
-that expr^0 will always return the value of 1.
-.IP "( expr )"
-This alters the standard precedence to force the evaluation of the
-expression.
-.IP "var = expr"
-The variable is assigned the value of the expression.
-.IP "var <op>= expr"
-This is equivalent to "var = var <op> expr" with the exception that
-the "var" part is evaluated only once. This can make a difference if
-"var" is an array.
-.PP
- Relational expressions are a special kind of expression
-that always evaluate to 0 or 1, 0 if the relation is false and 1 if
-the relation is true. These may appear in any legal expression.
-(POSIX bc requires that relational expressions are used only in if,
-while, and for statements and that only one relational test may be
-done in them.) The relational operators are
-.IP "expr1 < expr2"
-The result is 1 if expr1 is strictly less than expr2.
-.IP "expr1 <= expr2"
-The result is 1 if expr1 is less than or equal to expr2.
-.IP "expr1 > expr2"
-The result is 1 if expr1 is strictly greater than expr2.
-.IP "expr1 >= expr2"
-The result is 1 if expr1 is greater than or equal to expr2.
-.IP "expr1 == expr2"
-The result is 1 if expr1 is equal to expr2.
-.IP "expr1 != expr2"
-The result is 1 if expr1 is not equal to expr2.
-.PP
-Boolean operations are also legal. (POSIX \fBbc\fR does NOT have
-boolean operations). The result of all boolean operations are 0 and 1
-(for false and true) as in relational expressions. The boolean
-operators are:
-.IP "!expr"
-The result is 1 if expr is 0.
-.IP "expr && expr"
-The result is 1 if both expressions are non-zero.
-.IP "expr || expr"
-The result is 1 if either expression is non-zero.
-.PP
-The expression precedence is as follows: (lowest to highest)
-.nf
-.RS
-|| operator, left associative
-&& operator, left associative
-! operator, nonassociative
-Relational operators, left associative
-Assignment operator, right associative
-+ and - operators, left associative
-*, / and % operators, left associative
-^ operator, right associative
-unary - operator, nonassociative
-++ and -- operators, nonassociative
-.RE
-.fi
-.PP
-This precedence was chosen so that POSIX compliant \fBbc\fR programs
-will run correctly. This will cause the use of the relational and
-logical operators to have some unusual behavior when used with
-assignment expressions. Consider the expression:
-.RS
-a = 3 < 5
-.RE
-.PP
-Most C programmers would assume this would assign the result of "3 <
-5" (the value 1) to the variable "a". What this does in \fBbc\fR is
-assign the value 3 to the variable "a" and then compare 3 to 5. It is
-best to use parenthesis when using relational and logical operators
-with the assignment operators.
-.PP
-There are a few more special expressions that are provided in \fBbc\fR.
-These have to do with user defined functions and standard
-functions. They all appear as "\fIname\fB(\fIparameters\fB)\fR".
-See the section on functions for user defined functions. The standard
-functions are:
-.IP "length ( expression )"
-The value of the length function is the number of significant digits in the
-expression.
-.IP "read ( )"
-The read function (an extension) will read a number from the standard
-input, regardless of where the function occurs. Beware, this can
-cause problems with the mixing of data and program in the standard input.
-The best use for this function is in a previously written program that
-needs input from the user, but never allows program code to be input
-from the user. The value of the read function is the number read from
-the standard input using the current value of the variable
-\fBibase\fR for the conversion base.
-.IP "scale ( expression )"
-The value of the scale function is the number of digits after the decimal
-point in the expression.
-.IP "sqrt ( expression )"
-The value of the sqrt function is the square root of the expression. If
-the expression is negative, a run time error is generated.
-.SS STATEMENTS
-Statements (as in most algebraic languages) provide the sequencing of
-expression evaluation. In \fBbc\fR statements are executed "as soon
-as possible." Execution happens when a newline in encountered and
-there is one or more complete statements. Due to this immediate
-execution, newlines are very important in \fBbc\fR. In fact, both a
-semicolon and a newline are used as statement separators. An
-improperly placed newline will cause a syntax error. Because newlines
-are statement separators, it is possible to hide a newline by using
-the backslash character. The sequence "\e<nl>", where <nl> is the
-newline appears to \fBbc\fR as whitespace instead of a newline. A
-statement list is a series of statements separated by semicolons and
-newlines. The following is a list of \fBbc\fR statements and what
-they do: (Things enclosed in brackets ([]) are optional parts of the
-statement.)
-.IP "expression"
-This statement does one of two things. If the expression starts with
-"<variable> <assignment> ...", it is considered to be an assignment
-statement. If the expression is not an assignment statement, the
-expression is evaluated and printed to the output. After the number
-is printed, a newline is printed. For example, "a=1" is an assignment
-statement and "(a=1)" is an expression that has an embedded
-assignment. All numbers that are printed are printed in the base
-specified by the variable \fBobase\fR. The legal values for \fB
-obase\fR are 2 through BC_BASE_MAX. (See the section LIMITS.) For
-bases 2 through 16, the usual method of writing numbers is used. For
-bases greater than 16, \fBbc\fR uses a multi-character digit method
-of printing the numbers where each higher base digit is printed as a
-base 10 number. The multi-character digits are separated by spaces.
-Each digit contains the number of characters required to represent the
-base ten value of "obase-1". Since numbers are of arbitrary
-precision, some numbers may not be printable on a single output line.
-These long numbers will be split across lines using the "\e" as the
-last character on a line. The maximum number of characters printed
-per line is 70. Due to the interactive nature of \fBbc\fR, printing
-a number causes the side effect of assigning the printed value to the
-special variable \fBlast\fR. This allows the user to recover the
-last value printed without having to retype the expression that
-printed the number. Assigning to \fBlast\fR is legal and will
-overwrite the last printed value with the assigned value. The newly
-assigned value will remain until the next number is printed or another
-value is assigned to \fBlast\fR. (Some installations may allow the
-use of a single period (.) which is not part of a number as a short
-hand notation for for \fBlast\fR.)
-.IP "string"
-The string is printed to the output. Strings start with a double quote
-character and contain all characters until the next double quote character.
-All characters are take literally, including any newline. No newline
-character is printed after the string.
-.IP "\fBprint\fR list"
-The print statement (an extension) provides another method of output.
-The "list" is a list of strings and expressions separated by commas.
-Each string or expression is printed in the order of the list. No
-terminating newline is printed. Expressions are evaluated and their
-value is printed and assigned to the variable \fBlast\fR. Strings
-in the print statement are printed to the output and may contain
-special characters. Special characters start with the backslash
-character (\e). The special characters recognized by \fBbc\fR are
-"a" (alert or bell), "b" (backspace), "f" (form feed), "n" (newline),
-"r" (carriage return), "q" (double quote), "t" (tab), and "\e" (backslash).
-Any other character following the backslash will be ignored.
-.IP "{ statement_list }"
-This is the compound statement. It allows multiple statements to be
-grouped together for execution.
-.IP "\fBif\fR ( expression ) statement1 [\fBelse\fR statement2]"
-The if statement evaluates the expression and executes statement1 or
-statement2 depending on the value of the expression. If the expression
-is non-zero, statement1 is executed. If statement2 is present and
-the value of the expression is 0, then statement2 is executed. (The
-else clause is an extension.)
-.IP "\fBwhile\fR ( expression ) statement"
-The while statement will execute the statement while the expression
-is non-zero. It evaluates the expression before each execution of
-the statement. Termination of the loop is caused by a zero
-expression value or the execution of a break statement.
-.IP "\fBfor\fR ( [expression1] ; [expression2] ; [expression3] ) statement"
-The for statement controls repeated execution of the statement.
-Expression1 is evaluated before the loop. Expression2 is evaluated
-before each execution of the statement. If it is non-zero, the statement
-is evaluated. If it is zero, the loop is terminated. After each
-execution of the statement, expression3 is evaluated before the reevaluation
-of expression2. If expression1 or expression3 are missing, nothing is
-evaluated at the point they would be evaluated.
-If expression2 is missing, it is the same as substituting
-the value 1 for expression2. (The optional expressions are an
-extension. POSIX \fBbc\fR requires all three expressions.)
-The following is equivalent code for the for statement:
-.nf
-.RS
-expression1;
-while (expression2) {
- statement;
- expression3;
-}
-.RE
-.fi
-.IP "\fBbreak\fR"
-This statement causes a forced exit of the most recent enclosing while
-statement or for statement.
-.IP "\fBcontinue\fR"
-The continue statement (an extension) causes the most recent enclosing
-for statement to start the next iteration.
-.IP "\fBhalt\fR"
-The halt statement (an extension) is an executed statement that causes
-the \fBbc\fR processor to quit only when it is executed. For example,
-"if (0 == 1) halt" will not cause \fBbc\fR to terminate because the halt is
-not executed.
-.IP "\fBreturn\fR"
-Return the value 0 from a function. (See the section on functions.)
-.IP "\fBreturn\fR ( expression )"
-Return the value of the expression from a function. (See the section on
-functions.) As an extension, the parenthesis are not required.
-.SS PSEUDO STATEMENTS
-These statements are not statements in the traditional sense. They are
-not executed statements. Their function is performed at "compile" time.
-.IP "\fBlimits\fR"
-Print the local limits enforced by the local version of \fBbc\fR. This
-is an extension.
-.IP "\fBquit\fR"
-When the quit statement is read, the \fBbc\fR processor
-is terminated, regardless of where the quit statement is found. For
-example, "if (0 == 1) quit" will cause \fBbc\fR to terminate.
-.IP "\fBwarranty\fR"
-Print a longer warranty notice. This is an extension.
-.SS FUNCTIONS
-Functions provide a method of defining a computation that can be executed
-later. Functions in
-.B bc
-always compute a value and return it to the caller. Function definitions
-are "dynamic" in the sense that a function is undefined until a definition
-is encountered in the input. That definition is then used until another
-definition function for the same name is encountered. The new definition
-then replaces the older definition. A function is defined as follows:
-.nf
-.RS
-\fBdefine \fIname \fB( \fIparameters \fB) { \fInewline
-\fI auto_list statement_list \fB}\fR
-.RE
-.fi
-A function call is just an expression of the form
-"\fIname\fB(\fIparameters\fB)\fR".
-.PP
-Parameters are numbers or arrays (an extension). In the function definition,
-zero or more parameters are defined by listing their names separated by
-commas. Numbers are only call by value parameters. Arrays are only
-call by variable. Arrays are specified in the parameter definition by
-the notation "\fIname\fB[]\fR". In the function call, actual parameters
-are full expressions for number parameters. The same notation is used
-for passing arrays as for defining array parameters. The named array is
-passed by variable to the function. Since function definitions are dynamic,
-parameter numbers and types are checked when a function is called. Any
-mismatch in number or types of parameters will cause a runtime error.
-A runtime error will also occur for the call to an undefined function.
-.PP
-The \fIauto_list\fR is an optional list of variables that are for
-"local" use. The syntax of the auto list (if present) is "\fBauto
-\fIname\fR, ... ;". (The semicolon is optional.) Each \fIname\fR is
-the name of an auto variable. Arrays may be specified by using the
-same notation as used in parameters. These variables have their
-values pushed onto a stack at the start of the function. The
-variables are then initialized to zero and used throughout the
-execution of the function. At function exit, these variables are
-popped so that the original value (at the time of the function call)
-of these variables are restored. The parameters are really auto
-variables that are initialized to a value provided in the function
-call. Auto variables are different than traditional local variables
-because if function A calls function B, B may access function
-A's auto variables by just using the same name, unless function B has
-called them auto variables. Due to the fact that auto variables and
-parameters are pushed onto a stack, \fBbc\fR supports recursive functions.
-.PP
-The function body is a list of \fBbc\fR statements. Again, statements
-are separated by semicolons or newlines. Return statements cause the
-termination of a function and the return of a value. There are two
-versions of the return statement. The first form, "\fBreturn\fR", returns
-the value 0 to the calling expression. The second form,
-"\fBreturn ( \fIexpression \fB)\fR", computes the value of the expression
-and returns that value to the calling expression. There is an implied
-"\fBreturn (0)\fR" at the end of every function. This allows a function
-to terminate and return 0 without an explicit return statement.
-.PP
-Functions also change the usage of the variable \fBibase\fR. All
-constants in the function body will be converted using the value of
-\fBibase\fR at the time of the function call. Changes of \fBibase\fR
-will be ignored during the execution of the function except for the
-standard function \fBread\fR, which will always use the current value
-of \fBibase\fR for conversion of numbers.
-.PP
-As an extension, the format of the definition has been slightly relaxed.
-The standard requires the opening brace be on the same line as the
-\fBdefine\fR keyword and all other parts must be on following lines.
-This version of \fBbc\fR will allow any number of newlines before and
-after the opening brace of the function. For example, the following
-definitions are legal.
-.nf
-.RS
-\f(CW
-define d (n) { return (2*n); }
-define d (n)
- { return (2*n); }
-\fR
-.RE
-.fi
-.SS MATH LIBRARY
-If \fBbc\fR is invoked with the \fB-l\fR option, a math library is preloaded
-and the default scale is set to 20. The math functions will calculate their
-results to the scale set at the time of their call.
-The math library defines the following functions:
-.IP "s (\fIx\fR)"
-The sine of x, x is in radians.
-.IP "c (\fIx\fR)"
-The cosine of x, x is in radians.
-.IP "a (\fIx\fR)"
-The arctangent of x, arctangent returns radians.
-.IP "l (\fIx\fR)"
-The natural logarithm of x.
-.IP "e (\fIx\fR)"
-The exponential function of raising e to the value x.
-.IP "j (\fIn,x\fR)"
-The bessel function of integer order n of x.
-.SS EXAMPLES
-In /bin/sh, the following will assign the value of "pi" to the shell
-variable \fBpi\fR.
-.RS
-\f(CW
-pi=$(echo "scale=10; 4*a(1)" | bc -l)
-\fR
-.RE
-.PP
-The following is the definition of the exponential function used in the
-math library. This function is written in POSIX \fBbc\fR.
-.nf
-.RS
-\f(CW
-scale = 20
-
-/* Uses the fact that e^x = (e^(x/2))^2
- When x is small enough, we use the series:
- e^x = 1 + x + x^2/2! + x^3/3! + ...
-*/
-
-define e(x) {
- auto a, d, e, f, i, m, v, z
-
- /* Check the sign of x. */
- if (x<0) {
- m = 1
- x = -x
- }
-
- /* Precondition x. */
- z = scale;
- scale = 4 + z + .44*x;
- while (x > 1) {
- f += 1;
- x /= 2;
- }
-
- /* Initialize the variables. */
- v = 1+x
- a = x
- d = 1
-
- for (i=2; 1; i++) {
- e = (a *= x) / (d *= i)
- if (e == 0) {
- if (f>0) while (f--) v = v*v;
- scale = z
- if (m) return (1/v);
- return (v/1);
- }
- v += e
- }
-}
-\fR
-.RE
-.fi
-.PP
-The following is code that uses the extended features of \fBbc\fR to
-implement a simple program for calculating checkbook balances. This
-program is best kept in a file so that it can be used many times
-without having to retype it at every use.
-.nf
-.RS
-\f(CW
-scale=2
-print "\enCheck book program!\en"
-print " Remember, deposits are negative transactions.\en"
-print " Exit by a 0 transaction.\en\en"
-
-print "Initial balance? "; bal = read()
-bal /= 1
-print "\en"
-while (1) {
- "current balance = "; bal
- "transaction? "; trans = read()
- if (trans == 0) break;
- bal -= trans
- bal /= 1
-}
-quit
-\fR
-.RE
-.fi
-.PP
-The following is the definition of the recursive factorial function.
-.nf
-.RS
-\f(CW
-define f (x) {
- if (x <= 1) return (1);
- return (f(x-1) * x);
-}
-\fR
-.RE
-.fi
-.SS READLINE AND LIBEDIT OPTIONS
-GNU \fBbc\fR can be compiled (via a configure option) to use the GNU
-\fBreadline\fR input editor library or the BSD \fBlibedit\fR library.
-This allows the user to do editing of lines before sending them
-to \fBbc\fR. It also allows for a history of previous lines typed.
-When this option is selected, \fBbc\fR has one more special variable.
-This special variable, \fBhistory\fR is the number of lines of history
-retained. For \fBreadline\fR, a value of -1 means that an unlimited
-number of history lines are retained. Setting the value of
-\fBhistory\fR to a positive number restricts the number of history
-lines to the number given. The value of 0 disables the history
-feature. The default value is 100. For more information, read the
-user manuals for the GNU \fBreadline\fR, \fBhistory\fR and BSD \fBlibedit\fR
-libraries. One can not enable both \fBreadline\fR and \fBlibedit\fR
-at the same time.
-.SS DIFFERENCES
-This version of
-.B bc
-was implemented from the POSIX P1003.2/D11 draft and contains
-several differences and extensions relative to the draft and
-traditional implementations.
-It is not implemented in the traditional way using
-.I dc(1).
-This version is a single process which parses and runs a byte code
-translation of the program. There is an "undocumented" option (-c)
-that causes the program to output the byte code to
-the standard output instead of running it. It was mainly used for
-debugging the parser and preparing the math library.
-.PP
-A major source of differences is
-extensions, where a feature is extended to add more functionality and
-additions, where new features are added.
-The following is the list of differences and extensions.
-.IP "LANG environment"
-This version does not conform to the POSIX standard in the processing
-of the LANG environment variable and all environment variables starting
-with LC_.
-.IP names
-Traditional and POSIX
-.B bc
-have single letter names for functions, variables and arrays. They have
-been extended to be multi-character names that start with a letter and
-may contain letters, numbers and the underscore character.
-.IP Strings
-Strings are not allowed to contain NUL characters. POSIX says all characters
-must be included in strings.
-.IP last
-POSIX \fBbc\fR does not have a \fBlast\fR variable. Some implementations
-of \fBbc\fR use the period (.) in a similar way.
-.IP comparisons
-POSIX \fBbc\fR allows comparisons only in the if statement, the while
-statement, and the second expression of the for statement. Also, only
-one relational operation is allowed in each of those statements.
-.IP "if statement, else clause"
-POSIX \fBbc\fR does not have an else clause.
-.IP "for statement"
-POSIX \fBbc\fR requires all expressions to be present in the for statement.
-.IP "&&, ||, !"
-POSIX \fBbc\fR does not have the logical operators.
-.IP "read function"
-POSIX \fBbc\fR does not have a read function.
-.IP "print statement"
-POSIX \fBbc\fR does not have a print statement .
-.IP "continue statement"
-POSIX \fBbc\fR does not have a continue statement.
-.IP "return statement"
-POSIX \fBbc\fR requires parentheses around the return expression.
-.IP "array parameters"
-POSIX \fBbc\fR does not (currently) support array parameters in full.
-The POSIX grammar allows for arrays in function definitions, but does
-not provide a method to specify an array as an actual parameter. (This
-is most likely an oversight in the grammar.) Traditional implementations
-of \fBbc\fR have only call by value array parameters.
-.IP "function format"
-POSIX \fBbc\fR requires the opening brace on the same line as the
-\fBdefine\fR key word and the \fBauto\fR statement on the next line.
-.IP "=+, =-, =*, =/, =%, =^"
-POSIX \fBbc\fR does not require these "old style" assignment operators to
-be defined. This version may allow these "old style" assignments. Use
-the limits statement to see if the installed version supports them. If
-it does support the "old style" assignment operators, the statement
-"a =- 1" will decrement \fBa\fR by 1 instead of setting \fBa\fR to the
-value -1.
-.IP "spaces in numbers"
-Other implementations of \fBbc\fR allow spaces in numbers. For example,
-"x=1 3" would assign the value 13 to the variable x. The same statement
-would cause a syntax error in this version of \fBbc\fR.
-.IP "errors and execution"
-This implementation varies from other implementations in terms of what
-code will be executed when syntax and other errors are found in the
-program. If a syntax error is found in a function definition, error
-recovery tries to find the beginning of a statement and continue to
-parse the function. Once a syntax error is found in the function, the
-function will not be callable and becomes undefined.
-Syntax errors in the interactive execution code will invalidate the
-current execution block. The execution block is terminated by an
-end of line that appears after a complete sequence of statements.
-For example,
-.nf
-.RS
-a = 1
-b = 2
-.RE
-.fi
-has two execution blocks and
-.nf
-.RS
-{ a = 1
- b = 2 }
-.RE
-.fi
-has one execution block. Any runtime error will terminate the execution
-of the current execution block. A runtime warning will not terminate the
-current execution block.
-.IP "Interrupts"
-During an interactive session, the SIGINT signal (usually generated by
-the control-C character from the terminal) will cause execution of the
-current execution block to be interrupted. It will display a "runtime"
-error indicating which function was interrupted. After all runtime
-structures have been cleaned up, a message will be printed to notify the
-user that \fBbc\fR is ready for more input. All previously defined functions
-remain defined and the value of all non-auto variables are the value at
-the point of interruption. All auto variables and function parameters
-are removed during the
-clean up process. During a non-interactive
-session, the SIGINT signal will terminate the entire run of \fBbc\fR.
-.SS LIMITS
-The following are the limits currently in place for this
-.B bc
-processor. Some of them may have been changed by an installation.
-Use the limits statement to see the actual values.
-.IP BC_BASE_MAX
-The maximum output base is currently set at 999. The maximum input base
-is 16.
-.IP BC_DIM_MAX
-This is currently an arbitrary limit of 65535 as distributed. Your
-installation may be different.
-.IP BC_SCALE_MAX
-The number of digits after the decimal point is limited to INT_MAX digits.
-Also, the number of digits before the decimal point is limited to INT_MAX
-digits.
-.IP BC_STRING_MAX
-The limit on the number of characters in a string is INT_MAX characters.
-.IP exponent
-The value of the exponent in the raise operation (^) is limited to LONG_MAX.
-.IP "variable names"
-The current limit on the number of unique names is 32767 for each of
-simple variables, arrays and functions.
-.SH ENVIRONMENT
-The following environment variables are processed by \fBbc\fR:
-.IP "POSIXLY_CORRECT"
-This is the same as the \fB-s\fR option.
-.IP "BC_ENV_ARGS"
-This is another mechanism to get arguments to \fBbc\fR. The
-format is the same as the command line arguments. These arguments
-are processed first, so any files listed in the environment arguments
-are processed before any command line argument files. This allows
-the user to set up "standard" options and files to be processed
-at every invocation of \fBbc\fR. The files in the environment
-variables would typically contain function definitions for functions
-the user wants defined every time \fBbc\fR is run.
-.IP "BC_LINE_LENGTH"
-This should be an integer specifying the number of characters in an
-output line for numbers. This includes the backslash and newline characters
-for long numbers.
-.SH DIAGNOSTICS
-If any file on the command line can not be opened, \fBbc\fR will report
-that the file is unavailable and terminate. Also, there are compile
-and run time diagnostics that should be self-explanatory.
-.SH BUGS
-Error recovery is not very good yet.
-.PP
-Email bug reports to
-.BR bug-bc@gnu.org .
-Be sure to include the word ``bc'' somewhere in the ``Subject:'' field.
-.SH AUTHOR
-.nf
-Philip A. Nelson
-philnelson@acm.org
-.fi
-.SH ACKNOWLEDGEMENTS
-The author would like to thank Steve Sommars (Steve.Sommars@att.com) for
-his extensive help in testing the implementation. Many great suggestions
-were given. This is a much better product due to his involvement.
diff --git a/contrib/bc/doc/bc.texi b/contrib/bc/doc/bc.texi
deleted file mode 100644
index a7cb9f6..0000000
--- a/contrib/bc/doc/bc.texi
+++ /dev/null
@@ -1,1014 +0,0 @@
-\input texinfo @c -*-texinfo-*-
-@c %**start of header
-@setfilename bc.info
-@settitle bc Command Manual
-@c %**end of header
-
-@c This file has the new style title page commands.
-@c Run `makeinfo' rather than `texinfo-format-buffer'.
-
-@smallbook
-
-@c tex
-@c \overfullrule=0pt
-@c end tex
-
-@titlepage
-@title @command{bc}
-@subtitle an arbitrary precision calculator language
-@subtitle version 1.06
-
-@author Philip A. Nelson
-@page
-
-This manual documents @command{bc}, an arbitrary precision calculator language.
-
-This manual is part of GNU @command{bc}.@*
-@sp4
-Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
-59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
-
-Permission is granted to make and distribute verbatim copies of
-this manual provided the copyright notice and this permission notice
-are preserved on all copies.
-
-@iftex
-Permission is granted to process this file through TeX and print the
-results, provided the printed document carries copying permission
-notice identical to this one except for the removal of this paragraph
-(this paragraph not being relevant to the printed manual).
-@end iftex
-
-Permission is granted to copy and distribute modified versions of this
-manual under the conditions for verbatim copying, provided that the entire
-resulting derived work is distributed under the terms of a permission
-notice identical to this one.
-
-Permission is granted to copy and distribute translations of this manual
-into another language, under the above conditions for modified versions,
-except that this permission notice may be stated in a translation approved
-by the Foundation.
-
-You may contact the author by:
-e-mail: @email{phil@@cs.wwu.edu}@*
-us-mail: Philip A. Nelson@*
-Computer Science Department, 9062@*
-Western Washington University@*
-Bellingham, WA 98226-9062
-
-@end titlepage
-
-@node Top, Introduction, (dir), (dir)
-
-@menu
-* Introduction::
-* Basic Elements::
-* Expressions::
-* Statements::
-* Functions::
-* Examples::
-* Readline and Libedit Options::
-* GNU @command{bc} and Other Implementations::
-* Limits::
-* Environment Variables::
-@end menu
-
-@node Introduction, Basic Elements, Top, Top
-@chapter Introduction
-@menu
-* Description::
-* Command Line Options::
-@end menu
-
-@node Description, Command Line Options, Introduction, Introduction
-@section Description
-
-@command{bc} [ -hlwsqv ] [long-options] [ @var{ file ...} ]
-
-@command{bc} is a language that supports arbitrary precision numbers
-with interactive execution of statements. There are some similarities
-in the syntax to the C programming language.
-A standard math library is available by command line option.
-If requested, the math library is defined before processing any files.
-@command{bc} starts by processing code from all the files listed
-on the command line in the order listed. After all files have been
-processed, @command{bc} reads from the standard input. All code is
-executed as it is read. (If a file contains a command to halt the
-processor, @command{bc} will never read from the standard input.)
-
-This version of @command{bc} contains several extensions beyond
-traditional @command{bc} implementations and the POSIX draft standard.
-Command line options can cause these extensions to print a warning or to
-be rejected. This document describes the language accepted by this
-processor. Extensions will be identified as such.
-
-The author would like to thank Steve Sommars
-(@email{Steve.Sommars@@att.com}) for his extensive help in testing the
-implementation. Many great suggestions were given. This is a much
-better product due to his involvement.
-
-Email bug reports to @email{bug-bc@@gnu.org}. Be sure to include
-the word ``bc'' somewhere in the ``Subject:'' field.
-
-@node Command Line Options, Numbers, Description, Introduction
-@section Command Line Options
-
-@command{bc} takes the following options from the command line:
-@table @code
-
-@item -h, --help
-Print the usage and exit.
-
-@item -l, --mathlib
-Define the standard math library.
-
-@item -w, --warn
-Give warnings for extensions to POSIX @command{bc}.
-
-@item -s, --standard
-Process exactly the POSIX @command{bc} language.
-
-@item -q, --quiet
-Do not print the normal GNU @command{bc} welcome.
-
-@item -v, --version
-Print the version number and copyright and quit.
-
-@end table
-
-
-@node Basic Elements, Expressions, Introduction, Top
-@chapter Basic Elements
-@menu
-* Numbers::
-* Variables::
-* Comments::
-@end menu
-
-@node Numbers, Variables, Command Line Options, Basic Elements
-@section Numbers
-
-The most basic element in @command{bc} is the number. Numbers are
-arbitrary precision numbers. This precision is both in the integer part
-and the fractional part. All numbers are represented internally in
-decimal and all computation is done in decimal. (This version truncates
-results from divide and multiply operations.) There are two attributes
-of numbers, the length and the scale. The length is the total number of
-significant decimal digits in a number and the scale is the total number
-of decimal digits after the decimal point. For example, .000001 has a
-length of 6 and scale of 6, while 1935.000 has a length of 7 and a scale
-of 3.
-
-@node Variables, Comments, Numbers, Basic Elements
-@section Variables
-
-Numbers are stored in two types of variables, simple variables and
-arrays. Both simple variables and array variables are named. Names
-begin with a letter followed by any number of letters, digits and
-underscores. All letters must be lower case. (Full alphanumeric
-names are an extension. In POSIX @command{bc} all names are a single
-lower case letter.) The type of variable is clear by the context
-because all array variable names will be followed by brackets ( [ ] ).
-
-There are four special variables, @var{scale}, @var{ibase}, @var{obase}, and
-@var{last}. @var{scale} defines how some operations use digits after the
-decimal point. The default value of @var{scale} is 0. @var{ibase}
-and @var{obase} define the conversion base for input and output
-numbers. The default for both input and output is base 10.
-@var{last} (an extension) is a variable that has the value of the last
-printed number. These will be discussed in further detail where
-appropriate. All of these variables may have values assigned to them
-as well as used in expressions.
-
-@node Comments, , Variables, Basic Elements
-@section Comments
-
-Comments in @command{bc} start with the characters @code{/*} and end with
-the characters @code{*/}. Comments may start anywhere and appear as a
-single space in the input. (This causes comments to delimit other
-input items. For example, a comment can not be found in the middle of
-a variable name.) Comments include any newlines (end of line) between
-the start and the end of the comment.
-
-To support the use of scripts for @command{bc}, a single line comment has been
-added as an extension. A single line comment starts at a @code{#}
-character and continues to the next end of the line. The end of line
-character is not part of the comment and is processed normally.
-
-@node Expressions, Statements, Basic Elements, Top
-@chapter Expressions
-
-@menu
-* About Expressions and Special Variables::
-* Basic Expressions::
-* Relational Expressions::
-* Boolean Expressions::
-* Precedence::
-* Special Expressions::
-@end menu
-
-@node About Expressions and Special Variables, Basic Expressions, Expressions, Expressions
-@section About Expressions and Special Variables
-
-The numbers are manipulated by expressions and statements. Since
-the language was designed to be interactive, statements and expressions
-are executed as soon as possible. There is no main program. Instead,
-code is executed as it is encountered. (Functions, discussed in
-detail later, are defined when encountered.)
-
-A simple expression is just a constant. @command{bc} converts constants
-into internal decimal numbers using the current input base, specified by
-the variable @var{ibase}. (There is an exception in functions.) The
-legal values of @var{ibase} are 2 through 16. Assigning a value outside
-this range to @var{ibase} will result in a value of 2 or 16. Input
-numbers may contain the characters 0-9 and A-F. (Note: They must be
-capitals. Lower case letters are variable names.) Single digit numbers
-always have the value of the digit regardless of the value of
-@var{ibase}. (i.e. A = 10.) For multi-digit numbers, @command{bc}
-changes all input digits greater or equal to @var{ibase} to the value of
-@var{ibase}-1. This makes the number @code{FFF} always be the largest
-3 digit number of the input base.
-
-Full expressions are similar to many other high level languages.
-Since there is only one kind of number, there are no rules for mixing
-types. Instead, there are rules on the scale of expressions. Every
-expression has a scale. This is derived from the scale of original
-numbers, the operation performed and in many cases, the value of the
-variable @var{scale}. Legal values of the variable @var{scale} are
-0 to the maximum number representable by a C integer.
-
-@node Basic Expressions, Relational Expressions, About Expressions and Special Variables, Expressions
-@section Basic Expressions
-
-In the following descriptions of legal expressions, "expr" refers to a
-complete expression and "@var{var}" refers to a simple or an array variable.
-A simple variable is just a
-
-@var{name}
-
-and an array variable is specified as
-
-@var{name}[@var{expr}]
-
-Unless specifically mentioned the scale of the result is the maximum
-scale of the expressions involved.
-
-@table @code
-@item - expr
-The result is the negation of the expression.
-
-@item ++ @var{var}
-The variable is incremented by one and the new value is the result of
-the expression.
-
-@item -- @var{var}
-The variable
-is decremented by one and the new value is the result of the
-expression.
-
-@item @var{var} ++
- The result of the expression is the value of
-the variable and then the variable is incremented by one.
-
-@item @var{var} --
-The result of the expression is the value of the variable and then
-the variable is decremented by one.
-
-@item expr + expr
-The result of the expression is the sum of the two expressions.
-
-@item expr - expr
-The result of the expression is the difference of the two expressions.
-
-@item expr * expr
-The result of the expression is the product of the two expressions.
-
-@item expr / expr
-The result of the expression is the quotient of the two expressions.
-The scale of the result is the value of the variable @code{scale}
-
-@item expr % expr
-The result of the expression is the "remainder" and it is computed in the
-following way. To compute a%b, first a/b is computed to @var{scale}
-digits. That result is used to compute a-(a/b)*b to the scale of the
-maximum of @var{scale}+scale(b) and scale(a). If @var{scale} is set
-to zero and both expressions are integers this expression is the
-integer remainder function.
-
-@item expr ^ expr
-The result of the expression is the value of the first raised to the
-second. The second expression must be an integer. (If the second
-expression is not an integer, a warning is generated and the
-expression is truncated to get an integer value.) The scale of the
-result is @var{scale} if the exponent is negative. If the exponent
-is positive the scale of the result is the minimum of the scale of the
-first expression times the value of the exponent and the maximum of
-@var{scale} and the scale of the first expression. (e.g. scale(a^b)
-= min(scale(a)*b, max(@var{scale}, scale(a))).) It should be noted
-that expr^0 will always return the value of 1.
-
-@item ( expr )
-This alters the standard precedence to force the evaluation of the
-expression.
-
-@item @var{var} = expr
-The variable is assigned the value of the expression.
-
-@item @var{var} <op>= expr
-This is equivalent to "@var{var} = @var{var} <op> expr" with the
-exception that the "@var{var}" part is evaluated only once. This can
-make a difference if "@var{var}" is an array.
-@end table
-
-@node Relational Expressions, Boolean Expressions, Basic Expressions, Expressions
-@section Relational Expressions
-
-Relational expressions are a special kind of expression that always
-evaluate to 0 or 1, 0 if the relation is false and 1 if the relation is
-true. These may appear in any legal expression. (POSIX @command{bc}
-requires that relational expressions are used only in @code{if},
-@code{while}, and @code{for} statements and that only one relational
-test may be done in them.) The relational operators are
-
-@table @code
-@item expr1 < expr2
-The result is 1 if expr1 is strictly less than expr2.
-
-@item expr1 <= expr2
-The result is 1 if expr1 is less than or equal to expr2.
-
-@item expr1 > expr2
-The result is 1 if expr1 is strictly greater than expr2.
-
-@item expr1 >= expr2
-The result is 1 if expr1 is greater than or equal to expr2.
-
-@item expr1 == expr2
-The result is 1 if expr1 is equal to expr2.
-
-@item expr1 != expr2
-The result is 1 if expr1 is not equal to expr2.
-@end table
-
-@node Boolean Expressions, Precedence, Relational Expressions, Expressions
-@section Boolean Expressions
-
-Boolean operations are also legal. (POSIX @command{bc} does NOT have
-boolean operations). The result of all boolean operations are 0 and 1
-(for false and true) as in relational expressions. The boolean
-operators are:
-
-@table @code
-@item !expr
-The result is 1 if expr is 0.
-
-@item expr && expr
-The result is 1 if both expressions are non-zero.
-
-@item expr || expr
-The result is 1 if either expression is non-zero.
-@end table
-
-@node Precedence, Special Expressions, Boolean Expressions, Expressions
-@section Precedence
-
-The expression precedence is as follows: (lowest to highest)
-
-@example
-|| operator, left associative
-&& operator, left associative
-! operator, nonassociative
-Relational operators, left associative
-Assignment operator, right associative
-+ and - operators, left associative
-*, / and % operators, left associative
-^ operator, right associative
-unary - operator, nonassociative
-++ and -- operators, nonassociative
-@end example
-
-This precedence was chosen so that POSIX compliant @command{bc} programs
-will run correctly. This will cause the use of the relational and
-logical operators to have some unusual behavior when used with
-assignment expressions. Consider the expression:
-
-@example
-a = 3 < 5
-@end example
-
-Most C programmers would assume this would assign the result of "3 <
-5" (the value 1) to the variable "a". What this does in @command{bc} is
-assign the value 3 to the variable "a" and then compare 3 to 5. It is
-best to use parentheses when using relational and logical operators
-with the assignment operators.
-
-@node Special Expressions, , Precedence, Expressions
-@section Special Expressions
-
-There are a few more special expressions that are provided in
-@command{bc}. These have to do with user-defined functions and standard
-functions. They all appear as
-"@var{name}@code{(}@var{parameters}@code{)}". @xref{Functions}, for
-user-defined functions. The standard functions are:
-
-@table @code
-@item length ( expression )
-The value of the length function is the number of significant digits in the
-expression.
-
-@item read ( )
-The @code{read} function (an extension) will read a number from the
-standard input, regardless of where the function occurs. Beware, this
-can cause problems with the mixing of data and program in the standard
-input. The best use for this function is in a previously written
-program that needs input from the user, but never allows program code to
-be input from the user. The value of the @code{read} function is the
-number read from the standard input using the current value of the
-variable @var{ibase} for the conversion base.
-
-@item scale ( expression )
-The value of the @code{scale} function is the number of digits after the
-decimal point in the expression.
-
-@item sqrt ( expression )
-The value of the @code{sqrt} function is the square root of the
-expression. If the expression is negative, a run time error is
-generated.
-@end table
-
-@node Statements, Functions, Expressions, Top
-@chapter Statements
-
-@menu
-* Pseudo Statements::
-@end menu
-
-Statements (as in most algebraic languages) provide the sequencing of
-expression evaluation. In @command{bc} statements are executed "as soon
-as possible." Execution happens when a newline in encountered and there
-is one or more complete statements. Due to this immediate execution,
-newlines are very important in @command{bc}. In fact, both a semicolon
-and a newline are used as statement separators. An improperly placed
-newline will cause a syntax error. Because newlines are statement
-separators, it is possible to hide a newline by using the backslash
-character. The sequence "\<nl>", where <nl> is the newline appears to
-@command{bc} as whitespace instead of a newline. A statement list is a
-series of statements separated by semicolons and newlines. The
-following is a list of @command{bc} statements and what they do: (Things
-enclosed in brackets ( [ ] ) are optional parts of the statement.)
-
-@table @var
-@item expression
-This statement does one of two things. If the expression starts with
-"<variable> <assignment> ...", it is considered to be an assignment
-statement. If the expression is not an assignment statement, the
-expression is evaluated and printed to the output. After the number is
-printed, a newline is printed. For example, "a=1" is an assignment
-statement and "(a=1)" is an expression that has an embedded assignment.
-All numbers that are printed are printed in the base specified by the
-variable @var{obase}. The legal values for @var{obase} are 2 through
-BC_BASE_MAX (@pxref{Environment Variables}). For bases 2 through 16,
-the usual method of writing numbers is used. For bases greater than 16,
-@command{bc} uses a multi-character digit method of printing the numbers
-where each higher base digit is printed as a base 10 number. The
-multi-character digits are separated by spaces. Each digit contains the
-number of characters required to represent the base ten value of
-"@var{obase} -1". Since numbers are of arbitrary precision, some
-numbers may not be printable on a single output line. These long
-numbers will be split across lines using the "\" as the last character
-on a line. The maximum number of characters printed per line is 70.
-Due to the interactive nature of @command{bc}, printing a number causes
-the side effect of assigning the printed value to the special variable
-@var{last}. This allows the user to recover the last value printed
-without having to retype the expression that printed the number.
-Assigning to @var{last} is legal and will overwrite the last printed
-value with the assigned value. The newly assigned value will remain
-until the next number is printed or another value is assigned to
-@var{last}. (Some installations may allow the use of a single period
-(.) which is not part of a number as a short hand notation for for
-@var{last}.)
-
-@item string
-The string is printed to the output. Strings start with a double quote
-character and contain all characters until the next double quote character.
-All characters are taken literally, including any newline. No newline
-character is printed after the string.
-
-@item @code{print} @var{list}
-The @code{print} statement (an extension) provides another method of
-output. The @var{list} is a list of strings and expressions separated by
-commas. Each string or expression is printed in the order of the list.
-No terminating newline is printed. Expressions are evaluated and their
-value is printed and assigned to the variable @code{last}. Strings in
-the print statement are printed to the output and may contain special
-characters. Special characters start with the backslash character (\e).
-The special characters recognized by @command{bc} are "a" (alert or
-bell), "b" (backspace), "f" (form feed), "n" (newline), "r" (carriage
-return), "q" (double quote), "t" (tab), and "\e" (backslash). Any other
-character following the backslash will be ignored.
-
-@item @{ statement_list @}
-This is the compound statement. It allows multiple statements to be
-grouped together for execution.
-
-@item @code{if} ( expression ) statement1 [@code{else} statement2]
-The if statement evaluates the expression and executes statement1 or
-statement2 depending on the value of the expression. If the expression
-is non-zero, statement1 is executed. If statement2 is present and
-the value of the expression is 0, then statement2 is executed. (The
-@code{else} clause is an extension.)
-
-@item @code{while} ( expression ) statement
-The while statement will execute the statement while the expression
-is non-zero. It evaluates the expression before each execution of
-the statement. Termination of the loop is caused by a zero
-expression value or the execution of a @code{break} statement.
-
-@item @code{for} ( [expression1] ; [expression2] ; [expression3] ) statement
-The @code{for} statement controls repeated execution of the statement.
-@var{Expression1} is evaluated before the loop. @var{Expression2} is
-evaluated before each execution of the statement. If it is non-zero,
-the statement is evaluated. If it is zero, the loop is terminated.
-After each execution of the statement, @var{expression3} is evaluated
-before the reevaluation of expression2. If @var{expression1} or
-@var{expression3} are missing, nothing is evaluated at the point they
-would be evaluated. If @var{expression2} is missing, it is the same as
-substituting the value 1 for @var{expression2}. (The optional
-expressions are an extension. POSIX @command{bc} requires all three
-expressions.) The following is equivalent code for the @code{for}
-statement:
-
-@example
-expression1;
-while (expression2) @{
- statement;
- expression3;
-@}
-@end example
-
-@item @code{break}
-This statement causes a forced exit of the most recent enclosing @code{while}
-statement or @code{for} statement.
-
-@item @code{continue}
-The @code{continue} statement (an extension) causes the most recent enclosing
-@code{for} statement to start the next iteration.
-
-@item @code{halt}
-The @code{halt} statement (an extension) is an executed statement that
-causes the @command{bc} processor to quit only when it is executed. For
-example, "if (0 == 1) halt" will not cause @command{bc} to terminate
-because the @code{halt} is not executed.
-
-@item @code{return}
-Return the value 0 from a function. (@xref{Functions}.)
-
-@item @code{return} ( expression )
-Return the value of the expression from a function. (@xref{Functions}.)
-As an extension, the parenthesis are not required.
-@end table
-
-@node Pseudo Statements, , Statements, Statements
-@section Pseudo Statements
-
-These statements are not statements in the traditional sense. They are
-not executed statements. Their function is performed at "compile" time.
-
-@table @code
-@item limits
-Print the local limits enforced by the local version of @command{bc}. This
-is an extension.
-
-@item quit
-When the @code{quit} statement is read, the @command{bc} processor
-is terminated, regardless of where the @code{quit} statement is found. For
-example, "if (0 == 1) quit" will cause @command{bc} to terminate.
-
-@item warranty
-Print a longer warranty notice. This is an extension.
-@end table
-
-@node Functions, Examples, Statements, Top
-@chapter Functions
-
-@menu
-* Math Library Functions::
-@end menu
-
-Functions provide a method of defining a computation that can be
-executed later. Functions in @command{bc} always compute a value and
-return it to the caller. Function definitions are "dynamic" in the
-sense that a function is undefined until a definition is encountered in
-the input. That definition is then used until another definition
-function for the same name is encountered. The new definition then
-replaces the older definition. A function is defined as follows:
-
-@example
-@code{define} @var{name} @code{(} @var{parameters} @code{)} @code{@{} @var{newline}
- @var{auto_list statement_list} @code{@}}
-@end example
-
-A function call is just an expression of the form
-"@code{name} @code{(}@var{parameters}@code{)}".
-
-Parameters are numbers or arrays (an extension). In the function definition,
-zero or more parameters are defined by listing their names separated by
-commas. Numbers are only call by value parameters. Arrays are only
-call by variable. Arrays are specified in the parameter definition by
-the notation "@var{name}@code{[ ]}". In the function call, actual parameters
-are full expressions for number parameters. The same notation is used
-for passing arrays as for defining array parameters. The named array is
-passed by variable to the function. Since function definitions are dynamic,
-parameter numbers and types are checked when a function is called. Any
-mismatch in number or types of parameters will cause a runtime error.
-A runtime error will also occur for the call to an undefined function.
-
-The @var{auto_list} is an optional list of variables that are for
-"local" use. The syntax of the auto list (if present) is "@code{auto}
-@var{name}, ... ;". (The semicolon is optional.) Each @var{name} is
-the name of an auto variable. Arrays may be specified by using the
-same notation as used in parameters. These variables have their
-values pushed onto a stack at the start of the function. The
-variables are then initialized to zero and used throughout the
-execution of the function. At function exit, these variables are
-popped so that the original value (at the time of the function call)
-of these variables are restored. The parameters are really auto
-variables that are initialized to a value provided in the function
-call.
-Auto variables are different than traditional local variables
-because if function A calls function B, B may access function
-A's auto variables by just using the same name, unless function B has
-called them auto variables. Due to the fact that auto variables and
-parameters are pushed onto a stack, @command{bc} supports recursive functions.
-
-The function body is a list of @command{bc} statements. Again, statements
-are separated by semicolons or newlines. Return statements cause the
-termination of a function and the return of a value. There are two
-versions of the return statement. The first form, "@code{return}", returns
-the value 0 to the calling expression. The second form,
-"@code{return} ( @var{expression} )", computes the value of the expression
-and returns that value to the calling expression. There is an implied
-"@code{return} (0)" at the end of every function. This allows a function
-to terminate and return 0 without an explicit @code{return} statement.
-
-Functions also change the usage of the variable @var{ibase}. All
-constants in the function body will be converted using the value of
-@var{ibase} at the time of the function call. Changes of @var{ibase}
-will be ignored during the execution of the function except for the
-standard function @code{read}, which will always use the current value
-of @var{ibase} for conversion of numbers.
-
-As an extension, the format of the definition has been slightly relaxed.
-The standard requires the opening brace be on the same line as the
-@code{define} keyword and all other parts must be on following lines.
-This version of @command{bc} will allow any number of newlines before and
-after the opening brace of the function. For example, the following
-definitions are legal.
-
-@example
- define d (n) @{ return (2*n); @}
- define d (n)
- @{ return (2*n); @}
-@end example
-
-
-@node Math Library Functions, , Functions, Functions
-@section Math Library Functions
-
-If @command{bc} is invoked with the @code{-l} option, a math library is
-preloaded and the default @var{scale} is set to 20. The math functions will
-calculate their results to the scale set at the time of their call. The
-math library defines the following functions:
-
-@table @code
-@item s (@var{x})
-The sine of @var{x}, @var{x} is in radians.
-
-@item c (@var{x})
-The cosine of @var{x}, @var{x} is in radians.
-
-@item a (@var{x})
-The arctangent of @var{x}, arctangent returns radians.
-
-@item l (@var{x})
-The natural logarithm of @var{x}.
-
-@item @var{e} (@var{x})
-The exponential function of raising @var{e} to the value @var{x}.
-
-@item @var{j} (@var{n,x})
-The bessel function of integer order @var{n} of @var{x}.
-@end table
-
-@node Examples, Readline and Libedit Options, Functions, Top
-@chapter Examples
-
-In /bin/sh, the following will assign the value of "pi" to the shell
-variable @var{pi}.
-@example
-
-pi=$(echo "scale=10; 4*a(1)" | bc -l)
-
-@end example
-
-The following is the definition of the exponential function used in the
-math library. This function is written in POSIX @command{bc}.
-
-@example
-
-scale = 20
-
-/* Uses the fact that e^x = (e^(x/2))^2
- When x is small enough, we use the series:
- e^x = 1 + x + x^2/2! + x^3/3! + ...
-*/
-
-define e(x) @{
- auto a, d, e, f, i, m, v, z
-
- /* Check the sign of x. */
- if (x<0) @{
- m = 1
- x = -x
- @}
-
- /* Precondition x. */
- z = scale;
- scale = 4 + z + .44*x;
- while (x > 1) @{
- f += 1;
- x /= 2;
- @}
-
- /* Initialize the variables. */
- v = 1+x
- a = x
- d = 1
-
- for (i=2; 1; i++) @{
- e = (a *= x) / (d *= i)
- if (e == 0) @{
- if (f>0) while (f--) v = v*v;
- scale = z
- if (m) return (1/v);
- return (v/1);
- @}
- v += e
- @}
-@}
-
-@end example
-
-The following is code that uses the extended features of @command{bc} to
-implement a simple program for calculating checkbook balances. This
-program is best kept in a file so that it can be used many times
-without having to retype it at every use.
-
-@example
-
-scale=2
-print "\nCheck book program\n!"
-print " Remember, deposits are negative transactions.\n"
-print " Exit by a 0 transaction.\n\n"
-
-print "Initial balance? "; bal = read()
-bal /= 1
-print "\n"
-while (1) @{
- "current balance = "; bal
- "transaction? "; trans = read()
- if (trans == 0) break;
- bal -= trans
- bal /= 1
-@}
-quit
-
-@end example
-
-
-The following is the definition of the recursive factorial function.
-
-@example
-
-define f (x) @{
- if (x <= 1) return (1);
- return (f(x-1) * x);
-@}
-
-@end example
-
-@node Readline and Libedit Options, GNU @command{bc} and Other Implementations, Examples, Top
-@chapter Readline and Libedit Options
-
-GNU @command{bc} can be compiled (via a configure option) to use the GNU
-@command{readline} input editor library or the BSD @command{libedit}
-library. This allows the user to do
-more editing of lines before sending them to @command{bc}. It also
-allows for a history of previous lines typed. When this option is
-selected, @command{bc} has one more special variable. This special
-variable, @var{history} is the number of lines of history retained. A
-value of -1 means that an unlimited number of history lines are
-retained. This is the default value. Setting the value of
-@var{history} to a positive number restricts the number of history lines
-to the number given. The value of 0 disables the history feature. For
-more information, read the user manuals for the GNU @command{readline},
-@command{history} and BSD @command{libedit} libraries. One can not
-enable both @command{readline} and @command{libedit} at the same time.
-
-@node GNU @command{bc} and Other Implementations, Limits, Readline and Libedit Options, Top
-@chapter GNU @command{bc} and Other Implementations
-
-This version of @command{bc} was implemented from the POSIX P1003.2/D11
-draft and contains several differences and extensions relative to the
-draft and traditional implementations. It is not implemented in the
-traditional way using @command{dc}. This version is a single process
-which parses and runs a byte code translation of the program. There is
-an "undocumented" option (-c) that causes the program to output the byte
-code to the standard output instead of running it. It was mainly used
-for debugging the parser and preparing the math library.
-
-A major source of differences is extensions, where a feature is extended
-to add more functionality and additions, where new features are added.
-The following is the list of differences and extensions.
-
-@table @var
-
-@item LANG environment
-This version does not conform to the POSIX standard in the processing
-of the LANG environment variable and all environment variables starting
-with LC_.
-
-@item names
-Traditional and POSIX @command{bc}
-have single letter names for functions, variables and arrays. They have
-been extended to be multi-character names that start with a letter and
-may contain letters, numbers and the underscore character.
-
-@item Strings
-Strings are not allowed to contain NUL characters. POSIX says all characters
-must be included in strings.
-
-@item last
-POSIX @command{bc} does not have a \fBlast variable. Some implementations
-of @command{bc} use the period (.) in a similar way.
-
-@item comparisons
-POSIX @command{bc} allows comparisons only in the @code{if} statement,
-the @code{while} statement, and the second expression of the @code{for}
-statement. Also, only one relational operation is allowed in each of
-those statements.
-
-@item if statement, else clause
-POSIX @command{bc} does not have an @code{else} clause.
-
-@item for statement
-POSIX @command{bc} requires all expressions to be present in the
-@code{for} statement.
-
-@item &&, ||, !
-POSIX @command{bc} does not have the logical operators.
-
-@item read function
-POSIX @command{bc} does not have a @code{read} function.
-
-@item print statement
-POSIX @command{bc} does not have a @code{print} statement.
-
-@item continue statement
-POSIX @command{bc} does not have a continue statement.
-
-@item array parameters
-POSIX @command{bc} does not (currently) support array parameters in full.
-The POSIX grammar allows for arrays in function definitions, but does
-not provide a method to specify an array as an actual parameter. (This
-is most likely an oversight in the grammar.) Traditional implementations
-of @command{bc} have only call by value array parameters.
-
-@item function format
-POSIX @command{bc} requires the opening brace on the same line as the
-@code{define} key word and the @code{auto} statement on the next line.
-
-@item =+, =-, =*, =/, =%, =^
-POSIX @command{bc} does not require these "old style" assignment
-operators to be defined. This version may allow these "old style"
-assignments. Use the @code{limits} statement to see if the installed
-version supports them. If it does support the "old style" assignment
-operators, the statement "a =- 1" will decrement @code{a} by 1 instead
-of setting @code{a} to the value -1.
-
-@item spaces in numbers
-Other implementations of @command{bc} allow spaces in numbers. For example,
-"x=1 3" would assign the value 13 to the variable x. The same statement
-would cause a syntax error in this version of @command{bc}.
-
-@item errors and execution
-This implementation varies from other implementations in terms of what
-code will be executed when syntax and other errors are found in the
-program. If a syntax error is found in a function definition, error
-recovery tries to find the beginning of a statement and continue to
-parse the function. Once a syntax error is found in the function, the
-function will not be callable and becomes undefined.
-Syntax errors in the interactive execution code will invalidate the
-current execution block. The execution block is terminated by an
-end of line that appears after a complete sequence of statements.
-For example,
-
-@example
-a = 1
-b = 2
-@end example
-
-has two execution blocks and
-
-@example
-@{ a = 1
- b = 2 @}
-@end example
-
-has one execution block. Any runtime error will terminate the execution
-of the current execution block. A runtime warning will not terminate the
-current execution block.
-
-@item Interrupts
-During an interactive session, the SIGINT signal (usually generated by
-the control-C character from the terminal) will cause execution of the
-current execution block to be interrupted. It will display a "runtime"
-error indicating which function was interrupted. After all runtime
-structures have been cleaned up, a message will be printed to notify the
-user that @command{bc} is ready for more input. All previously defined
-functions remain defined and the value of all non-auto variables are the
-value at the point of interruption. All auto variables and function
-parameters are removed during the clean up process. During a
-non-interactive session, the SIGINT signal will terminate the entire run
-of @command{bc}.
-@end table
-
-@node Limits, Environment Variables, GNU @command{bc} and Other Implementations, Top
-@chapter Limits
-
-The following are the limits currently in place for this @command{bc}
-processor. Some of them may have been changed by an installation. Use
-the @code{limits} statement to see the actual values.
-
-@table @code
-
-@item BC_BASE_MAX
-The maximum output base is currently set at 999. The maximum input base
-is 16.
-
-@item BC_DIM_MAX
-This is currently an arbitrary limit of 65535 as distributed. Your
-installation may be different.
-
-@item BC_SCALE_MAX
-The number of digits after the decimal point is limited to INT_MAX digits.
-Also, the number of digits before the decimal point is limited to INT_MAX
-digits.
-
-@item BC_STRING_MAX
-The limit on the number of characters in a string is INT_MAX characters.
-
-@item exponent
-The value of the exponent in the raise operation (^) is limited to LONG_MAX.
-
-@item multiply
-The multiply routine may yield incorrect results if a number
-has more than LONG_MAX / 90 total digits. For 32 bit longs, this number is
-23,860,929 digits.
-
-@item variable names
-The current limit on the number of unique names is 32767 for each of
-simple variables, arrays and functions.
-@end table
-
-@node Environment Variables, , Limits, Top
-@chapter Environment Variables
-
-The following environment variables are processed by @command{bc}:
-
-@table @code
-
-
-@item POSIXLY_CORRECT
-This is the same as the -s option (@pxref{Command Line Options}).
-
-@item BC_ENV_ARGS
-This is another mechanism to get arguments to @command{bc}. The format
-is the same as the command line arguments. These arguments are
-processed first, so any files listed in the environent arguments are
-processed before any command line argument files. This allows the user
-to set up "standard" options and files to be processed at every
-invocation of @command{bc}. The files in the environment variables
-would typically contain function definitions for functions the user
-wants defined every time @command{bc} is run.
-
-@item BC_LINE_LENGTH
-This should be an integer specifing the number of characters in an
-output line for numbers. This includes the backslash and newline
-characters for long numbers.
-@end table
-
-@contents
-@bye
-
-
diff --git a/contrib/bc/doc/dc.1 b/contrib/bc/doc/dc.1
deleted file mode 100644
index adaf5d0..0000000
--- a/contrib/bc/doc/dc.1
+++ /dev/null
@@ -1,490 +0,0 @@
-.\"
-.\" dc.1 - the *roff document processor source for the dc manual
-.\"
-.\" This file is part of GNU dc.
-.\" Copyright (C) 1994, 1997, 1998, 2000 Free Software Foundation, Inc.
-.\"
-.\" This program is free software; you can redistribute it and/or modify
-.\" it under the terms of the GNU General Public License as published by
-.\" the Free Software Foundation; either version 2 of the License , or
-.\" (at your option) any later version.
-.\"
-.\" This program is distributed in the hope that it will be useful,
-.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-.\" GNU General Public License for more details.
-.\"
-.\" You should have received a copy of the GNU General Public License
-.\" along with this program; see the file COPYING. If not, write to:
-.\" The Free Software Foundation, Inc.
-.\" 59 Temple Place, Suite 330
-.\" Boston, MA 02111 USA
-.\"
-.\" $FreeBSD$
-.\"
-.TH DC 1 "1997-03-25" "GNU Project"
-.ds dc \fIdc\fP
-.ds Dc \fIDc\fP
-.SH NAME
-dc \- an arbitrary precision calculator
-.SH SYNOPSIS
-dc [-V] [--version] [-h] [--help]
- [-e scriptexpression] [--expression=scriptexpression]
- [-f scriptfile] [--file=scriptfile]
- [file ...]
-.SH DESCRIPTION
-.PP
-\*(Dc is a reverse-polish desk calculator which supports
-unlimited precision arithmetic.
-It also allows you to define and call macros.
-Normally \*(dc reads from the standard input;
-if any command arguments are given to it, they are filenames,
-and \*(dc reads and executes the contents of the files before reading
-from standard input.
-All normal output is to standard output;
-all error output is to standard error.
-.PP
-A reverse-polish calculator stores numbers on a stack.
-Entering a number pushes it on the stack.
-Arithmetic operations pop arguments off the stack and push the results.
-.PP
-To enter a number in
-.IR dc ,
-type the digits with an optional decimal point.
-Exponential notation is not supported.
-To enter a negative number,
-begin the number with ``_''.
-``-'' cannot be used for this,
-as it is a binary operator for subtraction instead.
-To enter two numbers in succession,
-separate them with spaces or newlines.
-These have no meaning as commands.
-.SH OPTIONS
-\*(Dc may be invoked with the following command-line options:
-.TP
-.B -V
-.TP
-.B --version
-Print out the version of \*(dc that is being run and a copyright notice,
-then exit.
-.TP
-.B -h
-.TP
-.B --help
-Print a usage message briefly summarizing these command-line options
-and the bug-reporting address,
-then exit.
-.TP
-.B -e \fIscript\fP
-.TP
-.BI --expression= script
-Add the commands in
-.I script
-to the set of commands to be run while processing the input.
-.TP
-.B -f \fIscript-file\fP
-.TP
-.BI --file= script-file
-Add the commands contained in the file
-.I script-file
-to the set of commands to be run while processing the input.
-.PP
-If any command-line parameters remain after processing the above,
-these parameters are interpreted as the names of input files to
-be processed.
-A file name of
-.B -
-refers to the standard input stream.
-The standard input will processed if no file names are specified.
-.PD
-.SH
-Printing Commands
-.TP
-.B p
-Prints the value on the top of the stack,
-without altering the stack.
-A newline is printed after the value.
-.TP
-.B n
-Prints the value on the top of the stack, popping it off,
-and does not print a newline after.
-.TP
-.B P
-Pops off the value on top of the stack.
-If it it a string, it is simply printed without a trailing newline.
-Otherwise it is a number, and the integer portion of its absolute
-value is printed out as a "base (UCHAR_MAX+1)" byte stream.
-Assuming that (UCHAR_MAX+1) is 256
-(as it is on most machines with 8-bit bytes),
-the sequence \fBKSK 0k1/ [_1*]sx d0>x [256~aPd0<x]dsxx sxLKk\fP
-could also accomplish this function,
-except for the side-effect of clobbering the x register.
-.TP
-.B f
-Prints the entire contents of the stack
-.ig
-and the contents of all of the registers,
-..
-without altering anything.
-This is a good command to use if you are lost or want
-to figure out what the effect of some command has been.
-.PD
-.SH
-Arithmetic
-.TP
-.B +
-Pops two values off the stack, adds them,
-and pushes the result.
-The precision of the result is determined only
-by the values of the arguments,
-and is enough to be exact.
-.TP
-.B -
-Pops two values,
-subtracts the first one popped from the second one popped,
-and pushes the result.
-.TP
-.B *
-Pops two values, multiplies them, and pushes the result.
-The number of fraction digits in the result depends on
-the current precision value and the number of fraction
-digits in the two arguments.
-.TP
-.B /
-Pops two values,
-divides the second one popped from the first one popped,
-and pushes the result.
-The number of fraction digits is specified by the precision value.
-.TP
-.B %
-Pops two values,
-computes the remainder of the division that the
-.B /
-command would do,
-and pushes that.
-The value computed is the same as that computed by
-the sequence \fBSd dld/ Ld*-\fP .
-.TP
-.B ~
-Pops two values,
-divides the second one popped from the first one popped.
-The quotient is pushed first, and the remainder is pushed next.
-The number of fraction digits used in the division
-is specified by the precision value.
-(The sequence \fBSdSn lnld/ LnLd%\fP could also accomplish
-this function, with slightly different error checking.)
-.TP
-.B ^
-Pops two values and exponentiates,
-using the first value popped as the exponent
-and the second popped as the base.
-The fraction part of the exponent is ignored.
-The precision value specifies the number of fraction
-digits in the result.
-.TP
-.B |
-Pops three values and computes a modular exponentiation.
-The first value popped is used as the reduction modulus;
-this value must be a non-zero number,
-and should be an integer.
-The second popped is used as the exponent;
-this value must be a non-negative number,
-and any fractional part of this exponent will be ignored.
-The third value popped is the base which gets exponentiated,
-which should be an integer.
-For small integers this is like the sequence \fBSm^Lm%\fP,
-but, unlike \fB^\fP, this command will work with arbitrarily large exponents.
-.TP
-.B v
-Pops one value,
-computes its square root,
-and pushes that.
-The precision value specifies the number of fraction digits in the result.
-.PP
-Most arithmetic operations are affected by the ``precision value'',
-which you can set with the
-.B k
-command.
-The default precision value is zero,
-which means that all arithmetic except for
-addition and subtraction produces integer results.
-.SH
-Stack Control
-.TP
-.B c
-Clears the stack, rendering it empty.
-.TP
-.B d
-Duplicates the value on the top of the stack,
-pushing another copy of it.
-Thus, ``4d*p'' computes 4 squared and prints it.
-.TP
-.B r
-Reverses the order of (swaps) the top two values on the stack.
-.SH
-Registers
-.PP
-\*(Dc provides at least 256 memory registers,
-each named by a single character.
-You can store a number or a string in a register and retrieve it later.
-.TP
-.BI s r
-Pop the value off the top of the stack and store
-it into register
-.IR r .
-.TP
-.BI l r
-Copy the value in register
-.I r
-and push it onto the stack.
-This does not alter the contents of
-.IR r .
-.PP
-Each register also contains its own stack.
-The current register value is the top of the register's stack.
-.TP
-.BI S r
-Pop the value off the top of the (main) stack and
-push it onto the stack of register
-.IR r .
-The previous value of the register becomes inaccessible.
-.TP
-.BI L r
-Pop the value off the top of register
-.IR r 's
-stack and push it onto the main stack.
-The previous value
-in register
-.IR r 's
-stack, if any,
-is now accessible via the
-.BI l r
-command.
-.ig
-.PP
-The
-.B f
-command prints a list of all registers that have contents stored in them,
-together with their contents.
-Only the current contents of each register
-(the top of its stack)
-is printed.
-..
-.SH
-Parameters
-.PP
-\*(Dc has three parameters that control its operation:
-the precision, the input radix, and the output radix.
-The precision specifies the number
-of fraction digits to keep in the result of most arithmetic operations.
-The input radix controls the interpretation of numbers typed in;
-all numbers typed in use this radix.
-The output radix is used for printing numbers.
-.PP
-The input and output radices are separate parameters;
-you can make them unequal,
-which can be useful or confusing.
-The input radix must be between 2 and 16 inclusive.
-The output radix must be at least 2.
-The precision must be zero or greater.
-The precision is always measured in decimal digits,
-regardless of the current input or output radix.
-.TP
-.B i
-Pops the value off the top of the stack
-and uses it to set the input radix.
-.TP
-.B o
-Pops the value off the top of the stack
-and uses it to set the output radix.
-.TP
-.B k
-Pops the value off the top of the stack
-and uses it to set the precision.
-.TP
-.B I
-Pushes the current input radix on the stack.
-.TP
-.B O
-Pushes the current output radix on the stack.
-.TP
-.B K
-Pushes the current precision on the stack.
-.SH
-Strings
-.PP
-\*(Dc can operate on strings as well as on numbers.
-The only things you can do with strings are
-print them and execute them as macros
-(which means that the contents of the string are processed as
-\*(dc commands).
-All registers and the stack can hold strings,
-and \*(dc always knows whether any given object is a string or a number.
-Some commands such as arithmetic operations demand numbers
-as arguments and print errors if given strings.
-Other commands can accept either a number or a string;
-for example, the
-.B p
-command can accept either and prints the object
-according to its type.
-.TP
-.BI [ characters ]
-Makes a string containing
-.I characters
-(contained between balanced
-.B [
-and
-.B ]
-characters),
-and pushes it on the stack.
-For example,
-.B [foo]P
-prints the characters
-.B foo
-(with no newline).
-.TP
-.B a
-The top-of-stack is popped.
-If it was a number, then the low-order byte of this number
-is converted into a string and pushed onto the stack.
-Otherwise the top-of-stack was a string,
-and the first character of that string is pushed back.
-.TP
-.B x
-Pops a value off the stack and executes it as a macro.
-Normally it should be a string;
-if it is a number,
-it is simply pushed back onto the stack.
-For example,
-.B [1p]x
-executes the macro
-.B 1p
-which pushes
-.B 1
-on the stack and prints
-.B 1
-on a separate line.
-.PP
-Macros are most often stored in registers;
-.B [1p]sa
-stores a macro to print
-.B 1
-into register
-.BR a ,
-and
-.B lax
-invokes this macro.
-.TP
-.BI > r
-Pops two values off the stack and compares them
-assuming they are numbers,
-executing the contents of register
-.I r
-as a macro if the original top-of-stack
-is greater.
-Thus,
-.B 1 2>a
-will invoke register
-.BR a 's
-contents and
-.B 2 1>a
-will not.
-.TP
-.BI !> r
-Similar but invokes the macro if the original top-of-stack is
-not greater than (less than or equal to) what was the second-to-top.
-.TP
-.BI < r
-Similar but invokes the macro if the original top-of-stack is less.
-.TP
-.BI !< r
-Similar but invokes the macro if the original top-of-stack is
-not less than (greater than or equal to) what was the second-to-top.
-.TP
-.BI = r
-Similar but invokes the macro if the two numbers popped are equal.
-.TP
-.BI != r
-Similar but invokes the macro if the two numbers popped are not equal.
-.ig
-This can also be validly used to compare two strings for equality.
-..
-.TP
-.B ?
-Reads a line from the terminal and executes it.
-This command allows a macro to request input from the user.
-.TP
-.B q
-exits from a macro and also from the macro which invoked it.
-If called from the top level,
-or from a macro which was called directly from the top level,
-the
-.B q
-command will cause \*(dc to exit.
-.TP
-.B Q
-Pops a value off the stack and uses it as a count
-of levels of macro execution to be exited.
-Thus,
-.B 3Q
-exits three levels.
-The
-.B Q
-command will never cause \*(dc to exit.
-.SH
-Status Inquiry
-.TP
-.B Z
-Pops a value off the stack,
-calculates the number of digits it has
-(or number of characters, if it is a string)
-and pushes that number.
-.TP
-.B X
-Pops a value off the stack,
-calculates the number of fraction digits it has,
-and pushes that number.
-For a string,
-the value pushed is
-.\" -1.
-0.
-.TP
-.B z
-Pushes the current stack depth:
-the number of objects on the stack before the execution of the
-.B z
-command.
-.SH
-Miscellaneous
-.TP
-.B !
-Will run the rest of the line as a system command.
-Note that parsing of the !<, !=, and !> commands take precedence,
-so if you want to run a command starting with <, =, or > you will
-need to add a space after the !.
-.TP
-.B #
-Will interpret the rest of the line as a comment.
-.TP
-.BI : r
-Will pop the top two values off of the stack.
-The old second-to-top value will be stored in the array
-.IR r ,
-indexed by the old top-of-stack value.
-.TP
-.BI ; r
-Pops the top-of-stack and uses it as an index into
-the array
-.IR r .
-The selected value is then pushed onto the stack.
-.P
-Note that each stacked instance of a register has its own
-array associated with it.
-Thus \fB1 0:a 0Sa 2 0:a La 0;ap\fP will print 1,
-because the 2 was stored in an instance of 0:a that
-was later popped.
-.SH
-BUGS
-.PP
-Email bug reports to
-.BR bug-dc@gnu.org .
diff --git a/contrib/bc/doc/dc.texi b/contrib/bc/doc/dc.texi
deleted file mode 100644
index 0a4d973..0000000
--- a/contrib/bc/doc/dc.texi
+++ /dev/null
@@ -1,526 +0,0 @@
-\input texinfo @c -*-texinfo-*-
-@c %**start of header
-@setfilename dc.info
-@settitle dc, an arbitrary precision calculator
-@c %**end of header
-
-@c This file has the new style title page commands.
-@c Run `makeinfo' rather than `texinfo-format-buffer'.
-
-@c smallbook
-
-@c tex
-@c \overfullrule=0pt
-@c end tex
-
-@c Combine indices.
-@synindex cp fn
-@syncodeindex vr fn
-@syncodeindex ky fn
-@syncodeindex pg fn
-@syncodeindex tp fn
-
-@ifinfo
-@direntry
-* dc: (dc). Arbritrary precision RPN ``Desktop Calculator''.
-@end direntry
-This file documents @sc{dc}, an arbitrary precision calculator.
-
-Published by the Free Software Foundation, Inc.
-59 Temple Place, Suite 330
-Boston, MA 02111 USA
-
-Copyright (C) 1984, 1994, 1997, 1998, 2000 Free Software Foundation, Inc.
-
-Permission is granted to make and distribute verbatim copies of
-this manual provided the copyright notice and this permission notice
-are preserved on all copies.
-
-@ignore
-Permission is granted to process this file through TeX and print the
-results, provided the printed document carries copying permission
-notice identical to this one except for the removal of this paragraph
-(this paragraph not being relevant to the printed manual).
-
-@end ignore
-Permission is granted to copy and distribute modified versions of this
-manual under the conditions for verbatim copying, provided that the entire
-resulting derived work is distributed under the terms of a permission
-notice identical to this one.
-
-Permission is granted to copy and distribute translations of this manual
-into another language, under the above conditions for modified versions,
-except that this permission notice may be stated in a translation approved
-by the Foundation.
-@end ifinfo
-
-@setchapternewpage off
-
-@titlepage
-@title dc, an arbitrary precision calculator
-
-@author by Ken Pizzini
-@author original manual by Richard Stallman
-@page
-@vskip 0pt plus 1filll
-Copyright @copyright{} 1994, 1997, 1998 Free Software Foundation, Inc.
-
-@sp 2
-Published by the Free Software Foundation, @*
-59 Temple Place, Suite 330 @*
-Boston, MA 02111 USA
-
-Permission is granted to make and distribute verbatim copies of
-this manual provided the copyright notice and this permission notice
-are preserved on all copies.
-
-Permission is granted to copy and distribute modified versions of this
-manual under the conditions for verbatim copying, provided that the entire
-resulting derived work is distributed under the terms of a permission
-notice identical to this one.
-
-Permission is granted to copy and distribute translations of this manual
-into another language, under the above conditions for modified versions,
-except that this permission notice may be stated in a translation approved
-by the Foundation.
-
-@end titlepage
-@page
-
-@node Top, Introduction, (dir), (dir)
-
-@menu
-* Introduction:: Introduction
-* Invocation:: Invocation
-* Printing Commands:: Printing Commands
-* Arithmetic:: Arithmetic
-* Stack Control:: Stack Control
-* Registers:: Registers
-* Parameters:: Parameters
-* Strings:: Strings
-* Status Inquiry:: Status Inquiry
-* Miscellaneous:: Other commands
-* Reporting bugs:: Reporting bugs
-@end menu
-
-@node Introduction, Invocation, Top, Top
-@comment node-name, next, previous, up
-@chapter Introduction
-
-@sc{dc} is a reverse-polish desk calculator
-which supports unlimited precision arithmetic.
-It also allows you to define and call macros.
-Normally @sc{dc} reads from the standard input;
-if any command arguments are given to it, they are filenames,
-and @sc{dc} reads and executes the contents of the files
-instead of reading from standard input.
-All normal output is to standard output;
-all error messages are written to standard error.
-
-To exit, use @samp{q}.
-@kbd{C-c} does not exit;
-it is used to abort macros that are looping, etc.
-(Currently this is not true; @kbd{C-c} does exit.)
-
-A reverse-polish calculator stores numbers on a stack.
-Entering a number pushes it on the stack.
-Arithmetic operations pop arguments off the stack and push the results.
-
-To enter a number in @sc{dc}, type the digits,
-with an optional decimal point.
-Exponential notation is not supported.
-To enter a negative number, begin the number with @samp{_}.
-@samp{-} cannot be used for this, as it is a binary operator
-for subtraction instead.
-To enter two numbers in succession,
-separate them with spaces or newlines.
-These have no meaning as commands.
-
-@node Invocation, Printing Commands, Introduction, Top
-@chapter Invocation
-
-@sc{dc} may be invoked with the following command-line options:
-@table @samp
-
-@item -e @var{expr}
-@item --expression=@var{expr}
-Evaluate @var{expr} as @sc{dc} commands.
-
-@item -f @var{file}
-@item --file=@var{file}
-Read and evaluate @sc{dc} commands from @var{file}.
-
-@item -h
-@item --help
-Print a usage message summarizing the command-line options, then exit.
-
-@item -V
-@item --version
-Print the version information for this program, then exit.
-@end table
-
-If any command-line parameters remain after processing the options,
-these parameters are interpreted as additional @var{file}s whose
-contents are read and evaluated.
-A file name of @code{-} refers to the standard input stream.
-If no @code{-e} option was specified, and no files were specified,
-then the standard input will be read for commands to evaluate.
-
-@node Printing Commands, Arithmetic, Invocation, Top
-@chapter Printing Commands
-
-@table @samp
-@item p
-Prints the value on the top of the stack,
-without altering the stack.
-A newline is printed after the value.
-
-@item n
-Prints the value on the top of the stack, popping it off,
-and does not print a newline after.
-(This command is a GNU extension.)
-
-@item P
-Pops off the value on top of the stack.
-If it it a string, it is simply printed without a trailing newline.
-Otherwise it is a number, and the integer portion of its absolute
-value is printed out as a "base (UCHAR_MAX+1)" byte stream.
-Assuming that (UCHAR_MAX+1) is 256
-(as it is on most machines with 8-bit bytes),
-the sequence
-@code{KSK 0k1/ [_1*]sx d0>x [256~aPd0<x]dsxx sxLKk}
-could also accomplish this function,
-except for the side-effect of clobbering the x register.
-(Details of the behavior with a number are a GNU extension.)
-
-@item f
-Prints the entire contents of the stack
-@c and the contents of all of the registers,
-without altering anything.
-This is a good command to use if you are lost or want
-to figure out what the effect of some command has been.
-@end table
-
-@node Arithmetic, Stack Control, Printing Commands, Top
-@chapter Arithmetic
-
-@table @samp
-@item +
-Pops two values off the stack, adds them, and pushes the result.
-The precision of the result is determined only
-by the values of the arguments, and is enough to be exact.
-
-@item -
-Pops two values, subtracts the first one popped
-from the second one popped, and pushes the result.
-
-@item *
-Pops two values, multiplies them, and pushes the result.
-The number of fraction digits in the result is the largest of
-the precision value,
-the number of fraction digits in the multiplier,
-or the number of fraction digits in the multiplicand;
-but in no event exceeding the number of digits required for
-an exact result.
-
-@item /
-Pops two values, divides the second one popped
-from the first one popped, and pushes the result.
-The number of fraction digits is specified by the precision value.
-
-@item %
-Pops two values,
-computes the remainder of the division that
-the @samp{/} command would do,
-and pushes that.
-The value computed is the same as that computed by
-the sequence @code{Sd dld/ Ld*-} .
-
-@item ~
-Pops two values,
-divides the second one popped from the first one popped.
-The quotient is pushed first, and the remainder is pushed next.
-The number of fraction digits used in the division
-is specified by the precision value.
-(The sequence @code{SdSn lnld/ LnLd%} could also accomplish
-this function, with slightly different error checking.)
-(This command is a GNU extension.)
-
-@item ^
-Pops two values and exponentiates,
-using the first value popped as the exponent
-and the second popped as the base.
-The fraction part of the exponent is ignored.
-The precision value specifies the number of fraction
-digits in the result.
-
-@item |
-Pops three values and computes a modular exponentiation.
-The first value popped is used as the reduction modulus;
-this value must be a non-zero number,
-and the result may not be accurate if the modulus
-is not an integer.
-The second popped is used as the exponent;
-this value must be a non-negative number,
-and any fractional part of this exponent will be ignored.
-The third value popped is the base which gets exponentiated,
-which should be an integer.
-For small integers this is like the sequence @code{Sm^Lm%},
-but, unlike @code{^}, this command will work with arbritrarily large exponents.
-(This command is a GNU extension.)
-
-@item v
-Pops one value, computes its square root, and pushes that.
-The precision value specifies the number of fraction digits
-in the result.
-@end table
-
-Most arithmetic operations are affected by the @emph{precision value},
-which you can set with the @samp{k} command.
-The default precision value is zero,
-which means that all arithmetic except for
-addition and subtraction produces integer results.
-
-@node Stack Control, Registers, Arithmetic, Top
-@chapter Stack Control
-
-@table @samp
-@item c
-Clears the stack, rendering it empty.
-
-@item d
-Duplicates the value on the top of the stack,
-pushing another copy of it.
-Thus, @samp{4d*p} computes 4 squared and prints it.
-
-@item r
-Reverses the order of (swaps) the top two values on the stack.
-(This command is a GNU extension.)
-@end table
-
-@node Registers, Parameters, Stack Control, Top
-@chapter Registers
-
-@sc{dc} provides at least 256 memory registers,
-each named by a single character.
-You can store a number in a register and retrieve it later.
-
-@table @samp
-@item s@var{r}
-Pop the value off the top of the stack and
-store it into register @var{r}.
-
-@item l@var{r}
-Copy the value in register @var{r},
-and push it onto the stack.
-This does not alter the contents of @var{r}.
-
-Each register also contains its own stack.
-The current register value is the top of the register's stack.
-
-@item S@var{r}
-Pop the value off the top of the (main) stack and
-push it onto the stack of register @var{r}.
-The previous value of the register becomes inaccessible.
-
-@item L@var{r}
-Pop the value off the top of register @var{r}'s stack
-and push it onto the main stack.
-The previous value in register @var{r}'s stack, if any,
-is now accessible via the @samp{l@var{r}} command.
-@end table
-@c
-@c The @samp{f} command prints a list of all registers that have contents
-@c stored in them, together with their contents.
-@c Only the current contents of each register (the top of its stack)
-@c is printed.
-
-@node Parameters, Strings, Registers, Top
-@chapter Parameters
-
-@sc{dc} has three parameters that control its operation:
-the precision, the input radix, and the output radix.
-The precision specifies the number of fraction digits
-to keep in the result of most arithmetic operations.
-The input radix controls the interpretation of numbers typed in;
-@emph{all} numbers typed in use this radix.
-The output radix is used for printing numbers.
-
-The input and output radices are separate parameters;
-you can make them unequal, which can be useful or confusing.
-The input radix must be between 2 and 16 inclusive.
-The output radix must be at least 2.
-The precision must be zero or greater.
-The precision is always measured in decimal digits,
-regardless of the current input or output radix.
-
-@table @samp
-@item i
-Pops the value off the top of the stack
-and uses it to set the input radix.
-
-@item o
-Pops the value off the top of the stack
-and uses it to set the output radix.
-
-@item k
-Pops the value off the top of the stack
-and uses it to set the precision.
-
-@item I
-Pushes the current input radix on the stack.
-
-@item O
-Pushes the current output radix on the stack.
-
-@item K
-Pushes the current precision on the stack.
-
-@end table
-
-@node Strings, Status Inquiry, Parameters, Top
-@chapter Strings
-
-@sc{dc} can operate on strings as well as on numbers.
-The only things you can do with strings are print them
-and execute them as macros
-(which means that the contents of the string are processed as @sc{dc} commands).
-Both registers and the stack can hold strings,
-and @sc{dc} always knows whether any given object is a string or a number.
-Some commands such as arithmetic operations demand numbers
-as arguments and print errors if given strings.
-Other commands can accept either a number or a string;
-for example, the @samp{p} command can accept either and prints the object
-according to its type.
-
-@table @samp
-@item [@var{characters}]
-Makes a string containing @var{characters} and pushes it on the stack.
-For example, @samp{[foo]P} prints the characters @samp{foo}
-(with no newline).
-
-@item a
-The mnemonic for this is somewhat erroneous: asciify.
-The top-of-stack is popped.
-If it was a number, then the low-order byte of this number
-is converted into a string and pushed onto the stack.
-Otherwise the top-of-stack was a string,
-and the first character of that string is pushed back.
-(This command is a GNU extension.)
-
-@item x
-Pops a value off the stack and executes it as a macro.
-Normally it should be a string;
-if it is a number, it is simply pushed back onto the stack.
-For example, @samp{[1p]x} executes the macro @samp{1p},
-which pushes 1 on the stack and prints @samp{1} on a separate line.
-
-Macros are most often stored in registers;
-@samp{[1p]sa} stores a macro to print @samp{1} into register @samp{a},
-and @samp{lax} invokes the macro.
-
-@item >@var{r}
-Pops two values off the stack and compares them
-assuming they are numbers,
-executing the contents of register @var{r} as a macro
-if the original top-of-stack is greater.
-Thus, @samp{1 2>a} will invoke register @samp{a}'s contents
-and @samp{2 1>a} will not.
-
-@item !>@var{r}
-Similar but invokes the macro if the original top-of-stack is not greater
-(is less than or equal to) what was the second-to-top.
-
-@item <@var{r}
-Similar but invokes the macro if the original top-of-stack is less.
-
-@item !<@var{r}
-Similar but invokes the macro if the original top-of-stack is not less
-(is greater than or equal to) what was the second-to-top.
-
-@item =@var{r}
-Similar but invokes the macro if the two numbers popped are equal.
-@c This can also be validly used to compare two strings for equality.
-
-@item !=@var{r}
-Similar but invokes the macro if the two numbers popped are not equal.
-@c This can also be validly used to compare two strings for equality.
-
-@item ?
-Reads a line from the terminal and executes it.
-This command allows a macro to request input from the user.
-
-@item q
-During the execution of a macro,
-this command exits from the macro and also from the macro which invoked it.
-If called from the top level,
-or from a macro which was called directly from the top level,
-the @samp{q} command will cause @sc{dc} to exit.
-
-@item Q
-Pops a value off the stack and uses it as a count
-of levels of macro execution to be exited.
-Thus, @samp{3Q} exits three levels.
-@end table
-
-@node Status Inquiry, Miscellaneous, Strings, Top
-@chapter Status Inquiry
-
-@table @samp
-@item Z
-Pops a value off the stack,
-calculates the number of digits it has
-(or number of characters, if it is a string)
-and pushes that number.
-
-@item X
-Pops a value off the stack,
-calculates the number of fraction digits it has,
-and pushes that number.
-For a string, the value pushed is
-@c -1.
-0.
-
-@item z
-Pushes the current stack depth:
-the number of objects on the stack
-before the execution of the @samp{z} command.
-@end table
-
-@node Miscellaneous, Reporting bugs, Status Inquiry, Top
-@chapter Miscellaneous
-
-@table @samp
-@item !
-Will run the rest of the line as a system command.
-Note that parsing of the !<, !=, and !> commands take precidence,
-so if you want to run a command starting with <, =, or > you will
-need to add a space after the !.
-
-@item #
-Will interpret the rest of the line as a comment.
-(This command is a GNU extension.)
-
-@item :@var{r}
-Will pop the top two values off of the stack.
-The old second-to-top value will be stored in the array @var{r},
-indexed by the old top-of-stack value.
-
-@item ;@var{r}
-Pops the top-of-stack and uses it as an index into
-the array @var{r}.
-The selected value is then pushed onto the stack.
-@end table
-
-Note that each stacked instance of a register has its own
-array associated with it.
-Thus @samp{1 @var{0:a} 0S@var{a} 2 @var{0:a} L@var{a} @var{0;a}p}
-will print 1, because the 2 was stored in an instance of @var{0:a}
-that was later popped.
-
-@node Reporting bugs, , Miscellaneous, Top
-@chapter Reporting bugs
-
-Email bug reports to @email{bug-dc@@gnu.org}.
-@contents
-@bye
diff --git a/contrib/bc/h/number.h b/contrib/bc/h/number.h
deleted file mode 100644
index 8d78120..0000000
--- a/contrib/bc/h/number.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/* number.h: Arbitrary precision numbers header file. */
-/*
- Copyright (C) 1991, 1992, 1993, 1994, 1997, 2000 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to:
-
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111-1307 USA.
-
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-#ifndef _NUMBER_H_
-#define _NUMBER_H_
-
-typedef enum {PLUS, MINUS} sign;
-
-typedef struct bc_struct *bc_num;
-
-typedef struct bc_struct
- {
- sign n_sign;
- int n_len; /* The number of digits before the decimal point. */
- int n_scale; /* The number of digits after the decimal point. */
- int n_refs; /* The number of pointers to this number. */
- bc_num n_next; /* Linked list for available list. */
- char *n_ptr; /* The pointer to the actual storage.
- If NULL, n_value points to the inside of
- another number (bc_multiply...) and should
- not be "freed." */
- char *n_value; /* The number. Not zero char terminated.
- May not point to the same place as n_ptr as
- in the case of leading zeros generated. */
- } bc_struct;
-
-
-/* The base used in storing the numbers in n_value above.
- Currently this MUST be 10. */
-
-#define BASE 10
-
-/* Some useful macros and constants. */
-
-#define CH_VAL(c) (c - '0')
-#define BCD_CHAR(d) (d + '0')
-
-#ifdef MIN
-#undef MIN
-#undef MAX
-#endif
-#define MAX(a,b) ((a)>(b)?(a):(b))
-#define MIN(a,b) ((a)>(b)?(b):(a))
-#define ODD(a) ((a)&1)
-
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
-
-#ifndef LONG_MAX
-#define LONG_MAX 0x7ffffff
-#endif
-
-
-/* Global numbers. */
-extern bc_num _zero_;
-extern bc_num _one_;
-extern bc_num _two_;
-
-
-/* Function Prototypes */
-
-/* Define the _PROTOTYPE macro if it is needed. */
-
-#ifndef _PROTOTYPE
-#ifdef __STDC__
-#define _PROTOTYPE(func, args) func args
-#else
-#define _PROTOTYPE(func, args) func()
-#endif
-#endif
-
-_PROTOTYPE(void bc_init_numbers, (void));
-
-_PROTOTYPE(bc_num bc_new_num, (int length, int scale));
-
-_PROTOTYPE(void bc_free_num, (bc_num *num));
-
-_PROTOTYPE(bc_num bc_copy_num, (bc_num num));
-
-_PROTOTYPE(void bc_init_num, (bc_num *num));
-
-_PROTOTYPE(void bc_str2num, (bc_num *num, char *str, int scale));
-
-_PROTOTYPE(char *bc_num2str, (bc_num num));
-
-_PROTOTYPE(void bc_int2num, (bc_num *num, int val));
-
-_PROTOTYPE(long bc_num2long, (bc_num num));
-
-_PROTOTYPE(int bc_compare, (bc_num n1, bc_num n2));
-
-_PROTOTYPE(char bc_is_zero, (bc_num num));
-
-_PROTOTYPE(char bc_is_near_zero, (bc_num num, int scale));
-
-_PROTOTYPE(char bc_is_neg, (bc_num num));
-
-_PROTOTYPE(void bc_add, (bc_num n1, bc_num n2, bc_num *result, int scale_min));
-
-_PROTOTYPE(void bc_sub, (bc_num n1, bc_num n2, bc_num *result, int scale_min));
-
-_PROTOTYPE(void bc_multiply, (bc_num n1, bc_num n2, bc_num *prod, int scale));
-
-_PROTOTYPE(int bc_divide, (bc_num n1, bc_num n2, bc_num *quot, int scale));
-
-_PROTOTYPE(int bc_modulo, (bc_num num1, bc_num num2, bc_num *result,
- int scale));
-
-_PROTOTYPE(int bc_divmod, (bc_num num1, bc_num num2, bc_num *quot,
- bc_num *rem, int scale));
-
-_PROTOTYPE(int bc_raisemod, (bc_num base, bc_num expo, bc_num mod,
- bc_num *result, int scale));
-
-_PROTOTYPE(void bc_raise, (bc_num num1, bc_num num2, bc_num *result,
- int scale));
-
-_PROTOTYPE(int bc_sqrt, (bc_num *num, int scale));
-
-_PROTOTYPE(void bc_out_num, (bc_num num, int o_base, void (* out_char)(int),
- int leading_zero));
-
-#endif
diff --git a/contrib/bc/install-sh b/contrib/bc/install-sh
deleted file mode 100755
index ab74c88..0000000
--- a/contrib/bc/install-sh
+++ /dev/null
@@ -1,238 +0,0 @@
-#!/bin/sh
-#
-# install - install a program, script, or datafile
-# This comes from X11R5.
-#
-# Calling this script install-sh is preferred over install.sh, to prevent
-# `make' implicit rules from creating a file called install from it
-# when there is no Makefile.
-#
-# This script is compatible with the BSD install script, but was written
-# from scratch.
-#
-
-
-# set DOITPROG to echo to test this script
-
-# Don't use :- since 4.3BSD and earlier shells don't like it.
-doit="${DOITPROG-}"
-
-
-# put in absolute paths if you don't have them in your path; or use env. vars.
-
-mvprog="${MVPROG-mv}"
-cpprog="${CPPROG-cp}"
-chmodprog="${CHMODPROG-chmod}"
-chownprog="${CHOWNPROG-chown}"
-chgrpprog="${CHGRPPROG-chgrp}"
-stripprog="${STRIPPROG-strip}"
-rmprog="${RMPROG-rm}"
-mkdirprog="${MKDIRPROG-mkdir}"
-
-tranformbasename=""
-transform_arg=""
-instcmd="$mvprog"
-chmodcmd="$chmodprog 0755"
-chowncmd=""
-chgrpcmd=""
-stripcmd=""
-rmcmd="$rmprog -f"
-mvcmd="$mvprog"
-src=""
-dst=""
-dir_arg=""
-
-while [ x"$1" != x ]; do
- case $1 in
- -c) instcmd="$cpprog"
- shift
- continue;;
-
- -d) dir_arg=true
- shift
- continue;;
-
- -m) chmodcmd="$chmodprog $2"
- shift
- shift
- continue;;
-
- -o) chowncmd="$chownprog $2"
- shift
- shift
- continue;;
-
- -g) chgrpcmd="$chgrpprog $2"
- shift
- shift
- continue;;
-
- -s) stripcmd="$stripprog"
- shift
- continue;;
-
- -t=*) transformarg=`echo $1 | sed 's/-t=//'`
- shift
- continue;;
-
- -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
- shift
- continue;;
-
- *) if [ x"$src" = x ]
- then
- src=$1
- else
- # this colon is to work around a 386BSD /bin/sh bug
- :
- dst=$1
- fi
- shift
- continue;;
- esac
-done
-
-if [ x"$src" = x ]
-then
- echo "install: no input file specified"
- exit 1
-else
- true
-fi
-
-if [ x"$dir_arg" != x ]; then
- dst=$src
- src=""
-
- if [ -d $dst ]; then
- instcmd=:
- else
- instcmd=mkdir
- fi
-else
-
-# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
-# might cause directories to be created, which would be especially bad
-# if $src (and thus $dsttmp) contains '*'.
-
- if [ -f $src -o -d $src ]
- then
- true
- else
- echo "install: $src does not exist"
- exit 1
- fi
-
- if [ x"$dst" = x ]
- then
- echo "install: no destination specified"
- exit 1
- else
- true
- fi
-
-# If destination is a directory, append the input filename; if your system
-# does not like double slashes in filenames, you may need to add some logic
-
- if [ -d $dst ]
- then
- dst="$dst"/`basename $src`
- else
- true
- fi
-fi
-
-## this sed command emulates the dirname command
-dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
-
-# Make sure that the destination directory exists.
-# this part is taken from Noah Friedman's mkinstalldirs script
-
-# Skip lots of stat calls in the usual case.
-if [ ! -d "$dstdir" ]; then
-defaultIFS='
-'
-IFS="${IFS-${defaultIFS}}"
-
-oIFS="${IFS}"
-# Some sh's can't handle IFS=/ for some reason.
-IFS='%'
-set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
-IFS="${oIFS}"
-
-pathcomp=''
-
-while [ $# -ne 0 ] ; do
- pathcomp="${pathcomp}${1}"
- shift
-
- if [ ! -d "${pathcomp}" ] ;
- then
- $mkdirprog "${pathcomp}"
- else
- true
- fi
-
- pathcomp="${pathcomp}/"
-done
-fi
-
-if [ x"$dir_arg" != x ]
-then
- $doit $instcmd $dst &&
-
- if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
- if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
- if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
- if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
-else
-
-# If we're going to rename the final executable, determine the name now.
-
- if [ x"$transformarg" = x ]
- then
- dstfile=`basename $dst`
- else
- dstfile=`basename $dst $transformbasename |
- sed $transformarg`$transformbasename
- fi
-
-# don't allow the sed command to completely eliminate the filename
-
- if [ x"$dstfile" = x ]
- then
- dstfile=`basename $dst`
- else
- true
- fi
-
-# Make a temp file name in the proper directory.
-
- dsttmp=$dstdir/#inst.$$#
-
-# Move or copy the file name to the temp name
-
- $doit $instcmd $src $dsttmp &&
-
- trap "rm -f ${dsttmp}" 0 &&
-
-# and set any options; do chmod last to preserve setuid bits
-
-# If any of these fail, we abort the whole thing. If we want to
-# ignore errors from any of these, just make sure not to ignore
-# errors from the above "$doit $instcmd $src $dsttmp" command.
-
- if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
- if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
- if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
- if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
-
-# Now rename the file to the real destination.
-
- $doit $rmcmd -f $dstdir/$dstfile &&
- $doit $mvcmd $dsttmp $dstdir/$dstfile
-
-fi &&
-
-
-exit 0
diff --git a/contrib/bc/lib/Makefile.am b/contrib/bc/lib/Makefile.am
deleted file mode 100644
index 6f74b4d..0000000
--- a/contrib/bc/lib/Makefile.am
+++ /dev/null
@@ -1,26 +0,0 @@
-## Process this file with automake to produce Makefile.in
-noinst_LIBRARIES = libbc.a
-
-INCLUDES = -I. -I.. -I$(srcdir)/../h
-
-libbc_a_SOURCES = getopt.c getopt1.c vfprintf.c number.c
-
-DEFS = @DEFS@ $(DEFSADD)
-
-CFLAGS = @CFLAGS@ -Wall -funsigned-char
-
-MAINTAINERCLEANFILES = Makefile.in number.c
-
-newnumber.o: number.c muldigits.h
- $(CC) $(CFLAGS) $(INCLUDES) -c -DMULDIGITS -o newnumber.o $(srcdir)/number.c
-
-muldigits.h: testmul
- @echo "The following may take up to 10 minutes."
- testmul > muldigits.h
-
-testmul: testmul.o number.o
- $(CC) $(CFLAGS) -o testmul testmul.o number.o
-
-specialnumber: newnumber.o
- cp newnumber.o number.o
-
diff --git a/contrib/bc/lib/Makefile.in b/contrib/bc/lib/Makefile.in
deleted file mode 100644
index 5ffa593..0000000
--- a/contrib/bc/lib/Makefile.in
+++ /dev/null
@@ -1,283 +0,0 @@
-# Makefile.in generated automatically by automake 1.4 from Makefile.am
-
-# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-
-SHELL = @SHELL@
-
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
-VPATH = @srcdir@
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-
-bindir = @bindir@
-sbindir = @sbindir@
-libexecdir = @libexecdir@
-datadir = @datadir@
-sysconfdir = @sysconfdir@
-sharedstatedir = @sharedstatedir@
-localstatedir = @localstatedir@
-libdir = @libdir@
-infodir = @infodir@
-mandir = @mandir@
-includedir = @includedir@
-oldincludedir = /usr/include
-
-DESTDIR =
-
-pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-
-top_builddir = ..
-
-ACLOCAL = @ACLOCAL@
-AUTOCONF = @AUTOCONF@
-AUTOMAKE = @AUTOMAKE@
-AUTOHEADER = @AUTOHEADER@
-
-INSTALL = @INSTALL@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-transform = @program_transform_name@
-
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-CC = @CC@
-LEX = @LEX@
-MAKEINFO = @MAKEINFO@
-PACKAGE = @PACKAGE@
-RANLIB = @RANLIB@
-READLINELIB = @READLINELIB@
-VERSION = @VERSION@
-YACC = @YACC@
-
-noinst_LIBRARIES = libbc.a
-
-INCLUDES = -I. -I.. -I$(srcdir)/../h
-
-libbc_a_SOURCES = getopt.c getopt1.c vfprintf.c number.c
-
-DEFS = @DEFS@ $(DEFSADD)
-
-CFLAGS = @CFLAGS@ -Wall -funsigned-char
-
-MAINTAINERCLEANFILES = Makefile.in number.c
-mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
-CONFIG_HEADER = ../config.h
-CONFIG_CLEAN_FILES =
-LIBRARIES = $(noinst_LIBRARIES)
-
-CPPFLAGS = @CPPFLAGS@
-LDFLAGS = @LDFLAGS@
-LIBS = @LIBS@
-libbc_a_LIBADD =
-libbc_a_OBJECTS = getopt.o getopt1.o vfprintf.o number.o
-AR = ar
-COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-CCLD = $(CC)
-LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
-DIST_COMMON = Makefile.am Makefile.in
-
-
-DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-
-TAR = tar
-GZIP_ENV = --best
-SOURCES = $(libbc_a_SOURCES)
-OBJECTS = $(libbc_a_OBJECTS)
-
-all: all-redirect
-.SUFFIXES:
-.SUFFIXES: .S .c .o .s
-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
- cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps lib/Makefile
-
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
- cd $(top_builddir) \
- && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
-
-
-mostlyclean-noinstLIBRARIES:
-
-clean-noinstLIBRARIES:
- -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
-
-distclean-noinstLIBRARIES:
-
-maintainer-clean-noinstLIBRARIES:
-
-.c.o:
- $(COMPILE) -c $<
-
-.s.o:
- $(COMPILE) -c $<
-
-.S.o:
- $(COMPILE) -c $<
-
-mostlyclean-compile:
- -rm -f *.o core *.core
-
-clean-compile:
-
-distclean-compile:
- -rm -f *.tab.c
-
-maintainer-clean-compile:
-
-libbc.a: $(libbc_a_OBJECTS) $(libbc_a_DEPENDENCIES)
- -rm -f libbc.a
- $(AR) cru libbc.a $(libbc_a_OBJECTS) $(libbc_a_LIBADD)
- $(RANLIB) libbc.a
-
-tags: TAGS
-
-ID: $(HEADERS) $(SOURCES) $(LISP)
- list='$(SOURCES) $(HEADERS)'; \
- unique=`for i in $$list; do echo $$i; done | \
- awk ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
- here=`pwd` && cd $(srcdir) \
- && mkid -f$$here/ID $$unique $(LISP)
-
-TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
- tags=; \
- here=`pwd`; \
- list='$(SOURCES) $(HEADERS)'; \
- unique=`for i in $$list; do echo $$i; done | \
- awk ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
- test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
- || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
-
-mostlyclean-tags:
-
-clean-tags:
-
-distclean-tags:
- -rm -f TAGS ID
-
-maintainer-clean-tags:
-
-distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
-
-subdir = lib
-
-distdir: $(DISTFILES)
- @for file in $(DISTFILES); do \
- d=$(srcdir); \
- if test -d $$d/$$file; then \
- cp -pr $$/$$file $(distdir)/$$file; \
- else \
- test -f $(distdir)/$$file \
- || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
- || cp -p $$d/$$file $(distdir)/$$file || :; \
- fi; \
- done
-getopt.o: getopt.c ../config.h ../h/getopt.h
-getopt1.o: getopt1.c ../config.h ../h/getopt.h
-number.o: number.c ../config.h ../h/number.h
-vfprintf.o: vfprintf.c ../config.h
-
-info-am:
-info: info-am
-dvi-am:
-dvi: dvi-am
-check-am: all-am
-check: check-am
-installcheck-am:
-installcheck: installcheck-am
-install-exec-am:
-install-exec: install-exec-am
-
-install-data-am:
-install-data: install-data-am
-
-install-am: all-am
- @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-install: install-am
-uninstall-am:
-uninstall: uninstall-am
-all-am: Makefile $(LIBRARIES)
-all-redirect: all-am
-install-strip:
- $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
-installdirs:
-
-
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
- -rm -f Makefile $(CONFIG_CLEAN_FILES)
- -rm -f config.cache config.log stamp-h stamp-h[0-9]*
-
-maintainer-clean-generic:
- -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
-mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \
- mostlyclean-tags mostlyclean-generic
-
-mostlyclean: mostlyclean-am
-
-clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
- mostlyclean-am
-
-clean: clean-am
-
-distclean-am: distclean-noinstLIBRARIES distclean-compile \
- distclean-tags distclean-generic clean-am
-
-distclean: distclean-am
-
-maintainer-clean-am: maintainer-clean-noinstLIBRARIES \
- maintainer-clean-compile maintainer-clean-tags \
- maintainer-clean-generic distclean-am
- @echo "This command is intended for maintainers to use;"
- @echo "it deletes files that may require special tools to rebuild."
-
-maintainer-clean: maintainer-clean-am
-
-.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
-clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
-mostlyclean-compile distclean-compile clean-compile \
-maintainer-clean-compile tags mostlyclean-tags distclean-tags \
-clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
-check-am installcheck-am installcheck install-exec-am install-exec \
-install-data-am install-data install-am install uninstall-am uninstall \
-all-redirect all-am all installdirs mostlyclean-generic \
-distclean-generic clean-generic maintainer-clean-generic clean \
-mostlyclean distclean maintainer-clean
-
-
-newnumber.o: number.c muldigits.h
- $(CC) $(CFLAGS) $(INCLUDES) -c -DMULDIGITS -o newnumber.o $(srcdir)/number.c
-
-muldigits.h: testmul
- @echo "The following may take up to 10 minutes."
- testmul > muldigits.h
-
-testmul: testmul.o number.o
- $(CC) $(CFLAGS) -o testmul testmul.o number.o
-
-specialnumber: newnumber.o
- cp newnumber.o number.o
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/contrib/bc/lib/number.c b/contrib/bc/lib/number.c
deleted file mode 100644
index 1f913d5..0000000
--- a/contrib/bc/lib/number.c
+++ /dev/null
@@ -1,1793 +0,0 @@
-/* number.c: Implements arbitrary precision numbers. */
-/*
- Copyright (C) 1991, 1992, 1993, 1994, 1997, 2000 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to:
-
- The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111-1307 USA.
-
-
- You may contact the author by:
- e-mail: philnelson@acm.org
- us-mail: Philip A. Nelson
- Computer Science Department, 9062
- Western Washington University
- Bellingham, WA 98226-9062
-
-*************************************************************************/
-
-#include <stdio.h>
-#include <config.h>
-#include <number.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <ctype.h>/* Prototypes needed for external utility routines. */
-
-#define bc_rt_warn rt_warn
-#define bc_rt_error rt_error
-#define bc_out_of_memory out_of_memory
-
-_PROTOTYPE(void rt_warn, (char *mesg ,...));
-_PROTOTYPE(void rt_error, (char *mesg ,...));
-_PROTOTYPE(void out_of_memory, (void));
-
-/* Storage used for special numbers. */
-bc_num _zero_;
-bc_num _one_;
-bc_num _two_;
-
-static bc_num _bc_Free_list = NULL;
-
-/* new_num allocates a number and sets fields to known values. */
-
-bc_num
-bc_new_num (length, scale)
- int length, scale;
-{
- bc_num temp;
-
- if (_bc_Free_list != NULL) {
- temp = _bc_Free_list;
- _bc_Free_list = temp->n_next;
- } else {
- temp = (bc_num) malloc (sizeof(bc_struct));
- if (temp == NULL) bc_out_of_memory ();
- }
- temp->n_sign = PLUS;
- temp->n_len = length;
- temp->n_scale = scale;
- temp->n_refs = 1;
- temp->n_ptr = (char *) malloc (length+scale);
- if (temp->n_ptr == NULL) bc_out_of_memory();
- temp->n_value = temp->n_ptr;
- memset (temp->n_ptr, 0, length+scale);
- return temp;
-}
-
-/* "Frees" a bc_num NUM. Actually decreases reference count and only
- frees the storage if reference count is zero. */
-
-void
-bc_free_num (num)
- bc_num *num;
-{
- if (*num == NULL) return;
- (*num)->n_refs--;
- if ((*num)->n_refs == 0) {
- if ((*num)->n_ptr)
- free ((*num)->n_ptr);
- (*num)->n_next = _bc_Free_list;
- _bc_Free_list = *num;
- }
- *num = NULL;
-}
-
-
-/* Intitialize the number package! */
-
-void
-bc_init_numbers ()
-{
- _zero_ = bc_new_num (1,0);
- _one_ = bc_new_num (1,0);
- _one_->n_value[0] = 1;
- _two_ = bc_new_num (1,0);
- _two_->n_value[0] = 2;
-}
-
-
-/* Make a copy of a number! Just increments the reference count! */
-
-bc_num
-bc_copy_num (num)
- bc_num num;
-{
- num->n_refs++;
- return num;
-}
-
-
-/* Initialize a number NUM by making it a copy of zero. */
-
-void
-bc_init_num (num)
- bc_num *num;
-{
- *num = bc_copy_num (_zero_);
-}
-
-/* For many things, we may have leading zeros in a number NUM.
- _bc_rm_leading_zeros just moves the data "value" pointer to the
- correct place and adjusts the length. */
-
-static void
-_bc_rm_leading_zeros (num)
- bc_num num;
-{
- /* We can move n_value to point to the first non zero digit! */
- while (*num->n_value == 0 && num->n_len > 1) {
- num->n_value++;
- num->n_len--;
- }
-}
-
-
-/* Compare two bc numbers. Return value is 0 if equal, -1 if N1 is less
- than N2 and +1 if N1 is greater than N2. If USE_SIGN is false, just
- compare the magnitudes. */
-
-static int
-_bc_do_compare (n1, n2, use_sign, ignore_last)
- bc_num n1, n2;
- int use_sign;
- int ignore_last;
-{
- char *n1ptr, *n2ptr;
- int count;
-
- /* First, compare signs. */
- if (use_sign && n1->n_sign != n2->n_sign)
- {
- if (n1->n_sign == PLUS)
- return (1); /* Positive N1 > Negative N2 */
- else
- return (-1); /* Negative N1 < Positive N1 */
- }
-
- /* Now compare the magnitude. */
- if (n1->n_len != n2->n_len)
- {
- if (n1->n_len > n2->n_len)
- {
- /* Magnitude of n1 > n2. */
- if (!use_sign || n1->n_sign == PLUS)
- return (1);
- else
- return (-1);
- }
- else
- {
- /* Magnitude of n1 < n2. */
- if (!use_sign || n1->n_sign == PLUS)
- return (-1);
- else
- return (1);
- }
- }
-
- /* If we get here, they have the same number of integer digits.
- check the integer part and the equal length part of the fraction. */
- count = n1->n_len + MIN (n1->n_scale, n2->n_scale);
- n1ptr = n1->n_value;
- n2ptr = n2->n_value;
-
- while ((count > 0) && (*n1ptr == *n2ptr))
- {
- n1ptr++;
- n2ptr++;
- count--;
- }
- if (ignore_last && count == 1 && n1->n_scale == n2->n_scale)
- return (0);
- if (count != 0)
- {
- if (*n1ptr > *n2ptr)
- {
- /* Magnitude of n1 > n2. */
- if (!use_sign || n1->n_sign == PLUS)
- return (1);
- else
- return (-1);
- }
- else
- {
- /* Magnitude of n1 < n2. */
- if (!use_sign || n1->n_sign == PLUS)
- return (-1);
- else
- return (1);
- }
- }
-
- /* They are equal up to the last part of the equal part of the fraction. */
- if (n1->n_scale != n2->n_scale)
- {
- if (n1->n_scale > n2->n_scale)
- {
- for (count = n1->n_scale-n2->n_scale; count>0; count--)
- if (*n1ptr++ != 0)
- {
- /* Magnitude of n1 > n2. */
- if (!use_sign || n1->n_sign == PLUS)
- return (1);
- else
- return (-1);
- }
- }
- else
- {
- for (count = n2->n_scale-n1->n_scale; count>0; count--)
- if (*n2ptr++ != 0)
- {
- /* Magnitude of n1 < n2. */
- if (!use_sign || n1->n_sign == PLUS)
- return (-1);
- else
- return (1);
- }
- }
- }
-
- /* They must be equal! */
- return (0);
-}
-
-
-/* This is the "user callable" routine to compare numbers N1 and N2. */
-
-int
-bc_compare (n1, n2)
- bc_num n1, n2;
-{
- return _bc_do_compare (n1, n2, TRUE, FALSE);
-}
-
-/* In some places we need to check if the number is negative. */
-
-char
-bc_is_neg (num)
- bc_num num;
-{
- return num->n_sign == MINUS;
-}
-
-/* In some places we need to check if the number NUM is zero. */
-
-char
-bc_is_zero (num)
- bc_num num;
-{
- int count;
- char *nptr;
-
- /* Quick check. */
- if (num == _zero_) return TRUE;
-
- /* Initialize */
- count = num->n_len + num->n_scale;
- nptr = num->n_value;
-
- /* The check */
- while ((count > 0) && (*nptr++ == 0)) count--;
-
- if (count != 0)
- return FALSE;
- else
- return TRUE;
-}
-
-/* In some places we need to check if the number NUM is almost zero.
- Specifically, all but the last digit is 0 and the last digit is 1.
- Last digit is defined by scale. */
-
-char
-bc_is_near_zero (num, scale)
- bc_num num;
- int scale;
-{
- int count;
- char *nptr;
-
- /* Error checking */
- if (scale > num->n_scale)
- scale = num->n_scale;
-
- /* Initialize */
- count = num->n_len + scale;
- nptr = num->n_value;
-
- /* The check */
- while ((count > 0) && (*nptr++ == 0)) count--;
-
- if (count != 0 && (count != 1 || *--nptr != 1))
- return FALSE;
- else
- return TRUE;
-}
-
-
-/* Perform addition: N1 is added to N2 and the value is
- returned. The signs of N1 and N2 are ignored.
- SCALE_MIN is to set the minimum scale of the result. */
-
-static bc_num
-_bc_do_add (n1, n2, scale_min)
- bc_num n1, n2;
- int scale_min;
-{
- bc_num sum;
- int sum_scale, sum_digits;
- char *n1ptr, *n2ptr, *sumptr;
- int carry, n1bytes, n2bytes;
- int count;
-
- /* Prepare sum. */
- sum_scale = MAX (n1->n_scale, n2->n_scale);
- sum_digits = MAX (n1->n_len, n2->n_len) + 1;
- sum = bc_new_num (sum_digits, MAX(sum_scale, scale_min));
-
- /* Zero extra digits made by scale_min. */
- if (scale_min > sum_scale)
- {
- sumptr = (char *) (sum->n_value + sum_scale + sum_digits);
- for (count = scale_min - sum_scale; count > 0; count--)
- *sumptr++ = 0;
- }
-
- /* Start with the fraction part. Initialize the pointers. */
- n1bytes = n1->n_scale;
- n2bytes = n2->n_scale;
- n1ptr = (char *) (n1->n_value + n1->n_len + n1bytes - 1);
- n2ptr = (char *) (n2->n_value + n2->n_len + n2bytes - 1);
- sumptr = (char *) (sum->n_value + sum_scale + sum_digits - 1);
-
- /* Add the fraction part. First copy the longer fraction.*/
- if (n1bytes != n2bytes)
- {
- if (n1bytes > n2bytes)
- while (n1bytes>n2bytes)
- { *sumptr-- = *n1ptr--; n1bytes--;}
- else
- while (n2bytes>n1bytes)
- { *sumptr-- = *n2ptr--; n2bytes--;}
- }
-
- /* Now add the remaining fraction part and equal size integer parts. */
- n1bytes += n1->n_len;
- n2bytes += n2->n_len;
- carry = 0;
- while ((n1bytes > 0) && (n2bytes > 0))
- {
- *sumptr = *n1ptr-- + *n2ptr-- + carry;
- if (*sumptr > (BASE-1))
- {
- carry = 1;
- *sumptr -= BASE;
- }
- else
- carry = 0;
- sumptr--;
- n1bytes--;
- n2bytes--;
- }
-
- /* Now add carry the longer integer part. */
- if (n1bytes == 0)
- { n1bytes = n2bytes; n1ptr = n2ptr; }
- while (n1bytes-- > 0)
- {
- *sumptr = *n1ptr-- + carry;
- if (*sumptr > (BASE-1))
- {
- carry = 1;
- *sumptr -= BASE;
- }
- else
- carry = 0;
- sumptr--;
- }
-
- /* Set final carry. */
- if (carry == 1)
- *sumptr += 1;
-
- /* Adjust sum and return. */
- _bc_rm_leading_zeros (sum);
- return sum;
-}
-
-
-/* Perform subtraction: N2 is subtracted from N1 and the value is
- returned. The signs of N1 and N2 are ignored. Also, N1 is
- assumed to be larger than N2. SCALE_MIN is the minimum scale
- of the result. */
-
-static bc_num
-_bc_do_sub (n1, n2, scale_min)
- bc_num n1, n2;
- int scale_min;
-{
- bc_num diff;
- int diff_scale, diff_len;
- int min_scale, min_len;
- char *n1ptr, *n2ptr, *diffptr;
- int borrow, count, val;
-
- /* Allocate temporary storage. */
- diff_len = MAX (n1->n_len, n2->n_len);
- diff_scale = MAX (n1->n_scale, n2->n_scale);
- min_len = MIN (n1->n_len, n2->n_len);
- min_scale = MIN (n1->n_scale, n2->n_scale);
- diff = bc_new_num (diff_len, MAX(diff_scale, scale_min));
-
- /* Zero extra digits made by scale_min. */
- if (scale_min > diff_scale)
- {
- diffptr = (char *) (diff->n_value + diff_len + diff_scale);
- for (count = scale_min - diff_scale; count > 0; count--)
- *diffptr++ = 0;
- }
-
- /* Initialize the subtract. */
- n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale -1);
- n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale -1);
- diffptr = (char *) (diff->n_value + diff_len + diff_scale -1);
-
- /* Subtract the numbers. */
- borrow = 0;
-
- /* Take care of the longer scaled number. */
- if (n1->n_scale != min_scale)
- {
- /* n1 has the longer scale */
- for (count = n1->n_scale - min_scale; count > 0; count--)
- *diffptr-- = *n1ptr--;
- }
- else
- {
- /* n2 has the longer scale */
- for (count = n2->n_scale - min_scale; count > 0; count--)
- {
- val = - *n2ptr-- - borrow;
- if (val < 0)
- {
- val += BASE;
- borrow = 1;
- }
- else
- borrow = 0;
- *diffptr-- = val;
- }
- }
-
- /* Now do the equal length scale and integer parts. */
-
- for (count = 0; count < min_len + min_scale; count++)
- {
- val = *n1ptr-- - *n2ptr-- - borrow;
- if (val < 0)
- {
- val += BASE;
- borrow = 1;
- }
- else
- borrow = 0;
- *diffptr-- = val;
- }
-
- /* If n1 has more digits then n2, we now do that subtract. */
- if (diff_len != min_len)
- {
- for (count = diff_len - min_len; count > 0; count--)
- {
- val = *n1ptr-- - borrow;
- if (val < 0)
- {
- val += BASE;
- borrow = 1;
- }
- else
- borrow = 0;
- *diffptr-- = val;
- }
- }
-
- /* Clean up and return. */
- _bc_rm_leading_zeros (diff);
- return diff;
-}
-
-
-/* Here is the full subtract routine that takes care of negative numbers.
- N2 is subtracted from N1 and the result placed in RESULT. SCALE_MIN
- is the minimum scale for the result. */
-
-void
-bc_sub (n1, n2, result, scale_min)
- bc_num n1, n2, *result;
- int scale_min;
-{
- bc_num diff = NULL;
- int cmp_res;
- int res_scale;
-
- if (n1->n_sign != n2->n_sign)
- {
- diff = _bc_do_add (n1, n2, scale_min);
- diff->n_sign = n1->n_sign;
- }
- else
- {
- /* subtraction must be done. */
- /* Compare magnitudes. */
- cmp_res = _bc_do_compare (n1, n2, FALSE, FALSE);
- switch (cmp_res)
- {
- case -1:
- /* n1 is less than n2, subtract n1 from n2. */
- diff = _bc_do_sub (n2, n1, scale_min);
- diff->n_sign = (n2->n_sign == PLUS ? MINUS : PLUS);
- break;
- case 0:
- /* They are equal! return zero! */
- res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale));
- diff = bc_new_num (1, res_scale);
- memset (diff->n_value, 0, res_scale+1);
- break;
- case 1:
- /* n2 is less than n1, subtract n2 from n1. */
- diff = _bc_do_sub (n1, n2, scale_min);
- diff->n_sign = n1->n_sign;
- break;
- }
- }
-
- /* Clean up and return. */
- bc_free_num (result);
- *result = diff;
-}
-
-
-/* Here is the full add routine that takes care of negative numbers.
- N1 is added to N2 and the result placed into RESULT. SCALE_MIN
- is the minimum scale for the result. */
-
-void
-bc_add (n1, n2, result, scale_min)
- bc_num n1, n2, *result;
- int scale_min;
-{
- bc_num sum = NULL;
- int cmp_res;
- int res_scale;
-
- if (n1->n_sign == n2->n_sign)
- {
- sum = _bc_do_add (n1, n2, scale_min);
- sum->n_sign = n1->n_sign;
- }
- else
- {
- /* subtraction must be done. */
- cmp_res = _bc_do_compare (n1, n2, FALSE, FALSE); /* Compare magnitudes. */
- switch (cmp_res)
- {
- case -1:
- /* n1 is less than n2, subtract n1 from n2. */
- sum = _bc_do_sub (n2, n1, scale_min);
- sum->n_sign = n2->n_sign;
- break;
- case 0:
- /* They are equal! return zero with the correct scale! */
- res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale));
- sum = bc_new_num (1, res_scale);
- memset (sum->n_value, 0, res_scale+1);
- break;
- case 1:
- /* n2 is less than n1, subtract n2 from n1. */
- sum = _bc_do_sub (n1, n2, scale_min);
- sum->n_sign = n1->n_sign;
- }
- }
-
- /* Clean up and return. */
- bc_free_num (result);
- *result = sum;
-}
-
-/* Recursive vs non-recursive multiply crossover ranges. */
-#if defined(MULDIGITS)
-#include "muldigits.h"
-#else
-#define MUL_BASE_DIGITS 80
-#endif
-
-int mul_base_digits = MUL_BASE_DIGITS;
-#define MUL_SMALL_DIGITS mul_base_digits/4
-
-/* Multiply utility routines */
-
-static bc_num
-new_sub_num (length, scale, value)
- int length, scale;
- char *value;
-{
- bc_num temp;
-
- if (_bc_Free_list != NULL) {
- temp = _bc_Free_list;
- _bc_Free_list = temp->n_next;
- } else {
- temp = (bc_num) malloc (sizeof(bc_struct));
- if (temp == NULL) bc_out_of_memory ();
- }
- temp->n_sign = PLUS;
- temp->n_len = length;
- temp->n_scale = scale;
- temp->n_refs = 1;
- temp->n_ptr = NULL;
- temp->n_value = value;
- return temp;
-}
-
-static void
-_bc_simp_mul (bc_num n1, int n1len, bc_num n2, int n2len, bc_num *prod,
- int full_scale)
-{
- char *n1ptr, *n2ptr, *pvptr;
- char *n1end, *n2end; /* To the end of n1 and n2. */
- int indx, sum, prodlen;
-
- prodlen = n1len+n2len+1;
-
- *prod = bc_new_num (prodlen, 0);
-
- n1end = (char *) (n1->n_value + n1len - 1);
- n2end = (char *) (n2->n_value + n2len - 1);
- pvptr = (char *) ((*prod)->n_value + prodlen - 1);
- sum = 0;
-
- /* Here is the loop... */
- for (indx = 0; indx < prodlen-1; indx++)
- {
- n1ptr = (char *) (n1end - MAX(0, indx-n2len+1));
- n2ptr = (char *) (n2end - MIN(indx, n2len-1));
- while ((n1ptr >= n1->n_value) && (n2ptr <= n2end))
- sum += *n1ptr-- * *n2ptr++;
- *pvptr-- = sum % BASE;
- sum = sum / BASE;
- }
- *pvptr = sum;
-}
-
-
-/* A special adder/subtractor for the recursive divide and conquer
- multiply algorithm. Note: if sub is called, accum must
- be larger that what is being subtracted. Also, accum and val
- must have n_scale = 0. (e.g. they must look like integers. *) */
-static void
-_bc_shift_addsub (bc_num accum, bc_num val, int shift, int sub)
-{
- signed char *accp, *valp;
- int count, carry;
-
- count = val->n_len;
- if (val->n_value[0] == 0)
- count--;
- assert (accum->n_len+accum->n_scale >= shift+count);
-
- /* Set up pointers and others */
- accp = (signed char *)(accum->n_value +
- accum->n_len + accum->n_scale - shift - 1);
- valp = (signed char *)(val->n_value + val->n_len - 1);
- carry = 0;
-
- if (sub) {
- /* Subtraction, carry is really borrow. */
- while (count--) {
- *accp -= *valp-- + carry;
- if (*accp < 0) {
- carry = 1;
- *accp-- += BASE;
- } else {
- carry = 0;
- accp--;
- }
- }
- while (carry) {
- *accp -= carry;
- if (*accp < 0)
- *accp-- += BASE;
- else
- carry = 0;
- }
- } else {
- /* Addition */
- while (count--) {
- *accp += *valp-- + carry;
- if (*accp > (BASE-1)) {
- carry = 1;
- *accp-- -= BASE;
- } else {
- carry = 0;
- accp--;
- }
- }
- while (carry) {
- *accp += carry;
- if (*accp > (BASE-1))
- *accp-- -= BASE;
- else
- carry = 0;
- }
- }
-}
-
-/* Recursive divide and conquer multiply algorithm.
- Based on
- Let u = u0 + u1*(b^n)
- Let v = v0 + v1*(b^n)
- Then uv = (B^2n+B^n)*u1*v1 + B^n*(u1-u0)*(v0-v1) + (B^n+1)*u0*v0
-
- B is the base of storage, number of digits in u1,u0 close to equal.
-*/
-static void
-_bc_rec_mul (bc_num u, int ulen, bc_num v, int vlen, bc_num *prod,
- int full_scale)
-{
- bc_num u0, u1, v0, v1;
- int u0len, v0len;
- bc_num m1, m2, m3, d1, d2;
- int n, prodlen, m1zero;
- int d1len, d2len;
-
- /* Base case? */
- if ((ulen+vlen) < mul_base_digits
- || ulen < MUL_SMALL_DIGITS
- || vlen < MUL_SMALL_DIGITS ) {
- _bc_simp_mul (u, ulen, v, vlen, prod, full_scale);
- return;
- }
-
- /* Calculate n -- the u and v split point in digits. */
- n = (MAX(ulen, vlen)+1) / 2;
-
- /* Split u and v. */
- if (ulen < n) {
- u1 = bc_copy_num (_zero_);
- u0 = new_sub_num (ulen,0, u->n_value);
- } else {
- u1 = new_sub_num (ulen-n, 0, u->n_value);
- u0 = new_sub_num (n, 0, u->n_value+ulen-n);
- }
- if (vlen < n) {
- v1 = bc_copy_num (_zero_);
- v0 = new_sub_num (vlen,0, v->n_value);
- } else {
- v1 = new_sub_num (vlen-n, 0, v->n_value);
- v0 = new_sub_num (n, 0, v->n_value+vlen-n);
- }
- _bc_rm_leading_zeros (u1);
- _bc_rm_leading_zeros (u0);
- u0len = u0->n_len;
- _bc_rm_leading_zeros (v1);
- _bc_rm_leading_zeros (v0);
- v0len = v0->n_len;
-
- m1zero = bc_is_zero(u1) || bc_is_zero(v1);
-
- /* Calculate sub results ... */
-
- bc_init_num(&d1);
- bc_init_num(&d2);
- bc_sub (u1, u0, &d1, 0);
- d1len = d1->n_len;
- bc_sub (v0, v1, &d2, 0);
- d2len = d2->n_len;
-
-
- /* Do recursive multiplies and shifted adds. */
- if (m1zero)
- m1 = bc_copy_num (_zero_);
- else
- _bc_rec_mul (u1, u1->n_len, v1, v1->n_len, &m1, 0);
-
- if (bc_is_zero(d1) || bc_is_zero(d2))
- m2 = bc_copy_num (_zero_);
- else
- _bc_rec_mul (d1, d1len, d2, d2len, &m2, 0);
-
- if (bc_is_zero(u0) || bc_is_zero(v0))
- m3 = bc_copy_num (_zero_);
- else
- _bc_rec_mul (u0, u0->n_len, v0, v0->n_len, &m3, 0);
-
- /* Initialize product */
- prodlen = ulen+vlen+1;
- *prod = bc_new_num(prodlen, 0);
-
- if (!m1zero) {
- _bc_shift_addsub (*prod, m1, 2*n, 0);
- _bc_shift_addsub (*prod, m1, n, 0);
- }
- _bc_shift_addsub (*prod, m3, n, 0);
- _bc_shift_addsub (*prod, m3, 0, 0);
- _bc_shift_addsub (*prod, m2, n, d1->n_sign != d2->n_sign);
-
- /* Now clean up! */
- bc_free_num (&u1);
- bc_free_num (&u0);
- bc_free_num (&v1);
- bc_free_num (&m1);
- bc_free_num (&v0);
- bc_free_num (&m2);
- bc_free_num (&m3);
- bc_free_num (&d1);
- bc_free_num (&d2);
-}
-
-/* The multiply routine. N2 times N1 is put int PROD with the scale of
- the result being MIN(N2 scale+N1 scale, MAX (SCALE, N2 scale, N1 scale)).
- */
-
-void
-bc_multiply (n1, n2, prod, scale)
- bc_num n1, n2, *prod;
- int scale;
-{
- bc_num pval;
- int len1, len2;
- int full_scale, prod_scale;
-
- /* Initialize things. */
- len1 = n1->n_len + n1->n_scale;
- len2 = n2->n_len + n2->n_scale;
- full_scale = n1->n_scale + n2->n_scale;
- prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale)));
-
- /* Do the multiply */
- _bc_rec_mul (n1, len1, n2, len2, &pval, full_scale);
-
- /* Assign to prod and clean up the number. */
- pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
- pval->n_value = pval->n_ptr;
- pval->n_len = len2 + len1 + 1 - full_scale;
- pval->n_scale = prod_scale;
- _bc_rm_leading_zeros (pval);
- if (bc_is_zero (pval))
- pval->n_sign = PLUS;
- bc_free_num (prod);
- *prod = pval;
-}
-
-/* Some utility routines for the divide: First a one digit multiply.
- NUM (with SIZE digits) is multiplied by DIGIT and the result is
- placed into RESULT. It is written so that NUM and RESULT can be
- the same pointers. */
-
-static void
-_one_mult (num, size, digit, result)
- unsigned char *num;
- int size, digit;
- unsigned char *result;
-{
- int carry, value;
- unsigned char *nptr, *rptr;
-
- if (digit == 0)
- memset (result, 0, size);
- else
- {
- if (digit == 1)
- memcpy (result, num, size);
- else
- {
- /* Initialize */
- nptr = (unsigned char *) (num+size-1);
- rptr = (unsigned char *) (result+size-1);
- carry = 0;
-
- while (size-- > 0)
- {
- value = *nptr-- * digit + carry;
- *rptr-- = value % BASE;
- carry = value / BASE;
- }
-
- if (carry != 0) *rptr = carry;
- }
- }
-}
-
-
-/* The full division routine. This computes N1 / N2. It returns
- 0 if the division is ok and the result is in QUOT. The number of
- digits after the decimal point is SCALE. It returns -1 if division
- by zero is tried. The algorithm is found in Knuth Vol 2. p237. */
-
-int
-bc_divide (n1, n2, quot, scale)
- bc_num n1, n2, *quot;
- int scale;
-{
- bc_num qval;
- unsigned char *num1, *num2;
- unsigned char *ptr1, *ptr2, *n2ptr, *qptr;
- int scale1, val;
- unsigned int len1, len2, scale2, qdigits, extra, count;
- unsigned int qdig, qguess, borrow, carry;
- unsigned char *mval;
- char zero;
- unsigned int norm;
-
- /* Test for divide by zero. */
- if (bc_is_zero (n2)) return -1;
-
- /* Test for divide by 1. If it is we must truncate. */
- if (n2->n_scale == 0)
- {
- if (n2->n_len == 1 && *n2->n_value == 1)
- {
- qval = bc_new_num (n1->n_len, scale);
- qval->n_sign = (n1->n_sign == n2->n_sign ? PLUS : MINUS);
- memset (&qval->n_value[n1->n_len],0,scale);
- memcpy (qval->n_value, n1->n_value,
- n1->n_len + MIN(n1->n_scale,scale));
- bc_free_num (quot);
- *quot = qval;
- }
- }
-
- /* Set up the divide. Move the decimal point on n1 by n2's scale.
- Remember, zeros on the end of num2 are wasted effort for dividing. */
- scale2 = n2->n_scale;
- n2ptr = (unsigned char *) n2->n_value+n2->n_len+scale2-1;
- while ((scale2 > 0) && (*n2ptr-- == 0)) scale2--;
-
- len1 = n1->n_len + scale2;
- scale1 = n1->n_scale - scale2;
- if (scale1 < scale)
- extra = scale - scale1;
- else
- extra = 0;
- num1 = (unsigned char *) malloc (n1->n_len+n1->n_scale+extra+2);
- if (num1 == NULL) bc_out_of_memory();
- memset (num1, 0, n1->n_len+n1->n_scale+extra+2);
- memcpy (num1+1, n1->n_value, n1->n_len+n1->n_scale);
-
- len2 = n2->n_len + scale2;
- num2 = (unsigned char *) malloc (len2+1);
- if (num2 == NULL) bc_out_of_memory();
- memcpy (num2, n2->n_value, len2);
- *(num2+len2) = 0;
- n2ptr = num2;
- while (*n2ptr == 0)
- {
- n2ptr++;
- len2--;
- }
-
- /* Calculate the number of quotient digits. */
- if (len2 > len1+scale)
- {
- qdigits = scale+1;
- zero = TRUE;
- }
- else
- {
- zero = FALSE;
- if (len2>len1)
- qdigits = scale+1; /* One for the zero integer part. */
- else
- qdigits = len1-len2+scale+1;
- }
-
- /* Allocate and zero the storage for the quotient. */
- qval = bc_new_num (qdigits-scale,scale);
- memset (qval->n_value, 0, qdigits);
-
- /* Allocate storage for the temporary storage mval. */
- mval = (unsigned char *) malloc (len2+1);
- if (mval == NULL) bc_out_of_memory ();
-
- /* Now for the full divide algorithm. */
- if (!zero)
- {
- /* Normalize */
- norm = 10 / ((int)*n2ptr + 1);
- if (norm != 1)
- {
- _one_mult (num1, len1+scale1+extra+1, norm, num1);
- _one_mult (n2ptr, len2, norm, n2ptr);
- }
-
- /* Initialize divide loop. */
- qdig = 0;
- if (len2 > len1)
- qptr = (unsigned char *) qval->n_value+len2-len1;
- else
- qptr = (unsigned char *) qval->n_value;
-
- /* Loop */
- while (qdig <= len1+scale-len2)
- {
- /* Calculate the quotient digit guess. */
- if (*n2ptr == num1[qdig])
- qguess = 9;
- else
- qguess = (num1[qdig]*10 + num1[qdig+1]) / *n2ptr;
-
- /* Test qguess. */
- if (n2ptr[1]*qguess >
- (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10
- + num1[qdig+2])
- {
- qguess--;
- /* And again. */
- if (n2ptr[1]*qguess >
- (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10
- + num1[qdig+2])
- qguess--;
- }
-
- /* Multiply and subtract. */
- borrow = 0;
- if (qguess != 0)
- {
- *mval = 0;
- _one_mult (n2ptr, len2, qguess, mval+1);
- ptr1 = (unsigned char *) num1+qdig+len2;
- ptr2 = (unsigned char *) mval+len2;
- for (count = 0; count < len2+1; count++)
- {
- val = (int) *ptr1 - (int) *ptr2-- - borrow;
- if (val < 0)
- {
- val += 10;
- borrow = 1;
- }
- else
- borrow = 0;
- *ptr1-- = val;
- }
- }
-
- /* Test for negative result. */
- if (borrow == 1)
- {
- qguess--;
- ptr1 = (unsigned char *) num1+qdig+len2;
- ptr2 = (unsigned char *) n2ptr+len2-1;
- carry = 0;
- for (count = 0; count < len2; count++)
- {
- val = (int) *ptr1 + (int) *ptr2-- + carry;
- if (val > 9)
- {
- val -= 10;
- carry = 1;
- }
- else
- carry = 0;
- *ptr1-- = val;
- }
- if (carry == 1) *ptr1 = (*ptr1 + 1) % 10;
- }
-
- /* We now know the quotient digit. */
- *qptr++ = qguess;
- qdig++;
- }
- }
-
- /* Clean up and return the number. */
- qval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
- if (bc_is_zero (qval)) qval->n_sign = PLUS;
- _bc_rm_leading_zeros (qval);
- bc_free_num (quot);
- *quot = qval;
-
- /* Clean up temporary storage. */
- free (mval);
- free (num1);
- free (num2);
-
- return 0; /* Everything is OK. */
-}
-
-
-/* Division *and* modulo for numbers. This computes both NUM1 / NUM2 and
- NUM1 % NUM2 and puts the results in QUOT and REM, except that if QUOT
- is NULL then that store will be omitted.
- */
-
-int
-bc_divmod (num1, num2, quot, rem, scale)
- bc_num num1, num2, *quot, *rem;
- int scale;
-{
- bc_num quotient = NULL;
- bc_num temp;
- int rscale;
-
- /* Check for correct numbers. */
- if (bc_is_zero (num2)) return -1;
-
- /* Calculate final scale. */
- rscale = MAX (num1->n_scale, num2->n_scale+scale);
- bc_init_num(&temp);
-
- /* Calculate it. */
- bc_divide (num1, num2, &temp, scale);
- if (quot)
- quotient = bc_copy_num (temp);
- bc_multiply (temp, num2, &temp, rscale);
- bc_sub (num1, temp, rem, rscale);
- bc_free_num (&temp);
-
- if (quot)
- {
- bc_free_num (quot);
- *quot = quotient;
- }
-
- return 0; /* Everything is OK. */
-}
-
-
-/* Modulo for numbers. This computes NUM1 % NUM2 and puts the
- result in RESULT. */
-
-int
-bc_modulo (num1, num2, result, scale)
- bc_num num1, num2, *result;
- int scale;
-{
- return bc_divmod (num1, num2, NULL, result, scale);
-}
-
-/* Raise BASE to the EXPO power, reduced modulo MOD. The result is
- placed in RESULT. If a EXPO is not an integer,
- only the integer part is used. */
-
-int
-bc_raisemod (base, expo, mod, result, scale)
- bc_num base, expo, mod, *result;
- int scale;
-{
- bc_num power, exponent, parity, temp;
- int rscale;
-
- /* Check for correct numbers. */
- if (bc_is_zero(mod)) return -1;
- if (bc_is_neg(expo)) return -1;
-
- /* Set initial values. */
- power = bc_copy_num (base);
- exponent = bc_copy_num (expo);
- temp = bc_copy_num (_one_);
- bc_init_num(&parity);
-
- /* Check the base for scale digits. */
- if (base->n_scale != 0)
- bc_rt_warn ("non-zero scale in base");
-
- /* Check the exponent for scale digits. */
- if (exponent->n_scale != 0)
- {
- bc_rt_warn ("non-zero scale in exponent");
- bc_divide (exponent, _one_, &exponent, 0); /*truncate */
- }
-
- /* Check the modulus for scale digits. */
- if (mod->n_scale != 0)
- bc_rt_warn ("non-zero scale in modulus");
-
- /* Do the calculation. */
- rscale = MAX(scale, base->n_scale);
- while ( !bc_is_zero(exponent) )
- {
- (void) bc_divmod (exponent, _two_, &exponent, &parity, 0);
- if ( !bc_is_zero(parity) )
- {
- bc_multiply (temp, power, &temp, rscale);
- (void) bc_modulo (temp, mod, &temp, scale);
- }
-
- bc_multiply (power, power, &power, rscale);
- (void) bc_modulo (power, mod, &power, scale);
- }
-
- /* Assign the value. */
- bc_free_num (&power);
- bc_free_num (&exponent);
- bc_free_num (result);
- *result = temp;
- return 0; /* Everything is OK. */
-}
-
-/* Raise NUM1 to the NUM2 power. The result is placed in RESULT.
- Maximum exponent is LONG_MAX. If a NUM2 is not an integer,
- only the integer part is used. */
-
-void
-bc_raise (num1, num2, result, scale)
- bc_num num1, num2, *result;
- int scale;
-{
- bc_num temp, power;
- long exponent;
- int rscale;
- int pwrscale;
- int calcscale;
- char neg;
-
- /* Check the exponent for scale digits and convert to a long. */
- if (num2->n_scale != 0)
- bc_rt_warn ("non-zero scale in exponent");
- exponent = bc_num2long (num2);
- if (exponent == 0 && (num2->n_len > 1 || num2->n_value[0] != 0))
- bc_rt_error ("exponent too large in raise");
-
- /* Special case if exponent is a zero. */
- if (exponent == 0)
- {
- bc_free_num (result);
- *result = bc_copy_num (_one_);
- return;
- }
-
- /* Other initializations. */
- if (exponent < 0)
- {
- neg = TRUE;
- exponent = -exponent;
- rscale = scale;
- }
- else
- {
- neg = FALSE;
- rscale = MIN (num1->n_scale*exponent, MAX(scale, num1->n_scale));
- }
-
- /* Set initial value of temp. */
- power = bc_copy_num (num1);
- pwrscale = num1->n_scale;
- while ((exponent & 1) == 0)
- {
- pwrscale = 2*pwrscale;
- bc_multiply (power, power, &power, pwrscale);
- exponent = exponent >> 1;
- }
- temp = bc_copy_num (power);
- calcscale = pwrscale;
- exponent = exponent >> 1;
-
- /* Do the calculation. */
- while (exponent > 0)
- {
- pwrscale = 2*pwrscale;
- bc_multiply (power, power, &power, pwrscale);
- if ((exponent & 1) == 1) {
- calcscale = pwrscale + calcscale;
- bc_multiply (temp, power, &temp, calcscale);
- }
- exponent = exponent >> 1;
- }
-
- /* Assign the value. */
- if (neg)
- {
- bc_divide (_one_, temp, result, rscale);
- bc_free_num (&temp);
- }
- else
- {
- bc_free_num (result);
- *result = temp;
- if ((*result)->n_scale > rscale)
- (*result)->n_scale = rscale;
- }
- bc_free_num (&power);
-}
-
-/* Take the square root NUM and return it in NUM with SCALE digits
- after the decimal place. */
-
-int
-bc_sqrt (num, scale)
- bc_num *num;
- int scale;
-{
- int rscale, cmp_res, done;
- int cscale;
- bc_num guess, guess1, point5, diff;
-
- /* Initial checks. */
- cmp_res = bc_compare (*num, _zero_);
- if (cmp_res < 0)
- return 0; /* error */
- else
- {
- if (cmp_res == 0)
- {
- bc_free_num (num);
- *num = bc_copy_num (_zero_);
- return 1;
- }
- }
- cmp_res = bc_compare (*num, _one_);
- if (cmp_res == 0)
- {
- bc_free_num (num);
- *num = bc_copy_num (_one_);
- return 1;
- }
-
- /* Initialize the variables. */
- rscale = MAX (scale, (*num)->n_scale);
- bc_init_num(&guess);
- bc_init_num(&guess1);
- bc_init_num(&diff);
- point5 = bc_new_num (1,1);
- point5->n_value[1] = 5;
-
-
- /* Calculate the initial guess. */
- if (cmp_res < 0)
- {
- /* The number is between 0 and 1. Guess should start at 1. */
- guess = bc_copy_num (_one_);
- cscale = (*num)->n_scale;
- }
- else
- {
- /* The number is greater than 1. Guess should start at 10^(exp/2). */
- bc_int2num (&guess,10);
-
- bc_int2num (&guess1,(*num)->n_len);
- bc_multiply (guess1, point5, &guess1, 0);
- guess1->n_scale = 0;
- bc_raise (guess, guess1, &guess, 0);
- bc_free_num (&guess1);
- cscale = 3;
- }
-
- /* Find the square root using Newton's algorithm. */
- done = FALSE;
- while (!done)
- {
- bc_free_num (&guess1);
- guess1 = bc_copy_num (guess);
- bc_divide (*num, guess, &guess, cscale);
- bc_add (guess, guess1, &guess, 0);
- bc_multiply (guess, point5, &guess, cscale);
- bc_sub (guess, guess1, &diff, cscale+1);
- if (bc_is_near_zero (diff, cscale))
- {
- if (cscale < rscale+1)
- cscale = MIN (cscale*3, rscale+1);
- else
- done = TRUE;
- }
- }
-
- /* Assign the number and clean up. */
- bc_free_num (num);
- bc_divide (guess,_one_,num,rscale);
- bc_free_num (&guess);
- bc_free_num (&guess1);
- bc_free_num (&point5);
- bc_free_num (&diff);
- return 1;
-}
-
-
-/* The following routines provide output for bcd numbers package
- using the rules of POSIX bc for output. */
-
-/* This structure is used for saving digits in the conversion process. */
-typedef struct stk_rec {
- long digit;
- struct stk_rec *next;
-} stk_rec;
-
-/* The reference string for digits. */
-static char ref_str[] = "0123456789ABCDEF";
-
-
-/* A special output routine for "multi-character digits." Exactly
- SIZE characters must be output for the value VAL. If SPACE is
- non-zero, we must output one space before the number. OUT_CHAR
- is the actual routine for writing the characters. */
-
-void
-bc_out_long (val, size, space, out_char)
- long val;
- int size, space;
-#ifdef __STDC__
- void (*out_char)(int);
-#else
- void (*out_char)();
-#endif
-{
- char digits[40];
- int len, ix;
-
- if (space) (*out_char) (' ');
- sprintf (digits, "%ld", val);
- len = strlen (digits);
- while (size > len)
- {
- (*out_char) ('0');
- size--;
- }
- for (ix=0; ix < len; ix++)
- (*out_char) (digits[ix]);
-}
-
-/* Output of a bcd number. NUM is written in base O_BASE using OUT_CHAR
- as the routine to do the actual output of the characters. */
-
-void
-bc_out_num (num, o_base, out_char, leading_zero)
- bc_num num;
- int o_base;
-#ifdef __STDC__
- void (*out_char)(int);
-#else
- void (*out_char)();
-#endif
- int leading_zero;
-{
- char *nptr;
- int index, fdigit, pre_space;
- stk_rec *digits, *temp;
- bc_num int_part, frac_part, base, cur_dig, t_num, max_o_digit;
-
- /* The negative sign if needed. */
- if (num->n_sign == MINUS) (*out_char) ('-');
-
- /* Output the number. */
- if (bc_is_zero (num))
- (*out_char) ('0');
- else
- if (o_base == 10)
- {
- /* The number is in base 10, do it the fast way. */
- nptr = num->n_value;
- if (num->n_len > 1 || *nptr != 0)
- for (index=num->n_len; index>0; index--)
- (*out_char) (BCD_CHAR(*nptr++));
- else
- nptr++;
-
- if (leading_zero && bc_is_zero (num))
- (*out_char) ('0');
-
- /* Now the fraction. */
- if (num->n_scale > 0)
- {
- (*out_char) ('.');
- for (index=0; index<num->n_scale; index++)
- (*out_char) (BCD_CHAR(*nptr++));
- }
- }
- else
- {
- /* special case ... */
- if (leading_zero && bc_is_zero (num))
- (*out_char) ('0');
-
- /* The number is some other base. */
- digits = NULL;
- bc_init_num (&int_part);
- bc_divide (num, _one_, &int_part, 0);
- bc_init_num (&frac_part);
- bc_init_num (&cur_dig);
- bc_init_num (&base);
- bc_sub (num, int_part, &frac_part, 0);
- /* Make the INT_PART and FRAC_PART positive. */
- int_part->n_sign = PLUS;
- frac_part->n_sign = PLUS;
- bc_int2num (&base, o_base);
- bc_init_num (&max_o_digit);
- bc_int2num (&max_o_digit, o_base-1);
-
-
- /* Get the digits of the integer part and push them on a stack. */
- while (!bc_is_zero (int_part))
- {
- bc_modulo (int_part, base, &cur_dig, 0);
- temp = (stk_rec *) malloc (sizeof(stk_rec));
- if (temp == NULL) bc_out_of_memory();
- temp->digit = bc_num2long (cur_dig);
- temp->next = digits;
- digits = temp;
- bc_divide (int_part, base, &int_part, 0);
- }
-
- /* Print the digits on the stack. */
- if (digits != NULL)
- {
- /* Output the digits. */
- while (digits != NULL)
- {
- temp = digits;
- digits = digits->next;
- if (o_base <= 16)
- (*out_char) (ref_str[ (int) temp->digit]);
- else
- bc_out_long (temp->digit, max_o_digit->n_len, 1, out_char);
- free (temp);
- }
- }
-
- /* Get and print the digits of the fraction part. */
- if (num->n_scale > 0)
- {
- (*out_char) ('.');
- pre_space = 0;
- t_num = bc_copy_num (_one_);
- while (t_num->n_len <= num->n_scale) {
- bc_multiply (frac_part, base, &frac_part, num->n_scale);
- fdigit = bc_num2long (frac_part);
- bc_int2num (&int_part, fdigit);
- bc_sub (frac_part, int_part, &frac_part, 0);
- if (o_base <= 16)
- (*out_char) (ref_str[fdigit]);
- else {
- bc_out_long (fdigit, max_o_digit->n_len, pre_space, out_char);
- pre_space = 1;
- }
- bc_multiply (t_num, base, &t_num, 0);
- }
- bc_free_num (&t_num);
- }
-
- /* Clean up. */
- bc_free_num (&int_part);
- bc_free_num (&frac_part);
- bc_free_num (&base);
- bc_free_num (&cur_dig);
- bc_free_num (&max_o_digit);
- }
-}
-/* Convert a number NUM to a long. The function returns only the integer
- part of the number. For numbers that are too large to represent as
- a long, this function returns a zero. This can be detected by checking
- the NUM for zero after having a zero returned. */
-
-long
-bc_num2long (num)
- bc_num num;
-{
- long val;
- char *nptr;
- int index;
-
- /* Extract the int value, ignore the fraction. */
- val = 0;
- nptr = num->n_value;
- for (index=num->n_len; (index>0) && (val<=(LONG_MAX/BASE)); index--)
- val = val*BASE + *nptr++;
-
- /* Check for overflow. If overflow, return zero. */
- if (index>0) val = 0;
- if (val < 0) val = 0;
-
- /* Return the value. */
- if (num->n_sign == PLUS)
- return (val);
- else
- return (-val);
-}
-
-
-/* Convert an integer VAL to a bc number NUM. */
-
-void
-bc_int2num (num, val)
- bc_num *num;
- int val;
-{
- char buffer[30];
- char *bptr, *vptr;
- int ix = 1;
- char neg = 0;
-
- /* Sign. */
- if (val < 0)
- {
- neg = 1;
- val = -val;
- }
-
- /* Get things going. */
- bptr = buffer;
- *bptr++ = val % BASE;
- val = val / BASE;
-
- /* Extract remaining digits. */
- while (val != 0)
- {
- *bptr++ = val % BASE;
- val = val / BASE;
- ix++; /* Count the digits. */
- }
-
- /* Make the number. */
- bc_free_num (num);
- *num = bc_new_num (ix, 0);
- if (neg) (*num)->n_sign = MINUS;
-
- /* Assign the digits. */
- vptr = (*num)->n_value;
- while (ix-- > 0)
- *vptr++ = *--bptr;
-}
-
-/* Convert a numbers to a string. Base 10 only.*/
-
-char
-*num2str (num)
- bc_num num;
-{
- char *str, *sptr;
- char *nptr;
- int index, signch;
-
- /* Allocate the string memory. */
- signch = ( num->n_sign == PLUS ? 0 : 1 ); /* Number of sign chars. */
- if (num->n_scale > 0)
- str = (char *) malloc (num->n_len + num->n_scale + 2 + signch);
- else
- str = (char *) malloc (num->n_len + 1 + signch);
- if (str == NULL) bc_out_of_memory();
-
- /* The negative sign if needed. */
- sptr = str;
- if (signch) *sptr++ = '-';
-
- /* Load the whole number. */
- nptr = num->n_value;
- for (index=num->n_len; index>0; index--)
- *sptr++ = BCD_CHAR(*nptr++);
-
- /* Now the fraction. */
- if (num->n_scale > 0)
- {
- *sptr++ = '.';
- for (index=0; index<num->n_scale; index++)
- *sptr++ = BCD_CHAR(*nptr++);
- }
-
- /* Terminate the string and return it! */
- *sptr = '\0';
- return (str);
-}
-/* Convert strings to bc numbers. Base 10 only.*/
-
-void
-bc_str2num (num, str, scale)
- bc_num *num;
- char *str;
- int scale;
-{
- int digits, strscale;
- char *ptr, *nptr;
- char zero_int;
-
- /* Prepare num. */
- bc_free_num (num);
-
- /* Check for valid number and count digits. */
- ptr = str;
- digits = 0;
- strscale = 0;
- zero_int = FALSE;
- if ( (*ptr == '+') || (*ptr == '-')) ptr++; /* Sign */
- while (*ptr == '0') ptr++; /* Skip leading zeros. */
- while (isdigit((int)*ptr)) ptr++, digits++; /* digits */
- if (*ptr == '.') ptr++; /* decimal point */
- while (isdigit((int)*ptr)) ptr++, strscale++; /* digits */
- if ((*ptr != '\0') || (digits+strscale == 0))
- {
- *num = bc_copy_num (_zero_);
- return;
- }
-
- /* Adjust numbers and allocate storage and initialize fields. */
- strscale = MIN(strscale, scale);
- if (digits == 0)
- {
- zero_int = TRUE;
- digits = 1;
- }
- *num = bc_new_num (digits, strscale);
-
- /* Build the whole number. */
- ptr = str;
- if (*ptr == '-')
- {
- (*num)->n_sign = MINUS;
- ptr++;
- }
- else
- {
- (*num)->n_sign = PLUS;
- if (*ptr == '+') ptr++;
- }
- while (*ptr == '0') ptr++; /* Skip leading zeros. */
- nptr = (*num)->n_value;
- if (zero_int)
- {
- *nptr++ = 0;
- digits = 0;
- }
- for (;digits > 0; digits--)
- *nptr++ = CH_VAL(*ptr++);
-
-
- /* Build the fractional part. */
- if (strscale > 0)
- {
- ptr++; /* skip the decimal point! */
- for (;strscale > 0; strscale--)
- *nptr++ = CH_VAL(*ptr++);
- }
-}
-
-/* pn prints the number NUM in base 10. */
-
-static void
-out_char (int c)
-{
- putchar(c);
-}
-
-
-void
-pn (num)
- bc_num num;
-{
- bc_out_num (num, 10, out_char, 0);
- out_char ('\n');
-}
-
-
-/* pv prints a character array as if it was a string of bcd digits. */
-void
-pv (name, num, len)
- char *name;
- unsigned char *num;
- int len;
-{
- int i;
- printf ("%s=", name);
- for (i=0; i<len; i++) printf ("%c",BCD_CHAR(num[i]));
- printf ("\n");
-}
diff --git a/contrib/bc/lib/testmul.c b/contrib/bc/lib/testmul.c
deleted file mode 100644
index f7044d6..0000000
--- a/contrib/bc/lib/testmul.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/* compute the crossover for recursive and simple multiplication */
-
-#include <stdio.h>
-#include <time.h>
-#include "number.h"
-#ifndef VARARGS
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-/* from number.c ... */
-extern int mul_base_digits;
-/* extern int mul_small_digits; */
-extern bc_num _one_;
-
-/* global variables */
-int test_n = 1000;
-int test_time = 30 * CLOCKS_PER_SEC; /* 30 seconds */
-
-/* Other things for number.c. */
-int std_only;
-
-void
-out_of_memory()
-{
- fprintf (stderr, "Fatal error: Out of memory for malloc.\n");
- exit (1);
-}
-
-/* Runtime error will print a message and stop the machine. */
-
-#ifndef VARARGS
-#ifdef __STDC__
-void
-rt_error (char *mesg, ...)
-#else
-void
-rt_error (mesg)
- char *mesg;
-#endif
-#else
-void
-rt_error (mesg, va_alist)
- char *mesg;
-#endif
-{
- va_list args;
- char error_mesg [255];
-
-#ifndef VARARGS
- va_start (args, mesg);
-#else
- va_start (args);
-#endif
- vsprintf (error_mesg, mesg, args);
- va_end (args);
-
- fprintf (stderr, "Runtime error: %s\n", error_mesg);
-}
-
-/* A runtime warning tells of some action taken by the processor that
- may change the program execution but was not enough of a problem
- to stop the execution. */
-
-#ifndef VARARGS
-#ifdef __STDC__
-void
-rt_warn (char *mesg, ...)
-#else
-void
-rt_warn (mesg)
- char *mesg;
-#endif
-#else
-void
-rt_warn (mesg, va_alist)
- char *mesg;
-#endif
-{
- va_list args;
- char error_mesg [255];
-
-#ifndef VARARGS
- va_start (args, mesg);
-#else
- va_start (args);
-#endif
- vsprintf (error_mesg, mesg, args);
- va_end (args);
-
- fprintf (stderr, "Runtime warning: %s\n", error_mesg);
-}
-
-void
-out_char (int ch)
-{
- putchar (ch);
-}
-
-/* Time stuff !!! */
-
-int
-timeit ( bc_num a, bc_num b, int *n)
-{
- clock_t first;
- int i, res;
- bc_num c;
-
- bc_init_num (&c);
- first = clock();
- *n = 0;
- do {
- for (i=0; i<test_n; i++)
- bc_multiply(a,b,&c,0);
- *n += test_n;
- res = (int) (clock() - first);
- } while (res < test_time);
- return res;
-}
-
-int debug = 0; /* Print debugging messages? */
-
-int main (int argc, char **argv)
-{
- bc_num ten, num, expo, big;
-
- int min, max, mid;
-
-#if 0
- int smallsize;
-#endif
-
- int n1, n2;
- clock_t t1, t2;
- float permul1, permul2;
-
- /* args? */
- if (argc > 1)
- if (strcmp (argv[1], "-d") == 0)
- debug = 1;
-
- bc_init_numbers();
- bc_init_num (&ten);
- bc_init_num (&num);
- bc_init_num (&expo);
- bc_init_num (&big);
- bc_int2num (&ten, 10);
-
- if (debug)
- fprintf (stderr, "Timings are for %d multiplies\n"
- "Minimum time is %d seconds\n", test_n,
- test_time/CLOCKS_PER_SEC);
-
- /* Two of the same size */
- min = 10;
- max = 500;
-
- if (debug)
- fprintf (stderr, "Testing numbers of the same length.\n");
-
- while (min < max) {
- mid = (min+max)/2;
- if (debug) fprintf (stderr,"Checking %d...\n", mid);
-
- bc_int2num (&expo, mid);
- bc_raise (ten, expo, &num, 0);
- bc_sub (num, _one_, &num, 0);
-
- mul_base_digits = 2*mid+1;
- t1 = timeit (num, num, &n1);
- permul1 = (float)t1/(float)n1;
-
- mul_base_digits = 2*mid-1;
- t2 = timeit (num, num, &n2);
- permul2 = (float)t2/(float)n2;
-
- if (permul1 < permul2)
- min = mid+1;
- else
- max = mid-1;
-
- if (debug) {
- fprintf (stderr, "n1 = %d :: n2 = %d\n", n1, n2);
- fprintf (stderr, "p1 = %f :: p2 = %f\n", permul1, permul2);
- }
- }
-
- if (debug)
- fprintf (stderr, "Base digits crossover at %d digits\n", min);
- printf ("#define MUL_BASE_DIGITS %d\n", 2*min);
-
-
-#if 0
- mul_base_digits = min;
-
- /* Small one times a big one. */
-
- smallsize = min/2;
- bc_int2num (&expo, smallsize);
- bc_raise (ten, expo, &big, 0);
- bc_sub (num, _one_, &big, 0);
-
- min = min / 2;
- max = 500;
-
- if (debug)
- fprintf (stderr, "Testing numbers of the different length.\n");
-
- while (min < max) {
- mid = (min+max)/2;
- if (debug) fprintf (stderr, "Checking %d...\n", mid);
-
- bc_int2num (&expo, mid-smallsize);
- bc_raise (ten, expo, &num, 0);
- bc_sub (num, _one_, &num, 0);
-
- mul_small_digits = mid+1;
- t1 = timeit (big, num, &n1);
- permul1 = (float)t1/(float)n1;
-
- mul_small_digits = mid-1;
- t2 = timeit (big, num, &n2);
- permul2 = (float)t2/(float)n2;
-
- if (permul1 < permul2)
- min = mid+1;
- else
- max = mid-1;
-
- if (debug) {
- fprintf (stderr, "n1 = %d :: n2 = %d\n", n1, n2);
- fprintf (stderr, "p1 = %f :: p2 = %f\n", permul1, permul2);
- }
- }
-
- if (debug)
- fprintf (stderr, "Non equal digits crossover at %d total digits\n", min);
- printf ("#define MUL_SMALL_DIGITS = %d\n", min);
-
-#endif
-
- return 0;
-}
diff --git a/contrib/bc/lib/vfprintf.c b/contrib/bc/lib/vfprintf.c
deleted file mode 100644
index ad53d0c..0000000
--- a/contrib/bc/lib/vfprintf.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/* vfprintf.c -- this was provided for minix. It may not
- work on any other system. */
-
-#include "config.h"
-#ifndef HAVE_VPRINTF
-#ifndef HAVE_DOPRINT
- #error need vfprintf() or doprint()
-#else
-
-#ifdef HAVE_LIB_H
-#include <lib.h>
-#endif
-#ifdef HAVE_STDARG_H
-#include <stdarg.h>
-#endif
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-
-int vfprintf(file, format, argp)
-FILE *file;
-_CONST char *format;
-va_list argp;
-{
- _doprintf(file, format, argp);
- if (testflag(file, PERPRINTF)) fflush(file);
- return 0;
-}
-
-#endif /* HAVE_DOPRINT */
-#endif /* !HAVE_VFPRINTF */
diff --git a/contrib/bc/missing b/contrib/bc/missing
deleted file mode 100755
index e4b838c..0000000
--- a/contrib/bc/missing
+++ /dev/null
@@ -1,134 +0,0 @@
-#! /bin/sh
-# Common stub for a few missing GNU programs while installing.
-# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
-# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
-
-if test $# -eq 0; then
- echo 1>&2 "Try \`$0 --help' for more information"
- exit 1
-fi
-
-case "$1" in
-
- -h|--h|--he|--hel|--help)
- echo "\
-$0 [OPTION]... PROGRAM [ARGUMENT]...
-
-Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
-error status if there is no known handling for PROGRAM.
-
-Options:
- -h, --help display this help and exit
- -v, --version output version information and exit
-
-Supported PROGRAM values:
- aclocal touch file \`aclocal.m4'
- autoconf touch file \`configure'
- autoheader touch file \`config.h.in'
- automake touch all \`Makefile.in' files
- bison touch file \`y.tab.c'
- makeinfo touch the output file
- yacc touch file \`y.tab.c'"
- ;;
-
- -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
- echo "missing - GNU libit 0.0"
- ;;
-
- -*)
- echo 1>&2 "$0: Unknown \`$1' option"
- echo 1>&2 "Try \`$0 --help' for more information"
- exit 1
- ;;
-
- aclocal)
- echo 1>&2 "\
-WARNING: \`$1' is missing on your system. It should be needed only if
- you modified \`acinclude.m4' or \`configure.in'. You might want
- to install the \`Automake' and \`Perl' packages. Grab them from
- any GNU archive site."
- touch aclocal.m4
- ;;
-
- autoconf)
- echo 1>&2 "\
-WARNING: \`$1' is missing on your system. It should be needed only if
- you modified \`configure.in'. You might want to install the
- \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
- archive site."
- touch configure
- ;;
-
- autoheader)
- echo 1>&2 "\
-WARNING: \`$1' is missing on your system. It should be needed only if
- you modified \`acconfig.h' or \`configure.in'. You might want
- to install the \`Autoconf' and \`GNU m4' packages. Grab them
- from any GNU archive site."
- touch config.h.in
- ;;
-
- automake)
- echo 1>&2 "\
-WARNING: \`$1' is missing on your system. It should be needed only if
- you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
- You might want to install the \`Automake' and \`Perl' packages.
- Grab them from any GNU archive site."
- find . -type f -name Makefile.am -print \
- | sed 's/^\(.*\).am$/touch \1.in/' \
- | sh
- ;;
-
- bison|yacc)
- echo 1>&2 "\
-WARNING: \`$1' is missing on your system. It should be needed only if
- your modified any \`.y' file. For being effective, your
- modifications might require the \`Bison' package. Grab it from
- any GNU archive site."
- touch y.tab.c
- ;;
-
- makeinfo)
- echo 1>&2 "\
-WARNING: \`$1' is missing on your system. It should be needed only if
- you modified a \`.texi' or \`.texinfo' file, or any other file
- indirectly affecting the aspect of the manual. The spurious
- call might also be the consequence of using a buggy \`make' (AIX,
- DU, IRIX). You might want to install the \`Texinfo' package or
- the \`GNU make' package. Grab either from any GNU archive site."
- file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
- if test -z "$file"; then
- file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
- file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
- fi
- touch $file
- ;;
-
- *)
- echo 1>&2 "\
-WARNING: \`$1' is needed, and you do not seem to have it handy on your
- system. You might have modified some files without having the
- proper tools for further handling them. Check the \`README' file,
- it often tells you about the needed prerequirements for installing
- this package. You may also peek at any GNU archive site, in case
- some other package would contain this missing \`$1' program."
- exit 1
- ;;
-esac
-
-exit 0
diff --git a/contrib/bc/mkinstalldirs b/contrib/bc/mkinstalldirs
deleted file mode 100755
index cc8783e..0000000
--- a/contrib/bc/mkinstalldirs
+++ /dev/null
@@ -1,36 +0,0 @@
-#! /bin/sh
-# mkinstalldirs --- make directory hierarchy
-# Author: Noah Friedman <friedman@prep.ai.mit.edu>
-# Created: 1993-05-16
-# Last modified: 1994-03-25
-# Public domain
-
-errstatus=0
-
-for file in ${1+"$@"} ; do
- set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
- shift
-
- pathcomp=
- for d in ${1+"$@"} ; do
- pathcomp="$pathcomp$d"
- case "$pathcomp" in
- -* ) pathcomp=./$pathcomp ;;
- esac
-
- if test ! -d "$pathcomp"; then
- echo "mkdir $pathcomp" 1>&2
- mkdir "$pathcomp" > /dev/null 2>&1 || lasterr=$?
- fi
-
- if test ! -d "$pathcomp"; then
- errstatus=$lasterr
- fi
-
- pathcomp="$pathcomp/"
- done
-done
-
-exit $errstatus
-
-# mkinstalldirs ends here
diff --git a/contrib/bc/stamp-h.in b/contrib/bc/stamp-h.in
deleted file mode 100644
index 9788f70..0000000
--- a/contrib/bc/stamp-h.in
+++ /dev/null
@@ -1 +0,0 @@
-timestamp
diff --git a/contrib/csup/GNUmakefile b/contrib/csup/GNUmakefile
deleted file mode 100644
index 18fb071..0000000
--- a/contrib/csup/GNUmakefile
+++ /dev/null
@@ -1,64 +0,0 @@
-# A simple gmake Makefile, to be used on Linux and Darwin. It shouldn't
-# be used elsewhere because it assumes that the target system doesn't
-# support BSD extended file flags.
-#
-# $FreeBSD$
-#
-
-PREFIX?=/usr/local
-OWNER?= 0
-GROUP?= 0
-
-UNAME= $(shell uname -s)
-
-SRCS= attrstack.c config.c detailer.c diff.c fattr.c fixups.c fnmatch.c \
- globtree.c idcache.c keyword.c lex.rcs.c lister.c main.c misc.c mux.c \
- pathcomp.c parse.c proto.c rcsfile.c rcsparse.c rsyncfile.c status.c \
- stream.c threads.c token.c updater.c
-OBJS= $(SRCS:.c=.o)
-
-WARNS= -Wall -W -Wno-unused-parameter -Wmissing-prototypes -Wpointer-arith \
- -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wshadow \
- -Wcast-align -Wunused-parameter -Wchar-subscripts -Winline \
- -Wnested-externs -Wredundant-decls -Wno-format-y2k
-
-CFLAGS+= -g -O -pipe -DNDEBUG -I$(PREFIX)/include
-ifeq ($(UNAME), Linux)
- CFLAGS+= -D_XOPEN_SOURCE -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64
-endif
-ifeq ($(UNAME), Darwin)
- CFLAGS+= -DHAVE_FFLAGS
-endif
-CFLAGS+= $(WARNS)
-LDFLAGS= -L$(PREFIX)/lib -lcrypto -lz -lpthread
-
-.PHONY: all clean install
-
-all: csup csup.1.gz
-
-csup: $(OBJS)
- $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
-
-config.c: parse.h
-
-token.c: token.l
-
-parse.c: parse.y
-
-parse.h: parse.c
-
-clean:
- rm -f csup $(OBJS) parse.c parse.h token.c csup.1.gz
-
-%.o: %.c
- $(CC) $(CFLAGS) -c -o $@ $<
-
-%.c: %.y
- $(YACC) -d -o $@ $<
-
-csup.1.gz: csup.1
- gzip -cn $< > $@
-
-install: csup csup.1.gz
- install -s -o $(OWNER) -g $(GROUP) csup $(PREFIX)/bin
- install -s -o $(OWNER) -g $(GROUP) csup.1.gz $(PREFIX)/share/man/man1
diff --git a/contrib/csup/Makefile b/contrib/csup/Makefile
deleted file mode 100644
index ae34e75..0000000
--- a/contrib/csup/Makefile
+++ /dev/null
@@ -1,48 +0,0 @@
-# $FreeBSD$
-
-PREFIX?= /usr/local
-BINDIR?= ${PREFIX}/bin
-MANDIR?= ${PREFIX}/man/man
-
-UNAME!= /usr/bin/uname -s
-
-PROG= csup
-SRCS= attrstack.c auth.c config.c detailer.c diff.c fattr.c fixups.c fnmatch.c \
- globtree.c idcache.c keyword.c lister.c main.c misc.c mux.c parse.y \
- pathcomp.c proto.c status.c stream.c threads.c token.l updater.c \
- rcsfile.c rcsparse.c lex.rcs.c rsyncfile.c
-
-CFLAGS+= -I. -I${.CURDIR} -g -pthread -DHAVE_FFLAGS -DNDEBUG
-WARNS?= 1
-
-# A bit of tweaking is needed to get this Makefile working
-# with the bsd.prog.mk of all the *BSD OSes...
-.if (${UNAME} == "NetBSD")
-LDFLAGS+= -pthread
-YHEADER= yes
-
-.elif (${UNAME} == "OpenBSD")
-# I bet there's a better way to do this with the OpenBSD mk
-# framework but well, this works and I got bored.
-LDFLAGS+= -pthread
-YFLAGS= -d
-CLEANFILES+= parse.c parse.h y.tab.h
-
-config.c: parse.h
-
-token.l: parse.h
-
-y.tab.h: parse.c
-
-parse.h: y.tab.h
- cp ${.ALLSRC} ${.TARGET}
-
-.endif
-
-DPADD= ${LIBCRYPTO} ${LIBZ}
-LDADD= -lcrypto -lz
-
-SCRIPTS= cpasswd.sh
-MAN= csup.1 cpasswd.1
-
-.include <bsd.prog.mk>
diff --git a/contrib/dtc/Documentation/dtc-paper.bib b/contrib/dtc/Documentation/dtc-paper.bib
new file mode 100644
index 0000000..d01e2ff
--- /dev/null
+++ b/contrib/dtc/Documentation/dtc-paper.bib
@@ -0,0 +1,43 @@
+@STRING{pub-IEEE = "IEEE Computer Society"}
+@STRING{pub-IEEE:adr = "345 E. 47th St, New York, NY 10017, USA"}
+
+@BOOK{IEEE1275,
+ key = "IEEE1275",
+ title = "{IEEE} {S}tandard for {B}oot ({I}nitialization {C}onfiguration) {F}irmware: {C}ore {R}equirements and {P}ractices",
+ publisher = pub-IEEE,
+ address = pub-IEEE:adr,
+ series = "IEEE Std 1275-1994",
+ year = 1994,
+}
+
+@BOOK{IEEE1275-pci,
+ key = "IEEE1275-pci",
+ title = "{PCI} {B}us {B}inding to: {IEEE} {S}td 1275-1994 {S}tandard for {B}oot ({I}nitialization {C}onfiguration) {F}irmware",
+ publisher = pub-IEEE,
+ address = pub-IEEE:adr,
+ note = "Revision 2.1",
+ year = 1998,
+}
+
+@MISC{noof1,
+ author = "Benjamin Herrenschmidt",
+ title = "Booting the {L}inux/ppc kernel without {O}pen {F}irmware",
+ month = may,
+ year = 2005,
+ note = "v0.1, \url{http://ozlabs.org/pipermail/linuxppc64-dev/2005-May/004073.html}",
+}
+
+@MISC{noof5,
+ author = "Benjamin Herrenschmidt",
+ title = "Booting the {L}inux/ppc kernel without {O}pen {F}irmware",
+ month = nov,
+ year = 2005,
+ note = "v0.5, \url{http://ozlabs.org/pipermail/linuxppc64-dev/2005-December/006994.html}",
+}
+
+@MISC{dtcgit,
+ author = "David Gibson et al.",
+ title = "\dtc{}",
+ howpublished = "git tree",
+ note = "\url{http://ozlabs.org/~dgibson/dtc/dtc.git}",
+}
diff --git a/contrib/dtc/Documentation/dtc-paper.tex b/contrib/dtc/Documentation/dtc-paper.tex
new file mode 100644
index 0000000..4494226
--- /dev/null
+++ b/contrib/dtc/Documentation/dtc-paper.tex
@@ -0,0 +1,597 @@
+\documentclass[a4paper,twocolumn]{article}
+
+\usepackage{abstract}
+\usepackage{xspace}
+\usepackage{amssymb}
+\usepackage{latexsym}
+\usepackage{tabularx}
+\usepackage[T1]{fontenc}
+\usepackage{calc}
+\usepackage{listings}
+\usepackage{color}
+\usepackage{url}
+
+\title{Device trees everywhere}
+
+\author{David Gibson \texttt{<{dwg}{@}{au1.ibm.com}>}\\
+ Benjamin Herrenschmidt \texttt{<{benh}{@}{kernel.crashing.org}>}\\
+ \emph{OzLabs, IBM Linux Technology Center}}
+
+\newcommand{\R}{\textsuperscript{\textregistered}\xspace}
+\newcommand{\tm}{\textsuperscript{\texttrademark}\xspace}
+\newcommand{\tge}{$\geqslant$}
+%\newcommand{\ditto}{\textquotedbl\xspace}
+
+\newcommand{\fixme}[1]{$\bigstar$\emph{\textbf{\large #1}}$\bigstar$\xspace}
+
+\newcommand{\ppc}{\mbox{PowerPC}\xspace}
+\newcommand{\of}{Open Firmware\xspace}
+\newcommand{\benh}{Ben Herrenschmidt\xspace}
+\newcommand{\kexec}{\texttt{kexec()}\xspace}
+\newcommand{\dtbeginnode}{\texttt{OF\_DT\_BEGIN\_NODE\xspace}}
+\newcommand{\dtendnode}{\texttt{OF\_DT\_END\_NODE\xspace}}
+\newcommand{\dtprop}{\texttt{OF\_DT\_PROP\xspace}}
+\newcommand{\dtend}{\texttt{OF\_DT\_END\xspace}}
+\newcommand{\dtc}{\texttt{dtc}\xspace}
+\newcommand{\phandle}{\texttt{linux,phandle}\xspace}
+\begin{document}
+
+\maketitle
+
+\begin{abstract}
+ We present a method for booting a \ppc{}\R Linux\R kernel on an
+ embedded machine. To do this, we supply the kernel with a compact
+ flattened-tree representation of the system's hardware based on the
+ device tree supplied by Open Firmware on IBM\R servers and Apple\R
+ Power Macintosh\R machines.
+
+ The ``blob'' representing the device tree can be created using \dtc
+ --- the Device Tree Compiler --- that turns a simple text
+ representation of the tree into the compact representation used by
+ the kernel. The compiler can produce either a binary ``blob'' or an
+ assembler file ready to be built into a firmware or bootwrapper
+ image.
+
+ This flattened-tree approach is now the only supported method of
+ booting a \texttt{ppc64} kernel without Open Firmware, and we plan
+ to make it the only supported method for all \texttt{powerpc}
+ kernels in the future.
+\end{abstract}
+
+\section{Introduction}
+
+\subsection{OF and the device tree}
+
+Historically, ``everyday'' \ppc machines have booted with the help of
+\of (OF), a firmware environment defined by IEEE1275 \cite{IEEE1275}.
+Among other boot-time services, OF maintains a device tree that
+describes all of the system's hardware devices and how they're
+connected. During boot, before taking control of memory management,
+the Linux kernel uses OF calls to scan the device tree and transfer it
+to an internal representation that is used at run time to look up
+various device information.
+
+The device tree consists of nodes representing devices or
+buses\footnote{Well, mostly. There are a few special exceptions.}.
+Each node contains \emph{properties}, name--value pairs that give
+information about the device. The values are arbitrary byte strings,
+and for some properties, they contain tables or other structured
+information.
+
+\subsection{The bad old days}
+
+Embedded systems, by contrast, usually have a minimal firmware that
+might supply a few vital system parameters (size of RAM and the like),
+but nothing as detailed or complete as the OF device tree. This has
+meant that the various 32-bit \ppc embedded ports have required a
+variety of hacks spread across the kernel to deal with the lack of
+device tree. These vary from specialised boot wrappers to parse
+parameters (which are at least reasonably localised) to
+CONFIG-dependent hacks in drivers to override normal probe logic with
+hardcoded addresses for a particular board. As well as being ugly of
+itself, such CONFIG-dependent hacks make it hard to build a single
+kernel image that supports multiple embedded machines.
+
+Until relatively recently, the only 64-bit \ppc machines without OF
+were legacy (pre-POWER5\R) iSeries\R machines. iSeries machines often
+only have virtual IO devices, which makes it quite simple to work
+around the lack of a device tree. Even so, the lack means the iSeries
+boot sequence must be quite different from the pSeries or Macintosh,
+which is not ideal.
+
+The device tree also presents a problem for implementing \kexec. When
+the kernel boots, it takes over full control of the system from OF,
+even re-using OF's memory. So, when \kexec comes to boot another
+kernel, OF is no longer around for the second kernel to query.
+
+\section{The Flattened Tree}
+
+In May 2005 \benh implemented a new approach to handling the device
+tree that addresses all these problems. When booting on OF systems,
+the first thing the kernel runs is a small piece of code in
+\texttt{prom\_init.c}, which executes in the context of OF. This code
+walks the device tree using OF calls, and transcribes it into a
+compact, flattened format. The resulting device tree ``blob'' is then
+passed to the kernel proper, which eventually unflattens the tree into
+its runtime form. This blob is the only data communicated between the
+\texttt{prom\_init.c} bootstrap and the rest of the kernel.
+
+When OF isn't available, either because the machine doesn't have it at
+all or because \kexec has been used, the kernel instead starts
+directly from the entry point taking a flattened device tree. The
+device tree blob must be passed in from outside, rather than generated
+by part of the kernel from OF. For \kexec, the userland
+\texttt{kexec} tools build the blob from the runtime device tree
+before invoking the new kernel. For embedded systems the blob can
+come either from the embedded bootloader, or from a specialised
+version of the \texttt{zImage} wrapper for the system in question.
+
+\subsection{Properties of the flattened tree}
+
+The flattened tree format should be easy to handle, both for the
+kernel that parses it and the bootloader that generates it. In
+particular, the following properties are desirable:
+
+\begin{itemize}
+\item \emph{relocatable}: the bootloader or kernel should be able to
+ move the blob around as a whole, without needing to parse or adjust
+ its internals. In practice that means we must not use pointers
+ within the blob.
+\item \emph{insert and delete}: sometimes the bootloader might want to
+ make tweaks to the flattened tree, such as deleting or inserting a
+ node (or whole subtree). It should be possible to do this without
+ having to effectively regenerate the whole flattened tree. In
+ practice this means limiting the use of internal offsets in the blob
+ that need recalculation if a section is inserted or removed with
+ \texttt{memmove()}.
+\item \emph{compact}: embedded systems are frequently short of
+ resources, particularly RAM and flash memory space. Thus, the tree
+ representation should be kept as small as conveniently possible.
+\end{itemize}
+
+\subsection{Format of the device tree blob}
+\label{sec:format}
+
+\begin{figure}[htb!]
+ \centering
+ \footnotesize
+ \begin{tabular}{r|c|l}
+ \multicolumn{1}{r}{\textbf{Offset}}& \multicolumn{1}{c}{\textbf{Contents}} \\\cline{2-2}
+ \texttt{0x00} & \texttt{0xd00dfeed} & magic number \\\cline{2-2}
+ \texttt{0x04} & \emph{totalsize} \\\cline{2-2}
+ \texttt{0x08} & \emph{off\_struct} & \\\cline{2-2}
+ \texttt{0x0C} & \emph{off\_strs} & \\\cline{2-2}
+ \texttt{0x10} & \emph{off\_rsvmap} & \\\cline{2-2}
+ \texttt{0x14} & \emph{version} \\\cline{2-2}
+ \texttt{0x18} & \emph{last\_comp\_ver} & \\\cline{2-2}
+ \texttt{0x1C} & \emph{boot\_cpu\_id} & \tge v2 only\\\cline{2-2}
+ \texttt{0x20} & \emph{size\_strs} & \tge v3 only\\\cline{2-2}
+ \multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
+ \emph{off\_rsvmap} & \emph{address0} & memory reserve \\
+ + \texttt{0x04} & ...& table \\\cline{2-2}
+ + \texttt{0x08} & \emph{len0} & \\
+ + \texttt{0x0C} & ...& \\\cline{2-2}
+ \vdots & \multicolumn{1}{c|}{\vdots} & \\\cline{2-2}
+ & \texttt{0x00000000}- & end marker\\
+ & \texttt{00000000} & \\\cline{2-2}
+ & \texttt{0x00000000}- & \\
+ & \texttt{00000000} & \\\cline{2-2}
+ \multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
+ \emph{off\_strs} & \texttt{'n' 'a' 'm' 'e'} & strings block \\
+ + \texttt{0x04} & \texttt{~0~ 'm' 'o' 'd'} & \\
+ + \texttt{0x08} & \texttt{'e' 'l' ~0~ \makebox[\widthof{~~~}]{\textrm{...}}} & \\
+ \vdots & \multicolumn{1}{c|}{\vdots} & \\\cline{2-2}
+ \multicolumn{1}{r}{+ \emph{size\_strs}} \\
+ \multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
+ \emph{off\_struct} & \dtbeginnode & structure block \\\cline{2-2}
+ + \texttt{0x04} & \texttt{'/' ~0~ ~0~ ~0~} & root node\\\cline{2-2}
+ + \texttt{0x08} & \dtprop & \\\cline{2-2}
+ + \texttt{0x0C} & \texttt{0x00000005} & ``\texttt{model}''\\\cline{2-2}
+ + \texttt{0x10} & \texttt{0x00000008} & \\\cline{2-2}
+ + \texttt{0x14} & \texttt{'M' 'y' 'B' 'o'} & \\
+ + \texttt{0x18} & \texttt{'a' 'r' 'd' ~0~} & \\\cline{2-2}
+ \vdots & \multicolumn{1}{c|}{\vdots} & \\\cline{2-2}
+ & \texttt{\dtendnode} \\\cline{2-2}
+ & \texttt{\dtend} \\\cline{2-2}
+ \multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
+ \multicolumn{1}{r}{\emph{totalsize}} \\
+ \end{tabular}
+ \caption{Device tree blob layout}
+ \label{fig:blob-layout}
+\end{figure}
+
+The format for the blob we devised, was first described on the
+\texttt{linuxppc64-dev} mailing list in \cite{noof1}. The format has
+since evolved through various revisions, and the current version is
+included as part of the \dtc (see \S\ref{sec:dtc}) git tree,
+\cite{dtcgit}.
+
+Figure \ref{fig:blob-layout} shows the layout of the blob of data
+containing the device tree. It has three sections of variable size:
+the \emph{memory reserve table}, the \emph{structure block} and the
+\emph{strings block}. A small header gives the blob's size and
+version and the locations of the three sections, plus a handful of
+vital parameters used during early boot.
+
+The memory reserve map section gives a list of regions of memory that
+the kernel must not use\footnote{Usually such ranges contain some data
+structure initialised by the firmware that must be preserved by the
+kernel.}. The list is represented as a simple array of (address,
+size) pairs of 64 bit values, terminated by a zero size entry. The
+strings block is similarly simple, consisting of a number of
+null-terminated strings appended together, which are referenced from
+the structure block as described below.
+
+The structure block contains the device tree proper. Each node is
+introduced with a 32-bit \dtbeginnode tag, followed by the node's name
+as a null-terminated string, padded to a 32-bit boundary. Then
+follows all of the properties of the node, each introduced with a
+\dtprop tag, then all of the node's subnodes, each introduced with
+their own \dtbeginnode tag. The node ends with an \dtendnode tag, and
+after the \dtendnode for the root node is an \dtend tag, indicating
+the end of the whole tree\footnote{This is redundant, but included for
+ease of parsing.}. The structure block starts with the \dtbeginnode
+introducing the description of the root node (named \texttt{/}).
+
+Each property, after the \dtprop, has a 32-bit value giving an offset
+from the beginning of the strings block at which the property name is
+stored. Because it's common for many nodes to have properties with
+the same name, this approach can substantially reduce the total size
+of the blob. The name offset is followed by the length of the
+property value (as a 32-bit value) and then the data itself padded to
+a 32-bit boundary.
+
+\subsection{Contents of the tree}
+\label{sec:treecontents}
+
+Having seen how to represent the device tree structure as a flattened
+blob, what actually goes into the tree? The short answer is ``the
+same as an OF tree''. On OF systems, the flattened tree is
+transcribed directly from the OF device tree, so for simplicity we
+also use OF conventions for the tree on other systems.
+
+In many cases a flat tree can be simpler than a typical OF provided
+device tree. The flattened tree need only provide those nodes and
+properties that the kernel actually requires; the flattened tree
+generally need not include devices that the kernel can probe itself.
+For example, an OF device tree would normally include nodes for each
+PCI device on the system. A flattened tree need only include nodes
+for the PCI host bridges; the kernel will scan the buses thus
+described to find the subsidiary devices. The device tree can include
+nodes for devices where the kernel needs extra information, though:
+for example, for ISA devices on a subsidiary PCI/ISA bridge, or for
+devices with unusual interrupt routing.
+
+Where they exist, we follow the IEEE1275 bindings that specify how to
+describe various buses in the device tree (for example,
+\cite{IEEE1275-pci} describe how to represent PCI devices). The
+standard has not been updated for a long time, however, and lacks
+bindings for many modern buses and devices. In particular, embedded
+specific devices such as the various System-on-Chip buses are not
+covered. We intend to create new bindings for such buses, in keeping
+with the general conventions of IEEE1275 (a simple such binding for a
+System-on-Chip bus was included in \cite{noof5} a revision of
+\cite{noof1}).
+
+One complication arises for representing ``phandles'' in the flattened
+tree. In OF, each node in the tree has an associated phandle, a
+32-bit integer that uniquely identifies the node\footnote{In practice
+usually implemented as a pointer or offset within OF memory.}. This
+handle is used by the various OF calls to query and traverse the tree.
+Sometimes phandles are also used within the tree to refer to other
+nodes in the tree. For example, devices that produce interrupts
+generally have an \texttt{interrupt-parent} property giving the
+phandle of the interrupt controller that handles interrupts from this
+device. Parsing these and other interrupt related properties allows
+the kernel to build a complete representation of the system's
+interrupt tree, which can be quite different from the tree of bus
+connections.
+
+In the flattened tree, a node's phandle is represented by a special
+\phandle property. When the kernel generates a flattened tree from
+OF, it adds a \phandle property to each node, containing the phandle
+retrieved from OF. When the tree is generated without OF, however,
+only nodes that are actually referred to by phandle need to have this
+property.
+
+Another complication arises because nodes in an OF tree have two
+names. First they have the ``unit name'', which is how the node is
+referred to in an OF path. The unit name generally consists of a
+device type followed by an \texttt{@} followed by a \emph{unit
+address}. For example \texttt{/memory@0} is the full path of a memory
+node at address 0, \texttt{/ht@0,f2000000/pci@1} is the path of a PCI
+bus node, which is under a HyperTransport\tm bus node. The form of
+the unit address is bus dependent, but is generally derived from the
+node's \texttt{reg} property. In addition, nodes have a property,
+\texttt{name}, whose value is usually equal to the first path of the
+unit name. For example, the nodes in the previous example would have
+\texttt{name} properties equal to \texttt{memory} and \texttt{pci},
+respectively. To save space in the blob, the current version of the
+flattened tree format only requires the unit names to be present.
+When the kernel unflattens the tree, it automatically generates a
+\texttt{name} property from the node's path name.
+
+\section{The Device Tree Compiler}
+\label{sec:dtc}
+
+\begin{figure}[htb!]
+ \centering
+ \begin{lstlisting}[frame=single,basicstyle=\footnotesize\ttfamily,
+ tabsize=3,numbers=left,xleftmargin=2em]
+/memreserve/ 0x20000000-0x21FFFFFF;
+
+/ {
+ model = "MyBoard";
+ compatible = "MyBoardFamily";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ PowerPC,970@0 {
+ device_type = "cpu";
+ reg = <0>;
+ clock-frequency = <5f5e1000>;
+ timebase-frequency = <1FCA055>;
+ linux,boot-cpu;
+ i-cache-size = <10000>;
+ d-cache-size = <8000>;
+ };
+ };
+
+ memory@0 {
+ device_type = "memory";
+ memreg: reg = <00000000 00000000
+ 00000000 20000000>;
+ };
+
+ mpic@0x3fffdd08400 {
+ /* Interrupt controller */
+ /* ... */
+ };
+
+ pci@40000000000000 {
+ /* PCI host bridge */
+ /* ... */
+ };
+
+ chosen {
+ bootargs = "root=/dev/sda2";
+ linux,platform = <00000600>;
+ interrupt-controller =
+ < &/mpic@0x3fffdd08400 >;
+ };
+};
+\end{lstlisting}
+ \caption{Example \dtc source}
+ \label{fig:dts}
+\end{figure}
+
+As we've seen, the flattened device tree format provides a convenient
+way of communicating device tree information to the kernel. It's
+simple for the kernel to parse, and simple for bootloaders to
+manipulate. On OF systems, it's easy to generate the flattened tree
+by walking the OF maintained tree. However, for embedded systems, the
+flattened tree must be generated from scratch.
+
+Embedded bootloaders are generally built for a particular board. So,
+it's usually possible to build the device tree blob at compile time
+and include it in the bootloader image. For minor revisions of the
+board, the bootloader can contain code to make the necessary tweaks to
+the tree before passing it to the booted kernel.
+
+The device trees for embedded boards are usually quite simple, and
+it's possible to hand construct the necessary blob by hand, but doing
+so is tedious. The ``device tree compiler'', \dtc{}\footnote{\dtc can
+be obtained from \cite{dtcgit}.}, is designed to make creating device
+tree blobs easier by converting a text representation of the tree
+into the necessary blob.
+
+\subsection{Input and output formats}
+
+As well as the normal mode of compiling a device tree blob from text
+source, \dtc can convert a device tree between a number of
+representations. It can take its input in one of three different
+formats:
+\begin{itemize}
+\item source, the normal case. The device tree is described in a text
+ form, described in \S\ref{sec:dts}.
+\item blob (\texttt{dtb}), the flattened tree format described in
+ \S\ref{sec:format}. This mode is useful for checking a pre-existing
+ device tree blob.
+\item filesystem (\texttt{fs}), input is a directory tree in the
+ layout of \texttt{/proc/device-tree} (roughly, a directory for each
+ node in the device tree, a file for each property). This is useful
+ for building a blob for the device tree in use by the currently
+ running kernel.
+\end{itemize}
+
+In addition, \dtc can output the tree in one of three different
+formats:
+\begin{itemize}
+\item blob (\texttt{dtb}), as in \S\ref{sec:format}. The most
+ straightforward use of \dtc is to compile from ``source'' to
+ ``blob'' format.
+\item source (\texttt{dts}), as in \S\ref{sec:dts}. If used with blob
+ input, this allows \dtc to act as a ``decompiler''.
+\item assembler source (\texttt{asm}). \dtc can produce an assembler
+ file, which will assemble into a \texttt{.o} file containing the
+ device tree blob, with symbols giving the beginning of the blob and
+ its various subsections. This can then be linked directly into a
+ bootloader or firmware image.
+\end{itemize}
+
+For maximum applicability, \dtc can both read and write any of the
+existing revisions of the blob format. When reading, \dtc takes the
+version from the blob header, and when writing it takes a command line
+option specifying the desired version. It automatically makes any
+necessary adjustments to the tree that are necessary for the specified
+version. For example, formats before 0x10 require each node to have
+an explicit \texttt{name} property. When \dtc creates such a blob, it
+will automatically generate \texttt{name} properties from the unit
+names.
+
+\subsection{Source format}
+\label{sec:dts}
+
+The ``source'' format for \dtc is a text description of the device
+tree in a vaguely C-like form. Figure \ref{fig:dts} shows an
+example. The file starts with \texttt{/memreserve/} directives, which
+gives address ranges to add to the output blob's memory reserve table,
+then the device tree proper is described.
+
+Nodes of the tree are introduced with the node name, followed by a
+\texttt{\{} ... \texttt{\};} block containing the node's properties
+and subnodes. Properties are given as just {\emph{name} \texttt{=}
+ \emph{value}\texttt{;}}. The property values can be given in any
+of three forms:
+\begin{itemize}
+\item \emph{string} (for example, \texttt{"MyBoard"}). The property
+ value is the given string, including terminating NULL. C-style
+ escapes (\verb+\t+, \verb+\n+, \verb+\0+ and so forth) are allowed.
+\item \emph{cells} (for example, \texttt{<0 8000 f0000000>}). The
+ property value is made up of a list of 32-bit ``cells'', each given
+ as a hex value.
+\item \emph{bytestring} (for example, \texttt{[1234abcdef]}). The
+ property value is given as a hex bytestring.
+\end{itemize}
+
+Cell properties can also contain \emph{references}. Instead of a hex
+number, the source can give an ampersand (\texttt{\&}) followed by the
+full path to some node in the tree. For example, in Figure
+\ref{fig:dts}, the \texttt{/chosen} node has an
+\texttt{interrupt-controller} property referring to the interrupt
+controller described by the node \texttt{/mpic@0x3fffdd08400}. In the
+output tree, the value of the referenced node's phandle is included in
+the property. If that node doesn't have an explicit phandle property,
+\dtc will automatically create a unique phandle for it. This approach
+makes it easy to create interrupt trees without having to explicitly
+assign and remember phandles for the various interrupt controller
+nodes.
+
+The \dtc source can also include ``labels'', which are placed on a
+particular node or property. For example, Figure \ref{fig:dts} has a
+label ``\texttt{memreg}'' on the \texttt{reg} property of the node
+\texttt{/memory@0}. When using assembler output, corresponding labels
+in the output are generated, which will assemble into symbols
+addressing the part of the blob with the node or property in question.
+This is useful for the common case where an embedded board has an
+essentially fixed device tree with a few variable properties, such as
+the size of memory. The bootloader for such a board can have a device
+tree linked in, including a symbol referring to the right place in the
+blob to update the parameter with the correct value determined at
+runtime.
+
+\subsection{Tree checking}
+
+Between reading in the device tree and writing it out in the new
+format, \dtc performs a number of checks on the tree:
+\begin{itemize}
+\item \emph{syntactic structure}: \dtc checks that node and property
+ names contain only allowed characters and meet length restrictions.
+ It checks that a node does not have multiple properties or subnodes
+ with the same name.
+\item \emph{semantic structure}: In some cases, \dtc checks that
+ properties whose contents are defined by convention have appropriate
+ values. For example, it checks that \texttt{reg} properties have a
+ length that makes sense given the address forms specified by the
+ \texttt{\#address-cells} and \texttt{\#size-cells} properties. It
+ checks that properties such as \texttt{interrupt-parent} contain a
+ valid phandle.
+\item \emph{Linux requirements}: \dtc checks that the device tree
+ contains those nodes and properties that are required by the Linux
+ kernel to boot correctly.
+\end{itemize}
+
+These checks are useful to catch simple problems with the device tree,
+rather than having to debug the results on an embedded kernel. With
+the blob input mode, it can also be used for diagnosing problems with
+an existing blob.
+
+\section{Future Work}
+
+\subsection{Board ports}
+
+The flattened device tree has always been the only supported way to
+boot a \texttt{ppc64} kernel on an embedded system. With the merge of
+\texttt{ppc32} and \texttt{ppc64} code it has also become the only
+supported way to boot any merged \texttt{powerpc} kernel, 32-bit or
+64-bit. In fact, the old \texttt{ppc} architecture exists mainly just
+to support the old ppc32 embedded ports that have not been migrated
+to the flattened device tree approach. We plan to remove the
+\texttt{ppc} architecture eventually, which will mean porting all the
+various embedded boards to use the flattened device tree.
+
+\subsection{\dtc features}
+
+While it is already quite usable, there are a number of extra features
+that \dtc could include to make creating device trees more convenient:
+\begin{itemize}
+\item \emph{better tree checking}: Although \dtc already performs a
+ number of checks on the device tree, they are rather haphazard. In
+ many cases \dtc will give up after detecting a minor error early and
+ won't pick up more interesting errors later on. There is a
+ \texttt{-f} parameter that forces \dtc to generate an output tree
+ even if there are errors. At present, this needs to be used more
+ often than one might hope, because \dtc is bad at deciding which
+ errors should really be fatal, and which rate mere warnings.
+\item \emph{binary include}: Occasionally, it is useful for the device
+ tree to incorporate as a property a block of binary data for some
+ board-specific purpose. For example, many of Apple's device trees
+ incorporate bytecode drivers for certain platform devices. \dtc's
+ source format ought to allow this by letting a property's value be
+ read directly from a binary file.
+\item \emph{macros}: it might be useful for \dtc to implement some
+ sort of macros so that a tree containing a number of similar devices
+ (for example, multiple identical ethernet controllers or PCI buses)
+ can be written more quickly. At present, this can be accomplished
+ in part by running the source file through CPP before compiling with
+ \dtc. It's not clear whether ``native'' support for macros would be
+ more useful.
+\end{itemize}
+
+\bibliographystyle{amsplain}
+\bibliography{dtc-paper}
+
+\section*{About the authors}
+
+David Gibson has been a member of the IBM Linux Technology Center,
+working from Canberra, Australia, since 2001. Recently he has worked
+on Linux hugepage support and performance counter support for ppc64,
+as well as the device tree compiler. In the past, he has worked on
+bringup for various ppc and ppc64 embedded systems, the orinoco
+wireless driver, ramfs, and a userspace checkpointing system
+(\texttt{esky}).
+
+Benjamin Herrenschmidt was a MacOS developer for about 10 years, but
+ultimately saw the light and installed Linux on his Apple PowerPC
+machine. After writing a bootloader, BootX, for it in 1998, he
+started contributing to the PowerPC Linux port in various areas,
+mostly around the support for Apple machines. He became official
+PowerMac maintainer in 2001. In 2003, he joined the IBM Linux
+Technology Center in Canberra, Australia, where he ported the 64 bit
+PowerPC kernel to Apple G5 machines and the Maple embedded board,
+among others things. He's a member of the ppc64 development ``team''
+and one of his current goals is to make the integration of embedded
+platforms smoother and more maintainable than in the 32-bit PowerPC
+kernel.
+
+\section*{Legal Statement}
+
+This work represents the view of the author and does not necessarily
+represent the view of IBM.
+
+IBM, \ppc, \ppc Architecture, POWER5, pSeries and iSeries are
+trademarks or registered trademarks of International Business Machines
+Corporation in the United States and/or other countries.
+
+Apple and Power Macintosh are a registered trademarks of Apple
+Computer Inc. in the United States, other countries, or both.
+
+Linux is a registered trademark of Linus Torvalds.
+
+Other company, product, and service names may be trademarks or service
+marks of others.
+
+\end{document}
diff --git a/contrib/dtc/Documentation/dts-format.txt b/contrib/dtc/Documentation/dts-format.txt
new file mode 100644
index 0000000..a655b87
--- /dev/null
+++ b/contrib/dtc/Documentation/dts-format.txt
@@ -0,0 +1,110 @@
+Device Tree Source Format (version 1)
+=====================================
+
+The Device Tree Source (DTS) format is a textual representation of a
+device tree in a form that can be processed by dtc into a binary
+device tree in the form expected by the kernel. The description below
+is not a formal syntax definition of DTS, but describes the basic
+constructs used to represent device trees.
+
+Node and property definitions
+-----------------------------
+
+Device tree nodes are defined with a node name and unit address with
+braces marking the start and end of the node definition. They may be
+preceded by a label.
+
+ [label:] node-name[@unit-address] {
+ [properties definitions]
+ [child nodes]
+ }
+
+Nodes may contain property definitions and/or child node
+definitions. If both are present, properties must come before child
+nodes.
+
+Property definitions are name value pairs in the form:
+ [label:] property-name = value;
+except for properties with empty (zero length) value which have the
+form:
+ [label:] property-name;
+
+Property values may be defined as an array of 32-bit integer cells, as
+NUL-terminated strings, as bytestrings or a combination of these.
+
+* Arrays of cells are represented by angle brackets surrounding a
+ space separated list of C-style integers
+
+ e.g. interrupts = <17 0xc>;
+
+* A 64-bit value is represented with two 32-bit cells.
+
+ e.g. clock-frequency = <0x00000001 0x00000000>;
+
+* A NUL-terminated string value is represented using double quotes
+ (the property value is considered to include the terminating NUL
+ character).
+
+ e.g. compatible = "simple-bus";
+
+* A bytestring is enclosed in square brackets [] with each byte
+ represented by two hexadecimal digits. Spaces between each byte are
+ optional.
+
+ e.g. local-mac-address = [00 00 12 34 56 78]; or equivalently
+ local-mac-address = [000012345678];
+
+* Values may have several comma-separated components, which are
+ concatenated together.
+ e.g. compatible = "ns16550", "ns8250";
+ example = <0xf00f0000 19>, "a strange property format";
+
+* In a cell array a reference to another node will be expanded to that
+ node's phandle. References may by '&' followed by a node's label:
+ e.g. interrupt-parent = < &mpic >;
+ or they may be '&' followed by a node's full path in braces:
+ e.g. interrupt-parent = < &{/soc/interrupt-controller@40000} >;
+
+* Outside a cell array, a reference to another node will be expanded
+ to that node's full path.
+ e.g. ethernet0 = &EMAC0;
+
+* Labels may also appear before or after any component of a property
+ value, or between cells of a cell array, or between bytes of a
+ bytestring.
+ e.g. reg = reglabel: <0 sizelabel: 0x1000000>;
+ e.g. prop = [ab cd ef byte4: 00 ff fe];
+ e.g. str = start: "string value" end: ;
+
+
+File layout
+-----------
+
+Version 1 DTS files have the overall layout:
+ /dts-v1/;
+
+ [memory reservations]
+
+ / {
+ [property definitions]
+ [child nodes]
+ };
+
+* The "/dts-v1/;" must be present to identify the file as a version 1
+ DTS (dts files without this tag will be treated by dtc as being in
+ the obsolete "version 0", which uses a different format for integers
+ amongst other small but incompatible changes).
+
+* Memory reservations define an entry for the device tree blob's
+ memory reservation table. They have the form:
+ e.g. /memreserve/ <address> <length>;
+ Where <address> and <length> are 64-bit C-style integers.
+
+* The / { ... }; section defines the root node of the device tree.
+
+* C style (/* ... */) and C++ style (// ...) comments are supported.
+
+
+
+ -- David Gibson <david@gibson.dropbear.id.au>
+ -- Yoder Stuart <stuart.yoder@freescale.com>
diff --git a/contrib/dtc/Documentation/manual.txt b/contrib/dtc/Documentation/manual.txt
new file mode 100644
index 0000000..f8a8a7b
--- /dev/null
+++ b/contrib/dtc/Documentation/manual.txt
@@ -0,0 +1,652 @@
+Device Tree Compiler Manual
+===========================
+
+I - "dtc", the device tree compiler
+ 1) Obtaining Sources
+ 2) Description
+ 3) Command Line
+ 4) Source File
+ 4.1) Overview
+ 4.2) Properties
+ 4.3) Labels and References
+
+II - The DT block format
+ 1) Header
+ 2) Device tree generalities
+ 3) Device tree "structure" block
+ 4) Device tree "strings" block
+
+
+III - libfdt
+
+IV - Utility Tools
+ 1) convert-dtsv0 -- Conversion to Version 1
+ 1) ftdump
+
+
+I - "dtc", the device tree compiler
+===================================
+
+1) Sources
+
+Source code for the Device Tree Compiler can be found at jdl.com.
+The gitweb interface is:
+
+ http://git.jdl.com/gitweb/
+
+The repository is here:
+
+ git://www.jdl.com/software/dtc.git
+ http://www.jdl.com/software/dtc.git
+
+Tarballs of the 1.0.0 and latest releases are here:
+
+ http://www.jdl.com/software/dtc-v1.2.0.tgz
+ http://www.jdl.com/software/dtc-latest.tgz
+
+
+2) Description
+
+The Device Tree Compiler, dtc, takes as input a device-tree in
+a given format and outputs a device-tree in another format.
+Typically, the input format is "dts", a human readable source
+format, and creates a "dtb", or binary format as output.
+
+The currently supported Input Formats are:
+
+ - "dtb": "blob" format. A flattened device-tree block with
+ header in one binary blob.
+
+ - "dts": "source" format. A text file containing a "source"
+ for a device-tree.
+
+ - "fs" format. A representation equivalent to the output of
+ /proc/device-tree where nodes are directories and
+ properties are files.
+
+The currently supported Output Formats are:
+
+ - "dtb": "blob" format
+
+ - "dts": "source" format
+
+ - "asm": assembly language file. A file that can be sourced
+ by gas to generate a device-tree "blob". That file can
+ then simply be added to your Makefile. Additionally, the
+ assembly file exports some symbols that can be used.
+
+
+3) Command Line
+
+The syntax of the dtc command line is:
+
+ dtc [options] [<input_filename>]
+
+Options:
+
+ <input_filename>
+ The name of the input source file. If no <input_filename>
+ or "-" is given, stdin is used.
+
+ -b <number>
+ Set the physical boot cpu.
+
+ -f
+ Force. Try to produce output even if the input tree has errors.
+
+ -h
+ Emit a brief usage and help message.
+
+ -I <input_format>
+ The source input format, as listed above.
+
+ -o <output_filename>
+ The name of the generated output file. Use "-" for stdout.
+
+ -O <output_format>
+ The generated output format, as listed above.
+
+ -q
+ Quiet: -q suppress warnings, -qq errors, -qqq all
+
+ -R <number>
+ Make space for <number> reserve map entries
+ Relevant for dtb and asm output only.
+
+ -S <bytes>
+ Ensure the blob at least <bytes> long, adding additional
+ space if needed.
+
+ -v
+ Print DTC version and exit.
+
+ -V <output_version>
+ Generate output conforming to the given <output_version>.
+ By default the most recent version is generated.
+ Relevant for dtb and asm output only.
+
+
+The <output_version> defines what version of the "blob" format will be
+generated. Supported versions are 1, 2, 3, 16 and 17. The default is
+always the most recent version and is likely the highest number.
+
+Additionally, dtc performs various sanity checks on the tree.
+
+
+4) Device Tree Source file
+
+4.1) Overview
+
+Here is a very rough overview of the layout of a DTS source file:
+
+
+ sourcefile: list_of_memreserve devicetree
+
+ memreserve: label 'memreserve' ADDR ADDR ';'
+ | label 'memreserve' ADDR '-' ADDR ';'
+
+ devicetree: '/' nodedef
+
+ nodedef: '{' list_of_property list_of_subnode '}' ';'
+
+ property: label PROPNAME '=' propdata ';'
+
+ propdata: STRING
+ | '<' list_of_cells '>'
+ | '[' list_of_bytes ']'
+
+ subnode: label nodename nodedef
+
+That structure forms a hierarchical layout of nodes and properties
+rooted at an initial node as:
+
+ / {
+ }
+
+Both classic C style and C++ style comments are supported.
+
+Source files may be directly included using the syntax:
+
+ /include/ "filename"
+
+
+4.2) Properties
+
+Properties are named, possibly labeled, values. Each value
+is one of:
+
+ - A null-teminated C-like string,
+ - A numeric value fitting in 32 bits,
+ - A list of 32-bit values
+ - A byte sequence
+
+Here are some example property definitions:
+
+ - A property containing a 0 terminated string
+
+ property1 = "string_value";
+
+ - A property containing a numerical 32-bit hexadecimal value
+
+ property2 = <1234abcd>;
+
+ - A property containing 3 numerical 32-bit hexadecimal values
+
+ property3 = <12345678 12345678 deadbeef>;
+
+ - A property whose content is an arbitrary array of bytes
+
+ property4 = [0a 0b 0c 0d de ea ad be ef];
+
+
+Node may contain sub-nodes to obtain a hierarchical structure.
+For example:
+
+ - A child node named "childnode" whose unit name is
+ "childnode at address". It it turn has a string property
+ called "childprop".
+
+ childnode@addresss {
+ childprop = "hello\n";
+ };
+
+
+By default, all numeric values are hexadecimal. Alternate bases
+may be specified using a prefix "d#" for decimal, "b#" for binary,
+and "o#" for octal.
+
+Strings support common escape sequences from C: "\n", "\t", "\r",
+"\(octal value)", "\x(hex value)".
+
+
+4.3) Labels and References
+
+Labels may be applied to nodes or properties. Labels appear
+before a node name, and are referenced using an ampersand: &label.
+Absolute node path names are also allowed in node references.
+
+In this exmaple, a node is labled "mpic" and then referenced:
+
+ mpic: interrupt-controller@40000 {
+ ...
+ };
+
+ ethernet-phy@3 {
+ interrupt-parent = <&mpic>;
+ ...
+ };
+
+And used in properties, lables may appear before or after any value:
+
+ randomnode {
+ prop: string = data: "mystring\n" data_end: ;
+ ...
+ };
+
+
+
+II - The DT block format
+========================
+
+This chapter defines the format of the flattened device-tree
+passed to the kernel. The actual content of the device tree
+are described in the kernel documentation in the file
+
+ linux-2.6/Documentation/powerpc/booting-without-of.txt
+
+You can find example of code manipulating that format within
+the kernel. For example, the file:
+
+ including arch/powerpc/kernel/prom_init.c
+
+will generate a flattened device-tree from the Open Firmware
+representation. Other utilities such as fs2dt, which is part of
+the kexec tools, will generate one from a filesystem representation.
+Some bootloaders such as U-Boot provide a bit more support by
+using the libfdt code.
+
+For booting the kernel, the device tree block has to be in main memory.
+It has to be accessible in both real mode and virtual mode with no
+mapping other than main memory. If you are writing a simple flash
+bootloader, it should copy the block to RAM before passing it to
+the kernel.
+
+
+1) Header
+---------
+
+The kernel is entered with r3 pointing to an area of memory that is
+roughly described in include/asm-powerpc/prom.h by the structure
+boot_param_header:
+
+ struct boot_param_header {
+ u32 magic; /* magic word OF_DT_HEADER */
+ u32 totalsize; /* total size of DT block */
+ u32 off_dt_struct; /* offset to structure */
+ u32 off_dt_strings; /* offset to strings */
+ u32 off_mem_rsvmap; /* offset to memory reserve map */
+ u32 version; /* format version */
+ u32 last_comp_version; /* last compatible version */
+
+ /* version 2 fields below */
+ u32 boot_cpuid_phys; /* Which physical CPU id we're
+ booting on */
+ /* version 3 fields below */
+ u32 size_dt_strings; /* size of the strings block */
+
+ /* version 17 fields below */
+ u32 size_dt_struct; /* size of the DT structure block */
+ };
+
+Along with the constants:
+
+ /* Definitions used by the flattened device tree */
+ #define OF_DT_HEADER 0xd00dfeed /* 4: version,
+ 4: total size */
+ #define OF_DT_BEGIN_NODE 0x1 /* Start node: full name
+ */
+ #define OF_DT_END_NODE 0x2 /* End node */
+ #define OF_DT_PROP 0x3 /* Property: name off,
+ size, content */
+ #define OF_DT_END 0x9
+
+All values in this header are in big endian format, the various
+fields in this header are defined more precisely below. All "offset"
+values are in bytes from the start of the header; that is from the
+value of r3.
+
+ - magic
+
+ This is a magic value that "marks" the beginning of the
+ device-tree block header. It contains the value 0xd00dfeed and is
+ defined by the constant OF_DT_HEADER
+
+ - totalsize
+
+ This is the total size of the DT block including the header. The
+ "DT" block should enclose all data structures defined in this
+ chapter (who are pointed to by offsets in this header). That is,
+ the device-tree structure, strings, and the memory reserve map.
+
+ - off_dt_struct
+
+ This is an offset from the beginning of the header to the start
+ of the "structure" part the device tree. (see 2) device tree)
+
+ - off_dt_strings
+
+ This is an offset from the beginning of the header to the start
+ of the "strings" part of the device-tree
+
+ - off_mem_rsvmap
+
+ This is an offset from the beginning of the header to the start
+ of the reserved memory map. This map is a list of pairs of 64-
+ bit integers. Each pair is a physical address and a size. The
+ list is terminated by an entry of size 0. This map provides the
+ kernel with a list of physical memory areas that are "reserved"
+ and thus not to be used for memory allocations, especially during
+ early initialization. The kernel needs to allocate memory during
+ boot for things like un-flattening the device-tree, allocating an
+ MMU hash table, etc... Those allocations must be done in such a
+ way to avoid overriding critical things like, on Open Firmware
+ capable machines, the RTAS instance, or on some pSeries, the TCE
+ tables used for the iommu. Typically, the reserve map should
+ contain _at least_ this DT block itself (header,total_size). If
+ you are passing an initrd to the kernel, you should reserve it as
+ well. You do not need to reserve the kernel image itself. The map
+ should be 64-bit aligned.
+
+ - version
+
+ This is the version of this structure. Version 1 stops
+ here. Version 2 adds an additional field boot_cpuid_phys.
+ Version 3 adds the size of the strings block, allowing the kernel
+ to reallocate it easily at boot and free up the unused flattened
+ structure after expansion. Version 16 introduces a new more
+ "compact" format for the tree itself that is however not backward
+ compatible. Version 17 adds an additional field, size_dt_struct,
+ allowing it to be reallocated or moved more easily (this is
+ particularly useful for bootloaders which need to make
+ adjustments to a device tree based on probed information). You
+ should always generate a structure of the highest version defined
+ at the time of your implementation. Currently that is version 17,
+ unless you explicitly aim at being backward compatible.
+
+ - last_comp_version
+
+ Last compatible version. This indicates down to what version of
+ the DT block you are backward compatible. For example, version 2
+ is backward compatible with version 1 (that is, a kernel build
+ for version 1 will be able to boot with a version 2 format). You
+ should put a 1 in this field if you generate a device tree of
+ version 1 to 3, or 16 if you generate a tree of version 16 or 17
+ using the new unit name format.
+
+ - boot_cpuid_phys
+
+ This field only exist on version 2 headers. It indicate which
+ physical CPU ID is calling the kernel entry point. This is used,
+ among others, by kexec. If you are on an SMP system, this value
+ should match the content of the "reg" property of the CPU node in
+ the device-tree corresponding to the CPU calling the kernel entry
+ point (see further chapters for more informations on the required
+ device-tree contents)
+
+ - size_dt_strings
+
+ This field only exists on version 3 and later headers. It
+ gives the size of the "strings" section of the device tree (which
+ starts at the offset given by off_dt_strings).
+
+ - size_dt_struct
+
+ This field only exists on version 17 and later headers. It gives
+ the size of the "structure" section of the device tree (which
+ starts at the offset given by off_dt_struct).
+
+So the typical layout of a DT block (though the various parts don't
+need to be in that order) looks like this (addresses go from top to
+bottom):
+
+ ------------------------------
+ r3 -> | struct boot_param_header |
+ ------------------------------
+ | (alignment gap) (*) |
+ ------------------------------
+ | memory reserve map |
+ ------------------------------
+ | (alignment gap) |
+ ------------------------------
+ | |
+ | device-tree structure |
+ | |
+ ------------------------------
+ | (alignment gap) |
+ ------------------------------
+ | |
+ | device-tree strings |
+ | |
+ -----> ------------------------------
+ |
+ |
+ --- (r3 + totalsize)
+
+ (*) The alignment gaps are not necessarily present; their presence
+ and size are dependent on the various alignment requirements of
+ the individual data blocks.
+
+
+2) Device tree generalities
+---------------------------
+
+This device-tree itself is separated in two different blocks, a
+structure block and a strings block. Both need to be aligned to a 4
+byte boundary.
+
+First, let's quickly describe the device-tree concept before detailing
+the storage format. This chapter does _not_ describe the detail of the
+required types of nodes & properties for the kernel, this is done
+later in chapter III.
+
+The device-tree layout is strongly inherited from the definition of
+the Open Firmware IEEE 1275 device-tree. It's basically a tree of
+nodes, each node having two or more named properties. A property can
+have a value or not.
+
+It is a tree, so each node has one and only one parent except for the
+root node who has no parent.
+
+A node has 2 names. The actual node name is generally contained in a
+property of type "name" in the node property list whose value is a
+zero terminated string and is mandatory for version 1 to 3 of the
+format definition (as it is in Open Firmware). Version 16 makes it
+optional as it can generate it from the unit name defined below.
+
+There is also a "unit name" that is used to differentiate nodes with
+the same name at the same level, it is usually made of the node
+names, the "@" sign, and a "unit address", which definition is
+specific to the bus type the node sits on.
+
+The unit name doesn't exist as a property per-se but is included in
+the device-tree structure. It is typically used to represent "path" in
+the device-tree. More details about the actual format of these will be
+below.
+
+The kernel powerpc generic code does not make any formal use of the
+unit address (though some board support code may do) so the only real
+requirement here for the unit address is to ensure uniqueness of
+the node unit name at a given level of the tree. Nodes with no notion
+of address and no possible sibling of the same name (like /memory or
+/cpus) may omit the unit address in the context of this specification,
+or use the "@0" default unit address. The unit name is used to define
+a node "full path", which is the concatenation of all parent node
+unit names separated with "/".
+
+The root node doesn't have a defined name, and isn't required to have
+a name property either if you are using version 3 or earlier of the
+format. It also has no unit address (no @ symbol followed by a unit
+address). The root node unit name is thus an empty string. The full
+path to the root node is "/".
+
+Every node which actually represents an actual device (that is, a node
+which isn't only a virtual "container" for more nodes, like "/cpus"
+is) is also required to have a "device_type" property indicating the
+type of node .
+
+Finally, every node that can be referenced from a property in another
+node is required to have a "linux,phandle" property. Real open
+firmware implementations provide a unique "phandle" value for every
+node that the "prom_init()" trampoline code turns into
+"linux,phandle" properties. However, this is made optional if the
+flattened device tree is used directly. An example of a node
+referencing another node via "phandle" is when laying out the
+interrupt tree which will be described in a further version of this
+document.
+
+This "linux, phandle" property is a 32-bit value that uniquely
+identifies a node. You are free to use whatever values or system of
+values, internal pointers, or whatever to generate these, the only
+requirement is that every node for which you provide that property has
+a unique value for it.
+
+Here is an example of a simple device-tree. In this example, an "o"
+designates a node followed by the node unit name. Properties are
+presented with their name followed by their content. "content"
+represents an ASCII string (zero terminated) value, while <content>
+represents a 32-bit hexadecimal value. The various nodes in this
+example will be discussed in a later chapter. At this point, it is
+only meant to give you a idea of what a device-tree looks like. I have
+purposefully kept the "name" and "linux,phandle" properties which
+aren't necessary in order to give you a better idea of what the tree
+looks like in practice.
+
+ / o device-tree
+ |- name = "device-tree"
+ |- model = "MyBoardName"
+ |- compatible = "MyBoardFamilyName"
+ |- #address-cells = <2>
+ |- #size-cells = <2>
+ |- linux,phandle = <0>
+ |
+ o cpus
+ | | - name = "cpus"
+ | | - linux,phandle = <1>
+ | | - #address-cells = <1>
+ | | - #size-cells = <0>
+ | |
+ | o PowerPC,970@0
+ | |- name = "PowerPC,970"
+ | |- device_type = "cpu"
+ | |- reg = <0>
+ | |- clock-frequency = <5f5e1000>
+ | |- 64-bit
+ | |- linux,phandle = <2>
+ |
+ o memory@0
+ | |- name = "memory"
+ | |- device_type = "memory"
+ | |- reg = <00000000 00000000 00000000 20000000>
+ | |- linux,phandle = <3>
+ |
+ o chosen
+ |- name = "chosen"
+ |- bootargs = "root=/dev/sda2"
+ |- linux,phandle = <4>
+
+This tree is almost a minimal tree. It pretty much contains the
+minimal set of required nodes and properties to boot a linux kernel;
+that is, some basic model informations at the root, the CPUs, and the
+physical memory layout. It also includes misc information passed
+through /chosen, like in this example, the platform type (mandatory)
+and the kernel command line arguments (optional).
+
+The /cpus/PowerPC,970@0/64-bit property is an example of a
+property without a value. All other properties have a value. The
+significance of the #address-cells and #size-cells properties will be
+explained in chapter IV which defines precisely the required nodes and
+properties and their content.
+
+
+3) Device tree "structure" block
+
+The structure of the device tree is a linearized tree structure. The
+"OF_DT_BEGIN_NODE" token starts a new node, and the "OF_DT_END_NODE"
+ends that node definition. Child nodes are simply defined before
+"OF_DT_END_NODE" (that is nodes within the node). A 'token' is a 32
+bit value. The tree has to be "finished" with a OF_DT_END token
+
+Here's the basic structure of a single node:
+
+ * token OF_DT_BEGIN_NODE (that is 0x00000001)
+ * for version 1 to 3, this is the node full path as a zero
+ terminated string, starting with "/". For version 16 and later,
+ this is the node unit name only (or an empty string for the
+ root node)
+ * [align gap to next 4 bytes boundary]
+ * for each property:
+ * token OF_DT_PROP (that is 0x00000003)
+ * 32-bit value of property value size in bytes (or 0 if no
+ value)
+ * 32-bit value of offset in string block of property name
+ * property value data if any
+ * [align gap to next 4 bytes boundary]
+ * [child nodes if any]
+ * token OF_DT_END_NODE (that is 0x00000002)
+
+So the node content can be summarized as a start token, a full path,
+a list of properties, a list of child nodes, and an end token. Every
+child node is a full node structure itself as defined above.
+
+NOTE: The above definition requires that all property definitions for
+a particular node MUST precede any subnode definitions for that node.
+Although the structure would not be ambiguous if properties and
+subnodes were intermingled, the kernel parser requires that the
+properties come first (up until at least 2.6.22). Any tools
+manipulating a flattened tree must take care to preserve this
+constraint.
+
+4) Device tree "strings" block
+
+In order to save space, property names, which are generally redundant,
+are stored separately in the "strings" block. This block is simply the
+whole bunch of zero terminated strings for all property names
+concatenated together. The device-tree property definitions in the
+structure block will contain offset values from the beginning of the
+strings block.
+
+
+III - libfdt
+============
+
+This library should be merged into dtc proper.
+This library should likely be worked into U-Boot and the kernel.
+
+
+IV - Utility Tools
+==================
+
+1) convert-dtsv0 -- Conversion to Version 1
+
+convert-dtsv0 is a small utility program which converts (DTS)
+Device Tree Source from the obsolete version 0 to version 1.
+
+Version 1 DTS files are marked by line "/dts-v1/;" at the top of the file.
+
+The syntax of the convert-dtsv0 command line is:
+
+ convert-dtsv0 [<input_filename ... >]
+
+Each file passed will be converted to the new /dts-v1/ version by creating
+a new file with a "v1" appended the filename.
+
+Comments, empty lines, etc. are preserved.
+
+
+2) ftdump -- Flat Tree dumping utility
+
+The ftdump program prints a readable version of a flat device tree file.
+
+The syntax of the ftdump command line is:
+
+ ftdump <DTB-file-name>
diff --git a/contrib/dtc/GPL b/contrib/dtc/GPL
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/contrib/dtc/GPL
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/contrib/dtc/Makefile b/contrib/dtc/Makefile
new file mode 100644
index 0000000..d7549b2
--- /dev/null
+++ b/contrib/dtc/Makefile
@@ -0,0 +1,245 @@
+#
+# Device Tree Compiler
+#
+
+#
+# Version information will be constructed in this order:
+# EXTRAVERSION might be "-rc", for example.
+# LOCAL_VERSION is likely from command line.
+# CONFIG_LOCALVERSION from some future config system.
+#
+VERSION = 1
+PATCHLEVEL = 2
+SUBLEVEL = 0
+EXTRAVERSION =
+LOCAL_VERSION =
+CONFIG_LOCALVERSION =
+
+CPPFLAGS = -I libfdt
+CFLAGS = -Wall -g -Os -fPIC -Wpointer-arith -Wcast-qual
+
+BISON = bison
+LEX = flex
+
+INSTALL = /usr/bin/install
+DESTDIR =
+PREFIX = $(HOME)
+BINDIR = $(PREFIX)/bin
+LIBDIR = $(PREFIX)/lib
+INCLUDEDIR = $(PREFIX)/include
+
+HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
+ sed -e 's/\(cygwin\).*/cygwin/')
+
+ifeq ($(HOSTOS),darwin)
+SHAREDLIB_EXT=dylib
+SHAREDLIB_LINK_OPTIONS=-dynamiclib -Wl,-install_name -Wl,
+else
+SHAREDLIB_EXT=so
+SHAREDLIB_LINK_OPTIONS=-shared -Wl,--version-script=$(LIBFDT_version) -Wl,-soname,
+endif
+
+#
+# Overall rules
+#
+ifdef V
+VECHO = :
+else
+VECHO = echo " "
+ARFLAGS = rc
+.SILENT:
+endif
+
+NODEPTARGETS = clean
+ifeq ($(MAKECMDGOALS),)
+DEPTARGETS = all
+else
+DEPTARGETS = $(filter-out $(NODEPTARGETS),$(MAKECMDGOALS))
+endif
+
+#
+# Rules for versioning
+#
+
+DTC_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+VERSION_FILE = version_gen.h
+
+CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
+ else if [ -x /bin/bash ]; then echo /bin/bash; \
+ else echo sh; fi ; fi)
+
+nullstring :=
+space := $(nullstring) # end of line
+
+localver_config = $(subst $(space),, $(string) \
+ $(patsubst "%",%,$(CONFIG_LOCALVERSION)))
+
+localver_cmd = $(subst $(space),, $(string) \
+ $(patsubst "%",%,$(LOCALVERSION)))
+
+localver_scm = $(shell $(CONFIG_SHELL) ./scripts/setlocalversion)
+localver_full = $(localver_config)$(localver_cmd)$(localver_scm)
+
+dtc_version = $(DTC_VERSION)$(localver_full)
+
+# Contents of the generated version file.
+define filechk_version
+ (echo "#define DTC_VERSION \"DTC $(dtc_version)\""; )
+endef
+
+define filechk
+ set -e; \
+ echo ' CHK $@'; \
+ mkdir -p $(dir $@); \
+ $(filechk_$(1)) < $< > $@.tmp; \
+ if [ -r $@ ] && cmp -s $@ $@.tmp; then \
+ rm -f $@.tmp; \
+ else \
+ echo ' UPD $@'; \
+ mv -f $@.tmp $@; \
+ fi;
+endef
+
+
+include Makefile.convert-dtsv0
+include Makefile.dtc
+include Makefile.ftdump
+
+BIN += convert-dtsv0
+BIN += dtc
+BIN += ftdump
+
+
+all: $(BIN) libfdt
+
+
+ifneq ($(DEPTARGETS),)
+-include $(DTC_OBJS:%.o=%.d)
+-include $(CONVERT_OBJS:%.o=%.d)
+-include $(FTDUMP_OBJS:%.o=%.d)
+endif
+
+
+
+#
+# Rules for libfdt
+#
+LIBFDT_objdir = libfdt
+LIBFDT_srcdir = libfdt
+LIBFDT_archive = $(LIBFDT_objdir)/libfdt.a
+LIBFDT_lib = $(LIBFDT_objdir)/libfdt.$(SHAREDLIB_EXT)
+LIBFDT_include = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_INCLUDES))
+LIBFDT_version = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_VERSION))
+
+include $(LIBFDT_srcdir)/Makefile.libfdt
+
+.PHONY: libfdt
+libfdt: $(LIBFDT_archive) $(LIBFDT_lib)
+
+$(LIBFDT_archive): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
+$(LIBFDT_lib): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
+
+libfdt_clean:
+ @$(VECHO) CLEAN "(libfdt)"
+ rm -f $(addprefix $(LIBFDT_objdir)/,$(STD_CLEANFILES))
+ rm -f $(LIBFDT_objdir)/*.so
+
+ifneq ($(DEPTARGETS),)
+-include $(LIBFDT_OBJS:%.o=$(LIBFDT_objdir)/%.d)
+endif
+
+# This stops make from generating the lex and bison output during
+# auto-dependency computation, but throwing them away as an
+# intermediate target and building them again "for real"
+.SECONDARY: $(DTC_GEN_SRCS) $(CONVERT_GEN_SRCS)
+
+install: all
+ @$(VECHO) INSTALL
+ $(INSTALL) -d $(DESTDIR)$(BINDIR)
+ $(INSTALL) $(BIN) $(DESTDIR)$(BINDIR)
+ $(INSTALL) -d $(DESTDIR)$(LIBDIR)
+ $(INSTALL) $(LIBFDT_lib) $(DESTDIR)$(LIBDIR)
+ $(INSTALL) -m 644 $(LIBFDT_archive) $(DESTDIR)$(LIBDIR)
+ $(INSTALL) -d $(DESTDIR)$(INCLUDEDIR)
+ $(INSTALL) -m 644 $(LIBFDT_include) $(DESTDIR)$(INCLUDEDIR)
+
+$(VERSION_FILE): Makefile FORCE
+ $(call filechk,version)
+
+
+dtc: $(DTC_OBJS)
+
+convert-dtsv0: $(CONVERT_OBJS)
+ @$(VECHO) LD $@
+ $(LINK.c) -o $@ $^
+
+ftdump: $(FTDUMP_OBJS)
+
+
+#
+# Testsuite rules
+#
+TESTS_PREFIX=tests/
+include tests/Makefile.tests
+
+#
+# Clean rules
+#
+STD_CLEANFILES = *~ *.o *.so *.d *.a *.i *.s core a.out vgcore.* \
+ *.tab.[ch] *.lex.c *.output
+
+clean: libfdt_clean tests_clean
+ @$(VECHO) CLEAN
+ rm -f $(STD_CLEANFILES)
+ rm -f $(VERSION_FILE)
+ rm -f $(BIN)
+
+#
+# Generic compile rules
+#
+%: %.o
+ @$(VECHO) LD $@
+ $(LINK.c) -o $@ $^
+
+%.o: %.c
+ @$(VECHO) CC $@
+ $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
+
+%.o: %.S
+ @$(VECHO) AS $@
+ $(CC) $(CPPFLAGS) $(AFLAGS) -D__ASSEMBLY__ -o $@ -c $<
+
+%.d: %.c
+ @$(VECHO) DEP $<
+ $(CC) $(CPPFLAGS) -MM -MG -MT "$*.o $@" $< > $@
+
+%.d: %.S
+ @$(VECHO) DEP $<
+ $(CC) $(CPPFLAGS) -MM -MG -MT "$*.o $@" $< > $@
+
+%.i: %.c
+ @$(VECHO) CPP $@
+ $(CC) $(CPPFLAGS) -E $< > $@
+
+%.s: %.c
+ @$(VECHO) CC -S $@
+ $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -S $<
+
+%.a:
+ @$(VECHO) AR $@
+ $(AR) $(ARFLAGS) $@ $^
+
+$(LIBFDT_lib):
+ @$(VECHO) LD $@
+ $(CC) $(LDFLAGS) -fPIC $(SHAREDLIB_LINK_OPTIONS)$(notdir $@) -o $(LIBFDT_objdir)/libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT) $^
+ ln -sf libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT) $(LIBFDT_objdir)/libfdt.$(SHAREDLIB_EXT)
+
+%.lex.c: %.l
+ @$(VECHO) LEX $@
+ $(LEX) -o$@ $<
+
+%.tab.c %.tab.h %.output: %.y
+ @$(VECHO) BISON $@
+ $(BISON) -d $<
+
+FORCE:
diff --git a/contrib/dtc/Makefile.convert-dtsv0 b/contrib/dtc/Makefile.convert-dtsv0
new file mode 100644
index 0000000..08ea40a
--- /dev/null
+++ b/contrib/dtc/Makefile.convert-dtsv0
@@ -0,0 +1,13 @@
+#
+# This is not a complete Makefile of itself.
+# Instead, it is designed to be easily embeddable
+# into other systems of Makefiles.
+#
+
+CONVERT_SRCS = \
+ srcpos.c \
+ util.c
+
+CONVERT_GEN_SRCS = convert-dtsv0-lexer.lex.c
+
+CONVERT_OBJS = $(CONVERT_SRCS:%.c=%.o) $(CONVERT_GEN_SRCS:%.c=%.o)
diff --git a/contrib/dtc/Makefile.ftdump b/contrib/dtc/Makefile.ftdump
new file mode 100644
index 0000000..b70905a
--- /dev/null
+++ b/contrib/dtc/Makefile.ftdump
@@ -0,0 +1,12 @@
+#
+# This is not a complete Makefile of itself.
+# Instead, it is designed to be easily embeddable
+# into other systems of Makefiles.
+#
+
+FTDUMP_SRCS = \
+ ftdump.c
+
+FTDUMP_GEN_SRCS =
+
+FTDUMP_OBJS = $(FTDUMP_SRCS:%.c=%.o) $(FTDUMP_GEN_SRCS:%.c=%.o)
diff --git a/contrib/dtc/README.license b/contrib/dtc/README.license
new file mode 100644
index 0000000..d56c88f
--- /dev/null
+++ b/contrib/dtc/README.license
@@ -0,0 +1,56 @@
+Licensing and contribution policy of dtc and libfdt
+===================================================
+
+This dtc package contains two pieces of software: dtc itself, and
+libfdt which comprises the files in the libfdt/ subdirectory. These
+two pieces of software, although closely related, are quite distinct.
+dtc does not incoporate or rely on libfdt for its operation, nor vice
+versa. It is important that these two pieces of software have
+different license conditions.
+
+As the copyright banners in each source file attest, dtc is licensed
+under the GNU GPL. The full text of the GPL can be found in the file
+entitled 'GPL' which should be included in this package. dtc code,
+therefore, may not be incorporated into works which do not have a GPL
+compatible license.
+
+libfdt, however, is GPL/BSD dual-licensed. That is, it may be used
+either under the terms of the GPL, or under the terms of the 2-clause
+BSD license (aka the ISC license). The full terms of that license are
+given in the copyright banners of each of the libfdt source files.
+This is, in practice, equivalent to being BSD licensed, since the
+terms of the BSD license are strictly more permissive than the GPL.
+
+I made the decision to license libfdt in this way because I want to
+encourage widespread and correct usage of flattened device trees,
+including by proprietary or otherwise GPL-incompatible firmware or
+tools. Allowing libfdt to be used under the terms of the BSD license
+makes that it easier for vendors or authors of such software to do so.
+
+This does mean that libfdt code could be "stolen" - say, included in a
+proprietary fimware and extended without contributing those extensions
+back to the libfdt mainline. While I hope that doesn't happen, I
+believe the goal of allowing libfdt to be widely used is more
+important than avoiding that. libfdt is quite small, and hardly
+rocket science; so the incentive for such impolite behaviour is small,
+and the inconvenience caused therby is not dire.
+
+Licenses such as the LGPL which would allow code to be used in non-GPL
+software, but also require contributions to be returned were
+considered. However, libfdt is designed to be used in firmwares and
+other environments with unusual technical constraints. It's difficult
+to anticipate all possible changes which might be needed to meld
+libfdt into such environments and so difficult to suitably word a
+license that puts the boundary between what is and isn't permitted in
+the intended place. Again, I judged encouraging widespread use of
+libfdt by keeping the license terms simple and familiar to be the more
+important goal.
+
+**IMPORTANT** It's intended that all of libfdt as released remain
+permissively licensed this way. Therefore only contributions which
+are released under these terms can be merged into the libfdt mainline.
+
+
+David Gibson <david@gibson.dropbear.id.au>
+(principal original author of dtc and libfdt)
+2 November 2007
diff --git a/contrib/dtc/TODO b/contrib/dtc/TODO
new file mode 100644
index 0000000..a3e7182
--- /dev/null
+++ b/contrib/dtc/TODO
@@ -0,0 +1,8 @@
+- Bugfixes:
+ * Proper handling of boot cpu information
+- Generate mem reserve map
+ * linux,reserve-map property
+ * generating reserve entry for device tree itself
+ * generating reserve entries from tce, rtas etc. properties
+- Expression support
+- Macro system
diff --git a/contrib/dtc/checks.c b/contrib/dtc/checks.c
new file mode 100644
index 0000000..031cc59
--- /dev/null
+++ b/contrib/dtc/checks.c
@@ -0,0 +1,611 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2007.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "dtc.h"
+
+#ifdef TRACE_CHECKS
+#define TRACE(c, ...) \
+ do { \
+ fprintf(stderr, "=== %s: ", (c)->name); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ } while (0)
+#else
+#define TRACE(c, fmt, ...) do { } while (0)
+#endif
+
+enum checklevel {
+ IGNORE = 0,
+ WARN = 1,
+ ERROR = 2,
+};
+
+enum checkstatus {
+ UNCHECKED = 0,
+ PREREQ,
+ PASSED,
+ FAILED,
+};
+
+struct check;
+
+typedef void (*tree_check_fn)(struct check *c, struct node *dt);
+typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node);
+typedef void (*prop_check_fn)(struct check *c, struct node *dt,
+ struct node *node, struct property *prop);
+
+struct check {
+ const char *name;
+ tree_check_fn tree_fn;
+ node_check_fn node_fn;
+ prop_check_fn prop_fn;
+ void *data;
+ enum checklevel level;
+ enum checkstatus status;
+ int inprogress;
+ int num_prereqs;
+ struct check **prereq;
+};
+
+#define CHECK(nm, tfn, nfn, pfn, d, lvl, ...) \
+ static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \
+ static struct check nm = { \
+ .name = #nm, \
+ .tree_fn = (tfn), \
+ .node_fn = (nfn), \
+ .prop_fn = (pfn), \
+ .data = (d), \
+ .level = (lvl), \
+ .status = UNCHECKED, \
+ .num_prereqs = ARRAY_SIZE(nm##_prereqs), \
+ .prereq = nm##_prereqs, \
+ };
+
+#define TREE_CHECK(nm, d, lvl, ...) \
+ CHECK(nm, check_##nm, NULL, NULL, d, lvl, __VA_ARGS__)
+#define NODE_CHECK(nm, d, lvl, ...) \
+ CHECK(nm, NULL, check_##nm, NULL, d, lvl, __VA_ARGS__)
+#define PROP_CHECK(nm, d, lvl, ...) \
+ CHECK(nm, NULL, NULL, check_##nm, d, lvl, __VA_ARGS__)
+#define BATCH_CHECK(nm, lvl, ...) \
+ CHECK(nm, NULL, NULL, NULL, NULL, lvl, __VA_ARGS__)
+
+#ifdef __GNUC__
+static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
+#endif
+static inline void check_msg(struct check *c, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+
+ if ((c->level < WARN) || (c->level <= quiet))
+ return; /* Suppress message */
+
+ fprintf(stderr, "%s (%s): ",
+ (c->level == ERROR) ? "ERROR" : "Warning", c->name);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+}
+
+#define FAIL(c, ...) \
+ do { \
+ TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \
+ (c)->status = FAILED; \
+ check_msg((c), __VA_ARGS__); \
+ } while (0)
+
+static void check_nodes_props(struct check *c, struct node *dt, struct node *node)
+{
+ struct node *child;
+ struct property *prop;
+
+ TRACE(c, "%s", node->fullpath);
+ if (c->node_fn)
+ c->node_fn(c, dt, node);
+
+ if (c->prop_fn)
+ for_each_property(node, prop) {
+ TRACE(c, "%s\t'%s'", node->fullpath, prop->name);
+ c->prop_fn(c, dt, node, prop);
+ }
+
+ for_each_child(node, child)
+ check_nodes_props(c, dt, child);
+}
+
+static int run_check(struct check *c, struct node *dt)
+{
+ int error = 0;
+ int i;
+
+ assert(!c->inprogress);
+
+ if (c->status != UNCHECKED)
+ goto out;
+
+ c->inprogress = 1;
+
+ for (i = 0; i < c->num_prereqs; i++) {
+ struct check *prq = c->prereq[i];
+ error |= run_check(prq, dt);
+ if (prq->status != PASSED) {
+ c->status = PREREQ;
+ check_msg(c, "Failed prerequisite '%s'",
+ c->prereq[i]->name);
+ }
+ }
+
+ if (c->status != UNCHECKED)
+ goto out;
+
+ if (c->node_fn || c->prop_fn)
+ check_nodes_props(c, dt, dt);
+
+ if (c->tree_fn)
+ c->tree_fn(c, dt);
+ if (c->status == UNCHECKED)
+ c->status = PASSED;
+
+ TRACE(c, "\tCompleted, status %d", c->status);
+
+out:
+ c->inprogress = 0;
+ if ((c->status != PASSED) && (c->level == ERROR))
+ error = 1;
+ return error;
+}
+
+/*
+ * Utility check functions
+ */
+
+static void check_is_string(struct check *c, struct node *root,
+ struct node *node)
+{
+ struct property *prop;
+ char *propname = c->data;
+
+ prop = get_property(node, propname);
+ if (!prop)
+ return; /* Not present, assumed ok */
+
+ if (!data_is_one_string(prop->val))
+ FAIL(c, "\"%s\" property in %s is not a string",
+ propname, node->fullpath);
+}
+#define CHECK_IS_STRING(nm, propname, lvl) \
+ CHECK(nm, NULL, check_is_string, NULL, (propname), (lvl))
+
+static void check_is_cell(struct check *c, struct node *root,
+ struct node *node)
+{
+ struct property *prop;
+ char *propname = c->data;
+
+ prop = get_property(node, propname);
+ if (!prop)
+ return; /* Not present, assumed ok */
+
+ if (prop->val.len != sizeof(cell_t))
+ FAIL(c, "\"%s\" property in %s is not a single cell",
+ propname, node->fullpath);
+}
+#define CHECK_IS_CELL(nm, propname, lvl) \
+ CHECK(nm, NULL, check_is_cell, NULL, (propname), (lvl))
+
+/*
+ * Structural check functions
+ */
+
+static void check_duplicate_node_names(struct check *c, struct node *dt,
+ struct node *node)
+{
+ struct node *child, *child2;
+
+ for_each_child(node, child)
+ for (child2 = child->next_sibling;
+ child2;
+ child2 = child2->next_sibling)
+ if (streq(child->name, child2->name))
+ FAIL(c, "Duplicate node name %s",
+ child->fullpath);
+}
+NODE_CHECK(duplicate_node_names, NULL, ERROR);
+
+static void check_duplicate_property_names(struct check *c, struct node *dt,
+ struct node *node)
+{
+ struct property *prop, *prop2;
+
+ for_each_property(node, prop)
+ for (prop2 = prop->next; prop2; prop2 = prop2->next)
+ if (streq(prop->name, prop2->name))
+ FAIL(c, "Duplicate property name %s in %s",
+ prop->name, node->fullpath);
+}
+NODE_CHECK(duplicate_property_names, NULL, ERROR);
+
+#define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
+#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define DIGITS "0123456789"
+#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
+
+static void check_node_name_chars(struct check *c, struct node *dt,
+ struct node *node)
+{
+ int n = strspn(node->name, c->data);
+
+ if (n < strlen(node->name))
+ FAIL(c, "Bad character '%c' in node %s",
+ node->name[n], node->fullpath);
+}
+NODE_CHECK(node_name_chars, PROPNODECHARS "@", ERROR);
+
+static void check_node_name_format(struct check *c, struct node *dt,
+ struct node *node)
+{
+ if (strchr(get_unitname(node), '@'))
+ FAIL(c, "Node %s has multiple '@' characters in name",
+ node->fullpath);
+}
+NODE_CHECK(node_name_format, NULL, ERROR, &node_name_chars);
+
+static void check_property_name_chars(struct check *c, struct node *dt,
+ struct node *node, struct property *prop)
+{
+ int n = strspn(prop->name, c->data);
+
+ if (n < strlen(prop->name))
+ FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
+ prop->name[n], prop->name, node->fullpath);
+}
+PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR);
+
+static void check_explicit_phandles(struct check *c, struct node *root,
+ struct node *node, struct property *prop)
+{
+ struct marker *m;
+ struct node *other;
+ cell_t phandle;
+
+ if (!streq(prop->name, "phandle")
+ && !streq(prop->name, "linux,phandle"))
+ return;
+
+ if (prop->val.len != sizeof(cell_t)) {
+ FAIL(c, "%s has bad length (%d) %s property",
+ node->fullpath, prop->val.len, prop->name);
+ return;
+ }
+
+ m = prop->val.markers;
+ for_each_marker_of_type(m, REF_PHANDLE) {
+ assert(m->offset == 0);
+ if (node != get_node_by_ref(root, m->ref))
+ /* "Set this node's phandle equal to some
+ * other node's phandle". That's nonsensical
+ * by construction. */ {
+ FAIL(c, "%s in %s is a reference to another node",
+ prop->name, node->fullpath);
+ return;
+ }
+ /* But setting this node's phandle equal to its own
+ * phandle is allowed - that means allocate a unique
+ * phandle for this node, even if it's not otherwise
+ * referenced. The value will be filled in later, so
+ * no further checking for now. */
+ return;
+ }
+
+ phandle = propval_cell(prop);
+
+ if ((phandle == 0) || (phandle == -1)) {
+ FAIL(c, "%s has bad value (0x%x) in %s property",
+ node->fullpath, phandle, prop->name);
+ return;
+ }
+
+ if (node->phandle && (node->phandle != phandle))
+ FAIL(c, "%s has %s property which replaces existing phandle information",
+ node->fullpath, prop->name);
+
+ other = get_node_by_phandle(root, phandle);
+ if (other && (other != node)) {
+ FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)",
+ node->fullpath, phandle, other->fullpath);
+ return;
+ }
+
+ node->phandle = phandle;
+}
+PROP_CHECK(explicit_phandles, NULL, ERROR);
+
+static void check_name_properties(struct check *c, struct node *root,
+ struct node *node)
+{
+ struct property **pp, *prop = NULL;
+
+ for (pp = &node->proplist; *pp; pp = &((*pp)->next))
+ if (streq((*pp)->name, "name")) {
+ prop = *pp;
+ break;
+ }
+
+ if (!prop)
+ return; /* No name property, that's fine */
+
+ if ((prop->val.len != node->basenamelen+1)
+ || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
+ FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead"
+ " of base node name)", node->fullpath, prop->val.val);
+ } else {
+ /* The name property is correct, and therefore redundant.
+ * Delete it */
+ *pp = prop->next;
+ free(prop->name);
+ data_free(prop->val);
+ free(prop);
+ }
+}
+CHECK_IS_STRING(name_is_string, "name", ERROR);
+NODE_CHECK(name_properties, NULL, ERROR, &name_is_string);
+
+/*
+ * Reference fixup functions
+ */
+
+static void fixup_phandle_references(struct check *c, struct node *dt,
+ struct node *node, struct property *prop)
+{
+ struct marker *m = prop->val.markers;
+ struct node *refnode;
+ cell_t phandle;
+
+ for_each_marker_of_type(m, REF_PHANDLE) {
+ assert(m->offset + sizeof(cell_t) <= prop->val.len);
+
+ refnode = get_node_by_ref(dt, m->ref);
+ if (! refnode) {
+ FAIL(c, "Reference to non-existent node or label \"%s\"\n",
+ m->ref);
+ continue;
+ }
+
+ phandle = get_node_phandle(dt, refnode);
+ *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
+ }
+}
+CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR,
+ &duplicate_node_names, &explicit_phandles);
+
+static void fixup_path_references(struct check *c, struct node *dt,
+ struct node *node, struct property *prop)
+{
+ struct marker *m = prop->val.markers;
+ struct node *refnode;
+ char *path;
+
+ for_each_marker_of_type(m, REF_PATH) {
+ assert(m->offset <= prop->val.len);
+
+ refnode = get_node_by_ref(dt, m->ref);
+ if (!refnode) {
+ FAIL(c, "Reference to non-existent node or label \"%s\"\n",
+ m->ref);
+ continue;
+ }
+
+ path = refnode->fullpath;
+ prop->val = data_insert_at_marker(prop->val, m, path,
+ strlen(path) + 1);
+ }
+}
+CHECK(path_references, NULL, NULL, fixup_path_references, NULL, ERROR,
+ &duplicate_node_names);
+
+/*
+ * Semantic checks
+ */
+CHECK_IS_CELL(address_cells_is_cell, "#address-cells", WARN);
+CHECK_IS_CELL(size_cells_is_cell, "#size-cells", WARN);
+CHECK_IS_CELL(interrupt_cells_is_cell, "#interrupt-cells", WARN);
+
+CHECK_IS_STRING(device_type_is_string, "device_type", WARN);
+CHECK_IS_STRING(model_is_string, "model", WARN);
+CHECK_IS_STRING(status_is_string, "status", WARN);
+
+static void fixup_addr_size_cells(struct check *c, struct node *dt,
+ struct node *node)
+{
+ struct property *prop;
+
+ node->addr_cells = -1;
+ node->size_cells = -1;
+
+ prop = get_property(node, "#address-cells");
+ if (prop)
+ node->addr_cells = propval_cell(prop);
+
+ prop = get_property(node, "#size-cells");
+ if (prop)
+ node->size_cells = propval_cell(prop);
+}
+CHECK(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, WARN,
+ &address_cells_is_cell, &size_cells_is_cell);
+
+#define node_addr_cells(n) \
+ (((n)->addr_cells == -1) ? 2 : (n)->addr_cells)
+#define node_size_cells(n) \
+ (((n)->size_cells == -1) ? 1 : (n)->size_cells)
+
+static void check_reg_format(struct check *c, struct node *dt,
+ struct node *node)
+{
+ struct property *prop;
+ int addr_cells, size_cells, entrylen;
+
+ prop = get_property(node, "reg");
+ if (!prop)
+ return; /* No "reg", that's fine */
+
+ if (!node->parent) {
+ FAIL(c, "Root node has a \"reg\" property");
+ return;
+ }
+
+ if (prop->val.len == 0)
+ FAIL(c, "\"reg\" property in %s is empty", node->fullpath);
+
+ addr_cells = node_addr_cells(node->parent);
+ size_cells = node_size_cells(node->parent);
+ entrylen = (addr_cells + size_cells) * sizeof(cell_t);
+
+ if ((prop->val.len % entrylen) != 0)
+ FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) "
+ "(#address-cells == %d, #size-cells == %d)",
+ node->fullpath, prop->val.len, addr_cells, size_cells);
+}
+NODE_CHECK(reg_format, NULL, WARN, &addr_size_cells);
+
+static void check_ranges_format(struct check *c, struct node *dt,
+ struct node *node)
+{
+ struct property *prop;
+ int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen;
+
+ prop = get_property(node, "ranges");
+ if (!prop)
+ return;
+
+ if (!node->parent) {
+ FAIL(c, "Root node has a \"ranges\" property");
+ return;
+ }
+
+ p_addr_cells = node_addr_cells(node->parent);
+ p_size_cells = node_size_cells(node->parent);
+ c_addr_cells = node_addr_cells(node);
+ c_size_cells = node_size_cells(node);
+ entrylen = (p_addr_cells + c_addr_cells + c_size_cells) * sizeof(cell_t);
+
+ if (prop->val.len == 0) {
+ if (p_addr_cells != c_addr_cells)
+ FAIL(c, "%s has empty \"ranges\" property but its "
+ "#address-cells (%d) differs from %s (%d)",
+ node->fullpath, c_addr_cells, node->parent->fullpath,
+ p_addr_cells);
+ if (p_size_cells != c_size_cells)
+ FAIL(c, "%s has empty \"ranges\" property but its "
+ "#size-cells (%d) differs from %s (%d)",
+ node->fullpath, c_size_cells, node->parent->fullpath,
+ p_size_cells);
+ } else if ((prop->val.len % entrylen) != 0) {
+ FAIL(c, "\"ranges\" property in %s has invalid length (%d bytes) "
+ "(parent #address-cells == %d, child #address-cells == %d, "
+ "#size-cells == %d)", node->fullpath, prop->val.len,
+ p_addr_cells, c_addr_cells, c_size_cells);
+ }
+}
+NODE_CHECK(ranges_format, NULL, WARN, &addr_size_cells);
+
+/*
+ * Style checks
+ */
+static void check_avoid_default_addr_size(struct check *c, struct node *dt,
+ struct node *node)
+{
+ struct property *reg, *ranges;
+
+ if (!node->parent)
+ return; /* Ignore root node */
+
+ reg = get_property(node, "reg");
+ ranges = get_property(node, "ranges");
+
+ if (!reg && !ranges)
+ return;
+
+ if ((node->parent->addr_cells == -1))
+ FAIL(c, "Relying on default #address-cells value for %s",
+ node->fullpath);
+
+ if ((node->parent->size_cells == -1))
+ FAIL(c, "Relying on default #size-cells value for %s",
+ node->fullpath);
+}
+NODE_CHECK(avoid_default_addr_size, NULL, WARN, &addr_size_cells);
+
+static void check_obsolete_chosen_interrupt_controller(struct check *c,
+ struct node *dt)
+{
+ struct node *chosen;
+ struct property *prop;
+
+ chosen = get_node_by_path(dt, "/chosen");
+ if (!chosen)
+ return;
+
+ prop = get_property(chosen, "interrupt-controller");
+ if (prop)
+ FAIL(c, "/chosen has obsolete \"interrupt-controller\" "
+ "property");
+}
+TREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN);
+
+static struct check *check_table[] = {
+ &duplicate_node_names, &duplicate_property_names,
+ &node_name_chars, &node_name_format, &property_name_chars,
+ &name_is_string, &name_properties,
+ &explicit_phandles,
+ &phandle_references, &path_references,
+
+ &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
+ &device_type_is_string, &model_is_string, &status_is_string,
+
+ &addr_size_cells, &reg_format, &ranges_format,
+
+ &avoid_default_addr_size,
+ &obsolete_chosen_interrupt_controller,
+};
+
+void process_checks(int force, struct boot_info *bi)
+{
+ struct node *dt = bi->dt;
+ int i;
+ int error = 0;
+
+ for (i = 0; i < ARRAY_SIZE(check_table); i++) {
+ struct check *c = check_table[i];
+
+ if (c->level != IGNORE)
+ error = error || run_check(c, dt);
+ }
+
+ if (error) {
+ if (!force) {
+ fprintf(stderr, "ERROR: Input tree has errors, aborting "
+ "(use -f to force output)\n");
+ exit(2);
+ } else if (quiet < 3) {
+ fprintf(stderr, "Warning: Input tree has errors, "
+ "output forced\n");
+ }
+ }
+}
diff --git a/contrib/dtc/convert-dtsv0-lexer.l b/contrib/dtc/convert-dtsv0-lexer.l
new file mode 100644
index 0000000..59137f1
--- /dev/null
+++ b/contrib/dtc/convert-dtsv0-lexer.l
@@ -0,0 +1,238 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005, 2008.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+%option noyywrap nounput noinput
+
+%x INCLUDE
+%x BYTESTRING
+%x PROPNODENAME
+
+PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
+PATHCHAR ({PROPNODECHAR}|[/])
+LABEL [a-zA-Z_][a-zA-Z0-9_]*
+STRING \"([^\\"]|\\.)*\"
+WS [[:space:]]
+COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
+LINECOMMENT "//".*\n
+GAP ({WS}|{COMMENT}|{LINECOMMENT})*
+
+%{
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <errno.h>
+#include <assert.h>
+#include <fnmatch.h>
+
+#include "srcpos.h"
+#include "util.h"
+
+static int v1_tagged; /* = 0 */
+static int cbase = 16;
+static int saw_hyphen; /* = 0 */
+static unsigned long long last_val;
+static char *last_name; /* = NULL */
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+const struct {
+ const char *pattern;
+ int obase, width;
+} guess_table[] = {
+ { "*-frequency", 10, 0 },
+ { "num-*", 10, 0 },
+ { "#*-cells", 10, 0 },
+ { "*cache-line-size", 10, 0 },
+ { "*cache-block-size", 10, 0 },
+ { "*cache-size", 10, 0 },
+ { "*cache-sets", 10, 0 },
+ { "cell-index", 10, 0 },
+ { "bank-width", 10, 0 },
+ { "*-fifo-size", 10, 0 },
+ { "*-frame-size", 10, 0 },
+ { "*-channel", 10, 0 },
+ { "current-speed", 10, 0 },
+ { "phy-map", 16, 8 },
+ { "dcr-reg", 16, 3 },
+ { "reg", 16, 8 },
+ { "ranges", 16, 8},
+};
+%}
+
+%%
+<*>"/include/"{GAP}{STRING} ECHO;
+
+<*>\"([^\\"]|\\.)*\" ECHO;
+
+<*>"/dts-v1/" {
+ die("Input dts file is already version 1\n");
+ }
+
+<*>"/memreserve/" {
+ if (!v1_tagged) {
+ fprintf(yyout, "/dts-v1/;\n\n");
+ v1_tagged = 1;
+ }
+
+ ECHO;
+ BEGIN(INITIAL);
+ }
+
+<*>{LABEL}: ECHO;
+
+<INITIAL>[bodh]# {
+ if (*yytext == 'b')
+ cbase = 2;
+ else if (*yytext == 'o')
+ cbase = 8;
+ else if (*yytext == 'd')
+ cbase = 10;
+ else
+ cbase = 16;
+ }
+
+<INITIAL>[0-9a-fA-F]+ {
+ unsigned long long val;
+ int obase = 16, width = 0;
+ int i;
+
+ val = strtoull(yytext, NULL, cbase);
+
+ if (saw_hyphen)
+ val = val - last_val + 1;
+
+ if (last_name) {
+ for (i = 0; i < ARRAY_SIZE(guess_table); i++)
+ if (fnmatch(guess_table[i].pattern,
+ last_name, 0) == 0) {
+ obase = guess_table[i].obase;
+ width = guess_table[i].width;
+ }
+ } else {
+ obase = 16;
+ width = 16;
+ }
+
+ if (cbase != 16)
+ obase = cbase;
+
+ switch (obase) {
+ case 2:
+ case 16:
+ fprintf(yyout, "0x%0*llx", width, val);
+ break;
+ case 8:
+ fprintf(yyout, "0%0*llo", width, val);
+ break;
+ case 10:
+ fprintf(yyout, "%*llu", width, val);
+ break;
+ }
+
+ cbase = 16;
+ last_val = val;
+ saw_hyphen = 0;
+ }
+
+\&{LABEL} ECHO;
+
+"&{/"{PATHCHAR}+\} ECHO;
+
+<INITIAL>"&/"{PATHCHAR}+ fprintf(yyout, "&{/%s}", yytext + 2);
+
+<BYTESTRING>[0-9a-fA-F]{2} ECHO;
+
+<BYTESTRING>"]" {
+ ECHO;
+ BEGIN(INITIAL);
+ }
+
+<PROPNODENAME>{PROPNODECHAR}+ {
+ ECHO;
+ last_name = xstrdup(yytext);
+ BEGIN(INITIAL);
+ }
+
+<*>{GAP} ECHO;
+
+<*>- { /* Hack to convert old style memreserves */
+ saw_hyphen = 1;
+ fprintf(yyout, " ");
+ }
+
+<*>. {
+ if (!v1_tagged) {
+ fprintf(yyout, "/dts-v1/;\n\n");
+ v1_tagged = 1;
+ }
+
+ ECHO;
+ if (yytext[0] == '[') {
+ BEGIN(BYTESTRING);
+ }
+ if ((yytext[0] == '{')
+ || (yytext[0] == ';')) {
+ BEGIN(PROPNODENAME);
+ }
+ }
+
+%%
+static void usage(void)
+{
+ fprintf(stderr, "convert-dtsv0 <v0 dts file>...\n");
+ exit(3);
+}
+
+static void convert_file(const char *fname)
+{
+ const char suffix[] = "v1";
+ int len = strlen(fname);
+ char *newname;
+
+ newname = xmalloc(len + sizeof(suffix));
+ memcpy(newname, fname, len);
+ memcpy(newname + len, suffix, sizeof(suffix));
+
+ srcpos_file = dtc_open_file(fname, NULL);
+ yyin = srcpos_file->file;
+
+ yyout = fopen(newname, "w");
+ if (!yyout)
+ die("Couldn't open output file %s: %s\n",
+ newname, strerror(errno));
+
+ while(yylex())
+ ;
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+
+ if (argc < 2)
+ usage();
+
+ for (i = 1; i < argc; i++) {
+ fprintf(stderr, "Converting %s from dts v0 to dts v1\n", argv[i]);
+ convert_file(argv[i]);
+ }
+
+ exit(0);
+}
diff --git a/contrib/dtc/data.c b/contrib/dtc/data.c
new file mode 100644
index 0000000..fe555e8
--- /dev/null
+++ b/contrib/dtc/data.c
@@ -0,0 +1,321 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "dtc.h"
+
+void data_free(struct data d)
+{
+ struct marker *m, *nm;
+
+ m = d.markers;
+ while (m) {
+ nm = m->next;
+ free(m->ref);
+ free(m);
+ m = nm;
+ }
+
+ if (d.val)
+ free(d.val);
+}
+
+struct data data_grow_for(struct data d, int xlen)
+{
+ struct data nd;
+ int newsize;
+
+ if (xlen == 0)
+ return d;
+
+ nd = d;
+
+ newsize = xlen;
+
+ while ((d.len + xlen) > newsize)
+ newsize *= 2;
+
+ nd.val = xrealloc(d.val, newsize);
+
+ return nd;
+}
+
+struct data data_copy_mem(const char *mem, int len)
+{
+ struct data d;
+
+ d = data_grow_for(empty_data, len);
+
+ d.len = len;
+ memcpy(d.val, mem, len);
+
+ return d;
+}
+
+static char get_oct_char(const char *s, int *i)
+{
+ char x[4];
+ char *endx;
+ long val;
+
+ x[3] = '\0';
+ strncpy(x, s + *i, 3);
+
+ val = strtol(x, &endx, 8);
+
+ assert(endx > x);
+
+ (*i) += endx - x;
+ return val;
+}
+
+static char get_hex_char(const char *s, int *i)
+{
+ char x[3];
+ char *endx;
+ long val;
+
+ x[2] = '\0';
+ strncpy(x, s + *i, 2);
+
+ val = strtol(x, &endx, 16);
+ if (!(endx > x))
+ die("\\x used with no following hex digits\n");
+
+ (*i) += endx - x;
+ return val;
+}
+
+struct data data_copy_escape_string(const char *s, int len)
+{
+ int i = 0;
+ struct data d;
+ char *q;
+
+ d = data_grow_for(empty_data, strlen(s)+1);
+
+ q = d.val;
+ while (i < len) {
+ char c = s[i++];
+
+ if (c != '\\') {
+ q[d.len++] = c;
+ continue;
+ }
+
+ c = s[i++];
+ assert(c);
+ switch (c) {
+ case 'a':
+ q[d.len++] = '\a';
+ break;
+ case 'b':
+ q[d.len++] = '\b';
+ break;
+ case 't':
+ q[d.len++] = '\t';
+ break;
+ case 'n':
+ q[d.len++] = '\n';
+ break;
+ case 'v':
+ q[d.len++] = '\v';
+ break;
+ case 'f':
+ q[d.len++] = '\f';
+ break;
+ case 'r':
+ q[d.len++] = '\r';
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ i--; /* need to re-read the first digit as
+ * part of the octal value */
+ q[d.len++] = get_oct_char(s, &i);
+ break;
+ case 'x':
+ q[d.len++] = get_hex_char(s, &i);
+ break;
+ default:
+ q[d.len++] = c;
+ }
+ }
+
+ q[d.len++] = '\0';
+ return d;
+}
+
+struct data data_copy_file(FILE *f, size_t maxlen)
+{
+ struct data d = empty_data;
+
+ while (!feof(f) && (d.len < maxlen)) {
+ size_t chunksize, ret;
+
+ if (maxlen == -1)
+ chunksize = 4096;
+ else
+ chunksize = maxlen - d.len;
+
+ d = data_grow_for(d, chunksize);
+ ret = fread(d.val + d.len, 1, chunksize, f);
+
+ if (ferror(f))
+ die("Error reading file into data: %s", strerror(errno));
+
+ if (d.len + ret < d.len)
+ die("Overflow reading file into data\n");
+
+ d.len += ret;
+ }
+
+ return d;
+}
+
+struct data data_append_data(struct data d, const void *p, int len)
+{
+ d = data_grow_for(d, len);
+ memcpy(d.val + d.len, p, len);
+ d.len += len;
+ return d;
+}
+
+struct data data_insert_at_marker(struct data d, struct marker *m,
+ const void *p, int len)
+{
+ d = data_grow_for(d, len);
+ memmove(d.val + m->offset + len, d.val + m->offset, d.len - m->offset);
+ memcpy(d.val + m->offset, p, len);
+ d.len += len;
+
+ /* Adjust all markers after the one we're inserting at */
+ m = m->next;
+ for_each_marker(m)
+ m->offset += len;
+ return d;
+}
+
+static struct data data_append_markers(struct data d, struct marker *m)
+{
+ struct marker **mp = &d.markers;
+
+ /* Find the end of the markerlist */
+ while (*mp)
+ mp = &((*mp)->next);
+ *mp = m;
+ return d;
+}
+
+struct data data_merge(struct data d1, struct data d2)
+{
+ struct data d;
+ struct marker *m2 = d2.markers;
+
+ d = data_append_markers(data_append_data(d1, d2.val, d2.len), m2);
+
+ /* Adjust for the length of d1 */
+ for_each_marker(m2)
+ m2->offset += d1.len;
+
+ d2.markers = NULL; /* So data_free() doesn't clobber them */
+ data_free(d2);
+
+ return d;
+}
+
+struct data data_append_cell(struct data d, cell_t word)
+{
+ cell_t beword = cpu_to_fdt32(word);
+
+ return data_append_data(d, &beword, sizeof(beword));
+}
+
+struct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
+{
+ struct fdt_reserve_entry bere;
+
+ bere.address = cpu_to_fdt64(re->address);
+ bere.size = cpu_to_fdt64(re->size);
+
+ return data_append_data(d, &bere, sizeof(bere));
+}
+
+struct data data_append_addr(struct data d, uint64_t addr)
+{
+ uint64_t beaddr = cpu_to_fdt64(addr);
+
+ return data_append_data(d, &beaddr, sizeof(beaddr));
+}
+
+struct data data_append_byte(struct data d, uint8_t byte)
+{
+ return data_append_data(d, &byte, 1);
+}
+
+struct data data_append_zeroes(struct data d, int len)
+{
+ d = data_grow_for(d, len);
+
+ memset(d.val + d.len, 0, len);
+ d.len += len;
+ return d;
+}
+
+struct data data_append_align(struct data d, int align)
+{
+ int newlen = ALIGN(d.len, align);
+ return data_append_zeroes(d, newlen - d.len);
+}
+
+struct data data_add_marker(struct data d, enum markertype type, char *ref)
+{
+ struct marker *m;
+
+ m = xmalloc(sizeof(*m));
+ m->offset = d.len;
+ m->type = type;
+ m->ref = ref;
+ m->next = NULL;
+
+ return data_append_markers(d, m);
+}
+
+int data_is_one_string(struct data d)
+{
+ int i;
+ int len = d.len;
+
+ if (len == 0)
+ return 0;
+
+ for (i = 0; i < len-1; i++)
+ if (d.val[i] == '\0')
+ return 0;
+
+ if (d.val[len-1] != '\0')
+ return 0;
+
+ return 1;
+}
diff --git a/contrib/dtc/dtc-lexer.l b/contrib/dtc/dtc-lexer.l
new file mode 100644
index 0000000..96c2fce
--- /dev/null
+++ b/contrib/dtc/dtc-lexer.l
@@ -0,0 +1,266 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+%option noyywrap nounput noinput yylineno
+
+%x INCLUDE
+%x BYTESTRING
+%x PROPNODENAME
+%s V1
+
+PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
+PATHCHAR ({PROPNODECHAR}|[/])
+LABEL [a-zA-Z_][a-zA-Z0-9_]*
+STRING \"([^\\"]|\\.)*\"
+WS [[:space:]]
+COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
+LINECOMMENT "//".*\n
+
+%{
+#include "dtc.h"
+#include "srcpos.h"
+#include "dtc-parser.tab.h"
+
+YYLTYPE yylloc;
+
+#define YY_USER_ACTION \
+ { \
+ yylloc.file = srcpos_file; \
+ yylloc.first_line = yylineno; \
+ }
+
+/*#define LEXDEBUG 1*/
+
+#ifdef LEXDEBUG
+#define DPRINT(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
+#else
+#define DPRINT(fmt, ...) do { } while (0)
+#endif
+
+static int dts_version = 1;
+
+#define BEGIN_DEFAULT() DPRINT("<V1>\n"); \
+ BEGIN(V1); \
+
+static void push_input_file(const char *filename);
+static int pop_input_file(void);
+%}
+
+%%
+<*>"/include/"{WS}*{STRING} {
+ char *name = strchr(yytext, '\"') + 1;
+ yytext[yyleng-1] = '\0';
+ push_input_file(name);
+ }
+
+<*><<EOF>> {
+ if (!pop_input_file()) {
+ yyterminate();
+ }
+ }
+
+<*>{STRING} {
+ DPRINT("String: %s\n", yytext);
+ yylval.data = data_copy_escape_string(yytext+1,
+ yyleng-2);
+ return DT_STRING;
+ }
+
+<*>"/dts-v1/" {
+ DPRINT("Keyword: /dts-v1/\n");
+ dts_version = 1;
+ BEGIN_DEFAULT();
+ return DT_V1;
+ }
+
+<*>"/memreserve/" {
+ DPRINT("Keyword: /memreserve/\n");
+ BEGIN_DEFAULT();
+ return DT_MEMRESERVE;
+ }
+
+<*>{LABEL}: {
+ DPRINT("Label: %s\n", yytext);
+ yylval.labelref = xstrdup(yytext);
+ yylval.labelref[yyleng-1] = '\0';
+ return DT_LABEL;
+ }
+
+<V1>[0-9]+|0[xX][0-9a-fA-F]+ {
+ yylval.literal = xstrdup(yytext);
+ DPRINT("Literal: '%s'\n", yylval.literal);
+ return DT_LITERAL;
+ }
+
+\&{LABEL} { /* label reference */
+ DPRINT("Ref: %s\n", yytext+1);
+ yylval.labelref = xstrdup(yytext+1);
+ return DT_REF;
+ }
+
+"&{/"{PATHCHAR}+\} { /* new-style path reference */
+ yytext[yyleng-1] = '\0';
+ DPRINT("Ref: %s\n", yytext+2);
+ yylval.labelref = xstrdup(yytext+2);
+ return DT_REF;
+ }
+
+<BYTESTRING>[0-9a-fA-F]{2} {
+ yylval.byte = strtol(yytext, NULL, 16);
+ DPRINT("Byte: %02x\n", (int)yylval.byte);
+ return DT_BYTE;
+ }
+
+<BYTESTRING>"]" {
+ DPRINT("/BYTESTRING\n");
+ BEGIN_DEFAULT();
+ return ']';
+ }
+
+<PROPNODENAME>{PROPNODECHAR}+ {
+ DPRINT("PropNodeName: %s\n", yytext);
+ yylval.propnodename = xstrdup(yytext);
+ BEGIN_DEFAULT();
+ return DT_PROPNODENAME;
+ }
+
+"/incbin/" {
+ DPRINT("Binary Include\n");
+ return DT_INCBIN;
+ }
+
+<*>{WS}+ /* eat whitespace */
+<*>{COMMENT}+ /* eat C-style comments */
+<*>{LINECOMMENT}+ /* eat C++-style comments */
+
+<*>. {
+ DPRINT("Char: %c (\\x%02x)\n", yytext[0],
+ (unsigned)yytext[0]);
+ if (yytext[0] == '[') {
+ DPRINT("<BYTESTRING>\n");
+ BEGIN(BYTESTRING);
+ }
+ if ((yytext[0] == '{')
+ || (yytext[0] == ';')) {
+ DPRINT("<PROPNODENAME>\n");
+ BEGIN(PROPNODENAME);
+ }
+ return yytext[0];
+ }
+
+%%
+
+
+/*
+ * Stack of nested include file contexts.
+ */
+
+struct incl_file {
+ struct dtc_file *file;
+ YY_BUFFER_STATE yy_prev_buf;
+ int yy_prev_lineno;
+ struct incl_file *prev;
+};
+
+static struct incl_file *incl_file_stack;
+
+
+/*
+ * Detect infinite include recursion.
+ */
+#define MAX_INCLUDE_DEPTH (100)
+
+static int incl_depth = 0;
+
+
+static void push_input_file(const char *filename)
+{
+ struct incl_file *incl_file;
+ struct dtc_file *newfile;
+ struct search_path search, *searchptr = NULL;
+
+ assert(filename);
+
+ if (incl_depth++ >= MAX_INCLUDE_DEPTH)
+ die("Includes nested too deeply");
+
+ if (srcpos_file) {
+ search.dir = srcpos_file->dir;
+ search.next = NULL;
+ search.prev = NULL;
+ searchptr = &search;
+ }
+
+ newfile = dtc_open_file(filename, searchptr);
+
+ incl_file = xmalloc(sizeof(struct incl_file));
+
+ /*
+ * Save current context.
+ */
+ incl_file->yy_prev_buf = YY_CURRENT_BUFFER;
+ incl_file->yy_prev_lineno = yylineno;
+ incl_file->file = srcpos_file;
+ incl_file->prev = incl_file_stack;
+
+ incl_file_stack = incl_file;
+
+ /*
+ * Establish new context.
+ */
+ srcpos_file = newfile;
+ yylineno = 1;
+ yyin = newfile->file;
+ yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+}
+
+
+static int pop_input_file(void)
+{
+ struct incl_file *incl_file;
+
+ if (incl_file_stack == 0)
+ return 0;
+
+ dtc_close_file(srcpos_file);
+
+ /*
+ * Pop.
+ */
+ --incl_depth;
+ incl_file = incl_file_stack;
+ incl_file_stack = incl_file->prev;
+
+ /*
+ * Recover old context.
+ */
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(incl_file->yy_prev_buf);
+ yylineno = incl_file->yy_prev_lineno;
+ srcpos_file = incl_file->file;
+ yyin = incl_file->file ? incl_file->file->file : NULL;
+
+ /*
+ * Free old state.
+ */
+ free(incl_file);
+
+ return 1;
+}
diff --git a/contrib/dtc/dtc-parser.y b/contrib/dtc/dtc-parser.y
new file mode 100644
index 0000000..4411aed
--- /dev/null
+++ b/contrib/dtc/dtc-parser.y
@@ -0,0 +1,321 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+
+%{
+#include <stdio.h>
+
+#include "dtc.h"
+#include "srcpos.h"
+
+YYLTYPE yylloc;
+
+extern int yylex(void);
+extern void yyerror(char const *s);
+
+extern struct boot_info *the_boot_info;
+extern int treesource_error;
+
+static unsigned long long eval_literal(const char *s, int base, int bits);
+%}
+
+%union {
+ char *propnodename;
+ char *literal;
+ char *labelref;
+ unsigned int cbase;
+ uint8_t byte;
+ struct data data;
+
+ uint64_t addr;
+ cell_t cell;
+ struct property *prop;
+ struct property *proplist;
+ struct node *node;
+ struct node *nodelist;
+ struct reserve_info *re;
+}
+
+%token DT_V1
+%token DT_MEMRESERVE
+%token <propnodename> DT_PROPNODENAME
+%token <literal> DT_LITERAL
+%token <cbase> DT_BASE
+%token <byte> DT_BYTE
+%token <data> DT_STRING
+%token <labelref> DT_LABEL
+%token <labelref> DT_REF
+%token DT_INCBIN
+
+%type <data> propdata
+%type <data> propdataprefix
+%type <re> memreserve
+%type <re> memreserves
+%type <addr> addr
+%type <data> celllist
+%type <cell> cellval
+%type <data> bytestring
+%type <prop> propdef
+%type <proplist> proplist
+
+%type <node> devicetree
+%type <node> nodedef
+%type <node> subnode
+%type <nodelist> subnodes
+%type <labelref> label
+
+%%
+
+sourcefile:
+ DT_V1 ';' memreserves devicetree
+ {
+ the_boot_info = build_boot_info($3, $4, 0);
+ }
+ ;
+
+memreserves:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ | memreserve memreserves
+ {
+ $$ = chain_reserve_entry($1, $2);
+ }
+ ;
+
+memreserve:
+ label DT_MEMRESERVE addr addr ';'
+ {
+ $$ = build_reserve_entry($3, $4, $1);
+ }
+ ;
+
+addr:
+ DT_LITERAL
+ {
+ $$ = eval_literal($1, 0, 64);
+ }
+ ;
+
+devicetree:
+ '/' nodedef
+ {
+ $$ = name_node($2, "", NULL);
+ }
+ ;
+
+nodedef:
+ '{' proplist subnodes '}' ';'
+ {
+ $$ = build_node($2, $3);
+ }
+ ;
+
+proplist:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ | proplist propdef
+ {
+ $$ = chain_property($2, $1);
+ }
+ ;
+
+propdef:
+ label DT_PROPNODENAME '=' propdata ';'
+ {
+ $$ = build_property($2, $4, $1);
+ }
+ | label DT_PROPNODENAME ';'
+ {
+ $$ = build_property($2, empty_data, $1);
+ }
+ ;
+
+propdata:
+ propdataprefix DT_STRING
+ {
+ $$ = data_merge($1, $2);
+ }
+ | propdataprefix '<' celllist '>'
+ {
+ $$ = data_merge($1, $3);
+ }
+ | propdataprefix '[' bytestring ']'
+ {
+ $$ = data_merge($1, $3);
+ }
+ | propdataprefix DT_REF
+ {
+ $$ = data_add_marker($1, REF_PATH, $2);
+ }
+ | propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')'
+ {
+ struct search_path path = { srcpos_file->dir, NULL, NULL };
+ struct dtc_file *file = dtc_open_file($4.val, &path);
+ struct data d = empty_data;
+
+ if ($6 != 0)
+ if (fseek(file->file, $6, SEEK_SET) != 0)
+ srcpos_error(&yylloc,
+ "Couldn't seek to offset %llu in \"%s\": %s",
+ (unsigned long long)$6,
+ $4.val,
+ strerror(errno));
+
+ d = data_copy_file(file->file, $8);
+
+ $$ = data_merge($1, d);
+ dtc_close_file(file);
+ }
+ | propdataprefix DT_INCBIN '(' DT_STRING ')'
+ {
+ struct search_path path = { srcpos_file->dir, NULL, NULL };
+ struct dtc_file *file = dtc_open_file($4.val, &path);
+ struct data d = empty_data;
+
+ d = data_copy_file(file->file, -1);
+
+ $$ = data_merge($1, d);
+ dtc_close_file(file);
+ }
+ | propdata DT_LABEL
+ {
+ $$ = data_add_marker($1, LABEL, $2);
+ }
+ ;
+
+propdataprefix:
+ /* empty */
+ {
+ $$ = empty_data;
+ }
+ | propdata ','
+ {
+ $$ = $1;
+ }
+ | propdataprefix DT_LABEL
+ {
+ $$ = data_add_marker($1, LABEL, $2);
+ }
+ ;
+
+celllist:
+ /* empty */
+ {
+ $$ = empty_data;
+ }
+ | celllist cellval
+ {
+ $$ = data_append_cell($1, $2);
+ }
+ | celllist DT_REF
+ {
+ $$ = data_append_cell(data_add_marker($1, REF_PHANDLE,
+ $2), -1);
+ }
+ | celllist DT_LABEL
+ {
+ $$ = data_add_marker($1, LABEL, $2);
+ }
+ ;
+
+cellval:
+ DT_LITERAL
+ {
+ $$ = eval_literal($1, 0, 32);
+ }
+ ;
+
+bytestring:
+ /* empty */
+ {
+ $$ = empty_data;
+ }
+ | bytestring DT_BYTE
+ {
+ $$ = data_append_byte($1, $2);
+ }
+ | bytestring DT_LABEL
+ {
+ $$ = data_add_marker($1, LABEL, $2);
+ }
+ ;
+
+subnodes:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ | subnode subnodes
+ {
+ $$ = chain_node($1, $2);
+ }
+ | subnode propdef
+ {
+ yyerror("syntax error: properties must precede subnodes");
+ YYERROR;
+ }
+ ;
+
+subnode:
+ label DT_PROPNODENAME nodedef
+ {
+ $$ = name_node($3, $2, $1);
+ }
+ ;
+
+label:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ | DT_LABEL
+ {
+ $$ = $1;
+ }
+ ;
+
+%%
+
+void yyerror(char const *s)
+{
+ srcpos_error(&yylloc, "%s", s);
+ treesource_error = 1;
+}
+
+static unsigned long long eval_literal(const char *s, int base, int bits)
+{
+ unsigned long long val;
+ char *e;
+
+ errno = 0;
+ val = strtoull(s, &e, base);
+ if (*e)
+ yyerror("bad characters in literal");
+ else if ((errno == ERANGE)
+ || ((bits < 64) && (val >= (1ULL << bits))))
+ yyerror("literal out of range");
+ else if (errno != 0)
+ yyerror("bad literal");
+ return val;
+}
diff --git a/contrib/dtc/dtc.c b/contrib/dtc/dtc.c
new file mode 100644
index 0000000..800664c
--- /dev/null
+++ b/contrib/dtc/dtc.c
@@ -0,0 +1,247 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "dtc.h"
+#include "srcpos.h"
+
+#include "version_gen.h"
+
+/*
+ * Command line options
+ */
+int quiet; /* Level of quietness */
+int reservenum; /* Number of memory reservation slots */
+int minsize; /* Minimum blob size */
+int padsize; /* Additional padding to blob */
+int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
+
+char *join_path(const char *path, const char *name)
+{
+ int lenp = strlen(path);
+ int lenn = strlen(name);
+ int len;
+ int needslash = 1;
+ char *str;
+
+ len = lenp + lenn + 2;
+ if ((lenp > 0) && (path[lenp-1] == '/')) {
+ needslash = 0;
+ len--;
+ }
+
+ str = xmalloc(len);
+ memcpy(str, path, lenp);
+ if (needslash) {
+ str[lenp] = '/';
+ lenp++;
+ }
+ memcpy(str+lenp, name, lenn+1);
+ return str;
+}
+
+static void fill_fullpaths(struct node *tree, const char *prefix)
+{
+ struct node *child;
+ const char *unit;
+
+ tree->fullpath = join_path(prefix, tree->name);
+
+ unit = strchr(tree->name, '@');
+ if (unit)
+ tree->basenamelen = unit - tree->name;
+ else
+ tree->basenamelen = strlen(tree->name);
+
+ for_each_child(tree, child)
+ fill_fullpaths(child, tree->fullpath);
+}
+
+static void __attribute__ ((noreturn)) usage(void)
+{
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, "\tdtc [options] <input file>\n");
+ fprintf(stderr, "\nOptions:\n");
+ fprintf(stderr, "\t-h\n");
+ fprintf(stderr, "\t\tThis help text\n");
+ fprintf(stderr, "\t-q\n");
+ fprintf(stderr, "\t\tQuiet: -q suppress warnings, -qq errors, -qqq all\n");
+ fprintf(stderr, "\t-I <input format>\n");
+ fprintf(stderr, "\t\tInput formats are:\n");
+ fprintf(stderr, "\t\t\tdts - device tree source text\n");
+ fprintf(stderr, "\t\t\tdtb - device tree blob\n");
+ fprintf(stderr, "\t\t\tfs - /proc/device-tree style directory\n");
+ fprintf(stderr, "\t-o <output file>\n");
+ fprintf(stderr, "\t-O <output format>\n");
+ fprintf(stderr, "\t\tOutput formats are:\n");
+ fprintf(stderr, "\t\t\tdts - device tree source text\n");
+ fprintf(stderr, "\t\t\tdtb - device tree blob\n");
+ fprintf(stderr, "\t\t\tasm - assembler source\n");
+ fprintf(stderr, "\t-V <output version>\n");
+ fprintf(stderr, "\t\tBlob version to produce, defaults to %d (relevant for dtb\n\t\tand asm output only)\n", DEFAULT_FDT_VERSION);
+ fprintf(stderr, "\t-R <number>\n");
+ fprintf(stderr, "\t\tMake space for <number> reserve map entries (relevant for \n\t\tdtb and asm output only)\n");
+ fprintf(stderr, "\t-S <bytes>\n");
+ fprintf(stderr, "\t\tMake the blob at least <bytes> long (extra space)\n");
+ fprintf(stderr, "\t-p <bytes>\n");
+ fprintf(stderr, "\t\tAdd padding to the blob of <bytes> long (extra space)\n");
+ fprintf(stderr, "\t-b <number>\n");
+ fprintf(stderr, "\t\tSet the physical boot cpu\n");
+ fprintf(stderr, "\t-f\n");
+ fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n");
+ fprintf(stderr, "\t-v\n");
+ fprintf(stderr, "\t\tPrint DTC version and exit\n");
+ fprintf(stderr, "\t-H <phandle format>\n");
+ fprintf(stderr, "\t\tphandle formats are:\n");
+ fprintf(stderr, "\t\t\tlegacy - \"linux,phandle\" properties only\n");
+ fprintf(stderr, "\t\t\tepapr - \"phandle\" properties only\n");
+ fprintf(stderr, "\t\t\tboth - Both \"linux,phandle\" and \"phandle\" properties\n");
+ exit(3);
+}
+
+int main(int argc, char *argv[])
+{
+ struct boot_info *bi;
+ const char *inform = "dts";
+ const char *outform = "dts";
+ const char *outname = "-";
+ int force = 0, check = 0;
+ const char *arg;
+ int opt;
+ FILE *outf = NULL;
+ int outversion = DEFAULT_FDT_VERSION;
+ long long cmdline_boot_cpuid = -1;
+
+ quiet = 0;
+ reservenum = 0;
+ minsize = 0;
+ padsize = 0;
+
+ while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:vH:")) != EOF) {
+ switch (opt) {
+ case 'I':
+ inform = optarg;
+ break;
+ case 'O':
+ outform = optarg;
+ break;
+ case 'o':
+ outname = optarg;
+ break;
+ case 'V':
+ outversion = strtol(optarg, NULL, 0);
+ break;
+ case 'R':
+ reservenum = strtol(optarg, NULL, 0);
+ break;
+ case 'S':
+ minsize = strtol(optarg, NULL, 0);
+ break;
+ case 'p':
+ padsize = strtol(optarg, NULL, 0);
+ break;
+ case 'f':
+ force = 1;
+ break;
+ case 'c':
+ check = 1;
+ break;
+ case 'q':
+ quiet++;
+ break;
+ case 'b':
+ cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
+ break;
+ case 'v':
+ printf("Version: %s\n", DTC_VERSION);
+ exit(0);
+ case 'H':
+ if (streq(optarg, "legacy"))
+ phandle_format = PHANDLE_LEGACY;
+ else if (streq(optarg, "epapr"))
+ phandle_format = PHANDLE_EPAPR;
+ else if (streq(optarg, "both"))
+ phandle_format = PHANDLE_BOTH;
+ else
+ die("Invalid argument \"%s\" to -H option\n",
+ optarg);
+ break;
+
+ case 'h':
+ default:
+ usage();
+ }
+ }
+
+ if (argc > (optind+1))
+ usage();
+ else if (argc < (optind+1))
+ arg = "-";
+ else
+ arg = argv[optind];
+
+ /* minsize and padsize are mutually exclusive */
+ if (minsize && padsize)
+ die("Can't set both -p and -S\n");
+
+ if (minsize)
+ fprintf(stderr, "DTC: Use of \"-S\" is deprecated; it will be removed soon, use \"-p\" instead\n");
+
+ fprintf(stderr, "DTC: %s->%s on file \"%s\"\n",
+ inform, outform, arg);
+
+ if (streq(inform, "dts"))
+ bi = dt_from_source(arg);
+ else if (streq(inform, "fs"))
+ bi = dt_from_fs(arg);
+ else if(streq(inform, "dtb"))
+ bi = dt_from_blob(arg);
+ else
+ die("Unknown input format \"%s\"\n", inform);
+
+ if (cmdline_boot_cpuid != -1)
+ bi->boot_cpuid_phys = cmdline_boot_cpuid;
+
+ fill_fullpaths(bi->dt, "");
+ process_checks(force, bi);
+
+
+ if (streq(outname, "-")) {
+ outf = stdout;
+ } else {
+ outf = fopen(outname, "w");
+ if (! outf)
+ die("Couldn't open output file %s: %s\n",
+ outname, strerror(errno));
+ }
+
+ if (streq(outform, "dts")) {
+ dt_to_source(outf, bi);
+ } else if (streq(outform, "dtb")) {
+ dt_to_blob(outf, bi, outversion);
+ } else if (streq(outform, "asm")) {
+ dt_to_asm(outf, bi, outversion);
+ } else if (streq(outform, "null")) {
+ /* do nothing */
+ } else {
+ die("Unknown output format \"%s\"\n", outform);
+ }
+
+ exit(0);
+}
diff --git a/contrib/dtc/dtc.h b/contrib/dtc/dtc.h
new file mode 100644
index 0000000..0d7f0ed
--- /dev/null
+++ b/contrib/dtc/dtc.h
@@ -0,0 +1,231 @@
+#ifndef _DTC_H
+#define _DTC_H
+
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <libfdt_env.h>
+#include <fdt.h>
+
+#include "util.h"
+
+#ifdef DEBUG
+#define debug(fmt,args...) printf(fmt, ##args)
+#else
+#define debug(fmt,args...)
+#endif
+
+
+#define DEFAULT_FDT_VERSION 17
+
+/*
+ * Command line options
+ */
+extern int quiet; /* Level of quietness */
+extern int reservenum; /* Number of memory reservation slots */
+extern int minsize; /* Minimum blob size */
+extern int padsize; /* Additional padding to blob */
+extern int phandle_format; /* Use linux,phandle or phandle properties */
+
+#define PHANDLE_LEGACY 0x1
+#define PHANDLE_EPAPR 0x2
+#define PHANDLE_BOTH 0x3
+
+typedef uint32_t cell_t;
+
+
+#define streq(a, b) (strcmp((a), (b)) == 0)
+#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
+
+#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+/* Data blobs */
+enum markertype {
+ REF_PHANDLE,
+ REF_PATH,
+ LABEL,
+};
+
+struct marker {
+ enum markertype type;
+ int offset;
+ char *ref;
+ struct marker *next;
+};
+
+struct data {
+ int len;
+ char *val;
+ struct marker *markers;
+};
+
+
+#define empty_data ((struct data){ /* all .members = 0 or NULL */ })
+
+#define for_each_marker(m) \
+ for (; (m); (m) = (m)->next)
+#define for_each_marker_of_type(m, t) \
+ for_each_marker(m) \
+ if ((m)->type == (t))
+
+void data_free(struct data d);
+
+struct data data_grow_for(struct data d, int xlen);
+
+struct data data_copy_mem(const char *mem, int len);
+struct data data_copy_escape_string(const char *s, int len);
+struct data data_copy_file(FILE *f, size_t len);
+
+struct data data_append_data(struct data d, const void *p, int len);
+struct data data_insert_at_marker(struct data d, struct marker *m,
+ const void *p, int len);
+struct data data_merge(struct data d1, struct data d2);
+struct data data_append_cell(struct data d, cell_t word);
+struct data data_append_re(struct data d, const struct fdt_reserve_entry *re);
+struct data data_append_addr(struct data d, uint64_t addr);
+struct data data_append_byte(struct data d, uint8_t byte);
+struct data data_append_zeroes(struct data d, int len);
+struct data data_append_align(struct data d, int align);
+
+struct data data_add_marker(struct data d, enum markertype type, char *ref);
+
+int data_is_one_string(struct data d);
+
+/* DT constraints */
+
+#define MAX_PROPNAME_LEN 31
+#define MAX_NODENAME_LEN 31
+
+/* Live trees */
+struct property {
+ char *name;
+ struct data val;
+
+ struct property *next;
+
+ char *label;
+};
+
+struct node {
+ char *name;
+ struct property *proplist;
+ struct node *children;
+
+ struct node *parent;
+ struct node *next_sibling;
+
+ char *fullpath;
+ int basenamelen;
+
+ cell_t phandle;
+ int addr_cells, size_cells;
+
+ char *label;
+};
+
+#define for_each_property(n, p) \
+ for ((p) = (n)->proplist; (p); (p) = (p)->next)
+
+#define for_each_child(n, c) \
+ for ((c) = (n)->children; (c); (c) = (c)->next_sibling)
+
+struct property *build_property(char *name, struct data val, char *label);
+struct property *chain_property(struct property *first, struct property *list);
+struct property *reverse_properties(struct property *first);
+
+struct node *build_node(struct property *proplist, struct node *children);
+struct node *name_node(struct node *node, char *name, char *label);
+struct node *chain_node(struct node *first, struct node *list);
+
+void add_property(struct node *node, struct property *prop);
+void add_child(struct node *parent, struct node *child);
+
+const char *get_unitname(struct node *node);
+struct property *get_property(struct node *node, const char *propname);
+cell_t propval_cell(struct property *prop);
+struct node *get_subnode(struct node *node, const char *nodename);
+struct node *get_node_by_path(struct node *tree, const char *path);
+struct node *get_node_by_label(struct node *tree, const char *label);
+struct node *get_node_by_phandle(struct node *tree, cell_t phandle);
+struct node *get_node_by_ref(struct node *tree, const char *ref);
+cell_t get_node_phandle(struct node *root, struct node *node);
+
+/* Boot info (tree plus memreserve information */
+
+struct reserve_info {
+ struct fdt_reserve_entry re;
+
+ struct reserve_info *next;
+
+ char *label;
+};
+
+struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len, char *label);
+struct reserve_info *chain_reserve_entry(struct reserve_info *first,
+ struct reserve_info *list);
+struct reserve_info *add_reserve_entry(struct reserve_info *list,
+ struct reserve_info *new);
+
+
+struct boot_info {
+ struct reserve_info *reservelist;
+ struct node *dt; /* the device tree */
+ uint32_t boot_cpuid_phys;
+};
+
+struct boot_info *build_boot_info(struct reserve_info *reservelist,
+ struct node *tree, uint32_t boot_cpuid_phys);
+
+/* Checks */
+
+void process_checks(int force, struct boot_info *bi);
+
+/* Flattened trees */
+
+void dt_to_blob(FILE *f, struct boot_info *bi, int version);
+void dt_to_asm(FILE *f, struct boot_info *bi, int version);
+
+struct boot_info *dt_from_blob(const char *fname);
+
+/* Tree source */
+
+void dt_to_source(FILE *f, struct boot_info *bi);
+struct boot_info *dt_from_source(const char *f);
+
+/* FS trees */
+
+struct boot_info *dt_from_fs(const char *dirname);
+
+/* misc */
+
+char *join_path(const char *path, const char *name);
+
+#endif /* _DTC_H */
diff --git a/contrib/dtc/flattree.c b/contrib/dtc/flattree.c
new file mode 100644
index 0000000..3eb0201
--- /dev/null
+++ b/contrib/dtc/flattree.c
@@ -0,0 +1,927 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "dtc.h"
+#include "srcpos.h"
+
+#define FTF_FULLPATH 0x1
+#define FTF_VARALIGN 0x2
+#define FTF_NAMEPROPS 0x4
+#define FTF_BOOTCPUID 0x8
+#define FTF_STRTABSIZE 0x10
+#define FTF_STRUCTSIZE 0x20
+#define FTF_NOPS 0x40
+
+static struct version_info {
+ int version;
+ int last_comp_version;
+ int hdr_size;
+ int flags;
+} version_table[] = {
+ {1, 1, FDT_V1_SIZE,
+ FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS},
+ {2, 1, FDT_V2_SIZE,
+ FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID},
+ {3, 1, FDT_V3_SIZE,
+ FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID|FTF_STRTABSIZE},
+ {16, 16, FDT_V3_SIZE,
+ FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_NOPS},
+ {17, 16, FDT_V17_SIZE,
+ FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
+};
+
+struct emitter {
+ void (*cell)(void *, cell_t);
+ void (*string)(void *, char *, int);
+ void (*align)(void *, int);
+ void (*data)(void *, struct data);
+ void (*beginnode)(void *, const char *);
+ void (*endnode)(void *, const char *);
+ void (*property)(void *, const char *);
+};
+
+static void bin_emit_cell(void *e, cell_t val)
+{
+ struct data *dtbuf = e;
+
+ *dtbuf = data_append_cell(*dtbuf, val);
+}
+
+static void bin_emit_string(void *e, char *str, int len)
+{
+ struct data *dtbuf = e;
+
+ if (len == 0)
+ len = strlen(str);
+
+ *dtbuf = data_append_data(*dtbuf, str, len);
+ *dtbuf = data_append_byte(*dtbuf, '\0');
+}
+
+static void bin_emit_align(void *e, int a)
+{
+ struct data *dtbuf = e;
+
+ *dtbuf = data_append_align(*dtbuf, a);
+}
+
+static void bin_emit_data(void *e, struct data d)
+{
+ struct data *dtbuf = e;
+
+ *dtbuf = data_append_data(*dtbuf, d.val, d.len);
+}
+
+static void bin_emit_beginnode(void *e, const char *label)
+{
+ bin_emit_cell(e, FDT_BEGIN_NODE);
+}
+
+static void bin_emit_endnode(void *e, const char *label)
+{
+ bin_emit_cell(e, FDT_END_NODE);
+}
+
+static void bin_emit_property(void *e, const char *label)
+{
+ bin_emit_cell(e, FDT_PROP);
+}
+
+static struct emitter bin_emitter = {
+ .cell = bin_emit_cell,
+ .string = bin_emit_string,
+ .align = bin_emit_align,
+ .data = bin_emit_data,
+ .beginnode = bin_emit_beginnode,
+ .endnode = bin_emit_endnode,
+ .property = bin_emit_property,
+};
+
+static void emit_label(FILE *f, const char *prefix, const char *label)
+{
+ fprintf(f, "\t.globl\t%s_%s\n", prefix, label);
+ fprintf(f, "%s_%s:\n", prefix, label);
+ fprintf(f, "_%s_%s:\n", prefix, label);
+}
+
+static void emit_offset_label(FILE *f, const char *label, int offset)
+{
+ fprintf(f, "\t.globl\t%s\n", label);
+ fprintf(f, "%s\t= . + %d\n", label, offset);
+}
+
+#define ASM_EMIT_BELONG(f, fmt, ...) \
+ { \
+ fprintf((f), "\t.byte\t((" fmt ") >> 24) & 0xff\n", __VA_ARGS__); \
+ fprintf((f), "\t.byte\t((" fmt ") >> 16) & 0xff\n", __VA_ARGS__); \
+ fprintf((f), "\t.byte\t((" fmt ") >> 8) & 0xff\n", __VA_ARGS__); \
+ fprintf((f), "\t.byte\t(" fmt ") & 0xff\n", __VA_ARGS__); \
+ }
+
+static void asm_emit_cell(void *e, cell_t val)
+{
+ FILE *f = e;
+
+ fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n",
+ (val >> 24) & 0xff, (val >> 16) & 0xff,
+ (val >> 8) & 0xff, val & 0xff);
+}
+
+static void asm_emit_string(void *e, char *str, int len)
+{
+ FILE *f = e;
+ char c = 0;
+
+ if (len != 0) {
+ /* XXX: ewww */
+ c = str[len];
+ str[len] = '\0';
+ }
+
+ fprintf(f, "\t.string\t\"%s\"\n", str);
+
+ if (len != 0) {
+ str[len] = c;
+ }
+}
+
+static void asm_emit_align(void *e, int a)
+{
+ FILE *f = e;
+
+ fprintf(f, "\t.balign\t%d, 0\n", a);
+}
+
+static void asm_emit_data(void *e, struct data d)
+{
+ FILE *f = e;
+ int off = 0;
+ struct marker *m = d.markers;
+
+ for_each_marker_of_type(m, LABEL)
+ emit_offset_label(f, m->ref, m->offset);
+
+ while ((d.len - off) >= sizeof(uint32_t)) {
+ asm_emit_cell(e, fdt32_to_cpu(*((uint32_t *)(d.val+off))));
+ off += sizeof(uint32_t);
+ }
+
+ while ((d.len - off) >= 1) {
+ fprintf(f, "\t.byte\t0x%hhx\n", d.val[off]);
+ off += 1;
+ }
+
+ assert(off == d.len);
+}
+
+static void asm_emit_beginnode(void *e, const char *label)
+{
+ FILE *f = e;
+
+ if (label) {
+ fprintf(f, "\t.globl\t%s\n", label);
+ fprintf(f, "%s:\n", label);
+ }
+ fprintf(f, "\t/* FDT_BEGIN_NODE */\n");
+ asm_emit_cell(e, FDT_BEGIN_NODE);
+}
+
+static void asm_emit_endnode(void *e, const char *label)
+{
+ FILE *f = e;
+
+ fprintf(f, "\t/* FDT_END_NODE */\n");
+ asm_emit_cell(e, FDT_END_NODE);
+ if (label) {
+ fprintf(f, "\t.globl\t%s_end\n", label);
+ fprintf(f, "%s_end:\n", label);
+ }
+}
+
+static void asm_emit_property(void *e, const char *label)
+{
+ FILE *f = e;
+
+ if (label) {
+ fprintf(f, "\t.globl\t%s\n", label);
+ fprintf(f, "%s:\n", label);
+ }
+ fprintf(f, "\t/* FDT_PROP */\n");
+ asm_emit_cell(e, FDT_PROP);
+}
+
+static struct emitter asm_emitter = {
+ .cell = asm_emit_cell,
+ .string = asm_emit_string,
+ .align = asm_emit_align,
+ .data = asm_emit_data,
+ .beginnode = asm_emit_beginnode,
+ .endnode = asm_emit_endnode,
+ .property = asm_emit_property,
+};
+
+static int stringtable_insert(struct data *d, const char *str)
+{
+ int i;
+
+ /* FIXME: do this more efficiently? */
+
+ for (i = 0; i < d->len; i++) {
+ if (streq(str, d->val + i))
+ return i;
+ }
+
+ *d = data_append_data(*d, str, strlen(str)+1);
+ return i;
+}
+
+static void flatten_tree(struct node *tree, struct emitter *emit,
+ void *etarget, struct data *strbuf,
+ struct version_info *vi)
+{
+ struct property *prop;
+ struct node *child;
+ int seen_name_prop = 0;
+
+ emit->beginnode(etarget, tree->label);
+
+ if (vi->flags & FTF_FULLPATH)
+ emit->string(etarget, tree->fullpath, 0);
+ else
+ emit->string(etarget, tree->name, 0);
+
+ emit->align(etarget, sizeof(cell_t));
+
+ for_each_property(tree, prop) {
+ int nameoff;
+
+ if (streq(prop->name, "name"))
+ seen_name_prop = 1;
+
+ nameoff = stringtable_insert(strbuf, prop->name);
+
+ emit->property(etarget, prop->label);
+ emit->cell(etarget, prop->val.len);
+ emit->cell(etarget, nameoff);
+
+ if ((vi->flags & FTF_VARALIGN) && (prop->val.len >= 8))
+ emit->align(etarget, 8);
+
+ emit->data(etarget, prop->val);
+ emit->align(etarget, sizeof(cell_t));
+ }
+
+ if ((vi->flags & FTF_NAMEPROPS) && !seen_name_prop) {
+ emit->property(etarget, NULL);
+ emit->cell(etarget, tree->basenamelen+1);
+ emit->cell(etarget, stringtable_insert(strbuf, "name"));
+
+ if ((vi->flags & FTF_VARALIGN) && ((tree->basenamelen+1) >= 8))
+ emit->align(etarget, 8);
+
+ emit->string(etarget, tree->name, tree->basenamelen);
+ emit->align(etarget, sizeof(cell_t));
+ }
+
+ for_each_child(tree, child) {
+ flatten_tree(child, emit, etarget, strbuf, vi);
+ }
+
+ emit->endnode(etarget, tree->label);
+}
+
+static struct data flatten_reserve_list(struct reserve_info *reservelist,
+ struct version_info *vi)
+{
+ struct reserve_info *re;
+ struct data d = empty_data;
+ static struct fdt_reserve_entry null_re = {0,0};
+ int j;
+
+ for (re = reservelist; re; re = re->next) {
+ d = data_append_re(d, &re->re);
+ }
+ /*
+ * Add additional reserved slots if the user asked for them.
+ */
+ for (j = 0; j < reservenum; j++) {
+ d = data_append_re(d, &null_re);
+ }
+
+ return d;
+}
+
+static void make_fdt_header(struct fdt_header *fdt,
+ struct version_info *vi,
+ int reservesize, int dtsize, int strsize,
+ int boot_cpuid_phys)
+{
+ int reserve_off;
+
+ reservesize += sizeof(struct fdt_reserve_entry);
+
+ memset(fdt, 0xff, sizeof(*fdt));
+
+ fdt->magic = cpu_to_fdt32(FDT_MAGIC);
+ fdt->version = cpu_to_fdt32(vi->version);
+ fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version);
+
+ /* Reserve map should be doubleword aligned */
+ reserve_off = ALIGN(vi->hdr_size, 8);
+
+ fdt->off_mem_rsvmap = cpu_to_fdt32(reserve_off);
+ fdt->off_dt_struct = cpu_to_fdt32(reserve_off + reservesize);
+ fdt->off_dt_strings = cpu_to_fdt32(reserve_off + reservesize
+ + dtsize);
+ fdt->totalsize = cpu_to_fdt32(reserve_off + reservesize + dtsize + strsize);
+
+ if (vi->flags & FTF_BOOTCPUID)
+ fdt->boot_cpuid_phys = cpu_to_fdt32(boot_cpuid_phys);
+ if (vi->flags & FTF_STRTABSIZE)
+ fdt->size_dt_strings = cpu_to_fdt32(strsize);
+ if (vi->flags & FTF_STRUCTSIZE)
+ fdt->size_dt_struct = cpu_to_fdt32(dtsize);
+}
+
+void dt_to_blob(FILE *f, struct boot_info *bi, int version)
+{
+ struct version_info *vi = NULL;
+ int i;
+ struct data blob = empty_data;
+ struct data reservebuf = empty_data;
+ struct data dtbuf = empty_data;
+ struct data strbuf = empty_data;
+ struct fdt_header fdt;
+ int padlen = 0;
+
+ for (i = 0; i < ARRAY_SIZE(version_table); i++) {
+ if (version_table[i].version == version)
+ vi = &version_table[i];
+ }
+ if (!vi)
+ die("Unknown device tree blob version %d\n", version);
+
+ flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi);
+ bin_emit_cell(&dtbuf, FDT_END);
+
+ reservebuf = flatten_reserve_list(bi->reservelist, vi);
+
+ /* Make header */
+ make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
+ bi->boot_cpuid_phys);
+
+ /*
+ * If the user asked for more space than is used, adjust the totalsize.
+ */
+ if (minsize > 0) {
+ padlen = minsize - fdt32_to_cpu(fdt.totalsize);
+ if ((padlen < 0) && (quiet < 1))
+ fprintf(stderr,
+ "Warning: blob size %d >= minimum size %d\n",
+ fdt32_to_cpu(fdt.totalsize), minsize);
+ }
+
+ if (padsize > 0)
+ padlen = padsize;
+
+ if (padlen > 0) {
+ int tsize = fdt32_to_cpu(fdt.totalsize);
+ tsize += padlen;
+ fdt.totalsize = cpu_to_fdt32(tsize);
+ }
+
+ /*
+ * Assemble the blob: start with the header, add with alignment
+ * the reserve buffer, add the reserve map terminating zeroes,
+ * the device tree itself, and finally the strings.
+ */
+ blob = data_append_data(blob, &fdt, vi->hdr_size);
+ blob = data_append_align(blob, 8);
+ blob = data_merge(blob, reservebuf);
+ blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry));
+ blob = data_merge(blob, dtbuf);
+ blob = data_merge(blob, strbuf);
+
+ /*
+ * If the user asked for more space than is used, pad out the blob.
+ */
+ if (padlen > 0)
+ blob = data_append_zeroes(blob, padlen);
+
+ if (fwrite(blob.val, blob.len, 1, f) != 1) {
+ if (ferror(f))
+ die("Error writing device tree blob: %s\n",
+ strerror(errno));
+ else
+ die("Short write on device tree blob\n");
+ }
+
+ /*
+ * data_merge() frees the right-hand element so only the blob
+ * remains to be freed.
+ */
+ data_free(blob);
+}
+
+static void dump_stringtable_asm(FILE *f, struct data strbuf)
+{
+ const char *p;
+ int len;
+
+ p = strbuf.val;
+
+ while (p < (strbuf.val + strbuf.len)) {
+ len = strlen(p);
+ fprintf(f, "\t.string \"%s\"\n", p);
+ p += len+1;
+ }
+}
+
+void dt_to_asm(FILE *f, struct boot_info *bi, int version)
+{
+ struct version_info *vi = NULL;
+ int i;
+ struct data strbuf = empty_data;
+ struct reserve_info *re;
+ const char *symprefix = "dt";
+
+ for (i = 0; i < ARRAY_SIZE(version_table); i++) {
+ if (version_table[i].version == version)
+ vi = &version_table[i];
+ }
+ if (!vi)
+ die("Unknown device tree blob version %d\n", version);
+
+ fprintf(f, "/* autogenerated by dtc, do not edit */\n\n");
+
+ emit_label(f, symprefix, "blob_start");
+ emit_label(f, symprefix, "header");
+ fprintf(f, "\t/* magic */\n");
+ asm_emit_cell(f, FDT_MAGIC);
+ fprintf(f, "\t/* totalsize */\n");
+ ASM_EMIT_BELONG(f, "_%s_blob_abs_end - _%s_blob_start",
+ symprefix, symprefix);
+ fprintf(f, "\t/* off_dt_struct */\n");
+ ASM_EMIT_BELONG(f, "_%s_struct_start - _%s_blob_start",
+ symprefix, symprefix);
+ fprintf(f, "\t/* off_dt_strings */\n");
+ ASM_EMIT_BELONG(f, "_%s_strings_start - _%s_blob_start",
+ symprefix, symprefix);
+ fprintf(f, "\t/* off_mem_rsvmap */\n");
+ ASM_EMIT_BELONG(f, "_%s_reserve_map - _%s_blob_start",
+ symprefix, symprefix);
+ fprintf(f, "\t/* version */\n");
+ asm_emit_cell(f, vi->version);
+ fprintf(f, "\t/* last_comp_version */\n");
+ asm_emit_cell(f, vi->last_comp_version);
+
+ if (vi->flags & FTF_BOOTCPUID) {
+ fprintf(f, "\t/* boot_cpuid_phys */\n");
+ asm_emit_cell(f, bi->boot_cpuid_phys);
+ }
+
+ if (vi->flags & FTF_STRTABSIZE) {
+ fprintf(f, "\t/* size_dt_strings */\n");
+ ASM_EMIT_BELONG(f, "_%s_strings_end - _%s_strings_start",
+ symprefix, symprefix);
+ }
+
+ if (vi->flags & FTF_STRUCTSIZE) {
+ fprintf(f, "\t/* size_dt_struct */\n");
+ ASM_EMIT_BELONG(f, "_%s_struct_end - _%s_struct_start",
+ symprefix, symprefix);
+ }
+
+ /*
+ * Reserve map entries.
+ * Align the reserve map to a doubleword boundary.
+ * Each entry is an (address, size) pair of u64 values.
+ * Always supply a zero-sized temination entry.
+ */
+ asm_emit_align(f, 8);
+ emit_label(f, symprefix, "reserve_map");
+
+ fprintf(f, "/* Memory reserve map from source file */\n");
+
+ /*
+ * Use .long on high and low halfs of u64s to avoid .quad
+ * as it appears .quad isn't available in some assemblers.
+ */
+ for (re = bi->reservelist; re; re = re->next) {
+ if (re->label) {
+ fprintf(f, "\t.globl\t%s\n", re->label);
+ fprintf(f, "%s:\n", re->label);
+ }
+ ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.address >> 32));
+ ASM_EMIT_BELONG(f, "0x%08x",
+ (unsigned int)(re->re.address & 0xffffffff));
+ ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size >> 32));
+ ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size & 0xffffffff));
+ }
+ for (i = 0; i < reservenum; i++) {
+ fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
+ }
+
+ fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
+
+ emit_label(f, symprefix, "struct_start");
+ flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi);
+
+ fprintf(f, "\t/* FDT_END */\n");
+ asm_emit_cell(f, FDT_END);
+ emit_label(f, symprefix, "struct_end");
+
+ emit_label(f, symprefix, "strings_start");
+ dump_stringtable_asm(f, strbuf);
+ emit_label(f, symprefix, "strings_end");
+
+ emit_label(f, symprefix, "blob_end");
+
+ /*
+ * If the user asked for more space than is used, pad it out.
+ */
+ if (minsize > 0) {
+ fprintf(f, "\t.space\t%d - (_%s_blob_end - _%s_blob_start), 0\n",
+ minsize, symprefix, symprefix);
+ }
+ if (padsize > 0) {
+ fprintf(f, "\t.space\t%d, 0\n", padsize);
+ }
+ emit_label(f, symprefix, "blob_abs_end");
+
+ data_free(strbuf);
+}
+
+struct inbuf {
+ char *base, *limit, *ptr;
+};
+
+static void inbuf_init(struct inbuf *inb, void *base, void *limit)
+{
+ inb->base = base;
+ inb->limit = limit;
+ inb->ptr = inb->base;
+}
+
+static void flat_read_chunk(struct inbuf *inb, void *p, int len)
+{
+ if ((inb->ptr + len) > inb->limit)
+ die("Premature end of data parsing flat device tree\n");
+
+ memcpy(p, inb->ptr, len);
+
+ inb->ptr += len;
+}
+
+static uint32_t flat_read_word(struct inbuf *inb)
+{
+ uint32_t val;
+
+ assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
+
+ flat_read_chunk(inb, &val, sizeof(val));
+
+ return fdt32_to_cpu(val);
+}
+
+static void flat_realign(struct inbuf *inb, int align)
+{
+ int off = inb->ptr - inb->base;
+
+ inb->ptr = inb->base + ALIGN(off, align);
+ if (inb->ptr > inb->limit)
+ die("Premature end of data parsing flat device tree\n");
+}
+
+static char *flat_read_string(struct inbuf *inb)
+{
+ int len = 0;
+ const char *p = inb->ptr;
+ char *str;
+
+ do {
+ if (p >= inb->limit)
+ die("Premature end of data parsing flat device tree\n");
+ len++;
+ } while ((*p++) != '\0');
+
+ str = xstrdup(inb->ptr);
+
+ inb->ptr += len;
+
+ flat_realign(inb, sizeof(uint32_t));
+
+ return str;
+}
+
+static struct data flat_read_data(struct inbuf *inb, int len)
+{
+ struct data d = empty_data;
+
+ if (len == 0)
+ return empty_data;
+
+ d = data_grow_for(d, len);
+ d.len = len;
+
+ flat_read_chunk(inb, d.val, len);
+
+ flat_realign(inb, sizeof(uint32_t));
+
+ return d;
+}
+
+static char *flat_read_stringtable(struct inbuf *inb, int offset)
+{
+ const char *p;
+
+ p = inb->base + offset;
+ while (1) {
+ if (p >= inb->limit || p < inb->base)
+ die("String offset %d overruns string table\n",
+ offset);
+
+ if (*p == '\0')
+ break;
+
+ p++;
+ }
+
+ return xstrdup(inb->base + offset);
+}
+
+static struct property *flat_read_property(struct inbuf *dtbuf,
+ struct inbuf *strbuf, int flags)
+{
+ uint32_t proplen, stroff;
+ char *name;
+ struct data val;
+
+ proplen = flat_read_word(dtbuf);
+ stroff = flat_read_word(dtbuf);
+
+ name = flat_read_stringtable(strbuf, stroff);
+
+ if ((flags & FTF_VARALIGN) && (proplen >= 8))
+ flat_realign(dtbuf, 8);
+
+ val = flat_read_data(dtbuf, proplen);
+
+ return build_property(name, val, NULL);
+}
+
+
+static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
+{
+ struct reserve_info *reservelist = NULL;
+ struct reserve_info *new;
+ const char *p;
+ struct fdt_reserve_entry re;
+
+ /*
+ * Each entry is a pair of u64 (addr, size) values for 4 cell_t's.
+ * List terminates at an entry with size equal to zero.
+ *
+ * First pass, count entries.
+ */
+ p = inb->ptr;
+ while (1) {
+ flat_read_chunk(inb, &re, sizeof(re));
+ re.address = fdt64_to_cpu(re.address);
+ re.size = fdt64_to_cpu(re.size);
+ if (re.size == 0)
+ break;
+
+ new = build_reserve_entry(re.address, re.size, NULL);
+ reservelist = add_reserve_entry(reservelist, new);
+ }
+
+ return reservelist;
+}
+
+
+static char *nodename_from_path(const char *ppath, const char *cpath)
+{
+ int plen;
+
+ plen = strlen(ppath);
+
+ if (!strneq(ppath, cpath, plen))
+ die("Path \"%s\" is not valid as a child of \"%s\"\n",
+ cpath, ppath);
+
+ /* root node is a special case */
+ if (!streq(ppath, "/"))
+ plen++;
+
+ return xstrdup(cpath + plen);
+}
+
+static struct node *unflatten_tree(struct inbuf *dtbuf,
+ struct inbuf *strbuf,
+ const char *parent_flatname, int flags)
+{
+ struct node *node;
+ char *flatname;
+ uint32_t val;
+
+ node = build_node(NULL, NULL);
+
+ flatname = flat_read_string(dtbuf);
+
+ if (flags & FTF_FULLPATH)
+ node->name = nodename_from_path(parent_flatname, flatname);
+ else
+ node->name = flatname;
+
+ do {
+ struct property *prop;
+ struct node *child;
+
+ val = flat_read_word(dtbuf);
+ switch (val) {
+ case FDT_PROP:
+ if (node->children)
+ fprintf(stderr, "Warning: Flat tree input has "
+ "subnodes preceding a property.\n");
+ prop = flat_read_property(dtbuf, strbuf, flags);
+ add_property(node, prop);
+ break;
+
+ case FDT_BEGIN_NODE:
+ child = unflatten_tree(dtbuf,strbuf, flatname, flags);
+ add_child(node, child);
+ break;
+
+ case FDT_END_NODE:
+ break;
+
+ case FDT_END:
+ die("Premature FDT_END in device tree blob\n");
+ break;
+
+ case FDT_NOP:
+ if (!(flags & FTF_NOPS))
+ fprintf(stderr, "Warning: NOP tag found in flat tree"
+ " version <16\n");
+
+ /* Ignore */
+ break;
+
+ default:
+ die("Invalid opcode word %08x in device tree blob\n",
+ val);
+ }
+ } while (val != FDT_END_NODE);
+
+ return node;
+}
+
+
+struct boot_info *dt_from_blob(const char *fname)
+{
+ struct dtc_file *dtcf;
+ uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
+ uint32_t off_dt, off_str, off_mem_rsvmap;
+ int rc;
+ char *blob;
+ struct fdt_header *fdt;
+ char *p;
+ struct inbuf dtbuf, strbuf;
+ struct inbuf memresvbuf;
+ int sizeleft;
+ struct reserve_info *reservelist;
+ struct node *tree;
+ uint32_t val;
+ int flags = 0;
+
+ dtcf = dtc_open_file(fname, NULL);
+
+ rc = fread(&magic, sizeof(magic), 1, dtcf->file);
+ if (ferror(dtcf->file))
+ die("Error reading DT blob magic number: %s\n",
+ strerror(errno));
+ if (rc < 1) {
+ if (feof(dtcf->file))
+ die("EOF reading DT blob magic number\n");
+ else
+ die("Mysterious short read reading magic number\n");
+ }
+
+ magic = fdt32_to_cpu(magic);
+ if (magic != FDT_MAGIC)
+ die("Blob has incorrect magic number\n");
+
+ rc = fread(&totalsize, sizeof(totalsize), 1, dtcf->file);
+ if (ferror(dtcf->file))
+ die("Error reading DT blob size: %s\n", strerror(errno));
+ if (rc < 1) {
+ if (feof(dtcf->file))
+ die("EOF reading DT blob size\n");
+ else
+ die("Mysterious short read reading blob size\n");
+ }
+
+ totalsize = fdt32_to_cpu(totalsize);
+ if (totalsize < FDT_V1_SIZE)
+ die("DT blob size (%d) is too small\n", totalsize);
+
+ blob = xmalloc(totalsize);
+
+ fdt = (struct fdt_header *)blob;
+ fdt->magic = cpu_to_fdt32(magic);
+ fdt->totalsize = cpu_to_fdt32(totalsize);
+
+ sizeleft = totalsize - sizeof(magic) - sizeof(totalsize);
+ p = blob + sizeof(magic) + sizeof(totalsize);
+
+ while (sizeleft) {
+ if (feof(dtcf->file))
+ die("EOF before reading %d bytes of DT blob\n",
+ totalsize);
+
+ rc = fread(p, 1, sizeleft, dtcf->file);
+ if (ferror(dtcf->file))
+ die("Error reading DT blob: %s\n",
+ strerror(errno));
+
+ sizeleft -= rc;
+ p += rc;
+ }
+
+ off_dt = fdt32_to_cpu(fdt->off_dt_struct);
+ off_str = fdt32_to_cpu(fdt->off_dt_strings);
+ off_mem_rsvmap = fdt32_to_cpu(fdt->off_mem_rsvmap);
+ version = fdt32_to_cpu(fdt->version);
+ boot_cpuid_phys = fdt32_to_cpu(fdt->boot_cpuid_phys);
+
+ if (off_mem_rsvmap >= totalsize)
+ die("Mem Reserve structure offset exceeds total size\n");
+
+ if (off_dt >= totalsize)
+ die("DT structure offset exceeds total size\n");
+
+ if (off_str > totalsize)
+ die("String table offset exceeds total size\n");
+
+ if (version >= 3) {
+ uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings);
+ if (off_str+size_str > totalsize)
+ die("String table extends past total size\n");
+ inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
+ } else {
+ inbuf_init(&strbuf, blob + off_str, blob + totalsize);
+ }
+
+ if (version >= 17) {
+ size_dt = fdt32_to_cpu(fdt->size_dt_struct);
+ if (off_dt+size_dt > totalsize)
+ die("Structure block extends past total size\n");
+ }
+
+ if (version < 16) {
+ flags |= FTF_FULLPATH | FTF_NAMEPROPS | FTF_VARALIGN;
+ } else {
+ flags |= FTF_NOPS;
+ }
+
+ inbuf_init(&memresvbuf,
+ blob + off_mem_rsvmap, blob + totalsize);
+ inbuf_init(&dtbuf, blob + off_dt, blob + totalsize);
+
+ reservelist = flat_read_mem_reserve(&memresvbuf);
+
+ val = flat_read_word(&dtbuf);
+
+ if (val != FDT_BEGIN_NODE)
+ die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);
+
+ tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
+
+ val = flat_read_word(&dtbuf);
+ if (val != FDT_END)
+ die("Device tree blob doesn't end with FDT_END\n");
+
+ free(blob);
+
+ dtc_close_file(dtcf);
+
+ return build_boot_info(reservelist, tree, boot_cpuid_phys);
+}
diff --git a/contrib/dtc/fstree.c b/contrib/dtc/fstree.c
new file mode 100644
index 0000000..7aee982
--- /dev/null
+++ b/contrib/dtc/fstree.c
@@ -0,0 +1,92 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "dtc.h"
+
+#include <dirent.h>
+#include <sys/stat.h>
+
+static struct node *read_fstree(const char *dirname)
+{
+ DIR *d;
+ struct dirent *de;
+ struct stat st;
+ struct node *tree;
+
+ d = opendir(dirname);
+ if (!d)
+ die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno));
+
+ tree = build_node(NULL, NULL);
+
+ while ((de = readdir(d)) != NULL) {
+ char *tmpnam;
+
+ if (streq(de->d_name, ".")
+ || streq(de->d_name, ".."))
+ continue;
+
+ tmpnam = join_path(dirname, de->d_name);
+
+ if (lstat(tmpnam, &st) < 0)
+ die("stat(%s): %s\n", tmpnam, strerror(errno));
+
+ if (S_ISREG(st.st_mode)) {
+ struct property *prop;
+ FILE *pfile;
+
+ pfile = fopen(tmpnam, "r");
+ if (! pfile) {
+ fprintf(stderr,
+ "WARNING: Cannot open %s: %s\n",
+ tmpnam, strerror(errno));
+ } else {
+ prop = build_property(xstrdup(de->d_name),
+ data_copy_file(pfile,
+ st.st_size),
+ NULL);
+ add_property(tree, prop);
+ fclose(pfile);
+ }
+ } else if (S_ISDIR(st.st_mode)) {
+ struct node *newchild;
+
+ newchild = read_fstree(tmpnam);
+ newchild = name_node(newchild, xstrdup(de->d_name),
+ NULL);
+ add_child(tree, newchild);
+ }
+
+ free(tmpnam);
+ }
+
+ return tree;
+}
+
+struct boot_info *dt_from_fs(const char *dirname)
+{
+ struct node *tree;
+
+ tree = read_fstree(dirname);
+ tree = name_node(tree, "", NULL);
+
+ return build_boot_info(NULL, tree, 0);
+}
+
diff --git a/contrib/dtc/ftdump.c b/contrib/dtc/ftdump.c
new file mode 100644
index 0000000..bce6535
--- /dev/null
+++ b/contrib/dtc/ftdump.c
@@ -0,0 +1,208 @@
+/*
+ * ftdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com>
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <fdt.h>
+#include <libfdt_env.h>
+
+#define FTDUMP_BUF_SIZE 65536
+
+#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
+#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
+#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4)))
+
+static int is_printable_string(const void *data, int len)
+{
+ const char *s = data;
+ const char *ss;
+
+ /* zero length is not */
+ if (len == 0)
+ return 0;
+
+ /* must terminate with zero */
+ if (s[len - 1] != '\0')
+ return 0;
+
+ ss = s;
+ while (*s && isprint(*s))
+ s++;
+
+ /* not zero, or not done yet */
+ if (*s != '\0' || (s + 1 - ss) < len)
+ return 0;
+
+ return 1;
+}
+
+static void print_data(const char *data, int len)
+{
+ int i;
+ const char *p = data;
+
+ /* no data, don't print */
+ if (len == 0)
+ return;
+
+ if (is_printable_string(data, len)) {
+ printf(" = \"%s\"", (const char *)data);
+ } else if ((len % 4) == 0) {
+ printf(" = <");
+ for (i = 0; i < len; i += 4)
+ printf("0x%08x%s", fdt32_to_cpu(GET_CELL(p)),
+ i < (len - 4) ? " " : "");
+ printf(">");
+ } else {
+ printf(" = [");
+ for (i = 0; i < len; i++)
+ printf("%02x%s", *p++, i < len - 1 ? " " : "");
+ printf("]");
+ }
+}
+
+static void dump_blob(void *blob)
+{
+ struct fdt_header *bph = blob;
+ uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap);
+ uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct);
+ uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings);
+ struct fdt_reserve_entry *p_rsvmap =
+ (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap);
+ const char *p_struct = (const char *)blob + off_dt;
+ const char *p_strings = (const char *)blob + off_str;
+ uint32_t version = fdt32_to_cpu(bph->version);
+ uint32_t totalsize = fdt32_to_cpu(bph->totalsize);
+ uint32_t tag;
+ const char *p, *s, *t;
+ int depth, sz, shift;
+ int i;
+ uint64_t addr, size;
+
+ depth = 0;
+ shift = 4;
+
+ printf("/dts-v1/;\n");
+ printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic));
+ printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize);
+ printf("// off_dt_struct:\t0x%x\n", off_dt);
+ printf("// off_dt_strings:\t0x%x\n", off_str);
+ printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
+ printf("// version:\t\t%d\n", version);
+ printf("// last_comp_version:\t%d\n",
+ fdt32_to_cpu(bph->last_comp_version));
+ if (version >= 2)
+ printf("// boot_cpuid_phys:\t0x%x\n",
+ fdt32_to_cpu(bph->boot_cpuid_phys));
+
+ if (version >= 3)
+ printf("// size_dt_strings:\t0x%x\n",
+ fdt32_to_cpu(bph->size_dt_strings));
+ if (version >= 17)
+ printf("// size_dt_struct:\t0x%x\n",
+ fdt32_to_cpu(bph->size_dt_struct));
+ printf("\n");
+
+ for (i = 0; ; i++) {
+ addr = fdt64_to_cpu(p_rsvmap[i].address);
+ size = fdt64_to_cpu(p_rsvmap[i].size);
+ if (addr == 0 && size == 0)
+ break;
+
+ printf("/memreserve/ %llx %llx;\n",
+ (unsigned long long)addr, (unsigned long long)size);
+ }
+
+ p = p_struct;
+ while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
+
+ /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */
+
+ if (tag == FDT_BEGIN_NODE) {
+ s = p;
+ p = PALIGN(p + strlen(s) + 1, 4);
+
+ if (*s == '\0')
+ s = "/";
+
+ printf("%*s%s {\n", depth * shift, "", s);
+
+ depth++;
+ continue;
+ }
+
+ if (tag == FDT_END_NODE) {
+ depth--;
+
+ printf("%*s};\n", depth * shift, "");
+ continue;
+ }
+
+ if (tag == FDT_NOP) {
+ printf("%*s// [NOP]\n", depth * shift, "");
+ continue;
+ }
+
+ if (tag != FDT_PROP) {
+ fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag);
+ break;
+ }
+ sz = fdt32_to_cpu(GET_CELL(p));
+ s = p_strings + fdt32_to_cpu(GET_CELL(p));
+ if (version < 16 && sz >= 8)
+ p = PALIGN(p, 8);
+ t = p;
+
+ p = PALIGN(p + sz, 4);
+
+ printf("%*s%s", depth * shift, "", s);
+ print_data(t, sz);
+ printf(";\n");
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+ FILE *fp;
+ char *buf;
+ int size;
+
+ if (argc < 2) {
+ fprintf(stderr, "supply input filename\n");
+ return 5;
+ }
+
+ if (strcmp(argv[1], "-") == 0) {
+ fp = stdin;
+ } else {
+ fp = fopen(argv[1], "rb");
+ if (fp == NULL) {
+ fprintf(stderr, "unable to open %s\n", argv[1]);
+ return 10;
+ }
+ }
+
+ buf = malloc(FTDUMP_BUF_SIZE);
+ if (!buf) {
+ fprintf(stderr, "Couldn't allocate %d byte buffer\n", FTDUMP_BUF_SIZE);
+ return 10;
+ }
+
+ size = fread(buf, 1, FTDUMP_BUF_SIZE, fp);
+ if (size == FTDUMP_BUF_SIZE) {
+ fprintf(stderr, "file too large (maximum is %d bytes)\n", FTDUMP_BUF_SIZE);
+ return 10;
+ }
+
+ dump_blob(buf);
+
+ fclose(fp);
+
+ return 0;
+}
diff --git a/contrib/dtc/libfdt/Makefile.libfdt b/contrib/dtc/libfdt/Makefile.libfdt
new file mode 100644
index 0000000..341c803
--- /dev/null
+++ b/contrib/dtc/libfdt/Makefile.libfdt
@@ -0,0 +1,9 @@
+# Makefile.libfdt
+#
+# This is not a complete Makefile of itself. Instead, it is designed to
+# be easily embeddable into other systems of Makefiles.
+#
+LIBFDT_INCLUDES = fdt.h libfdt.h
+LIBFDT_VERSION = version.lds
+LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
+LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
diff --git a/contrib/dtc/libfdt/TODO b/contrib/dtc/libfdt/TODO
new file mode 100644
index 0000000..288437e
--- /dev/null
+++ b/contrib/dtc/libfdt/TODO
@@ -0,0 +1,3 @@
+- Tree traversal functions
+- Graft function
+- Complete libfdt.h documenting comments
diff --git a/contrib/dtc/libfdt/fdt.c b/contrib/dtc/libfdt/fdt.c
new file mode 100644
index 0000000..b1130c2
--- /dev/null
+++ b/contrib/dtc/libfdt/fdt.c
@@ -0,0 +1,213 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_check_header(const void *fdt)
+{
+ if (fdt_magic(fdt) == FDT_MAGIC) {
+ /* Complete tree */
+ if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+ return -FDT_ERR_BADVERSION;
+ if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
+ return -FDT_ERR_BADVERSION;
+ } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+ /* Unfinished sequential-write blob */
+ if (fdt_size_dt_struct(fdt) == 0)
+ return -FDT_ERR_BADSTATE;
+ } else {
+ return -FDT_ERR_BADMAGIC;
+ }
+
+ return 0;
+}
+
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
+{
+ const char *p;
+
+ if (fdt_version(fdt) >= 0x11)
+ if (((offset + len) < offset)
+ || ((offset + len) > fdt_size_dt_struct(fdt)))
+ return NULL;
+
+ p = _fdt_offset_ptr(fdt, offset);
+
+ if (p + len < p)
+ return NULL;
+ return p;
+}
+
+uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
+{
+ const uint32_t *tagp, *lenp;
+ uint32_t tag;
+ int offset = startoffset;
+ const char *p;
+
+ *nextoffset = -FDT_ERR_TRUNCATED;
+ tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
+ if (!tagp)
+ return FDT_END; /* premature end */
+ tag = fdt32_to_cpu(*tagp);
+ offset += FDT_TAGSIZE;
+
+ *nextoffset = -FDT_ERR_BADSTRUCTURE;
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ /* skip name */
+ do {
+ p = fdt_offset_ptr(fdt, offset++, 1);
+ } while (p && (*p != '\0'));
+ if (!p)
+ return FDT_END; /* premature end */
+ break;
+
+ case FDT_PROP:
+ lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
+ if (!lenp)
+ return FDT_END; /* premature end */
+ /* skip-name offset, length and value */
+ offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ + fdt32_to_cpu(*lenp);
+ break;
+
+ case FDT_END:
+ case FDT_END_NODE:
+ case FDT_NOP:
+ break;
+
+ default:
+ return FDT_END;
+ }
+
+ if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
+ return FDT_END; /* premature end */
+
+ *nextoffset = FDT_TAGALIGN(offset);
+ return tag;
+}
+
+int _fdt_check_node_offset(const void *fdt, int offset)
+{
+ if ((offset < 0) || (offset % FDT_TAGSIZE)
+ || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
+ return -FDT_ERR_BADOFFSET;
+
+ return offset;
+}
+
+int fdt_next_node(const void *fdt, int offset, int *depth)
+{
+ int nextoffset = 0;
+ uint32_t tag;
+
+ if (offset >= 0)
+ if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
+ return nextoffset;
+
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+ switch (tag) {
+ case FDT_PROP:
+ case FDT_NOP:
+ break;
+
+ case FDT_BEGIN_NODE:
+ if (depth)
+ (*depth)++;
+ break;
+
+ case FDT_END_NODE:
+ if (depth && ((--(*depth)) < 0))
+ return nextoffset;
+ break;
+
+ case FDT_END:
+ if ((nextoffset >= 0)
+ || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
+ return -FDT_ERR_NOTFOUND;
+ else
+ return nextoffset;
+ }
+ } while (tag != FDT_BEGIN_NODE);
+
+ return offset;
+}
+
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
+{
+ int len = strlen(s) + 1;
+ const char *last = strtab + tabsize - len;
+ const char *p;
+
+ for (p = strtab; p <= last; p++)
+ if (memcmp(p, s, len) == 0)
+ return p;
+ return NULL;
+}
+
+int fdt_move(const void *fdt, void *buf, int bufsize)
+{
+ FDT_CHECK_HEADER(fdt);
+
+ if (fdt_totalsize(fdt) > bufsize)
+ return -FDT_ERR_NOSPACE;
+
+ memmove(buf, fdt, fdt_totalsize(fdt));
+ return 0;
+}
diff --git a/contrib/dtc/libfdt/fdt.h b/contrib/dtc/libfdt/fdt.h
new file mode 100644
index 0000000..48ccfd9
--- /dev/null
+++ b/contrib/dtc/libfdt/fdt.h
@@ -0,0 +1,60 @@
+#ifndef _FDT_H
+#define _FDT_H
+
+#ifndef __ASSEMBLY__
+
+struct fdt_header {
+ uint32_t magic; /* magic word FDT_MAGIC */
+ uint32_t totalsize; /* total size of DT block */
+ uint32_t off_dt_struct; /* offset to structure */
+ uint32_t off_dt_strings; /* offset to strings */
+ uint32_t off_mem_rsvmap; /* offset to memory reserve map */
+ uint32_t version; /* format version */
+ uint32_t last_comp_version; /* last compatible version */
+
+ /* version 2 fields below */
+ uint32_t boot_cpuid_phys; /* Which physical CPU id we're
+ booting on */
+ /* version 3 fields below */
+ uint32_t size_dt_strings; /* size of the strings block */
+
+ /* version 17 fields below */
+ uint32_t size_dt_struct; /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+ uint64_t address;
+ uint64_t size;
+};
+
+struct fdt_node_header {
+ uint32_t tag;
+ char name[0];
+};
+
+struct fdt_property {
+ uint32_t tag;
+ uint32_t len;
+ uint32_t nameoff;
+ char data[0];
+};
+
+#endif /* !__ASSEMBLY */
+
+#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
+#define FDT_TAGSIZE sizeof(uint32_t)
+
+#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
+#define FDT_END_NODE 0x2 /* End node */
+#define FDT_PROP 0x3 /* Property: name off,
+ size, content */
+#define FDT_NOP 0x4 /* nop */
+#define FDT_END 0x9
+
+#define FDT_V1_SIZE (7*sizeof(uint32_t))
+#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t))
+#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t))
+#define FDT_V16_SIZE FDT_V3_SIZE
+#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t))
+
+#endif /* _FDT_H */
diff --git a/contrib/dtc/libfdt/fdt_ro.c b/contrib/dtc/libfdt/fdt_ro.c
new file mode 100644
index 0000000..951cc74
--- /dev/null
+++ b/contrib/dtc/libfdt/fdt_ro.c
@@ -0,0 +1,523 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_nodename_eq(const void *fdt, int offset,
+ const char *s, int len)
+{
+ const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
+
+ if (! p)
+ /* short match */
+ return 0;
+
+ if (memcmp(p, s, len) != 0)
+ return 0;
+
+ if (p[len] == '\0')
+ return 1;
+ else if (!memchr(s, '@', len) && (p[len] == '@'))
+ return 1;
+ else
+ return 0;
+}
+
+const char *fdt_string(const void *fdt, int stroffset)
+{
+ return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+}
+
+static int _fdt_string_eq(const void *fdt, int stroffset,
+ const char *s, int len)
+{
+ const char *p = fdt_string(fdt, stroffset);
+
+ return (strlen(p) == len) && (memcmp(p, s, len) == 0);
+}
+
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
+{
+ FDT_CHECK_HEADER(fdt);
+ *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
+ *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
+ return 0;
+}
+
+int fdt_num_mem_rsv(const void *fdt)
+{
+ int i = 0;
+
+ while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
+ i++;
+ return i;
+}
+
+int fdt_subnode_offset_namelen(const void *fdt, int offset,
+ const char *name, int namelen)
+{
+ int depth;
+
+ FDT_CHECK_HEADER(fdt);
+
+ for (depth = 0;
+ (offset >= 0) && (depth >= 0);
+ offset = fdt_next_node(fdt, offset, &depth))
+ if ((depth == 1)
+ && _fdt_nodename_eq(fdt, offset, name, namelen))
+ return offset;
+
+ if (depth < 0)
+ return -FDT_ERR_NOTFOUND;
+ return offset; /* error */
+}
+
+int fdt_subnode_offset(const void *fdt, int parentoffset,
+ const char *name)
+{
+ return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_path_offset(const void *fdt, const char *path)
+{
+ const char *end = path + strlen(path);
+ const char *p = path;
+ int offset = 0;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* see if we have an alias */
+ if (*path != '/') {
+ const char *q = strchr(path, '/');
+
+ if (!q)
+ q = end;
+
+ p = fdt_get_alias_namelen(fdt, p, q - p);
+ if (!p)
+ return -FDT_ERR_BADPATH;
+ offset = fdt_path_offset(fdt, p);
+
+ p = q;
+ }
+
+ while (*p) {
+ const char *q;
+
+ while (*p == '/')
+ p++;
+ if (! *p)
+ return offset;
+ q = strchr(p, '/');
+ if (! q)
+ q = end;
+
+ offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
+ if (offset < 0)
+ return offset;
+
+ p = q;
+ }
+
+ return offset;
+}
+
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
+{
+ const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
+ int err;
+
+ if (((err = fdt_check_header(fdt)) != 0)
+ || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+ goto fail;
+
+ if (len)
+ *len = strlen(nh->name);
+
+ return nh->name;
+
+ fail:
+ if (len)
+ *len = err;
+ return NULL;
+}
+
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+ int nodeoffset,
+ const char *name,
+ int namelen, int *lenp)
+{
+ uint32_t tag;
+ const struct fdt_property *prop;
+ int offset, nextoffset;
+ int err;
+
+ if (((err = fdt_check_header(fdt)) != 0)
+ || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+ goto fail;
+
+ nextoffset = err;
+ do {
+ offset = nextoffset;
+
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ switch (tag) {
+ case FDT_END:
+ if (nextoffset < 0)
+ err = nextoffset;
+ else
+ /* FDT_END tag with unclosed nodes */
+ err = -FDT_ERR_BADSTRUCTURE;
+ goto fail;
+
+ case FDT_PROP:
+ prop = _fdt_offset_ptr(fdt, offset);
+ if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
+ name, namelen)) {
+ /* Found it! */
+ if (lenp)
+ *lenp = fdt32_to_cpu(prop->len);
+
+ return prop;
+ }
+ break;
+ }
+ } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
+
+ err = -FDT_ERR_NOTFOUND;
+ fail:
+ if (lenp)
+ *lenp = err;
+ return NULL;
+}
+
+const struct fdt_property *fdt_get_property(const void *fdt,
+ int nodeoffset,
+ const char *name, int *lenp)
+{
+ return fdt_get_property_namelen(fdt, nodeoffset, name,
+ strlen(name), lenp);
+}
+
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+ const char *name, int namelen, int *lenp)
+{
+ const struct fdt_property *prop;
+
+ prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
+ if (! prop)
+ return NULL;
+
+ return prop->data;
+}
+
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+ const char *name, int *lenp)
+{
+ return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
+}
+
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
+{
+ const uint32_t *php;
+ int len;
+
+ /* FIXME: This is a bit sub-optimal, since we potentially scan
+ * over all the properties twice. */
+ php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
+ if (!php || (len != sizeof(*php))) {
+ php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
+ if (!php || (len != sizeof(*php)))
+ return 0;
+ }
+
+ return fdt32_to_cpu(*php);
+}
+
+const char *fdt_get_alias_namelen(const void *fdt,
+ const char *name, int namelen)
+{
+ int aliasoffset;
+
+ aliasoffset = fdt_path_offset(fdt, "/aliases");
+ if (aliasoffset < 0)
+ return NULL;
+
+ return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
+}
+
+const char *fdt_get_alias(const void *fdt, const char *name)
+{
+ return fdt_get_alias_namelen(fdt, name, strlen(name));
+}
+
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
+{
+ int pdepth = 0, p = 0;
+ int offset, depth, namelen;
+ const char *name;
+
+ FDT_CHECK_HEADER(fdt);
+
+ if (buflen < 2)
+ return -FDT_ERR_NOSPACE;
+
+ for (offset = 0, depth = 0;
+ (offset >= 0) && (offset <= nodeoffset);
+ offset = fdt_next_node(fdt, offset, &depth)) {
+ while (pdepth > depth) {
+ do {
+ p--;
+ } while (buf[p-1] != '/');
+ pdepth--;
+ }
+
+ if (pdepth >= depth) {
+ name = fdt_get_name(fdt, offset, &namelen);
+ if (!name)
+ return namelen;
+ if ((p + namelen + 1) <= buflen) {
+ memcpy(buf + p, name, namelen);
+ p += namelen;
+ buf[p++] = '/';
+ pdepth++;
+ }
+ }
+
+ if (offset == nodeoffset) {
+ if (pdepth < (depth + 1))
+ return -FDT_ERR_NOSPACE;
+
+ if (p > 1) /* special case so that root path is "/", not "" */
+ p--;
+ buf[p] = '\0';
+ return 0;
+ }
+ }
+
+ if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+ return -FDT_ERR_BADOFFSET;
+ else if (offset == -FDT_ERR_BADOFFSET)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ return offset; /* error from fdt_next_node() */
+}
+
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+ int supernodedepth, int *nodedepth)
+{
+ int offset, depth;
+ int supernodeoffset = -FDT_ERR_INTERNAL;
+
+ FDT_CHECK_HEADER(fdt);
+
+ if (supernodedepth < 0)
+ return -FDT_ERR_NOTFOUND;
+
+ for (offset = 0, depth = 0;
+ (offset >= 0) && (offset <= nodeoffset);
+ offset = fdt_next_node(fdt, offset, &depth)) {
+ if (depth == supernodedepth)
+ supernodeoffset = offset;
+
+ if (offset == nodeoffset) {
+ if (nodedepth)
+ *nodedepth = depth;
+
+ if (supernodedepth > depth)
+ return -FDT_ERR_NOTFOUND;
+ else
+ return supernodeoffset;
+ }
+ }
+
+ if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+ return -FDT_ERR_BADOFFSET;
+ else if (offset == -FDT_ERR_BADOFFSET)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_depth(const void *fdt, int nodeoffset)
+{
+ int nodedepth;
+ int err;
+
+ err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
+ if (err)
+ return (err < 0) ? err : -FDT_ERR_INTERNAL;
+ return nodedepth;
+}
+
+int fdt_parent_offset(const void *fdt, int nodeoffset)
+{
+ int nodedepth = fdt_node_depth(fdt, nodeoffset);
+
+ if (nodedepth < 0)
+ return nodedepth;
+ return fdt_supernode_atdepth_offset(fdt, nodeoffset,
+ nodedepth - 1, NULL);
+}
+
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+ const char *propname,
+ const void *propval, int proplen)
+{
+ int offset;
+ const void *val;
+ int len;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* FIXME: The algorithm here is pretty horrible: we scan each
+ * property of a node in fdt_getprop(), then if that didn't
+ * find what we want, we scan over them again making our way
+ * to the next node. Still it's the easiest to implement
+ * approach; performance can come later. */
+ for (offset = fdt_next_node(fdt, startoffset, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ val = fdt_getprop(fdt, offset, propname, &len);
+ if (val && (len == proplen)
+ && (memcmp(val, propval, len) == 0))
+ return offset;
+ }
+
+ return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
+{
+ int offset;
+
+ if ((phandle == 0) || (phandle == -1))
+ return -FDT_ERR_BADPHANDLE;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* FIXME: The algorithm here is pretty horrible: we
+ * potentially scan each property of a node in
+ * fdt_get_phandle(), then if that didn't find what
+ * we want, we scan over them again making our way to the next
+ * node. Still it's the easiest to implement approach;
+ * performance can come later. */
+ for (offset = fdt_next_node(fdt, -1, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ if (fdt_get_phandle(fdt, offset) == phandle)
+ return offset;
+ }
+
+ return offset; /* error from fdt_next_node() */
+}
+
+static int _fdt_stringlist_contains(const char *strlist, int listlen,
+ const char *str)
+{
+ int len = strlen(str);
+ const char *p;
+
+ while (listlen >= len) {
+ if (memcmp(str, strlist, len+1) == 0)
+ return 1;
+ p = memchr(strlist, '\0', listlen);
+ if (!p)
+ return 0; /* malformed strlist.. */
+ listlen -= (p-strlist) + 1;
+ strlist = p + 1;
+ }
+ return 0;
+}
+
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+ const char *compatible)
+{
+ const void *prop;
+ int len;
+
+ prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
+ if (!prop)
+ return len;
+ if (_fdt_stringlist_contains(prop, len, compatible))
+ return 0;
+ else
+ return 1;
+}
+
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+ const char *compatible)
+{
+ int offset, err;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* FIXME: The algorithm here is pretty horrible: we scan each
+ * property of a node in fdt_node_check_compatible(), then if
+ * that didn't find what we want, we scan over them again
+ * making our way to the next node. Still it's the easiest to
+ * implement approach; performance can come later. */
+ for (offset = fdt_next_node(fdt, startoffset, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ err = fdt_node_check_compatible(fdt, offset, compatible);
+ if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
+ return err;
+ else if (err == 0)
+ return offset;
+ }
+
+ return offset; /* error from fdt_next_node() */
+}
diff --git a/contrib/dtc/libfdt/fdt_rw.c b/contrib/dtc/libfdt/fdt_rw.c
new file mode 100644
index 0000000..994037b
--- /dev/null
+++ b/contrib/dtc/libfdt/fdt_rw.c
@@ -0,0 +1,465 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_blocks_misordered(const void *fdt,
+ int mem_rsv_size, int struct_size)
+{
+ return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
+ || (fdt_off_dt_struct(fdt) <
+ (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
+ || (fdt_off_dt_strings(fdt) <
+ (fdt_off_dt_struct(fdt) + struct_size))
+ || (fdt_totalsize(fdt) <
+ (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
+}
+
+static int _fdt_rw_check_header(void *fdt)
+{
+ FDT_CHECK_HEADER(fdt);
+
+ if (fdt_version(fdt) < 17)
+ return -FDT_ERR_BADVERSION;
+ if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
+ fdt_size_dt_struct(fdt)))
+ return -FDT_ERR_BADLAYOUT;
+ if (fdt_version(fdt) > 17)
+ fdt_set_version(fdt, 17);
+
+ return 0;
+}
+
+#define FDT_RW_CHECK_HEADER(fdt) \
+ { \
+ int err; \
+ if ((err = _fdt_rw_check_header(fdt)) != 0) \
+ return err; \
+ }
+
+static inline int _fdt_data_size(void *fdt)
+{
+ return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+}
+
+static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
+{
+ char *p = splicepoint;
+ char *end = (char *)fdt + _fdt_data_size(fdt);
+
+ if (((p + oldlen) < p) || ((p + oldlen) > end))
+ return -FDT_ERR_BADOFFSET;
+ if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
+ return -FDT_ERR_NOSPACE;
+ memmove(p + newlen, p + oldlen, end - p - oldlen);
+ return 0;
+}
+
+static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
+ int oldn, int newn)
+{
+ int delta = (newn - oldn) * sizeof(*p);
+ int err;
+ err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
+ if (err)
+ return err;
+ fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
+ fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+ return 0;
+}
+
+static int _fdt_splice_struct(void *fdt, void *p,
+ int oldlen, int newlen)
+{
+ int delta = newlen - oldlen;
+ int err;
+
+ if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
+ return err;
+
+ fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
+ fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+ return 0;
+}
+
+static int _fdt_splice_string(void *fdt, int newlen)
+{
+ void *p = (char *)fdt
+ + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+ int err;
+
+ if ((err = _fdt_splice(fdt, p, 0, newlen)))
+ return err;
+
+ fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
+ return 0;
+}
+
+static int _fdt_find_add_string(void *fdt, const char *s)
+{
+ char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
+ const char *p;
+ char *new;
+ int len = strlen(s) + 1;
+ int err;
+
+ p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
+ if (p)
+ /* found it */
+ return (p - strtab);
+
+ new = strtab + fdt_size_dt_strings(fdt);
+ err = _fdt_splice_string(fdt, len);
+ if (err)
+ return err;
+
+ memcpy(new, s, len);
+ return (new - strtab);
+}
+
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
+{
+ struct fdt_reserve_entry *re;
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
+ err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
+ if (err)
+ return err;
+
+ re->address = cpu_to_fdt64(address);
+ re->size = cpu_to_fdt64(size);
+ return 0;
+}
+
+int fdt_del_mem_rsv(void *fdt, int n)
+{
+ struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ if (n >= fdt_num_mem_rsv(fdt))
+ return -FDT_ERR_NOTFOUND;
+
+ err = _fdt_splice_mem_rsv(fdt, re, 1, 0);
+ if (err)
+ return err;
+ return 0;
+}
+
+static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
+ int len, struct fdt_property **prop)
+{
+ int oldlen;
+ int err;
+
+ *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+ if (! (*prop))
+ return oldlen;
+
+ if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
+ FDT_TAGALIGN(len))))
+ return err;
+
+ (*prop)->len = cpu_to_fdt32(len);
+ return 0;
+}
+
+static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
+ int len, struct fdt_property **prop)
+{
+ int proplen;
+ int nextoffset;
+ int namestroff;
+ int err;
+
+ if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+ return nextoffset;
+
+ namestroff = _fdt_find_add_string(fdt, name);
+ if (namestroff < 0)
+ return namestroff;
+
+ *prop = _fdt_offset_ptr_w(fdt, nextoffset);
+ proplen = sizeof(**prop) + FDT_TAGALIGN(len);
+
+ err = _fdt_splice_struct(fdt, *prop, 0, proplen);
+ if (err)
+ return err;
+
+ (*prop)->tag = cpu_to_fdt32(FDT_PROP);
+ (*prop)->nameoff = cpu_to_fdt32(namestroff);
+ (*prop)->len = cpu_to_fdt32(len);
+ return 0;
+}
+
+int fdt_set_name(void *fdt, int nodeoffset, const char *name)
+{
+ char *namep;
+ int oldlen, newlen;
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
+ if (!namep)
+ return oldlen;
+
+ newlen = strlen(name);
+
+ err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
+ FDT_TAGALIGN(newlen+1));
+ if (err)
+ return err;
+
+ memcpy(namep, name, newlen+1);
+ return 0;
+}
+
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ struct fdt_property *prop;
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
+ if (err == -FDT_ERR_NOTFOUND)
+ err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+ if (err)
+ return err;
+
+ memcpy(prop->data, val, len);
+ return 0;
+}
+
+int fdt_delprop(void *fdt, int nodeoffset, const char *name)
+{
+ struct fdt_property *prop;
+ int len, proplen;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+ if (! prop)
+ return len;
+
+ proplen = sizeof(*prop) + FDT_TAGALIGN(len);
+ return _fdt_splice_struct(fdt, prop, proplen, 0);
+}
+
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+ const char *name, int namelen)
+{
+ struct fdt_node_header *nh;
+ int offset, nextoffset;
+ int nodelen;
+ int err;
+ uint32_t tag;
+ uint32_t *endtag;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
+ if (offset >= 0)
+ return -FDT_ERR_EXISTS;
+ else if (offset != -FDT_ERR_NOTFOUND)
+ return offset;
+
+ /* Try to place the new node after the parent's properties */
+ fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ } while ((tag == FDT_PROP) || (tag == FDT_NOP));
+
+ nh = _fdt_offset_ptr_w(fdt, offset);
+ nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
+
+ err = _fdt_splice_struct(fdt, nh, 0, nodelen);
+ if (err)
+ return err;
+
+ nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+ memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
+ memcpy(nh->name, name, namelen);
+ endtag = (uint32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
+ *endtag = cpu_to_fdt32(FDT_END_NODE);
+
+ return offset;
+}
+
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
+{
+ return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_del_node(void *fdt, int nodeoffset)
+{
+ int endoffset;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+ if (endoffset < 0)
+ return endoffset;
+
+ return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
+ endoffset - nodeoffset, 0);
+}
+
+static void _fdt_packblocks(const char *old, char *new,
+ int mem_rsv_size, int struct_size)
+{
+ int mem_rsv_off, struct_off, strings_off;
+
+ mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
+ struct_off = mem_rsv_off + mem_rsv_size;
+ strings_off = struct_off + struct_size;
+
+ memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
+ fdt_set_off_mem_rsvmap(new, mem_rsv_off);
+
+ memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
+ fdt_set_off_dt_struct(new, struct_off);
+ fdt_set_size_dt_struct(new, struct_size);
+
+ memmove(new + strings_off, old + fdt_off_dt_strings(old),
+ fdt_size_dt_strings(old));
+ fdt_set_off_dt_strings(new, strings_off);
+ fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
+}
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize)
+{
+ int err;
+ int mem_rsv_size, struct_size;
+ int newsize;
+ const char *fdtstart = fdt;
+ const char *fdtend = fdtstart + fdt_totalsize(fdt);
+ char *tmp;
+
+ FDT_CHECK_HEADER(fdt);
+
+ mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+ * sizeof(struct fdt_reserve_entry);
+
+ if (fdt_version(fdt) >= 17) {
+ struct_size = fdt_size_dt_struct(fdt);
+ } else {
+ struct_size = 0;
+ while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
+ ;
+ if (struct_size < 0)
+ return struct_size;
+ }
+
+ if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
+ /* no further work necessary */
+ err = fdt_move(fdt, buf, bufsize);
+ if (err)
+ return err;
+ fdt_set_version(buf, 17);
+ fdt_set_size_dt_struct(buf, struct_size);
+ fdt_set_totalsize(buf, bufsize);
+ return 0;
+ }
+
+ /* Need to reorder */
+ newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+ + struct_size + fdt_size_dt_strings(fdt);
+
+ if (bufsize < newsize)
+ return -FDT_ERR_NOSPACE;
+
+ /* First attempt to build converted tree at beginning of buffer */
+ tmp = buf;
+ /* But if that overlaps with the old tree... */
+ if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
+ /* Try right after the old tree instead */
+ tmp = (char *)(uintptr_t)fdtend;
+ if ((tmp + newsize) > ((char *)buf + bufsize))
+ return -FDT_ERR_NOSPACE;
+ }
+
+ _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
+ memmove(buf, tmp, newsize);
+
+ fdt_set_magic(buf, FDT_MAGIC);
+ fdt_set_totalsize(buf, bufsize);
+ fdt_set_version(buf, 17);
+ fdt_set_last_comp_version(buf, 16);
+ fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
+
+ return 0;
+}
+
+int fdt_pack(void *fdt)
+{
+ int mem_rsv_size;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+ * sizeof(struct fdt_reserve_entry);
+ _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+ fdt_set_totalsize(fdt, _fdt_data_size(fdt));
+
+ return 0;
+}
diff --git a/contrib/dtc/libfdt/fdt_strerror.c b/contrib/dtc/libfdt/fdt_strerror.c
new file mode 100644
index 0000000..e6c3cee
--- /dev/null
+++ b/contrib/dtc/libfdt/fdt_strerror.c
@@ -0,0 +1,96 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+struct fdt_errtabent {
+ const char *str;
+};
+
+#define FDT_ERRTABENT(val) \
+ [(val)] = { .str = #val, }
+
+static struct fdt_errtabent fdt_errtable[] = {
+ FDT_ERRTABENT(FDT_ERR_NOTFOUND),
+ FDT_ERRTABENT(FDT_ERR_EXISTS),
+ FDT_ERRTABENT(FDT_ERR_NOSPACE),
+
+ FDT_ERRTABENT(FDT_ERR_BADOFFSET),
+ FDT_ERRTABENT(FDT_ERR_BADPATH),
+ FDT_ERRTABENT(FDT_ERR_BADSTATE),
+
+ FDT_ERRTABENT(FDT_ERR_TRUNCATED),
+ FDT_ERRTABENT(FDT_ERR_BADMAGIC),
+ FDT_ERRTABENT(FDT_ERR_BADVERSION),
+ FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
+ FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
+};
+#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
+
+const char *fdt_strerror(int errval)
+{
+ if (errval > 0)
+ return "<valid offset/length>";
+ else if (errval == 0)
+ return "<no error>";
+ else if (errval > -FDT_ERRTABSIZE) {
+ const char *s = fdt_errtable[-errval].str;
+
+ if (s)
+ return s;
+ }
+
+ return "<unknown error>";
+}
diff --git a/contrib/dtc/libfdt/fdt_sw.c b/contrib/dtc/libfdt/fdt_sw.c
new file mode 100644
index 0000000..55ebebf
--- /dev/null
+++ b/contrib/dtc/libfdt/fdt_sw.c
@@ -0,0 +1,256 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_sw_check_header(void *fdt)
+{
+ if (fdt_magic(fdt) != FDT_SW_MAGIC)
+ return -FDT_ERR_BADMAGIC;
+ /* FIXME: should check more details about the header state */
+ return 0;
+}
+
+#define FDT_SW_CHECK_HEADER(fdt) \
+ { \
+ int err; \
+ if ((err = _fdt_sw_check_header(fdt)) != 0) \
+ return err; \
+ }
+
+static void *_fdt_grab_space(void *fdt, size_t len)
+{
+ int offset = fdt_size_dt_struct(fdt);
+ int spaceleft;
+
+ spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
+ - fdt_size_dt_strings(fdt);
+
+ if ((offset + len < offset) || (offset + len > spaceleft))
+ return NULL;
+
+ fdt_set_size_dt_struct(fdt, offset + len);
+ return _fdt_offset_ptr_w(fdt, offset);
+}
+
+int fdt_create(void *buf, int bufsize)
+{
+ void *fdt = buf;
+
+ if (bufsize < sizeof(struct fdt_header))
+ return -FDT_ERR_NOSPACE;
+
+ memset(buf, 0, bufsize);
+
+ fdt_set_magic(fdt, FDT_SW_MAGIC);
+ fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+ fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+ fdt_set_totalsize(fdt, bufsize);
+
+ fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
+ sizeof(struct fdt_reserve_entry)));
+ fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
+ fdt_set_off_dt_strings(fdt, bufsize);
+
+ return 0;
+}
+
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
+{
+ struct fdt_reserve_entry *re;
+ int offset;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ if (fdt_size_dt_struct(fdt))
+ return -FDT_ERR_BADSTATE;
+
+ offset = fdt_off_dt_struct(fdt);
+ if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
+ return -FDT_ERR_NOSPACE;
+
+ re = (struct fdt_reserve_entry *)((char *)fdt + offset);
+ re->address = cpu_to_fdt64(addr);
+ re->size = cpu_to_fdt64(size);
+
+ fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
+
+ return 0;
+}
+
+int fdt_finish_reservemap(void *fdt)
+{
+ return fdt_add_reservemap_entry(fdt, 0, 0);
+}
+
+int fdt_begin_node(void *fdt, const char *name)
+{
+ struct fdt_node_header *nh;
+ int namelen = strlen(name) + 1;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
+ if (! nh)
+ return -FDT_ERR_NOSPACE;
+
+ nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+ memcpy(nh->name, name, namelen);
+ return 0;
+}
+
+int fdt_end_node(void *fdt)
+{
+ uint32_t *en;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ en = _fdt_grab_space(fdt, FDT_TAGSIZE);
+ if (! en)
+ return -FDT_ERR_NOSPACE;
+
+ *en = cpu_to_fdt32(FDT_END_NODE);
+ return 0;
+}
+
+static int _fdt_find_add_string(void *fdt, const char *s)
+{
+ char *strtab = (char *)fdt + fdt_totalsize(fdt);
+ const char *p;
+ int strtabsize = fdt_size_dt_strings(fdt);
+ int len = strlen(s) + 1;
+ int struct_top, offset;
+
+ p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
+ if (p)
+ return p - strtab;
+
+ /* Add it */
+ offset = -strtabsize - len;
+ struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+ if (fdt_totalsize(fdt) + offset < struct_top)
+ return 0; /* no more room :( */
+
+ memcpy(strtab + offset, s, len);
+ fdt_set_size_dt_strings(fdt, strtabsize + len);
+ return offset;
+}
+
+int fdt_property(void *fdt, const char *name, const void *val, int len)
+{
+ struct fdt_property *prop;
+ int nameoff;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ nameoff = _fdt_find_add_string(fdt, name);
+ if (nameoff == 0)
+ return -FDT_ERR_NOSPACE;
+
+ prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
+ if (! prop)
+ return -FDT_ERR_NOSPACE;
+
+ prop->tag = cpu_to_fdt32(FDT_PROP);
+ prop->nameoff = cpu_to_fdt32(nameoff);
+ prop->len = cpu_to_fdt32(len);
+ memcpy(prop->data, val, len);
+ return 0;
+}
+
+int fdt_finish(void *fdt)
+{
+ char *p = (char *)fdt;
+ uint32_t *end;
+ int oldstroffset, newstroffset;
+ uint32_t tag;
+ int offset, nextoffset;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ /* Add terminator */
+ end = _fdt_grab_space(fdt, sizeof(*end));
+ if (! end)
+ return -FDT_ERR_NOSPACE;
+ *end = cpu_to_fdt32(FDT_END);
+
+ /* Relocate the string table */
+ oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
+ newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+ memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
+ fdt_set_off_dt_strings(fdt, newstroffset);
+
+ /* Walk the structure, correcting string offsets */
+ offset = 0;
+ while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
+ if (tag == FDT_PROP) {
+ struct fdt_property *prop =
+ _fdt_offset_ptr_w(fdt, offset);
+ int nameoff;
+
+ nameoff = fdt32_to_cpu(prop->nameoff);
+ nameoff += fdt_size_dt_strings(fdt);
+ prop->nameoff = cpu_to_fdt32(nameoff);
+ }
+ offset = nextoffset;
+ }
+ if (nextoffset < 0)
+ return nextoffset;
+
+ /* Finally, adjust the header */
+ fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+ fdt_set_magic(fdt, FDT_MAGIC);
+ return 0;
+}
diff --git a/contrib/dtc/libfdt/fdt_wip.c b/contrib/dtc/libfdt/fdt_wip.c
new file mode 100644
index 0000000..6025fa1
--- /dev/null
+++ b/contrib/dtc/libfdt/fdt_wip.c
@@ -0,0 +1,118 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ void *propval;
+ int proplen;
+
+ propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
+ if (! propval)
+ return proplen;
+
+ if (proplen != len)
+ return -FDT_ERR_NOSPACE;
+
+ memcpy(propval, val, len);
+ return 0;
+}
+
+static void _fdt_nop_region(void *start, int len)
+{
+ uint32_t *p;
+
+ for (p = start; (char *)p < ((char *)start + len); p++)
+ *p = cpu_to_fdt32(FDT_NOP);
+}
+
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
+{
+ struct fdt_property *prop;
+ int len;
+
+ prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+ if (! prop)
+ return len;
+
+ _fdt_nop_region(prop, len + sizeof(*prop));
+
+ return 0;
+}
+
+int _fdt_node_end_offset(void *fdt, int offset)
+{
+ int depth = 0;
+
+ while ((offset >= 0) && (depth >= 0))
+ offset = fdt_next_node(fdt, offset, &depth);
+
+ return offset;
+}
+
+int fdt_nop_node(void *fdt, int nodeoffset)
+{
+ int endoffset;
+
+ endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+ if (endoffset < 0)
+ return endoffset;
+
+ _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
+ endoffset - nodeoffset);
+ return 0;
+}
diff --git a/contrib/dtc/libfdt/libfdt.h b/contrib/dtc/libfdt/libfdt.h
new file mode 100644
index 0000000..18de52b
--- /dev/null
+++ b/contrib/dtc/libfdt/libfdt.h
@@ -0,0 +1,1132 @@
+#ifndef _LIBFDT_H
+#define _LIBFDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 <libfdt_env.h>
+#include <fdt.h>
+
+#define FDT_FIRST_SUPPORTED_VERSION 0x10
+#define FDT_LAST_SUPPORTED_VERSION 0x11
+
+/* Error codes: informative error codes */
+#define FDT_ERR_NOTFOUND 1
+ /* FDT_ERR_NOTFOUND: The requested node or property does not exist */
+#define FDT_ERR_EXISTS 2
+ /* FDT_ERR_EXISTS: Attemped to create a node or property which
+ * already exists */
+#define FDT_ERR_NOSPACE 3
+ /* FDT_ERR_NOSPACE: Operation needed to expand the device
+ * tree, but its buffer did not have sufficient space to
+ * contain the expanded tree. Use fdt_open_into() to move the
+ * device tree to a buffer with more space. */
+
+/* Error codes: codes for bad parameters */
+#define FDT_ERR_BADOFFSET 4
+ /* FDT_ERR_BADOFFSET: Function was passed a structure block
+ * offset which is out-of-bounds, or which points to an
+ * unsuitable part of the structure for the operation. */
+#define FDT_ERR_BADPATH 5
+ /* FDT_ERR_BADPATH: Function was passed a badly formatted path
+ * (e.g. missing a leading / for a function which requires an
+ * absolute path) */
+#define FDT_ERR_BADPHANDLE 6
+ /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle
+ * value. phandle values of 0 and -1 are not permitted. */
+#define FDT_ERR_BADSTATE 7
+ /* FDT_ERR_BADSTATE: Function was passed an incomplete device
+ * tree created by the sequential-write functions, which is
+ * not sufficiently complete for the requested operation. */
+
+/* Error codes: codes for bad device tree blobs */
+#define FDT_ERR_TRUNCATED 8
+ /* FDT_ERR_TRUNCATED: Structure block of the given device tree
+ * ends without an FDT_END tag. */
+#define FDT_ERR_BADMAGIC 9
+ /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
+ * device tree at all - it is missing the flattened device
+ * tree magic number. */
+#define FDT_ERR_BADVERSION 10
+ /* FDT_ERR_BADVERSION: Given device tree has a version which
+ * can't be handled by the requested operation. For
+ * read-write functions, this may mean that fdt_open_into() is
+ * required to convert the tree to the expected version. */
+#define FDT_ERR_BADSTRUCTURE 11
+ /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
+ * structure block or other serious error (e.g. misnested
+ * nodes, or subnodes preceding properties). */
+#define FDT_ERR_BADLAYOUT 12
+ /* FDT_ERR_BADLAYOUT: For read-write functions, the given
+ * device tree has it's sub-blocks in an order that the
+ * function can't handle (memory reserve map, then structure,
+ * then strings). Use fdt_open_into() to reorganize the tree
+ * into a form suitable for the read-write operations. */
+
+/* "Can't happen" error indicating a bug in libfdt */
+#define FDT_ERR_INTERNAL 13
+ /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
+ * Should never be returned, if it is, it indicates a bug in
+ * libfdt itself. */
+
+#define FDT_ERR_MAX 13
+
+/**********************************************************************/
+/* Low-level functions (you probably don't need these) */
+/**********************************************************************/
+
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
+static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
+{
+ return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
+
+/**********************************************************************/
+/* Traversal functions */
+/**********************************************************************/
+
+int fdt_next_node(const void *fdt, int offset, int *depth);
+
+/**********************************************************************/
+/* General functions */
+/**********************************************************************/
+
+#define fdt_get_header(fdt, field) \
+ (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
+#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
+#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
+#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings))
+#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap))
+#define fdt_version(fdt) (fdt_get_header(fdt, version))
+#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys))
+#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
+#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct))
+
+#define __fdt_set_hdr(name) \
+ static inline void fdt_set_##name(void *fdt, uint32_t val) \
+ { \
+ struct fdt_header *fdth = (struct fdt_header*)fdt; \
+ fdth->name = cpu_to_fdt32(val); \
+ }
+__fdt_set_hdr(magic);
+__fdt_set_hdr(totalsize);
+__fdt_set_hdr(off_dt_struct);
+__fdt_set_hdr(off_dt_strings);
+__fdt_set_hdr(off_mem_rsvmap);
+__fdt_set_hdr(version);
+__fdt_set_hdr(last_comp_version);
+__fdt_set_hdr(boot_cpuid_phys);
+__fdt_set_hdr(size_dt_strings);
+__fdt_set_hdr(size_dt_struct);
+#undef __fdt_set_hdr
+
+/**
+ * fdt_check_header - sanity check a device tree or possible device tree
+ * @fdt: pointer to data which might be a flattened device tree
+ *
+ * fdt_check_header() checks that the given buffer contains what
+ * appears to be a flattened device tree with sane information in its
+ * header.
+ *
+ * returns:
+ * 0, if the buffer appears to contain a valid device tree
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings, as above
+ */
+int fdt_check_header(const void *fdt);
+
+/**
+ * fdt_move - move a device tree around in memory
+ * @fdt: pointer to the device tree to move
+ * @buf: pointer to memory where the device is to be moved
+ * @bufsize: size of the memory space at buf
+ *
+ * fdt_move() relocates, if possible, the device tree blob located at
+ * fdt to the buffer at buf of size bufsize. The buffer may overlap
+ * with the existing device tree blob at fdt. Therefore,
+ * fdt_move(fdt, fdt, fdt_totalsize(fdt))
+ * should always succeed.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_move(const void *fdt, void *buf, int bufsize);
+
+/**********************************************************************/
+/* Read-only functions */
+/**********************************************************************/
+
+/**
+ * fdt_string - retrieve a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ *
+ * fdt_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt.
+ *
+ * returns:
+ * a pointer to the string, on success
+ * NULL, if stroffset is out of bounds
+ */
+const char *fdt_string(const void *fdt, int stroffset);
+
+/**
+ * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
+ * @fdt: pointer to the device tree blob
+ *
+ * Returns the number of entries in the device tree blob's memory
+ * reservation map. This does not include the terminating 0,0 entry
+ * or any other (0,0) entries reserved for expansion.
+ *
+ * returns:
+ * the number of entries
+ */
+int fdt_num_mem_rsv(const void *fdt);
+
+/**
+ * fdt_get_mem_rsv - retrieve one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: pointers to 64-bit variables
+ *
+ * On success, *address and *size will contain the address and size of
+ * the n-th reserve map entry from the device tree blob, in
+ * native-endian format.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
+
+/**
+ * fdt_subnode_offset_namelen - find a subnode based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_subnode_offset(), but only examine the first
+ * namelen characters of name for matching the subnode name. This is
+ * useful for finding subnodes based on a portion of a larger string,
+ * such as a full path.
+ */
+int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+ const char *name, int namelen);
+/**
+ * fdt_subnode_offset - find a subnode of a given node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node at structure block
+ * offset parentoffset with the given name. name may include a unit
+ * address, in which case fdt_subnode_offset() will find the subnode
+ * with that unit address, or the unit address may be omitted, in
+ * which case fdt_subnode_offset() will find an arbitrary subnode
+ * whose name excluding unit address matches the given name.
+ *
+ * returns:
+ * structure block offset of the requested subnode (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_path_offset - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ *
+ * fdt_path_offset() finds a node of a given path in the device tree.
+ * Each path component may omit the unit address portion, but the
+ * results of this are undefined if any such path component is
+ * ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit
+ * address).
+ *
+ * returns:
+ * structure block offset of the node with the requested path (>=0), on success
+ * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ * -FDT_ERR_NOTFOUND, if the requested node does not exist
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_path_offset(const void *fdt, const char *path);
+
+/**
+ * fdt_get_name - retrieve the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the starting node
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_name() retrieves the name (including unit address) of the
+ * device tree node at structure block offset nodeoffset. If lenp is
+ * non-NULL, the length of this name is also returned, in the integer
+ * pointed to by lenp.
+ *
+ * returns:
+ * pointer to the node's name, on success
+ * If lenp is non-NULL, *lenp contains the length of that name (>=0)
+ * NULL, on error
+ * if lenp is non-NULL *lenp contains an error code (<0):
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
+
+/**
+ * fdt_get_property_namelen - find a property based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_get_property_namelen(), but only examine the first
+ * namelen characters of name for matching the property name.
+ */
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+ int nodeoffset,
+ const char *name,
+ int namelen, int *lenp);
+
+/**
+ * fdt_get_property - find a given property in a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property() retrieves a pointer to the fdt_property
+ * structure within the device tree blob corresponding to the property
+ * named 'name' of the node at offset nodeoffset. If lenp is
+ * non-NULL, the length of the property value is also returned, in the
+ * integer pointed to by lenp.
+ *
+ * returns:
+ * pointer to the structure representing the property
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_NOTFOUND, node does not have named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset,
+ const char *name, int *lenp);
+static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
+ const char *name,
+ int *lenp)
+{
+ return (struct fdt_property *)(uintptr_t)
+ fdt_get_property(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_getprop_namelen - get property value based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_getprop(), but only examine the first namelen
+ * characters of name for matching the property name.
+ */
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+ const char *name, int namelen, int *lenp);
+
+/**
+ * fdt_getprop - retrieve the value of a given property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ * pointer to the property's value
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_NOTFOUND, node does not have named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+ const char *name, int *lenp);
+static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
+ const char *name, int *lenp)
+{
+ return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_get_phandle - retrieve the phandle of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the node
+ *
+ * fdt_get_phandle() retrieves the phandle of the device tree node at
+ * structure block offset nodeoffset.
+ *
+ * returns:
+ * the phandle of the node at nodeoffset, on success (!= 0, != -1)
+ * 0, if the node has no phandle, or another error occurs
+ */
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_get_alias_namelen - get alias based on substring
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_get_alias(), but only examine the first namelen
+ * characters of name for matching the alias name.
+ */
+const char *fdt_get_alias_namelen(const void *fdt,
+ const char *name, int namelen);
+
+/**
+ * fdt_get_alias - retreive the path referenced by a given alias
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ *
+ * fdt_get_alias() retrieves the value of a given alias. That is, the
+ * value of the property named 'name' in the node /aliases.
+ *
+ * returns:
+ * a pointer to the expansion of the alias named 'name', of it exists
+ * NULL, if the given alias or the /aliases node does not exist
+ */
+const char *fdt_get_alias(const void *fdt, const char *name);
+
+/**
+ * fdt_get_path - determine the full path of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose path to find
+ * @buf: character buffer to contain the returned path (will be overwritten)
+ * @buflen: size of the character buffer at buf
+ *
+ * fdt_get_path() computes the full path of the node at offset
+ * nodeoffset, and records that path in the buffer at buf.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ * 0, on success
+ * buf contains the absolute path of the node at
+ * nodeoffset, as a NUL-terminated string.
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
+ * characters and will not fit in the given buffer.
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
+
+/**
+ * fdt_supernode_atdepth_offset - find a specific ancestor of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ * @supernodedepth: depth of the ancestor to find
+ * @nodedepth: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_supernode_atdepth_offset() finds an ancestor of the given node
+ * at a specific depth from the root (where the root itself has depth
+ * 0, its immediate subnodes depth 1 and so forth). So
+ * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL);
+ * will always return 0, the offset of the root node. If the node at
+ * nodeoffset has depth D, then:
+ * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL);
+ * will return nodeoffset itself.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+
+ * structure block offset of the node at node offset's ancestor
+ * of depth supernodedepth (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+ int supernodedepth, int *nodedepth);
+
+/**
+ * fdt_node_depth - find the depth of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_node_depth() finds the depth of a given node. The root node
+ * has depth 0, its immediate subnodes depth 1 and so forth.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ * depth of the node at nodeoffset (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_depth(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_parent_offset - find the parent of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_parent_offset() locates the parent node of a given node (that
+ * is, it finds the offset of the node which contains the node at
+ * nodeoffset as a subnode).
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset, *twice*.
+ *
+ * returns:
+ * structure block offset of the parent of the node at nodeoffset
+ * (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_parent_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_node_offset_by_prop_value - find nodes with a given property value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the first
+ * node after startoffset, which has a property named propname whose
+ * value is of length proplen and has value equal to propval; or if
+ * startoffset is -1, the very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ * offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
+ * propval, proplen);
+ * while (offset != -FDT_ERR_NOTFOUND) {
+ * // other code here
+ * offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
+ * propval, proplen);
+ * }
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0, >startoffset),
+ * on success
+ * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ * tree after startoffset
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+ const char *propname,
+ const void *propval, int proplen);
+
+/**
+ * fdt_node_offset_by_phandle - find the node with a given phandle
+ * @fdt: pointer to the device tree blob
+ * @phandle: phandle value
+ *
+ * fdt_node_offset_by_phandle() returns the offset of the node
+ * which has the given phandle value. If there is more than one node
+ * in the tree with the given phandle (an invalid tree), results are
+ * undefined.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0), on success
+ * -FDT_ERR_NOTFOUND, no node with that phandle exists
+ * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1)
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
+
+/**
+ * fdt_node_check_compatible: check a node's compatible property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @compatible: string to match against
+ *
+ *
+ * fdt_node_check_compatible() returns 0 if the given node contains a
+ * 'compatible' property with the given string as one of its elements,
+ * it returns non-zero otherwise, or on error.
+ *
+ * returns:
+ * 0, if the node has a 'compatible' property listing the given string
+ * 1, if the node has a 'compatible' property, but it does not list
+ * the given string
+ * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
+ * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+ const char *compatible);
+
+/**
+ * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @compatible: 'compatible' string to match against
+ *
+ * fdt_node_offset_by_compatible() returns the offset of the first
+ * node after startoffset, which has a 'compatible' property which
+ * lists the given compatible string; or if startoffset is -1, the
+ * very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ * offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ * while (offset != -FDT_ERR_NOTFOUND) {
+ * // other code here
+ * offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
+ * }
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0, >startoffset),
+ * on success
+ * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ * tree after startoffset
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+ const char *compatible);
+
+/**********************************************************************/
+/* Write-in-place functions */
+/**********************************************************************/
+
+/**
+ * fdt_setprop_inplace - change a property's value, but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * fdt_setprop_inplace() replaces the value of a given property with
+ * the data in val, of length len. This function cannot change the
+ * size of a property, and so will only work if len is equal to the
+ * current length of the property.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if len is not equal to the property's current length
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len);
+
+/**
+ * fdt_setprop_inplace_cell - change the value of a single-cell property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: cell (32-bit integer) value to replace the property with
+ *
+ * fdt_setprop_inplace_cell() replaces the value of a given property
+ * with the 32-bit integer cell value in val, converting val to
+ * big-endian if necessary. This function cannot change the size of a
+ * property, and so will only work if the property already exists and
+ * has length 4.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if the property's length is not equal to 4
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
+ const char *name, uint32_t val)
+{
+ val = cpu_to_fdt32(val);
+ return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_nop_property - replace a property with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_nop_property() will replace a given property's representation
+ * in the blob with FDT_NOP tags, effectively removing it from the
+ * tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the property, and will not alter or move any other part of the
+ * tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_nop_node - replace a node (subtree) with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_nop_node() will replace a given node's representation in the
+ * blob, including all its subnodes, if any, with FDT_NOP tags,
+ * effectively removing it from the tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the node and its properties and subnodes, and will not alter or
+ * move any other part of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Sequential write functions */
+/**********************************************************************/
+
+int fdt_create(void *buf, int bufsize);
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
+int fdt_finish_reservemap(void *fdt);
+int fdt_begin_node(void *fdt, const char *name);
+int fdt_property(void *fdt, const char *name, const void *val, int len);
+static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
+{
+ val = cpu_to_fdt32(val);
+ return fdt_property(fdt, name, &val, sizeof(val));
+}
+#define fdt_property_string(fdt, name, str) \
+ fdt_property(fdt, name, str, strlen(str)+1)
+int fdt_end_node(void *fdt);
+int fdt_finish(void *fdt);
+
+/**********************************************************************/
+/* Read-write functions */
+/**********************************************************************/
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize);
+int fdt_pack(void *fdt);
+
+/**
+ * fdt_add_mem_rsv - add one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: 64-bit values (native endian)
+ *
+ * Adds a reserve map entry to the given blob reserving a region at
+ * address address of length size.
+ *
+ * This function will insert data into the reserve map and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new reservation entry
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size);
+
+/**
+ * fdt_del_mem_rsv - remove a memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @n: entry to remove
+ *
+ * fdt_del_mem_rsv() removes the n-th memory reserve map entry from
+ * the blob.
+ *
+ * This function will delete data from the reservation table and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
+ * are less than n+1 reserve map entries)
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_mem_rsv(void *fdt, int n);
+
+/**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string. NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ * to contain the new name
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_setprop - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len);
+
+/**
+ * fdt_setprop_cell - set a property to a single cell value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_cell() sets the value of the named property in the
+ * given node to the given cell value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
+ uint32_t val)
+{
+ val = cpu_to_fdt32(val);
+ return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_setprop_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value for the property
+ *
+ * fdt_setprop_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_string(fdt, nodeoffset, name, str) \
+ fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_delprop - delete a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_del_property() will delete the given property.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_delprop(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_add_subnode_namelen - creates a new node based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_add_subnode(), but use only the first namelen
+ * characters of name as the name of the new node. This is useful for
+ * creating subnodes based on a portion of a larger string, such as a
+ * full path.
+ */
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+ const char *name, int namelen);
+
+/**
+ * fdt_add_subnode - creates a new node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_add_subnode() creates a new node as a subnode of the node at
+ * structure block offset parentoffset, with the given name (which
+ * should include the unit address, if any).
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+
+ * returns:
+ * structure block offset of the created nodeequested subnode (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ * the given name
+ * -FDT_ERR_NOSPACE, if there is insufficient free space in the
+ * blob to contain the new node
+ * -FDT_ERR_NOSPACE
+ * -FDT_ERR_BADLAYOUT
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_del_node - delete a node (subtree)
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_del_node() will remove the given node, including all its
+ * subnodes if any, from the blob.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Debugging / informational functions */
+/**********************************************************************/
+
+const char *fdt_strerror(int errval);
+
+#endif /* _LIBFDT_H */
diff --git a/contrib/dtc/libfdt/libfdt_env.h b/contrib/dtc/libfdt/libfdt_env.h
new file mode 100644
index 0000000..449bf60
--- /dev/null
+++ b/contrib/dtc/libfdt/libfdt_env.h
@@ -0,0 +1,23 @@
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#define _B(n) ((unsigned long long)((uint8_t *)&x)[n])
+static inline uint32_t fdt32_to_cpu(uint32_t x)
+{
+ return (_B(0) << 24) | (_B(1) << 16) | (_B(2) << 8) | _B(3);
+}
+#define cpu_to_fdt32(x) fdt32_to_cpu(x)
+
+static inline uint64_t fdt64_to_cpu(uint64_t x)
+{
+ return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32)
+ | (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7);
+}
+#define cpu_to_fdt64(x) fdt64_to_cpu(x)
+#undef _B
+
+#endif /* _LIBFDT_ENV_H */
diff --git a/contrib/dtc/libfdt/libfdt_internal.h b/contrib/dtc/libfdt/libfdt_internal.h
new file mode 100644
index 0000000..d2dcbd6
--- /dev/null
+++ b/contrib/dtc/libfdt/libfdt_internal.h
@@ -0,0 +1,94 @@
+#ifndef _LIBFDT_INTERNAL_H
+#define _LIBFDT_INTERNAL_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 <fdt.h>
+
+#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
+#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
+
+#define FDT_CHECK_HEADER(fdt) \
+ { \
+ int err; \
+ if ((err = fdt_check_header(fdt)) != 0) \
+ return err; \
+ }
+
+int _fdt_check_node_offset(const void *fdt, int offset);
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
+int _fdt_node_end_offset(void *fdt, int nodeoffset);
+
+static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
+{
+ return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
+}
+
+static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
+{
+ return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
+}
+
+static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
+{
+ const struct fdt_reserve_entry *rsv_table =
+ (const struct fdt_reserve_entry *)
+ ((const char *)fdt + fdt_off_mem_rsvmap(fdt));
+
+ return rsv_table + n;
+}
+static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
+{
+ return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
+}
+
+#define FDT_SW_MAGIC (~FDT_MAGIC)
+
+#endif /* _LIBFDT_INTERNAL_H */
diff --git a/contrib/dtc/libfdt/version.lds b/contrib/dtc/libfdt/version.lds
new file mode 100644
index 0000000..3c3994e
--- /dev/null
+++ b/contrib/dtc/libfdt/version.lds
@@ -0,0 +1,54 @@
+LIBFDT_1.2 {
+ global:
+ fdt_next_node;
+ fdt_check_header;
+ fdt_move;
+ fdt_string;
+ fdt_num_mem_rsv;
+ fdt_get_mem_rsv;
+ fdt_subnode_offset_namelen;
+ fdt_subnode_offset;
+ fdt_path_offset;
+ fdt_get_name;
+ fdt_get_property_namelen;
+ fdt_get_property;
+ fdt_getprop_namelen;
+ fdt_getprop;
+ fdt_get_phandle;
+ fdt_get_alias_namelen;
+ fdt_get_alias;
+ fdt_get_path;
+ fdt_supernode_atdepth_offset;
+ fdt_node_depth;
+ fdt_parent_offset;
+ fdt_node_offset_by_prop_value;
+ fdt_node_offset_by_phandle;
+ fdt_node_check_compatible;
+ fdt_node_offset_by_compatible;
+ fdt_setprop_inplace;
+ fdt_nop_property;
+ fdt_nop_node;
+ fdt_create;
+ fdt_add_reservemap_entry;
+ fdt_finish_reservemap;
+ fdt_begin_node;
+ fdt_property;
+ fdt_end_node;
+ fdt_finish;
+ fdt_open_into;
+ fdt_pack;
+ fdt_add_mem_rsv;
+ fdt_del_mem_rsv;
+ fdt_set_name;
+ fdt_setprop;
+ fdt_delprop;
+ fdt_add_subnode_namelen;
+ fdt_add_subnode;
+ fdt_del_node;
+ fdt_strerror;
+ fdt_offset_ptr;
+ fdt_next_tag;
+
+ local:
+ *;
+};
diff --git a/contrib/dtc/livetree.c b/contrib/dtc/livetree.c
new file mode 100644
index 0000000..9a482a8
--- /dev/null
+++ b/contrib/dtc/livetree.c
@@ -0,0 +1,320 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "dtc.h"
+
+/*
+ * Tree building functions
+ */
+
+struct property *build_property(char *name, struct data val, char *label)
+{
+ struct property *new = xmalloc(sizeof(*new));
+
+ new->name = name;
+ new->val = val;
+
+ new->next = NULL;
+
+ new->label = label;
+
+ return new;
+}
+
+struct property *chain_property(struct property *first, struct property *list)
+{
+ assert(first->next == NULL);
+
+ first->next = list;
+ return first;
+}
+
+struct property *reverse_properties(struct property *first)
+{
+ struct property *p = first;
+ struct property *head = NULL;
+ struct property *next;
+
+ while (p) {
+ next = p->next;
+ p->next = head;
+ head = p;
+ p = next;
+ }
+ return head;
+}
+
+struct node *build_node(struct property *proplist, struct node *children)
+{
+ struct node *new = xmalloc(sizeof(*new));
+ struct node *child;
+
+ memset(new, 0, sizeof(*new));
+
+ new->proplist = reverse_properties(proplist);
+ new->children = children;
+
+ for_each_child(new, child) {
+ child->parent = new;
+ }
+
+ return new;
+}
+
+struct node *name_node(struct node *node, char *name, char * label)
+{
+ assert(node->name == NULL);
+
+ node->name = name;
+
+ node->label = label;
+
+ return node;
+}
+
+struct node *chain_node(struct node *first, struct node *list)
+{
+ assert(first->next_sibling == NULL);
+
+ first->next_sibling = list;
+ return first;
+}
+
+void add_property(struct node *node, struct property *prop)
+{
+ struct property **p;
+
+ prop->next = NULL;
+
+ p = &node->proplist;
+ while (*p)
+ p = &((*p)->next);
+
+ *p = prop;
+}
+
+void add_child(struct node *parent, struct node *child)
+{
+ struct node **p;
+
+ child->next_sibling = NULL;
+ child->parent = parent;
+
+ p = &parent->children;
+ while (*p)
+ p = &((*p)->next_sibling);
+
+ *p = child;
+}
+
+struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size,
+ char *label)
+{
+ struct reserve_info *new = xmalloc(sizeof(*new));
+
+ new->re.address = address;
+ new->re.size = size;
+
+ new->next = NULL;
+
+ new->label = label;
+
+ return new;
+}
+
+struct reserve_info *chain_reserve_entry(struct reserve_info *first,
+ struct reserve_info *list)
+{
+ assert(first->next == NULL);
+
+ first->next = list;
+ return first;
+}
+
+struct reserve_info *add_reserve_entry(struct reserve_info *list,
+ struct reserve_info *new)
+{
+ struct reserve_info *last;
+
+ new->next = NULL;
+
+ if (! list)
+ return new;
+
+ for (last = list; last->next; last = last->next)
+ ;
+
+ last->next = new;
+
+ return list;
+}
+
+struct boot_info *build_boot_info(struct reserve_info *reservelist,
+ struct node *tree, uint32_t boot_cpuid_phys)
+{
+ struct boot_info *bi;
+
+ bi = xmalloc(sizeof(*bi));
+ bi->reservelist = reservelist;
+ bi->dt = tree;
+ bi->boot_cpuid_phys = boot_cpuid_phys;
+
+ return bi;
+}
+
+/*
+ * Tree accessor functions
+ */
+
+const char *get_unitname(struct node *node)
+{
+ if (node->name[node->basenamelen] == '\0')
+ return "";
+ else
+ return node->name + node->basenamelen + 1;
+}
+
+struct property *get_property(struct node *node, const char *propname)
+{
+ struct property *prop;
+
+ for_each_property(node, prop)
+ if (streq(prop->name, propname))
+ return prop;
+
+ return NULL;
+}
+
+cell_t propval_cell(struct property *prop)
+{
+ assert(prop->val.len == sizeof(cell_t));
+ return fdt32_to_cpu(*((cell_t *)prop->val.val));
+}
+
+struct node *get_subnode(struct node *node, const char *nodename)
+{
+ struct node *child;
+
+ for_each_child(node, child)
+ if (streq(child->name, nodename))
+ return child;
+
+ return NULL;
+}
+
+struct node *get_node_by_path(struct node *tree, const char *path)
+{
+ const char *p;
+ struct node *child;
+
+ if (!path || ! (*path))
+ return tree;
+
+ while (path[0] == '/')
+ path++;
+
+ p = strchr(path, '/');
+
+ for_each_child(tree, child) {
+ if (p && strneq(path, child->name, p-path))
+ return get_node_by_path(child, p+1);
+ else if (!p && streq(path, child->name))
+ return child;
+ }
+
+ return NULL;
+}
+
+struct node *get_node_by_label(struct node *tree, const char *label)
+{
+ struct node *child, *node;
+
+ assert(label && (strlen(label) > 0));
+
+ if (tree->label && streq(tree->label, label))
+ return tree;
+
+ for_each_child(tree, child) {
+ node = get_node_by_label(child, label);
+ if (node)
+ return node;
+ }
+
+ return NULL;
+}
+
+struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
+{
+ struct node *child, *node;
+
+ assert((phandle != 0) && (phandle != -1));
+
+ if (tree->phandle == phandle)
+ return tree;
+
+ for_each_child(tree, child) {
+ node = get_node_by_phandle(child, phandle);
+ if (node)
+ return node;
+ }
+
+ return NULL;
+}
+
+struct node *get_node_by_ref(struct node *tree, const char *ref)
+{
+ if (ref[0] == '/')
+ return get_node_by_path(tree, ref);
+ else
+ return get_node_by_label(tree, ref);
+}
+
+cell_t get_node_phandle(struct node *root, struct node *node)
+{
+ static cell_t phandle = 1; /* FIXME: ick, static local */
+
+ if ((node->phandle != 0) && (node->phandle != -1))
+ return node->phandle;
+
+ while (get_node_by_phandle(root, phandle))
+ phandle++;
+
+ node->phandle = phandle;
+
+ if (!get_property(node, "linux,phandle")
+ && (phandle_format & PHANDLE_LEGACY))
+ add_property(node,
+ build_property("linux,phandle",
+ data_append_cell(empty_data, phandle),
+ NULL));
+
+ if (!get_property(node, "phandle")
+ && (phandle_format & PHANDLE_EPAPR))
+ add_property(node,
+ build_property("phandle",
+ data_append_cell(empty_data, phandle),
+ NULL));
+
+ /* If the node *does* have a phandle property, we must
+ * be dealing with a self-referencing phandle, which will be
+ * fixed up momentarily in the caller */
+
+ return node->phandle;
+}
diff --git a/contrib/dtc/scripts/setlocalversion b/contrib/dtc/scripts/setlocalversion
new file mode 100755
index 0000000..82e4993
--- /dev/null
+++ b/contrib/dtc/scripts/setlocalversion
@@ -0,0 +1,22 @@
+#!/bin/sh
+# Print additional version information for non-release trees.
+
+usage() {
+ echo "Usage: $0 [srctree]" >&2
+ exit 1
+}
+
+cd "${1:-.}" || usage
+
+# Check for git and a git repo.
+if head=`git rev-parse --verify HEAD 2>/dev/null`; then
+ # Do we have an untagged version?
+ if git name-rev --tags HEAD | grep -E '^HEAD[[:space:]]+(.*~[0-9]*|undefined)$' > /dev/null; then
+ printf '%s%s' -g `echo "$head" | cut -c1-8`
+ fi
+
+ # Are there uncommitted changes?
+ if git diff-index HEAD | read dummy; then
+ printf '%s' -dirty
+ fi
+fi
diff --git a/contrib/dtc/srcpos.c b/contrib/dtc/srcpos.c
new file mode 100644
index 0000000..8bb0c02
--- /dev/null
+++ b/contrib/dtc/srcpos.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+
+#include "dtc.h"
+#include "srcpos.h"
+
+
+/*
+ * Like yylineno, this is the current open file pos.
+ */
+struct dtc_file *srcpos_file;
+
+/*
+ * The empty source position.
+ */
+
+struct dtc_file dtc_empty_file = {
+ .dir = NULL,
+ .name = "<no file>",
+ .file = NULL
+};
+
+srcpos srcpos_empty = {
+ .first_line = 0,
+ .first_column = 0,
+ .last_line = 0,
+ .last_column = 0,
+ .file = &dtc_empty_file
+};
+
+
+static int
+dtc_open_one(struct dtc_file *file, const char *search, const char *fname)
+{
+ char *fullname;
+
+ if (search) {
+ fullname = xmalloc(strlen(search) + strlen(fname) + 2);
+
+ strcpy(fullname, search);
+ strcat(fullname, "/");
+ strcat(fullname, fname);
+ } else {
+ fullname = xstrdup(fname);
+ }
+
+ file->file = fopen(fullname, "r");
+ if (!file->file) {
+ free(fullname);
+ return 0;
+ }
+
+ file->name = fullname;
+ return 1;
+}
+
+
+struct dtc_file *
+dtc_open_file(const char *fname, const struct search_path *search)
+{
+ static const struct search_path default_search = { NULL, NULL, NULL };
+
+ struct dtc_file *file;
+ const char *slash;
+
+ file = xmalloc(sizeof(struct dtc_file));
+
+ slash = strrchr(fname, '/');
+ if (slash) {
+ char *dir = xmalloc(slash - fname + 1);
+
+ memcpy(dir, fname, slash - fname);
+ dir[slash - fname] = 0;
+ file->dir = dir;
+ } else {
+ file->dir = NULL;
+ }
+
+ if (streq(fname, "-")) {
+ file->name = "stdin";
+ file->file = stdin;
+ return file;
+ }
+
+ if (fname[0] == '/') {
+ file->file = fopen(fname, "r");
+ if (!file->file)
+ goto fail;
+
+ file->name = xstrdup(fname);
+ return file;
+ }
+
+ if (!search)
+ search = &default_search;
+
+ while (search) {
+ if (dtc_open_one(file, search->dir, fname))
+ return file;
+
+ if (errno != ENOENT)
+ goto fail;
+
+ search = search->next;
+ }
+
+fail:
+ die("Couldn't open \"%s\": %s\n", fname, strerror(errno));
+}
+
+
+void
+dtc_close_file(struct dtc_file *file)
+{
+ if (fclose(file->file))
+ die("Error closing \"%s\": %s\n", file->name, strerror(errno));
+}
+
+
+srcpos *
+srcpos_copy(srcpos *pos)
+{
+ srcpos *pos_new;
+
+ pos_new = xmalloc(sizeof(srcpos));
+ memcpy(pos_new, pos, sizeof(srcpos));
+
+ return pos_new;
+}
+
+
+
+void
+srcpos_dump(srcpos *pos)
+{
+ printf("file : \"%s\"\n",
+ pos->file ? (char *) pos->file : "<no file>");
+ printf("first_line : %d\n", pos->first_line);
+ printf("first_column: %d\n", pos->first_column);
+ printf("last_line : %d\n", pos->last_line);
+ printf("last_column : %d\n", pos->last_column);
+ printf("file : %s\n", pos->file->name);
+}
+
+
+char *
+srcpos_string(srcpos *pos)
+{
+ const char *fname;
+ char col_buf[100];
+ char *pos_str;
+
+ if (!pos) {
+ fname = "<no-file>";
+ } else if (pos->file->name) {
+ fname = pos->file->name;
+ if (strcmp(fname, "-") == 0)
+ fname = "stdin";
+ } else {
+ fname = "<no-file>";
+ }
+
+ if (pos->first_line == pos->last_line) {
+ if (pos->first_column == pos->last_column) {
+ snprintf(col_buf, sizeof(col_buf),
+ "%d:%d",
+ pos->first_line, pos->first_column);
+ } else {
+ snprintf(col_buf, sizeof(col_buf),
+ "%d:%d-%d",
+ pos->first_line,
+ pos->first_column, pos->last_column);
+ }
+
+ } else {
+ snprintf(col_buf, sizeof(col_buf),
+ "%d:%d - %d:%d",
+ pos->first_line, pos->first_column,
+ pos->last_line, pos->last_column);
+ }
+
+ if (asprintf(&pos_str, "%s %s", fname, col_buf) == -1)
+ return "<unknown source position?";
+
+ return pos_str;
+}
+
+
+void
+srcpos_error(srcpos *pos, char const *fmt, ...)
+{
+ const char *srcstr;
+ va_list va;
+ va_start(va, fmt);
+
+ srcstr = srcpos_string(pos);
+
+ fprintf(stderr, "Error: %s ", srcstr);
+ vfprintf(stderr, fmt, va);
+ fprintf(stderr, "\n");
+
+ va_end(va);
+}
+
+
+void
+srcpos_warn(srcpos *pos, char const *fmt, ...)
+{
+ const char *srcstr;
+ va_list va;
+ va_start(va, fmt);
+
+ srcstr = srcpos_string(pos);
+
+ fprintf(stderr, "Warning: %s ", srcstr);
+ vfprintf(stderr, fmt, va);
+ fprintf(stderr, "\n");
+
+ va_end(va);
+}
diff --git a/contrib/dtc/srcpos.h b/contrib/dtc/srcpos.h
new file mode 100644
index 0000000..a6d0077
--- /dev/null
+++ b/contrib/dtc/srcpos.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef _SRCPOS_H_
+#define _SRCPOS_H_
+
+/*
+ * Augment the standard YYLTYPE with a filenum index into an
+ * array of all opened filenames.
+ */
+
+#include <stdio.h>
+
+struct dtc_file {
+ char *dir;
+ const char *name;
+ FILE *file;
+};
+
+#if ! defined(YYLTYPE) && ! defined(YYLTYPE_IS_DECLARED)
+typedef struct YYLTYPE {
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+ struct dtc_file *file;
+} YYLTYPE;
+
+#define YYLTYPE_IS_DECLARED 1
+#define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+/* Cater to old parser templates. */
+#ifndef YYID
+#define YYID(n) (n)
+#endif
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ (Current).file = YYRHSLOC (Rhs, N).file; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ (Current).file = YYRHSLOC (Rhs, 0).file; \
+ } \
+ while (YYID (0))
+
+
+typedef YYLTYPE srcpos;
+
+/*
+ * Fictional source position used for IR nodes that are
+ * created without otherwise knowing a true source position.
+ * For example,constant definitions from the command line.
+ */
+extern srcpos srcpos_empty;
+
+extern struct dtc_file *srcpos_file;
+
+struct search_path {
+ const char *dir; /* NULL for current directory */
+ struct search_path *prev, *next;
+};
+
+extern struct dtc_file *dtc_open_file(const char *fname,
+ const struct search_path *search);
+extern void dtc_close_file(struct dtc_file *file);
+
+extern srcpos *srcpos_copy(srcpos *pos);
+extern char *srcpos_string(srcpos *pos);
+extern void srcpos_dump(srcpos *pos);
+
+extern void srcpos_error(srcpos *pos, char const *, ...)
+ __attribute__((format(printf, 2, 3)));
+extern void srcpos_warn(srcpos *pos, char const *, ...)
+ __attribute__((format(printf, 2, 3)));
+
+#endif /* _SRCPOS_H_ */
diff --git a/contrib/dtc/treesource.c b/contrib/dtc/treesource.c
new file mode 100644
index 0000000..cc1751d
--- /dev/null
+++ b/contrib/dtc/treesource.c
@@ -0,0 +1,279 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "dtc.h"
+#include "srcpos.h"
+
+extern FILE *yyin;
+extern int yyparse(void);
+
+struct boot_info *the_boot_info;
+int treesource_error;
+
+struct boot_info *dt_from_source(const char *fname)
+{
+ the_boot_info = NULL;
+ treesource_error = 0;
+
+ srcpos_file = dtc_open_file(fname, NULL);
+ yyin = srcpos_file->file;
+
+ if (yyparse() != 0)
+ die("Unable to parse input tree\n");
+
+ if (treesource_error)
+ die("Syntax error parsing input tree\n");
+
+ return the_boot_info;
+}
+
+static void write_prefix(FILE *f, int level)
+{
+ int i;
+
+ for (i = 0; i < level; i++)
+ fputc('\t', f);
+}
+
+static int isstring(char c)
+{
+ return (isprint(c)
+ || (c == '\0')
+ || strchr("\a\b\t\n\v\f\r", c));
+}
+
+static void write_propval_string(FILE *f, struct data val)
+{
+ const char *str = val.val;
+ int i;
+ struct marker *m = val.markers;
+
+ assert(str[val.len-1] == '\0');
+
+ while (m && (m->offset == 0)) {
+ if (m->type == LABEL)
+ fprintf(f, "%s: ", m->ref);
+ m = m->next;
+ }
+ fprintf(f, "\"");
+
+ for (i = 0; i < (val.len-1); i++) {
+ char c = str[i];
+
+ switch (c) {
+ case '\a':
+ fprintf(f, "\\a");
+ break;
+ case '\b':
+ fprintf(f, "\\b");
+ break;
+ case '\t':
+ fprintf(f, "\\t");
+ break;
+ case '\n':
+ fprintf(f, "\\n");
+ break;
+ case '\v':
+ fprintf(f, "\\v");
+ break;
+ case '\f':
+ fprintf(f, "\\f");
+ break;
+ case '\r':
+ fprintf(f, "\\r");
+ break;
+ case '\\':
+ fprintf(f, "\\\\");
+ break;
+ case '\"':
+ fprintf(f, "\\\"");
+ break;
+ case '\0':
+ fprintf(f, "\", ");
+ while (m && (m->offset < i)) {
+ if (m->type == LABEL) {
+ assert(m->offset == (i+1));
+ fprintf(f, "%s: ", m->ref);
+ }
+ m = m->next;
+ }
+ fprintf(f, "\"");
+ break;
+ default:
+ if (isprint(c))
+ fprintf(f, "%c", c);
+ else
+ fprintf(f, "\\x%02hhx", c);
+ }
+ }
+ fprintf(f, "\"");
+
+ /* Wrap up any labels at the end of the value */
+ for_each_marker_of_type(m, LABEL) {
+ assert (m->offset == val.len);
+ fprintf(f, " %s:", m->ref);
+ }
+}
+
+static void write_propval_cells(FILE *f, struct data val)
+{
+ void *propend = val.val + val.len;
+ cell_t *cp = (cell_t *)val.val;
+ struct marker *m = val.markers;
+
+ fprintf(f, "<");
+ for (;;) {
+ while (m && (m->offset <= ((char *)cp - val.val))) {
+ if (m->type == LABEL) {
+ assert(m->offset == ((char *)cp - val.val));
+ fprintf(f, "%s: ", m->ref);
+ }
+ m = m->next;
+ }
+
+ fprintf(f, "0x%x", fdt32_to_cpu(*cp++));
+ if ((void *)cp >= propend)
+ break;
+ fprintf(f, " ");
+ }
+
+ /* Wrap up any labels at the end of the value */
+ for_each_marker_of_type(m, LABEL) {
+ assert (m->offset == val.len);
+ fprintf(f, " %s:", m->ref);
+ }
+ fprintf(f, ">");
+}
+
+static void write_propval_bytes(FILE *f, struct data val)
+{
+ void *propend = val.val + val.len;
+ const char *bp = val.val;
+ struct marker *m = val.markers;
+
+ fprintf(f, "[");
+ for (;;) {
+ while (m && (m->offset == (bp-val.val))) {
+ if (m->type == LABEL)
+ fprintf(f, "%s: ", m->ref);
+ m = m->next;
+ }
+
+ fprintf(f, "%02hhx", *bp++);
+ if ((const void *)bp >= propend)
+ break;
+ fprintf(f, " ");
+ }
+
+ /* Wrap up any labels at the end of the value */
+ for_each_marker_of_type(m, LABEL) {
+ assert (m->offset == val.len);
+ fprintf(f, " %s:", m->ref);
+ }
+ fprintf(f, "]");
+}
+
+static void write_propval(FILE *f, struct property *prop)
+{
+ int len = prop->val.len;
+ const char *p = prop->val.val;
+ struct marker *m = prop->val.markers;
+ int nnotstring = 0, nnul = 0;
+ int nnotstringlbl = 0, nnotcelllbl = 0;
+ int i;
+
+ if (len == 0) {
+ fprintf(f, ";\n");
+ return;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (! isstring(p[i]))
+ nnotstring++;
+ if (p[i] == '\0')
+ nnul++;
+ }
+
+ for_each_marker_of_type(m, LABEL) {
+ if ((m->offset > 0) && (prop->val.val[m->offset - 1] != '\0'))
+ nnotstringlbl++;
+ if ((m->offset % sizeof(cell_t)) != 0)
+ nnotcelllbl++;
+ }
+
+ fprintf(f, " = ");
+ if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul))
+ && (nnotstringlbl == 0)) {
+ write_propval_string(f, prop->val);
+ } else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
+ write_propval_cells(f, prop->val);
+ } else {
+ write_propval_bytes(f, prop->val);
+ }
+
+ fprintf(f, ";\n");
+}
+
+static void write_tree_source_node(FILE *f, struct node *tree, int level)
+{
+ struct property *prop;
+ struct node *child;
+
+ write_prefix(f, level);
+ if (tree->label)
+ fprintf(f, "%s: ", tree->label);
+ if (tree->name && (*tree->name))
+ fprintf(f, "%s {\n", tree->name);
+ else
+ fprintf(f, "/ {\n");
+
+ for_each_property(tree, prop) {
+ write_prefix(f, level+1);
+ if (prop->label)
+ fprintf(f, "%s: ", prop->label);
+ fprintf(f, "%s", prop->name);
+ write_propval(f, prop);
+ }
+ for_each_child(tree, child) {
+ fprintf(f, "\n");
+ write_tree_source_node(f, child, level+1);
+ }
+ write_prefix(f, level);
+ fprintf(f, "};\n");
+}
+
+
+void dt_to_source(FILE *f, struct boot_info *bi)
+{
+ struct reserve_info *re;
+
+ fprintf(f, "/dts-v1/;\n\n");
+
+ for (re = bi->reservelist; re; re = re->next) {
+ if (re->label)
+ fprintf(f, "%s: ", re->label);
+ fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n",
+ (unsigned long long)re->re.address,
+ (unsigned long long)re->re.size);
+ }
+
+ write_tree_source_node(f, bi->dt, 0);
+}
+
diff --git a/contrib/dtc/util.c b/contrib/dtc/util.c
new file mode 100644
index 0000000..33631ce
--- /dev/null
+++ b/contrib/dtc/util.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "dtc.h"
+
+char *xstrdup(const char *s)
+{
+ int len = strlen(s) + 1;
+ char *dup = xmalloc(len);
+
+ memcpy(dup, s, len);
+
+ return dup;
+}
diff --git a/contrib/dtc/util.h b/contrib/dtc/util.h
new file mode 100644
index 0000000..0fb60fe
--- /dev/null
+++ b/contrib/dtc/util.h
@@ -0,0 +1,55 @@
+#ifndef _UTIL_H
+#define _UTIL_H
+
+/*
+ * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+static inline void __attribute__((noreturn)) die(char * str, ...)
+{
+ va_list ap;
+
+ va_start(ap, str);
+ fprintf(stderr, "FATAL ERROR: ");
+ vfprintf(stderr, str, ap);
+ exit(1);
+}
+
+static inline void *xmalloc(size_t len)
+{
+ void *new = malloc(len);
+
+ if (!new)
+ die("malloc() failed\n");
+
+ return new;
+}
+
+static inline void *xrealloc(void *p, size_t len)
+{
+ void *new = realloc(p, len);
+
+ if (!new)
+ die("realloc() failed (len=%d)\n", len);
+
+ return new;
+}
+
+extern char *xstrdup(const char *s);
+
+#endif /* _UTIL_H */
diff --git a/contrib/gcc/config/mips/freebsd.h b/contrib/gcc/config/mips/freebsd.h
index b53dae6..6627e03 100644
--- a/contrib/gcc/config/mips/freebsd.h
+++ b/contrib/gcc/config/mips/freebsd.h
@@ -130,10 +130,67 @@ Boston, MA 02110-1301, USA. */
if (TARGET_MIPS16) \
builtin_define ("__mips16"); \
\
+ if (mips_abi == ABI_N32) \
+ { \
+ builtin_define ("__mips_n32"); \
+ builtin_define ("_ABIN32=2"); \
+ builtin_define ("_MIPS_SIM=_ABIN32"); \
+ builtin_define ("_MIPS_SZLONG=32"); \
+ builtin_define ("_MIPS_SZPTR=32"); \
+ } \
+ else if (mips_abi == ABI_64) \
+ { \
+ builtin_define ("__mips_n64"); \
+ builtin_define ("_ABI64=3"); \
+ builtin_define ("_MIPS_SIM=_ABI64"); \
+ builtin_define ("_MIPS_SZLONG=64"); \
+ builtin_define ("_MIPS_SZPTR=64"); \
+ } \
+ else if (mips_abi == ABI_O64) \
+ { \
+ builtin_define ("__mips_o64"); \
+ builtin_define ("_ABIO64=4"); \
+ builtin_define ("_MIPS_SIM=_ABIO64"); \
+ builtin_define ("_MIPS_SZLONG=64"); \
+ builtin_define ("_MIPS_SZPTR=64"); \
+ } \
+ else if (mips_abi == ABI_EABI) \
+ { \
+ builtin_define ("__mips_eabi"); \
+ builtin_define ("_ABIEMB=5"); \
+ builtin_define ("_MIPS_SIM=_ABIEMB"); \
+ if (TARGET_LONG64) \
+ builtin_define ("_MIPS_SZLONG=64"); \
+ else \
+ builtin_define ("_MIPS_SZLONG=32"); \
+ if (TARGET_64BIT) \
+ builtin_define ("_MIPS_SZPTR=64"); \
+ else \
+ builtin_define ("_MIPS_SZPTR=32"); \
+ } \
+ else \
+ { \
+ builtin_define ("__mips_o32"); \
+ builtin_define ("_ABIO32=1"); \
+ builtin_define ("_MIPS_SIM=_ABIO32"); \
+ builtin_define ("_MIPS_SZLONG=32"); \
+ builtin_define ("_MIPS_SZPTR=32"); \
+ } \
+ if (TARGET_FLOAT64) \
+ builtin_define ("_MIPS_FPSET=32"); \
+ else \
+ builtin_define ("_MIPS_FPSET=16"); \
+ \
+ builtin_define ("_MIPS_SZINT=32"); \
+ \
MIPS_CPP_SET_PROCESSOR ("_MIPS_ARCH", mips_arch_info); \
MIPS_CPP_SET_PROCESSOR ("_MIPS_TUNE", mips_tune_info); \
\
- if (ISA_MIPS3) \
+ if (ISA_MIPS1) \
+ builtin_define ("__mips=1"); \
+ else if (ISA_MIPS2) \
+ builtin_define ("__mips=2"); \
+ else if (ISA_MIPS3) \
builtin_define ("__mips=3"); \
else if (ISA_MIPS4) \
builtin_define ("__mips=4"); \
@@ -152,7 +209,12 @@ Boston, MA 02110-1301, USA. */
builtin_define ("__mips=64"); \
builtin_define ("__mips_isa_rev=1"); \
} \
- \
+/* else if (ISA_MIPS64R2) \
+ { \
+ builtin_define ("__mips=64"); \
+ builtin_define ("__mips_isa_rev=2"); \
+ } \
+*/ \
if (TARGET_HARD_FLOAT) \
builtin_define ("__mips_hard_float"); \
else if (TARGET_SOFT_FLOAT) \
@@ -167,18 +229,6 @@ Boston, MA 02110-1301, USA. */
builtin_define ("__MIPSEL__"); \
\
/* No language dialect defines. */ \
- \
- if (mips_abi == ABI_EABI) \
- builtin_define ("__mips_eabi"); \
- else if (mips_abi == ABI_N32) \
- builtin_define ("__mips_n32"); \
- else if (mips_abi == ABI_64) \
- builtin_define ("__mips_n64"); \
- else if (mips_abi == ABI_O64) \
- builtin_define ("__mips_o64"); \
- else \
- builtin_define ("__mips_o32"); \
- \
if (TARGET_ABICALLS) \
builtin_define ("__ABICALLS__"); \
} \
@@ -241,6 +291,15 @@ Boston, MA 02110-1301, USA. */
#undef LOCAL_LABEL_PREFIX
#define LOCAL_LABEL_PREFIX "."
+/* Currently we don't support 128bit long doubles, so for now we force
+ n32 to be 64bit. */
+#undef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE 64
+
+#ifdef IN_LIBGCC2
+#undef LIBGCC2_LONG_DOUBLE_TYPE_SIZE
+#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 64
+#endif
/************************[ Debugger stuff ]*********************************/
diff --git a/contrib/gdb/gdb/config/mips/nm-fbsd.h b/contrib/gdb/gdb/config/mips/nm-fbsd.h
new file mode 100644
index 0000000..a23a6d9
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/nm-fbsd.h
@@ -0,0 +1,48 @@
+/***********************************************************************
+Copyright 2003-2006 Raza Microelectronics, Inc.(RMI).
+This is a derived work from software originally provided by the external
+entity identified below. The licensing terms and warranties specified in
+the header of the original work apply to this derived work.
+Contribution by RMI:
+*****************************#RMI_1#**********************************/
+/* Native-dependent definitions for NetBSD/mips.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef NM_FBSD_H
+#define NM_FBSD_H
+
+/* Override child_pid_to_exec_file in 'inftarg.c'. */
+#define CHILD_PID_TO_EXEC_FILE
+
+/* Type of the third argument to the `ptrace' system call. */
+#define PTRACE_ARG3_TYPE caddr_t
+
+/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'. */
+#define FETCH_INFERIOR_REGISTERS
+
+/* We can attach and detach. */
+#define ATTACH_DETACH
+
+/* Shared library support. */
+
+#include "solib.h"
+
+#endif /* NM_FBSD_H */
diff --git a/contrib/gdb/gdb/config/mips/tm-fbsd.h b/contrib/gdb/gdb/config/mips/tm-fbsd.h
new file mode 100644
index 0000000..7f69f0b
--- /dev/null
+++ b/contrib/gdb/gdb/config/mips/tm-fbsd.h
@@ -0,0 +1,43 @@
+/***********************************************************************
+Copyright 2003-2006 Raza Microelectronics, Inc.(RMI).
+This is a derived work from software originally provided by the external
+entity identified below. The licensing terms and warranties specified in
+the header of the original work apply to this derived work.
+Contribution by RMI:
+*****************************#RMI_1#**********************************/
+/* Target-dependent definitions for NetBSD/mips.
+ Copyright 2002 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef TM_FBSD_H
+#define TM_FBSD_H
+
+#include "mips/tm-mips.h"
+#include "solib.h"
+
+/* We don't want to inherit tm-mips.h's shared library trampoline code. */
+#undef IN_SOLIB_CALL_TRAMPOLINE
+#undef IN_SOLIB_RETURN_TRAMPOLINE
+#undef SKIP_TRAMPOLINE_CODE
+#undef IGNORE_HELPER_CALL
+
+/* XXX undef a bunch of stuff we want to use multi-arch */
+#undef IN_SIGTRAMP
+#endif /* TM_FBSD_H */
diff --git a/contrib/gdb/gdb/mips-tdep.h b/contrib/gdb/gdb/mips-tdep.h
index 7a00ffa..af9a3c8 100644
--- a/contrib/gdb/gdb/mips-tdep.h
+++ b/contrib/gdb/gdb/mips-tdep.h
@@ -62,6 +62,17 @@ struct mips_regnum
extern const struct mips_regnum *mips_regnum (struct gdbarch *gdbarch);
enum {
+ MIPS_S0_REGNUM = 16,
+ MIPS_S1_REGNUM = 17,
+ MIPS_S2_REGNUM = 18,
+ MIPS_S3_REGNUM = 19,
+ MIPS_S4_REGNUM = 20,
+ MIPS_S5_REGNUM = 21,
+ MIPS_S6_REGNUM = 22,
+ MIPS_S7_REGNUM = 23,
+ MIPS_SP_REGNUM = 29,
+ MIPS_FP_REGNUM = 30,
+ MIPS_RA_REGNUM = 31,
MIPS_EMBED_LO_REGNUM = 33,
MIPS_EMBED_HI_REGNUM = 34,
MIPS_EMBED_BADVADDR_REGNUM = 35,
diff --git a/contrib/gdb/gdb/mipsfbsd-nat.c b/contrib/gdb/gdb/mipsfbsd-nat.c
new file mode 100644
index 0000000..8b58971
--- /dev/null
+++ b/contrib/gdb/gdb/mipsfbsd-nat.c
@@ -0,0 +1,108 @@
+/***********************************************************************
+Copyright 2003-2006 Raza Microelectronics, Inc.(RMI).
+This is a derived work from software originally provided by the external
+entity identified below. The licensing terms and warranties specified in
+the header of the original work apply to this derived work.
+Contribution by RMI:
+*****************************#RMI_1#**********************************/
+/* Native-dependent code for MIPS systems running NetBSD.
+ Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "inferior.h"
+#include "regcache.h"
+
+#include "mipsfbsd-tdep.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+
+/* Determine if PT_GETREGS fetches this register. */
+static int
+getregs_supplies (int regno)
+{
+ return ((regno) >= ZERO_REGNUM && (regno) <= PC_REGNUM);
+}
+
+void
+fetch_inferior_registers (int regno)
+{
+ if (regno == -1 || getregs_supplies (regno))
+ {
+ struct reg regs;
+
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ mipsfbsd_supply_reg ((char *) &regs, regno);
+ if (regno != -1)
+ return;
+ }
+
+ if (regno == -1 || regno >= FP0_REGNUM)
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get floating point status");
+
+ mipsfbsd_supply_fpreg ((char *) &fpregs, regno);
+ }
+}
+
+void
+store_inferior_registers (int regno)
+{
+ if (regno == -1 || getregs_supplies (regno))
+ {
+ struct reg regs;
+
+ if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't get registers");
+
+ mipsfbsd_fill_reg ((char *) &regs, regno);
+
+ if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+ perror_with_name ("Couldn't write registers");
+
+ if (regno != -1)
+ return;
+ }
+
+ if (regno == -1 || regno >= FP0_REGNUM)
+ {
+ struct fpreg fpregs;
+
+ if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't get floating point status");
+
+ mipsfbsd_fill_fpreg ((char *) &fpregs, regno);
+
+ if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+ perror_with_name ("Couldn't write floating point status");
+ }
+}
diff --git a/contrib/gdb/gdb/mipsfbsd-tdep.c b/contrib/gdb/gdb/mipsfbsd-tdep.c
new file mode 100644
index 0000000..0be5d27
--- /dev/null
+++ b/contrib/gdb/gdb/mipsfbsd-tdep.c
@@ -0,0 +1,579 @@
+/***********************************************************************
+Copyright 2003-2006 Raza Microelectronics, Inc.(RMI).
+This is a derived work from software originally provided by the external
+entity identified below. The licensing terms and warranties specified in
+the header of the original work apply to this derived work.
+Contribution by RMI:
+*****************************#RMI_1#**********************************/
+/* Target-dependent code for MIPS systems running NetBSD.
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+ Contributed by Wasabi Systems, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "target.h"
+#include "value.h"
+#include "osabi.h"
+
+#include "nbsd-tdep.h"
+#include "mipsfbsd-tdep.h"
+#include "mips-tdep.h"
+
+#include "solib-svr4.h"
+
+#include <sys/procfs.h>
+#include "gregset.h"
+#include "trad-frame.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "bfd.h"
+#include "objfiles.h"
+
+/* Conveniently, GDB uses the same register numbering as the
+ ptrace register structure used by NetBSD/mips. */
+
+void
+mipsfbsd_supply_reg (char *regs, int regno)
+{
+ int i;
+
+ for (i = 0; i <= PC_REGNUM; i++)
+ {
+ if (regno == i || regno == -1)
+ {
+ if (CANNOT_FETCH_REGISTER (i))
+ supply_register (i, NULL);
+ else
+ supply_register (i, regs + (i * mips_regsize (current_gdbarch)));
+ }
+ }
+}
+void
+supply_gregset (gdb_gregset_t *gregs)
+{
+ mipsfbsd_supply_reg((char *)gregs, -1);
+}
+
+void
+mipsfbsd_fill_reg (char *regs, int regno)
+{
+ int i;
+
+ for (i = 0; i <= PC_REGNUM; i++)
+ if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i))
+ regcache_collect (i, regs + (i * mips_regsize (current_gdbarch)));
+}
+
+void
+fill_gregset (gdb_gregset_t *gregs, int regno)
+{
+ mipsfbsd_fill_reg ((char *)gregs, regno);
+}
+
+void
+mipsfbsd_supply_fpreg (char *fpregs, int regno)
+{
+ int i;
+
+ for (i = FP0_REGNUM;
+ i <= mips_regnum (current_gdbarch)->fp_implementation_revision;
+ i++)
+ {
+ if (regno == i || regno == -1)
+ {
+ if (CANNOT_FETCH_REGISTER (i))
+ supply_register (i, NULL);
+ else
+ supply_register (i,
+ fpregs + ((i - FP0_REGNUM) * mips_regsize (current_gdbarch)));
+ }
+ }
+}
+
+void
+supply_fpregset (gdb_fpregset_t *fpregs)
+{
+ mipsfbsd_supply_fpreg((char *)fpregs, -1);
+}
+
+void
+mipsfbsd_fill_fpreg (char *fpregs, int regno)
+{
+ int i;
+
+ for (i = FP0_REGNUM; i <= mips_regnum (current_gdbarch)->fp_control_status;
+ i++)
+ if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i))
+ regcache_collect (i,
+ fpregs + ((i - FP0_REGNUM) * mips_regsize (current_gdbarch)));
+}
+
+void
+fill_fpregset (gdb_fpregset_t *fpregs, int regno)
+{
+ mipsfbsd_fill_fpreg ((char *)fpregs, regno);
+}
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR ignore)
+{
+ char *regs, *fpregs;
+
+ /* We get everything from one section. */
+ if (which != 0)
+ return;
+
+ regs = core_reg_sect;
+ fpregs = core_reg_sect + SIZEOF_STRUCT_REG;
+
+ /* Integer registers. */
+ mipsfbsd_supply_reg (regs, -1);
+
+ /* Floating point registers. */
+ mipsfbsd_supply_fpreg (fpregs, -1);
+}
+
+static void
+fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR ignore)
+{
+ switch (which)
+ {
+ case 0: /* Integer registers. */
+ if (core_reg_size != SIZEOF_STRUCT_REG)
+ warning ("Wrong size register set in core file.");
+ else
+ mipsfbsd_supply_reg (core_reg_sect, -1);
+ break;
+
+ case 2: /* Floating point registers. */
+ if (core_reg_size != SIZEOF_STRUCT_FPREG)
+ warning ("Wrong size register set in core file.");
+ else
+ mipsfbsd_supply_fpreg (core_reg_sect, -1);
+ break;
+
+ default:
+ /* Don't know what kind of register request this is; just ignore it. */
+ break;
+ }
+}
+
+static struct core_fns mipsfbsd_core_fns =
+{
+ bfd_target_unknown_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+
+/*
+ * MIPSFBSD Offsets
+ * 0x7fff0000 User high mem -> USRSTACK [64K]
+ *
+ * 0x7ffefff0 ps_strings -> 16 bytes
+ *
+ * 0x7ffeffec sigcode -> 44 bytes
+ *
+ * 0x7ffeffc4 sigcode end env strings etc start
+ */
+#define MIPS_FBSD_SIGTRAMP_START (0x7ffeffc4)
+#define MIPS_FBSD_SIGTRAMP_END (0x7ffeffec)
+#define MIPS_FBSD_SIGTRAMP_STACK_MOD_START (0x7ffeffc8)
+#define MIPS_FBSD_SIGTRAMP_STACK_MOD_END (0x7ffeffd8)
+
+static LONGEST
+mipsfbsd_sigtramp_offset (CORE_ADDR pc)
+{
+ return pc < MIPS_FBSD_SIGTRAMP_END &&
+ pc >= MIPS_FBSD_SIGTRAMP_START ? 1 : -1;
+}
+
+static int
+fbsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ return (name && strcmp (name, "__sigtramp") == 0);
+}
+
+static int
+mipsfbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
+{
+ return (fbsd_pc_in_sigtramp (pc, func_name)
+ || mipsfbsd_sigtramp_offset (pc) >= 0);
+}
+
+static int
+is_sigtramp_sp_modified (CORE_ADDR pc)
+{
+ return (pc >= MIPS_FBSD_SIGTRAMP_STACK_MOD_START &&
+ pc <= MIPS_FBSD_SIGTRAMP_STACK_MOD_END);
+}
+
+
+/* Figure out where the longjmp will land. We expect that we have
+ just entered longjmp and haven't yet setup the stack frame, so
+ the args are still in the argument regs. A0_REGNUM points at the
+ jmp_buf structure from which we extract the PC that we will land
+ at. The PC is copied into *pc. This routine returns true on
+ success. */
+
+#define FBSD_MIPS_JB_PC (12)
+#define FBSD_MIPS_JB_ELEMENT_SIZE mips_regsize (current_gdbarch)
+#define FBSD_MIPS_JB_OFFSET (FBSD_MIPS_JB_PC * \
+ FBSD_MIPS_JB_ELEMENT_SIZE)
+
+static int
+mipsfbsd_get_longjmp_target (CORE_ADDR *pc)
+{
+ CORE_ADDR jb_addr;
+ char *buf;
+
+ buf = alloca (FBSD_MIPS_JB_ELEMENT_SIZE);
+
+ jb_addr = read_register (A0_REGNUM);
+
+ if (target_read_memory (jb_addr + FBSD_MIPS_JB_OFFSET, buf,
+ FBSD_MIPS_JB_ELEMENT_SIZE))
+ return 0;
+
+ *pc = extract_unsigned_integer (buf, FBSD_MIPS_JB_ELEMENT_SIZE);
+
+ return 1;
+}
+
+static int
+mipsfbsd_cannot_fetch_register (int regno)
+{
+ return (regno == ZERO_REGNUM
+ || regno == mips_regnum (current_gdbarch)->fp_implementation_revision);
+ /* XXX TODO: Are there other registers that we cannot fetch ? */
+}
+
+static int
+mipsfbsd_cannot_store_register (int regno)
+{
+ return (regno == ZERO_REGNUM
+ || regno == mips_regnum (current_gdbarch)->fp_implementation_revision);
+ /* XXX TODO: Are there other registers that we cannot write ? */
+}
+
+/*
+ * This structure is defined in mips-tdep.c.
+ */
+struct mips_frame_cache
+{
+ CORE_ADDR base;
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+/*
+ * Prologue cache for sigtramp frame
+ * When we land in sigtramp, sigcontext is saved on the
+ * stack just below the sigtramp's stack frame. We have
+ * the Registers saved at fixed offsets on the stack.
+ */
+
+#define MIPS_FBSD_SIGTRAMP_STACK_SIZE (48)
+#define MIPS_FBSD_SIGCONTEXT_REG_OFFSET (32)
+
+static struct mips_frame_cache *
+mipsfbsd_sigtramp_frame_cache (struct frame_info *next_frame,
+ void **this_cache)
+{
+ struct mips_frame_cache *cache;
+ CORE_ADDR gregs_addr, sp, pc;
+ int regnum;
+ int sigtramp_stack_size;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct mips_frame_cache);
+ *this_cache = cache;
+
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ /*
+ * Get sp of next frame which is the adjusted sp of
+ * tramp code.
+ */
+ sp = frame_unwind_register_unsigned(next_frame, NUM_REGS + SP_REGNUM);
+ pc = frame_unwind_register_unsigned(next_frame, NUM_REGS + PC_REGNUM);
+ sigtramp_stack_size = is_sigtramp_sp_modified(pc) ?
+ MIPS_FBSD_SIGTRAMP_STACK_SIZE : 0;
+ gregs_addr = sp + sigtramp_stack_size + MIPS_FBSD_SIGCONTEXT_REG_OFFSET;
+
+ for (regnum = 0; regnum < PC_REGNUM; regnum++) {
+ cache->saved_regs[NUM_REGS + regnum].addr = gregs_addr +
+ regnum * mips_regsize (current_gdbarch);
+ }
+ /* Only retrieve PC and SP */
+ cache->saved_regs[NUM_REGS + SP_REGNUM].addr = gregs_addr +
+ SP_REGNUM * ( mips_regsize (current_gdbarch));
+
+ cache->saved_regs[NUM_REGS + RA_REGNUM].addr = gregs_addr +
+ RA_REGNUM * ( mips_regsize (current_gdbarch));
+
+ cache->base = get_frame_memory_unsigned (next_frame,
+ cache->saved_regs[NUM_REGS + SP_REGNUM].addr,
+ mips_regsize (current_gdbarch));
+
+ /* Todo: Floating point registers */
+
+ cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc]
+ = cache->saved_regs[NUM_REGS + RA_REGNUM];
+
+ return *this_cache;
+}
+
+static void
+mipsfbsd_sigtramp_frame_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct mips_frame_cache *cache =
+ mipsfbsd_sigtramp_frame_cache (next_frame, this_cache);
+
+ (*this_id) = frame_id_build (cache->base,
+ cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc].addr);
+}
+
+static void
+mipsfbsd_sigtramp_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct mips_frame_cache *cache =
+ mipsfbsd_sigtramp_frame_cache (next_frame, this_cache);
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+
+static const struct frame_unwind mipsfbsd_sigtramp_frame_unwind =
+{
+ SIGTRAMP_FRAME,
+ mipsfbsd_sigtramp_frame_this_id,
+ mipsfbsd_sigtramp_frame_prev_register
+};
+
+static const struct frame_unwind *
+mipsfbsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ char *name;
+
+ find_pc_partial_function (pc, &name, NULL, NULL);
+ if (mipsfbsd_pc_in_sigtramp (pc, name) )
+ return &mipsfbsd_sigtramp_frame_unwind;
+
+ return NULL;
+}
+
+/*
+ * Find out if PC has landed into dynamic library stub.
+ * We can find it by seeing if the name of the object
+ * file section where the PC lies is "MIPS.stubs"
+ */
+
+int
+mipsfbsd_in_stub_section (CORE_ADDR pc, char *name)
+{
+ struct obj_section *s;
+ int retval = 0;
+
+ s = find_pc_section (pc);
+
+ retval = (s != NULL
+ && s->the_bfd_section->name != NULL
+ && strcmp (s->the_bfd_section->name, ".MIPS.stubs") == 0);
+ return (retval);
+}
+
+
+/*
+ * Prologue cache for dynamic library stub frame.
+ * This stub does not modify the SP, so we set the
+ * cache base to calling frame's SP
+ */
+static struct mips_frame_cache *
+mipsfbsd_stub_frame_cache (struct frame_info *next_frame,
+ void **this_cache)
+{
+ struct mips_frame_cache *cache;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct mips_frame_cache);
+ *this_cache = cache;
+
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+
+ cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc].realreg =
+ NUM_REGS + RA_REGNUM;
+ cache->base = frame_unwind_register_unsigned (next_frame,
+ NUM_REGS + SP_REGNUM);
+
+ return (*this_cache);
+}
+
+
+static void
+mipsfbsd_stub_frame_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct mips_frame_cache *cache =
+ mipsfbsd_stub_frame_cache (next_frame, this_cache);
+
+ (*this_id) = frame_id_build (cache->base,
+ cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc].addr);
+}
+
+static void
+mipsfbsd_stub_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct mips_frame_cache *cache =
+ mipsfbsd_stub_frame_cache (next_frame, this_cache);
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+
+
+static const struct frame_unwind mipsfbsd_stub_frame_unwind = {
+ NORMAL_FRAME,
+ mipsfbsd_stub_frame_this_id,
+ mipsfbsd_stub_frame_prev_register
+};
+
+static const struct frame_unwind *
+mipsfbsd_stub_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+
+ if (mipsfbsd_in_stub_section(pc, NULL))
+ return &mipsfbsd_stub_frame_unwind;
+
+ return NULL;
+}
+
+/*
+ * typedef struct link_map {
+ * caddr_t l_addr; /* Base Address of library
+ * #ifdef __mips__
+ * caddr_t l_offs; /* Load Offset of library
+ * #endif
+ * const char *l_name; /* Absolute Path to Library
+ * const void *l_ld; /* Pointer to .dynamic in memory
+ * struct link_map *l_next, *l_prev; /* linked list of of mapped libs
+ * } Link_map;
+ *
+ * struct r_debug {
+ * int r_version; /* not used
+ * struct link_map *r_map; /* list of loaded images
+ * void (*r_brk)(struct r_debug *, struct link_map *);
+ * /* pointer to break point
+ * enum {
+ * RT_CONSISTENT, /* things are stable
+ * RT_ADD, /* adding a shared library
+ * RT_DELETE /* removing a shared library
+ * } r_state;
+ * };
+ *
+ */
+
+static struct link_map_offsets *
+mipsfbsd_ilp32_solib_svr4_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = NULL;
+
+ if (lmp == NULL)
+ {
+ lmp = &lmo;
+
+ lmo.r_debug_size = 16;
+
+ lmo.r_map_offset = 4;
+ lmo.r_map_size = 4;
+
+ lmo.link_map_size = 24;
+
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 4;
+
+ lmo.l_name_offset = 8;
+ lmo.l_name_size = 4;
+
+ lmo.l_next_offset = 16;
+ lmo.l_next_size = 4;
+
+ lmo.l_prev_offset = 20;
+ lmo.l_prev_size = 4;
+ }
+
+ return lmp;
+}
+
+static void
+mipsfbsd_init_abi (struct gdbarch_info info,
+ struct gdbarch *gdbarch)
+{
+ set_gdbarch_pc_in_sigtramp (gdbarch, mipsfbsd_pc_in_sigtramp);
+
+ set_gdbarch_get_longjmp_target (gdbarch, mipsfbsd_get_longjmp_target);
+
+ set_gdbarch_cannot_fetch_register (gdbarch, mipsfbsd_cannot_fetch_register);
+ set_gdbarch_cannot_store_register (gdbarch, mipsfbsd_cannot_store_register);
+
+ set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ mipsfbsd_ilp32_solib_svr4_fetch_link_map_offsets);
+ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+ set_gdbarch_in_solib_call_trampoline (gdbarch, mipsfbsd_in_stub_section);
+
+ /* frame sniffers */
+ frame_unwind_append_sniffer (gdbarch, mipsfbsd_sigtramp_frame_sniffer);
+ frame_unwind_append_sniffer (gdbarch, mipsfbsd_stub_frame_sniffer);
+
+}
+
+void
+_initialize_mipsfbsd_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_FREEBSD_ELF,
+ mipsfbsd_init_abi);
+}
diff --git a/contrib/gdb/gdb/mipsfbsd-tdep.h b/contrib/gdb/gdb/mipsfbsd-tdep.h
new file mode 100644
index 0000000..6b00bb4
--- /dev/null
+++ b/contrib/gdb/gdb/mipsfbsd-tdep.h
@@ -0,0 +1,40 @@
+/***********************************************************************
+Copyright 2003-2006 Raza Microelectronics, Inc.(RMI).
+This is a derived work from software originally provided by the external
+entity identified below. The licensing terms and warranties specified in
+the header of the original work apply to this derived work.
+Contribution by RMI:
+*****************************#RMI_1#**********************************/
+/* Common target dependent code for GDB on MIPS systems running NetBSD.
+ Copyright 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef mipsfbsd_TDEP_H
+#define mipsfbsd_TDEP_H
+
+void mipsfbsd_supply_reg (char *, int);
+void mipsfbsd_fill_reg (char *, int);
+
+void mipsfbsd_supply_fpreg (char *, int);
+void mipsfbsd_fill_fpreg (char *, int);
+
+#define SIZEOF_STRUCT_REG (38 * mips_regsize (current_gdbarch))
+#define SIZEOF_STRUCT_FPREG (33 * mips_regsize (current_gdbarch))
+
+#endif /* mipsfbsd_TDEP_H */
diff --git a/lib/libc/stdtime/asctime.c b/contrib/tzcode/stdtime/asctime.c
index 30606f1..30606f1 100644
--- a/lib/libc/stdtime/asctime.c
+++ b/contrib/tzcode/stdtime/asctime.c
diff --git a/lib/libc/stdtime/ctime.3 b/contrib/tzcode/stdtime/ctime.3
index 143bc2c..143bc2c 100644
--- a/lib/libc/stdtime/ctime.3
+++ b/contrib/tzcode/stdtime/ctime.3
diff --git a/lib/libc/stdtime/difftime.c b/contrib/tzcode/stdtime/difftime.c
index d16f9a0..d16f9a0 100644
--- a/lib/libc/stdtime/difftime.c
+++ b/contrib/tzcode/stdtime/difftime.c
diff --git a/lib/libc/stdtime/localtime.c b/contrib/tzcode/stdtime/localtime.c
index bee916b..bee916b 100644
--- a/lib/libc/stdtime/localtime.c
+++ b/contrib/tzcode/stdtime/localtime.c
diff --git a/lib/libc/stdtime/private.h b/contrib/tzcode/stdtime/private.h
index dda5bef..dda5bef 100644
--- a/lib/libc/stdtime/private.h
+++ b/contrib/tzcode/stdtime/private.h
diff --git a/lib/libc/stdtime/time2posix.3 b/contrib/tzcode/stdtime/time2posix.3
index 1a1ec95..1a1ec95 100644
--- a/lib/libc/stdtime/time2posix.3
+++ b/contrib/tzcode/stdtime/time2posix.3
diff --git a/lib/libc/stdtime/tzfile.5 b/contrib/tzcode/stdtime/tzfile.5
index 1606b5a..1606b5a 100644
--- a/lib/libc/stdtime/tzfile.5
+++ b/contrib/tzcode/stdtime/tzfile.5
diff --git a/lib/libc/stdtime/tzfile.h b/contrib/tzcode/stdtime/tzfile.h
index 85b945e..85b945e 100644
--- a/lib/libc/stdtime/tzfile.h
+++ b/contrib/tzcode/stdtime/tzfile.h
diff --git a/contrib/tzcode/zic/README b/contrib/tzcode/zic/README
new file mode 100644
index 0000000..5cb701e
--- /dev/null
+++ b/contrib/tzcode/zic/README
@@ -0,0 +1,88 @@
+@(#)README 8.3
+This file is in the public domain, so clarified as of
+2009-05-17 by Arthur David Olson.
+
+$FreeBSD$
+
+"What time is it?" -- Richard Deacon as The King
+"Any time you want it to be." -- Frank Baxter as The Scientist
+ (from the Bell System film "About Time")
+
+The 1989 update of the time zone package featured
+
+* POSIXization (including interpretation of POSIX-style TZ environment
+ variables, provided by Guy Harris),
+* ANSIfication (including versions of "mktime" and "difftime"),
+* SVIDulation (an "altzone" variable)
+* MACHination (the "gtime" function)
+* corrections to some time zone data (including corrections to the rules
+ for Great Britain and New Zealand)
+* reference data from the United States Naval Observatory for folks who
+ want to do additional time zones
+* and the 1989 data for Saudi Arabia.
+
+(Since this code will be treated as "part of the implementation" in some places
+and as "part of the application" in others, there's no good way to name
+functions, such as timegm, that are not part of the proposed ANSI C standard;
+such functions have kept their old, underscore-free names in this update.)
+
+And the "dysize" function has disappeared; it was present to allow compilation
+of the "date" command on old BSD systems, and a version of "date" is now
+provided in the package. The "date" command is not created when you "make all"
+since it may lack options provided by the version distributed with your
+operating system, or may not interact with the system in the same way the
+native version does.
+
+Since POSIX frowns on correct leap second handling, the default behavior of
+the "zic" command (in the absence of a "-L" option) has been changed to omit
+leap second information from its output files.
+
+Here is a recipe for acquiring, building, installing, and testing the
+tz distribution on a GNU/Linux or similar host.
+
+ mkdir tz
+ cd tz
+ wget 'ftp://elsie.nci.nih.gov/pub/tz*.tar.gz'
+ gzip -dc tzcode*.tar.gz | tar -xf -
+ gzip -dc tzdata*.tar.gz | tar -xf -
+
+Be sure to read the comments in "Makefile" and make any changes needed
+to make things right for your system, especially if you are using some
+platform other than GNU/Linux. Then run the following commands,
+substituting your desired installation directory for "$HOME/tzdir":
+
+ make TOPDIR=$HOME/tzdir install
+ $HOME/tzdir/etc/zdump -v America/Los_Angeles
+
+To use the new functions, use a "-ltz" option when compiling or linking.
+
+Historical local time information has been included here to:
+
+* provide a compendium of data about the history of civil time
+ that is useful even if the data are not 100% accurate;
+
+* give an idea of the variety of local time rules that have
+ existed in the past and thus an idea of the variety that may be
+ expected in the future;
+
+* provide a test of the generality of the local time rule description
+ system.
+
+The information in the time zone data files is by no means authoritative;
+the files currently do not even attempt to cover all time stamps before
+1970, and there are undoubtedly errors even for time stamps since 1970.
+If you know that the rules are different from those in a file, by all means
+feel free to change file (and please send the changed version to
+tz@elsie.nci.nih.gov for use in the future). Europeans take note!
+
+Thanks to these Timezone Caballeros who've made major contributions to the
+time conversion package: Keith Bostic; Bob Devine; Paul Eggert; Robert Elz;
+Guy Harris; Mark Horton; John Mackin; and Bradley White. Thanks also to
+Michael Bloom, Art Neilson, Stephen Prince, John Sovereign, and Frank Wales
+for testing work, and to Gwillim Law for checking local mean time data.
+None of them are responsible for remaining errors.
+
+Look in the ~ftp/pub directory of elsie.nci.nih.gov
+for updated versions of these files.
+
+Please send comments or information to tz@elsie.nci.nih.gov.
diff --git a/usr.sbin/zic/Theory b/contrib/tzcode/zic/Theory
index 752125c..752125c 100644
--- a/usr.sbin/zic/Theory
+++ b/contrib/tzcode/zic/Theory
diff --git a/usr.sbin/zic/ialloc.c b/contrib/tzcode/zic/ialloc.c
index 1694c29..1694c29 100644
--- a/usr.sbin/zic/ialloc.c
+++ b/contrib/tzcode/zic/ialloc.c
diff --git a/usr.sbin/zic/private.h b/contrib/tzcode/zic/private.h
index ecbf612..ecbf612 100644
--- a/usr.sbin/zic/private.h
+++ b/contrib/tzcode/zic/private.h
diff --git a/usr.sbin/zic/scheck.c b/contrib/tzcode/zic/scheck.c
index abdb4ba..abdb4ba 100644
--- a/usr.sbin/zic/scheck.c
+++ b/contrib/tzcode/zic/scheck.c
diff --git a/usr.sbin/zic/zdump.8 b/contrib/tzcode/zic/zdump.8
index 9ac0a03..9ac0a03 100644
--- a/usr.sbin/zic/zdump.8
+++ b/contrib/tzcode/zic/zdump.8
diff --git a/usr.sbin/zic/zdump.c b/contrib/tzcode/zic/zdump.c
index 0f61125..0f61125 100644
--- a/usr.sbin/zic/zdump.c
+++ b/contrib/tzcode/zic/zdump.c
diff --git a/contrib/tzcode/zic/zdump/Makefile b/contrib/tzcode/zic/zdump/Makefile
new file mode 100644
index 0000000..7ee8db3
--- /dev/null
+++ b/contrib/tzcode/zic/zdump/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/..
+
+PROG= zdump
+MAN= zdump.8
+SRCS= zdump.c ialloc.c scheck.c
+
+CFLAGS+= -DTM_GMTOFF=tm_gmtoff -DTM_ZONE=tm_zone -DSTD_INSPIRED -DPCTS
+CFLAGS+= -DHAVE_LONG_DOUBLE -DTZDIR=\"/usr/share/zoneinfo\" -Demkdir=mkdir
+CFLAGS+= -I${.CURDIR}/.. -I${.CURDIR}/../../../lib/libc/stdtime
+
+WARNS?= 2
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/zic/zic.8 b/contrib/tzcode/zic/zic.8
index f7ff815b..f7ff815b 100644
--- a/usr.sbin/zic/zic.8
+++ b/contrib/tzcode/zic/zic.8
diff --git a/usr.sbin/zic/zic.c b/contrib/tzcode/zic/zic.c
index 7670056..7670056 100644
--- a/usr.sbin/zic/zic.c
+++ b/contrib/tzcode/zic/zic.c
diff --git a/contrib/tzcode/zic/zic/Makefile b/contrib/tzcode/zic/zic/Makefile
new file mode 100644
index 0000000..02dc6e2
--- /dev/null
+++ b/contrib/tzcode/zic/zic/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/..
+
+PROG= zic
+MAN= zic.8
+SRCS= zic.c ialloc.c scheck.c
+
+CFLAGS+= -DTM_GMTOFF=tm_gmtoff -DTM_ZONE=tm_zone -DSTD_INSPIRED -DPCTS
+CFLAGS+= -DHAVE_LONG_DOUBLE -DTZDIR=\"/usr/share/zoneinfo\" -Demkdir=mkdir
+CFLAGS+= -DHAVE_STRERROR -DHAVE_UNISTD_H
+CFLAGS+= -I${.CURDIR}/.. -I${.CURDIR}/../../../lib/libc/stdtime
+
+WARNS?= 2
+
+.include <bsd.prog.mk>
diff --git a/share/zoneinfo/africa b/contrib/tzdata/africa
index ad89bb7..ad89bb7 100644
--- a/share/zoneinfo/africa
+++ b/contrib/tzdata/africa
diff --git a/share/zoneinfo/antarctica b/contrib/tzdata/antarctica
index f18ae95..f18ae95 100644
--- a/share/zoneinfo/antarctica
+++ b/contrib/tzdata/antarctica
diff --git a/share/zoneinfo/asia b/contrib/tzdata/asia
index e9780ac..e9780ac 100644
--- a/share/zoneinfo/asia
+++ b/contrib/tzdata/asia
diff --git a/share/zoneinfo/australasia b/contrib/tzdata/australasia
index 3812390..3812390 100644
--- a/share/zoneinfo/australasia
+++ b/contrib/tzdata/australasia
diff --git a/share/zoneinfo/backward b/contrib/tzdata/backward
index c896968..c896968 100644
--- a/share/zoneinfo/backward
+++ b/contrib/tzdata/backward
diff --git a/share/zoneinfo/etcetera b/contrib/tzdata/etcetera
index 8f69280..8f69280 100644
--- a/share/zoneinfo/etcetera
+++ b/contrib/tzdata/etcetera
diff --git a/share/zoneinfo/europe b/contrib/tzdata/europe
index 05e3cae..05e3cae 100644
--- a/share/zoneinfo/europe
+++ b/contrib/tzdata/europe
diff --git a/share/zoneinfo/factory b/contrib/tzdata/factory
index 78c144e..78c144e 100644
--- a/share/zoneinfo/factory
+++ b/contrib/tzdata/factory
diff --git a/share/zoneinfo/leapseconds b/contrib/tzdata/leapseconds
index a3c95ef..a3c95ef 100644
--- a/share/zoneinfo/leapseconds
+++ b/contrib/tzdata/leapseconds
diff --git a/share/zoneinfo/northamerica b/contrib/tzdata/northamerica
index 5c25664..5c25664 100644
--- a/share/zoneinfo/northamerica
+++ b/contrib/tzdata/northamerica
diff --git a/share/zoneinfo/pacificnew b/contrib/tzdata/pacificnew
index e2512c1..e2512c1 100644
--- a/share/zoneinfo/pacificnew
+++ b/contrib/tzdata/pacificnew
diff --git a/share/zoneinfo/southamerica b/contrib/tzdata/southamerica
index 9c4edcb..7ad8170 100644
--- a/share/zoneinfo/southamerica
+++ b/contrib/tzdata/southamerica
@@ -1,5 +1,5 @@
# <pre>
-# @(#)southamerica 8.40
+# @(#)southamerica 8.41
# This file is in the public domain, so clarified as of
# 2009-05-17 by Arthur David Olson.
@@ -1364,8 +1364,24 @@ Rule Para 2002 2003 - Sep Sun>=1 0:00 1:00 S
# Decree 1,867 (2004-03-05)
# From Carlos Raul Perasso via Jesper Norgaard Welen (2006-10-13)
# <http://www.presidencia.gov.py/decretos/D1867.pdf>
-Rule Para 2004 max - Oct Sun>=15 0:00 1:00 S
-Rule Para 2005 max - Mar Sun>=8 0:00 0 -
+Rule Para 2004 2009 - Oct Sun>=15 0:00 1:00 S
+Rule Para 2005 2009 - Mar Sun>=8 0:00 0 -
+# From Carlos Raul Perasso (2010-02-18):
+# By decree number 3958 issued yesterday (
+# <a href="http://www.presidencia.gov.py/v1/wp-content/uploads/2010/02/decreto3958.pdf">
+# http://www.presidencia.gov.py/v1/wp-content/uploads/2010/02/decreto3958.pdf
+# </a>
+# )
+# Paraguay changes its DST schedule, postponing the March rule to April and
+# modifying the October date. The decree reads:
+# ...
+# Art. 1. It is hereby established that from the second Sunday of the month of
+# April of this year (2010), the official time is to be set back 60 minutes,
+# and that on the first Sunday of the month of October, it is to be set
+# forward 60 minutes, in all the territory of the Paraguayan Republic.
+# ...
+Rule Para 2010 max - Oct Sun<=7 0:00 1:00 S
+Rule Para 2010 max - Apr Sun>=8 0:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone America/Asuncion -3:50:40 - LMT 1890
diff --git a/share/zoneinfo/systemv b/contrib/tzdata/systemv
index 767388d..767388d 100644
--- a/share/zoneinfo/systemv
+++ b/contrib/tzdata/systemv
diff --git a/share/zoneinfo/yearistype.sh b/contrib/tzdata/yearistype.sh
index 66dbf89..66dbf89 100755
--- a/share/zoneinfo/yearistype.sh
+++ b/contrib/tzdata/yearistype.sh
diff --git a/share/zoneinfo/zone.tab b/contrib/tzdata/zone.tab
index c8fb250..c8fb250 100644
--- a/share/zoneinfo/zone.tab
+++ b/contrib/tzdata/zone.tab
diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf
index 7d0a7d2..35b3a7b 100644
--- a/etc/defaults/rc.conf
+++ b/etc/defaults/rc.conf
@@ -260,6 +260,9 @@ syslogd_flags="-s" # Flags to syslogd (if enabled).
inetd_enable="NO" # Run the network daemon dispatcher (YES/NO).
inetd_program="/usr/sbin/inetd" # path to inetd, if you want a different one.
inetd_flags="-wW -C 60" # Optional flags to inetd
+hastd_enable="NO" # Run the HAST daemon (YES/NO).
+hastd_program="/sbin/hastd" # path to hastd, if you want a different one.
+hastd_flags="" # Optional flags to hastd.
#
# named. It may be possible to run named in a sandbox, man security for
# details.
diff --git a/etc/mtree/BSD.usr.dist b/etc/mtree/BSD.usr.dist
index 8ccca1a..87f7ca3 100644
--- a/etc/mtree/BSD.usr.dist
+++ b/etc/mtree/BSD.usr.dist
@@ -193,8 +193,6 @@
..
IPv6
..
- bc
- ..
bootforth
..
cvs
@@ -215,6 +213,8 @@
..
find_interface
..
+ hast
+ ..
hostapd
..
ibcs2
diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile
index d0e24b3..17f7634 100755
--- a/etc/rc.d/Makefile
+++ b/etc/rc.d/Makefile
@@ -12,7 +12,7 @@ FILES= DAEMON FILESYSTEMS LOGIN NETWORKING SERVERS \
encswap \
faith fsck ftp-proxy ftpd \
gbde geli geli2 gssd \
- hcsecd \
+ hastd hcsecd \
hostapd hostid hostid_save hostname \
inetd initrandom \
ip6addrctl ipfilter ipfs ipfw ipmon \
diff --git a/etc/rc.d/hastd b/etc/rc.d/hastd
new file mode 100644
index 0000000..1100678
--- /dev/null
+++ b/etc/rc.d/hastd
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: hastd
+# REQUIRE: NETWORKING syslogd
+# BEFORE: DAEMON
+# KEYWORD: nojail shutdown
+
+. /etc/rc.subr
+
+name="hastd"
+rcvar=`set_rcvar`
+pidfile="/var/run/${name}.pid"
+command="/sbin/${name}"
+hastctl="/sbin/hastctl"
+required_files="/etc/hast.conf"
+stop_precmd="hastd_stop_precmd"
+required_modules="geom_gate:g_gate"
+
+hastd_stop_precmd()
+{
+ ${hastctl} role init all
+}
+
+load_rc_config $name
+run_rc_command "$1"
diff --git a/etc/rc.d/rtsold b/etc/rc.d/rtsold
index bbecebb..64a83e3 100755
--- a/etc/rc.d/rtsold
+++ b/etc/rc.d/rtsold
@@ -6,7 +6,7 @@
# PROVIDE: rtsold
# REQUIRE: netif
# BEFORE: NETWORKING
-# KEYWORD: nojail
+# KEYWORD: nojail shutdown
. /etc/rc.subr
diff --git a/games/fortune/datfiles/fortunes b/games/fortune/datfiles/fortunes
index b04ba66..ceff2a0 100644
--- a/games/fortune/datfiles/fortunes
+++ b/games/fortune/datfiles/fortunes
@@ -59620,3 +59620,19 @@ since I first called my brother's father dad.
Zymurgy's Law of Volunteer Labor:
People are always available for work in the past tense.
%
+This email and any files transmitted with it are confidential and
+intended solely for the use of the individual or entity to which they
+are addressed. If you are not the intended recipient of this
+transmission, please delete it immediately.
+
+Obviously, I am the idiot who sent it to you by mistake. Furthermore,
+there is no way I can force you to delete it. Worse, by the time you
+have reached this disclaimer you have already read the document.
+Telling you to forget it would seem absurd. In any event, I have no
+legal right to force you to take any action upon this email anyway.
+
+This entire disclaimer is just a waste of everyone's time and
+bandwidth. Therefore, let us just forget the whole thing and enjoy a
+cold beer instead.
+ -- found on the dovecot mailinglist
+%
diff --git a/games/fortune/fortune/fortune.c b/games/fortune/fortune/fortune.c
index edff26f..65ae35e 100644
--- a/games/fortune/fortune/fortune.c
+++ b/games/fortune/fortune/fortune.c
@@ -216,7 +216,7 @@ main(int argc, char *argv[])
sleep((unsigned int) max(Fort_len / CPERS, MINW));
}
- return (0);
+ exit(0);
}
void
diff --git a/gnu/usr.bin/Makefile b/gnu/usr.bin/Makefile
index d177c49..54f26cb 100644
--- a/gnu/usr.bin/Makefile
+++ b/gnu/usr.bin/Makefile
@@ -9,6 +9,7 @@ SUBDIR= ${_binutils} \
dialog \
diff \
diff3 \
+ dtc \
${_gdb} \
${_gperf} \
${_grep} \
@@ -21,10 +22,6 @@ SUBDIR= ${_binutils} \
sort \
${_texinfo}
-.if ${MACHINE_CPUARCH} == "mips"
-MK_GDB=no # not yet
-.endif
-
.if ${MK_CXX} != "no"
_gperf= gperf
.if ${MK_GROFF} != "no"
diff --git a/gnu/usr.bin/bc/Makefile b/gnu/usr.bin/bc/Makefile
deleted file mode 100644
index 74419f2..0000000
--- a/gnu/usr.bin/bc/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-# $FreeBSD$
-
-.include <bsd.own.mk>
-
-BCDIR= ${.CURDIR}/../../../contrib/bc
-.PATH: ${BCDIR}/bc ${BCDIR}/lib ${BCDIR}/doc ${BCDIR}/Examples
-
-PROG= bc
-SRCS= bc.y execute.c global.c load.c main.c scan.l storage.c util.c \
- number.c
-CFLAGS+=-I. -I${.CURDIR} -I${BCDIR}/h -I${BCDIR}/bc
-CFLAGS+=-DHAVE_CONFIG_H
-DPADD= ${LIBREADLINE} ${LIBTERMCAP}
-LDADD= -lreadline -ltermcap
-
-.if ${MK_EXAMPLES} != "no"
-FILES= ckbook.b pi.b primes.b twins.b
-FILESDIR= ${SHAREDIR}/examples/bc
-.endif
-
-.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/bc/config.h b/gnu/usr.bin/bc/config.h
deleted file mode 100644
index b9e3520..0000000
--- a/gnu/usr.bin/bc/config.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/* $FreeBSD$ */
-
-/* config.h. Generated automatically by configure. */
-/* config.h.in. Generated automatically from configure.in by autoheader. */
-
-/* Define to empty if the keyword does not work. */
-/* #undef const */
-
-/* Define if you don't have vprintf but do have _doprnt. */
-/* #undef HAVE_DOPRNT */
-
-/* Define if you have the vprintf function. */
-#define HAVE_VPRINTF 1
-
-/* Define if on MINIX. */
-/* #undef _MINIX */
-
-/* Define if the system does not provide POSIX.1 features except
- with this defined. */
-/* #undef _POSIX_1_SOURCE */
-
-/* Define if you need to in order for stat and other things to work. */
-/* #undef _POSIX_SOURCE */
-
-/* Define to `unsigned' if <sys/types.h> doesn't define. */
-/* #undef size_t */
-
-/* Define if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* Define if lex declares yytext as a char * by default, not a char[]. */
-#define YYTEXT_POINTER 1
-
-/* VERSION number for DC target*/
-#define DC_VERSION "1.3"
-
-/* COPYRIGHT notice for DC target */
-#define DC_COPYRIGHT "Copyright 1994, 1997, 1998, 2000 Free Software Foundation, Inc."
-
-/* COPYRIGHT notice for BC target */
-#define BC_COPYRIGHT "Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc."
-
-/* Define to use the readline library. */
-#define READLINE 1
-
-/* Define to use the BSD libedit library. */
-/* #define LIBEDIT 1 */
-
-/* Define to `size_t' if <sys/types.h> and <stddef.h> don't define. */
-/* #undef ptrdiff_t */
-
-/* Define if you have the isgraph function. */
-#define HAVE_ISGRAPH 1
-
-/* Define if you have the setvbuf function. */
-#define HAVE_SETVBUF 1
-
-/* Define if you have the <lib.h> header file. */
-/* #undef HAVE_LIB_H */
-
-/* Define if you have the <limits.h> header file. */
-#define HAVE_LIMITS_H 1
-
-/* Define if you have the <stdarg.h> header file. */
-#define HAVE_STDARG_H 1
-
-/* Define if you have the <stddef.h> header file. */
-#define HAVE_STDDEF_H 1
-
-/* Define if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define if you have the <unistd.h> header file. */
-#define HAVE_UNISTD_H 1
-
-/* Name of package */
-#define PACKAGE "bc"
-
-/* Version number of package */
-#define VERSION "1.06"
-
diff --git a/gnu/usr.bin/binutils/ld/Makefile.mips b/gnu/usr.bin/binutils/ld/Makefile.mips
index f1c0493..af24b9f 100644
--- a/gnu/usr.bin/binutils/ld/Makefile.mips
+++ b/gnu/usr.bin/binutils/ld/Makefile.mips
@@ -8,7 +8,8 @@ NATIVE_EMULATION=elf${_sz}btsmip_fbsd
NATIVE_EMULATION=elf${_sz}ltsmip_fbsd
.endif
-MIPS_ABIS=elf32btsmip_fbsd elf32ltsmip_fbsd elf64btsmip_fbsd elf64ltsmip_fbsd
+MIPS_ABIS=elf32btsmip_fbsd elf32ltsmip_fbsd elf64btsmip_fbsd elf64ltsmip_fbsd \
+ elf32btsmipn32_fbsd elf32ltsmipn32_fbsd
.for abi in ${MIPS_ABIS}
#.if (${abi} != ${NATIVE_EMULATION})
EMS+= ${abi}
diff --git a/gnu/usr.bin/binutils/ld/elf32btsmipn32_fbsd.sh b/gnu/usr.bin/binutils/ld/elf32btsmipn32_fbsd.sh
new file mode 100755
index 0000000..ef5afbc
--- /dev/null
+++ b/gnu/usr.bin/binutils/ld/elf32btsmipn32_fbsd.sh
@@ -0,0 +1,4 @@
+# $FreeBSD$
+. ${srcdir}/emulparams/elf32btsmip.sh
+. ${srcdir}/emulparams/elf_fbsd.sh
+GENERATE_PIE_SCRIPT=yes
diff --git a/gnu/usr.bin/binutils/ld/elf32ltsmipn32_fbsd.sh b/gnu/usr.bin/binutils/ld/elf32ltsmipn32_fbsd.sh
new file mode 100755
index 0000000..89c13d8
--- /dev/null
+++ b/gnu/usr.bin/binutils/ld/elf32ltsmipn32_fbsd.sh
@@ -0,0 +1,4 @@
+# $FreeBSD$
+. ${srcdir}/emulparams/elf32ltsmip.sh
+. ${srcdir}/emulparams/elf_fbsd.sh
+GENERATE_PIE_SCRIPT=yes
diff --git a/gnu/usr.bin/binutils/ld/genscripts.sh b/gnu/usr.bin/binutils/ld/genscripts.sh
index 20d1022..6f8da9f 100755
--- a/gnu/usr.bin/binutils/ld/genscripts.sh
+++ b/gnu/usr.bin/binutils/ld/genscripts.sh
@@ -50,6 +50,7 @@ fi
if test -d ldscripts; then
true
else
+ rm -f ldscripts
mkdir ldscripts
fi
diff --git a/gnu/usr.bin/dc/Makefile b/gnu/usr.bin/dc/Makefile
deleted file mode 100644
index 12de718..0000000
--- a/gnu/usr.bin/dc/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# $FreeBSD$
-
-BCDIR= ${.CURDIR}/../../../contrib/bc
-
-.PATH: ${BCDIR}/dc ${BCDIR}/lib ${BCDIR}/doc
-
-PROG= dc
-SRCS= array.c dc.c eval.c misc.c numeric.c stack.c string.c \
- number.c
-CFLAGS+=-I${.CURDIR}/../bc -I${BCDIR}/h -DHAVE_CONFIG_H
-DPADD= ${LIBM}
-LDADD= -lm
-SUBDIR= doc
-
-.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/dc/doc/Makefile b/gnu/usr.bin/dc/doc/Makefile
deleted file mode 100644
index 2b3d553..0000000
--- a/gnu/usr.bin/dc/doc/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# Makefile copyright Andreas Klemm <andreas@FreeBSD.ORG> 1998
-#
-# $FreeBSD$
-
-.PATH: ${.CURDIR}/../../../../contrib/bc/doc
-
-INFO = dc
-INFOSECTION= "System Utilities"
-INFOENTRY_dc= "* DC: (dc). The GNU Desktop Calculator."
-
-.include <bsd.info.mk>
diff --git a/gnu/usr.bin/diff/Makefile b/gnu/usr.bin/diff/Makefile
index 25d439f..ba5ab65 100644
--- a/gnu/usr.bin/diff/Makefile
+++ b/gnu/usr.bin/diff/Makefile
@@ -29,7 +29,7 @@ LDADD= -lgnuregex
.for f in diff.c context.c
${f}: ${DIFFSRC}/${f} ${.CURDIR}/${f}.diff
- patch -s -b .orig -o ${.TARGET} < ${.CURDIR}/${f}.diff ${DIFFSRC}/${f}
+ patch -s -o ${.TARGET} < ${.CURDIR}/${f}.diff ${DIFFSRC}/${f}
CLEANFILES+= ${f}
.endfor
diff --git a/gnu/usr.bin/diff3/Makefile b/gnu/usr.bin/diff3/Makefile
index 9fbb5db..6e9f867 100644
--- a/gnu/usr.bin/diff3/Makefile
+++ b/gnu/usr.bin/diff3/Makefile
@@ -20,7 +20,7 @@ CFLAGS+=-DDEFAULT_DIFF_PROGRAM=\"/usr/bin/diff\"
.for f in diff3.c
${f}: ${DIFFSRC}/${f} ${.CURDIR}/${f}.diff
- patch -s -b .orig -o ${.TARGET} < ${.CURDIR}/${f}.diff ${DIFFSRC}/${f}
+ patch -s -o ${.TARGET} < ${.CURDIR}/${f}.diff ${DIFFSRC}/${f}
CLEANFILES+= ${f}
.endfor
diff --git a/gnu/usr.bin/dtc/Makefile b/gnu/usr.bin/dtc/Makefile
new file mode 100644
index 0000000..3bab94e
--- /dev/null
+++ b/gnu/usr.bin/dtc/Makefile
@@ -0,0 +1,51 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+DTCDIR= ${.CURDIR}/../../../contrib/dtc
+LIBFDTDIR= ${.CURDIR}/../../../sys/contrib/libfdt
+.PATH: ${DTCDIR} ${LIBFDTDIR} ${DTCDIR}/tests
+
+PROG= dtc
+
+SRCS= dtc.c checks.c fstree.c livetree.c treesource.c data.c \
+ flattree.c srcpos.c util.c \
+ fdt.c fdt_ro.c fdt_rw.c fdt_strerror.c \
+ fdt_sw.c fdt_wip.c $(DTCDIR)/version_gen.h
+
+CFLAGS = -Wall -g -Os -fPIC -Wpointer-arith -Wcast-qual
+CFLAGS+= -I. -I${.CURDIR} -I${DTCDIR} -I${LIBFDTDIR}
+
+VERSIONMAJ!= awk '/^VERSION =/ { print $$3 }' $(DTCDIR)/Makefile
+VERSIONMIN!= awk '/^PATCHLEVEL =/ { print $$3 }' $(DTCDIR)/Makefile
+VERSIONSUB!= awk '/^SUBLEVEL =/ { print $$3 }' $(DTCDIR)/Makefile
+VERSIONEXTRA!= $(DTCDIR)/scripts/setlocalversion
+
+DTCVERSION:= ${VERSIONMAJ}.${VERSIONMIN}.${VERSIONSUB}${VERSIONEXTRA}
+DTCVERSIONFILE:= $(DTCDIR)/version_gen.h
+
+MAN=
+
+BISON= yacc
+LEX= lex
+
+OBJS+= dtc-parser.tab.o dtc-lexer.lex.o
+
+CLEANFILES+= dtc-parser.tab.o dtc-lexer.lex.o dtc-parser.tab.c \
+ dtc-parser.tab.h dtc-lexer.lex.c ${DTCVERSIONFILE}
+
+$(DTCVERSIONFILE):
+ @echo '#define DTC_VERSION "DTC ${DTCVERSION}"' > ${DTCVERSIONFILE}
+
+dtc-parser.tab.o: dtc-parser.tab.c dtc-parser.tab.h
+dtc-lexer.lex.o: dtc-lexer.lex.c dtc-parser.tab.h
+
+dtc-parser.tab.c: dtc-parser.y
+ $(BISON) -o$@ -d $(DTCDIR)/dtc-parser.y
+
+dtc-parser.tab.h: dtc-parser.tab.c
+
+dtc-lexer.lex.c: dtc-lexer.l
+ $(LEX) -o$@ $(DTCDIR)/dtc-lexer.l
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/gdb/arch/mips/Makefile b/gnu/usr.bin/gdb/arch/mips/Makefile
index ff05421..54180d9 100644
--- a/gnu/usr.bin/gdb/arch/mips/Makefile
+++ b/gnu/usr.bin/gdb/arch/mips/Makefile
@@ -1,10 +1,10 @@
# $FreeBSD$
.if !defined(GDB_CROSS_DEBUGGER)
-LIBSRCS+= mips-nat.c mips-nat.c mipsfbsd-nat.c
+LIBSRCS+= mipsfbsd-nat.c
.endif
LIBSRCS+= solib.c solib-svr4.c
-LIBSRCS+= mips-tdep.c mipsfbsd-tdep.c
+LIBSRCS+= mips-tdep.c mipsfbsd-tdep.c fbsd-proc.c
nm.h:
echo '#include "mips/nm-fbsd.h"' > ${.TARGET}
diff --git a/gnu/usr.bin/gdb/arch/mips/init.c b/gnu/usr.bin/gdb/arch/mips/init.c
index 3aa7ec5..27631f2 100644
--- a/gnu/usr.bin/gdb/arch/mips/init.c
+++ b/gnu/usr.bin/gdb/arch/mips/init.c
@@ -123,15 +123,19 @@ initialize_all_files (void)
_initialize_ser_pipe ();
_initialize_ser_tcp ();
#ifndef CROSS_DEBUGGER
+#if 0
_initialize_mipsfbsd_nat ();
_initialize_mips_nat ();
+#endif
_initialize_kernel_u_addr ();
_initialize_infptrace ();
_initialize_inftarg ();
_initialize_solib ();
_initialize_svr4_solib ();
+#if 0
_initialize_svr4_lm ();
#endif
+#endif
_initialize_remote ();
_initialize_dcache ();
_initialize_sr_support ();
diff --git a/gnu/usr.bin/gdb/gdbserver/Makefile b/gnu/usr.bin/gdb/gdbserver/Makefile
index 5df2341..ddac155 100644
--- a/gnu/usr.bin/gdb/gdbserver/Makefile
+++ b/gnu/usr.bin/gdb/gdbserver/Makefile
@@ -16,7 +16,7 @@ SRCS+= fbsd-low.c
SRCS+= fbsd-${MACHINE_CPUARCH}-low.c reg-${MACHINE_CPUARCH}.c
-.if ${MACHINE_CPUARCH} == "i386"
+.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
SRCS+= i387-fp.c
.endif
diff --git a/gnu/usr.bin/gdb/gdbserver/fbsd-amd64-low.c b/gnu/usr.bin/gdb/gdbserver/fbsd-amd64-low.c
new file mode 100644
index 0000000..82a8c93
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdbserver/fbsd-amd64-low.c
@@ -0,0 +1,213 @@
+/* GNU/FreeBSD/amd64 specific low level interface, for the remote server for GDB.
+ Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "server.h"
+#include "fbsd-low.h"
+#include "i387-fp.h"
+
+#include <sys/stddef.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+
+/* Mapping between the general-purpose registers in `struct user'
+ format and GDB's register array layout. */
+static int amd64_regmap[] = {
+ offsetof(struct reg, r_rax),
+ offsetof(struct reg, r_rbx),
+ offsetof(struct reg, r_rcx),
+ offsetof(struct reg, r_rdx),
+ offsetof(struct reg, r_rsi),
+ offsetof(struct reg, r_rdi),
+ offsetof(struct reg, r_rbp),
+ offsetof(struct reg, r_rsp),
+ offsetof(struct reg, r_r8),
+ offsetof(struct reg, r_r9),
+ offsetof(struct reg, r_r10),
+ offsetof(struct reg, r_r11),
+ offsetof(struct reg, r_r12),
+ offsetof(struct reg, r_r13),
+ offsetof(struct reg, r_r14),
+ offsetof(struct reg, r_r15),
+ offsetof(struct reg, r_rip),
+ offsetof(struct reg, r_rflags), /* XXX 64-bit */
+ offsetof(struct reg, r_cs),
+ offsetof(struct reg, r_ss),
+ offsetof(struct reg, r_ds),
+ offsetof(struct reg, r_es),
+ offsetof(struct reg, r_fs),
+ offsetof(struct reg, r_gs),
+};
+#define AMD64_NUM_REGS (sizeof(amd64_regmap) / sizeof(amd64_regmap[0]))
+
+static const char amd64_breakpoint[] = { 0xCC };
+#define AMD64_BP_LEN 1
+
+extern int debug_threads;
+
+static int
+amd64_cannot_store_register(int regno)
+{
+
+ return (regno >= AMD64_NUM_REGS);
+}
+
+static int
+amd64_cannot_fetch_register(int regno)
+{
+
+ return (regno >= AMD64_NUM_REGS);
+}
+
+static void
+amd64_fill_gregset(void *buf)
+{
+ int i;
+
+ for (i = 0; i < AMD64_NUM_REGS; i++)
+ collect_register(i, ((char *)buf) + amd64_regmap[i]);
+}
+
+static void
+amd64_store_gregset(const void *buf)
+{
+ int i;
+
+ for (i = 0; i < AMD64_NUM_REGS; i++)
+ supply_register(i, ((char *)buf) + amd64_regmap[i]);
+}
+
+static void
+amd64_fill_fpregset(void *buf)
+{
+
+ i387_cache_to_fsave(buf);
+}
+
+static void
+amd64_store_fpregset(const void *buf)
+{
+
+ i387_fsave_to_cache(buf);
+}
+
+static void
+amd64_fill_fpxregset(void *buf)
+{
+
+ i387_cache_to_fxsave(buf);
+}
+
+static void
+amd64_store_fpxregset(const void *buf)
+{
+
+ i387_fxsave_to_cache(buf);
+}
+
+
+struct regset_info target_regsets[] = {
+ {
+ PT_GETREGS,
+ PT_SETREGS,
+ sizeof(struct reg),
+ GENERAL_REGS,
+ amd64_fill_gregset,
+ amd64_store_gregset,
+ },
+#ifdef HAVE_PTRACE_GETFPXREGS
+ {
+ PTRACE_GETFPXREGS,
+ PTRACE_SETFPXREGS,
+ sizeof(elf_fpxregset_t),
+ EXTENDED_REGS,
+ amd64_fill_fpxregset,
+ amd64_store_fpxregset,
+ },
+#endif
+ {
+ PT_GETFPREGS,
+ PT_SETFPREGS,
+ sizeof(struct fpreg),
+ FP_REGS,
+ amd64_fill_fpregset,
+ amd64_store_fpregset,
+ },
+ {
+ 0,
+ 0,
+ -1,
+ -1,
+ NULL,
+ NULL,
+ }
+};
+
+static CORE_ADDR
+amd64_get_pc(void)
+{
+ unsigned long pc;
+
+ collect_register_by_name("rip", &pc);
+
+ if (debug_threads)
+ fprintf(stderr, "stop pc (before any decrement) is %016lx\n", pc);
+
+ return (pc);
+}
+
+static void
+amd64_set_pc(CORE_ADDR newpc)
+{
+
+ if (debug_threads)
+ fprintf(stderr, "set pc to %016lx\n", (long)newpc);
+ supply_register_by_name("rip", &newpc);
+}
+
+static int
+amd64_breakpoint_at(CORE_ADDR pc)
+{
+ unsigned char c;
+
+ read_inferior_memory(pc, &c, 1);
+ if (c == 0xCC)
+ return (1);
+
+ return (0);
+}
+
+struct fbsd_target_ops the_low_target = {
+ AMD64_NUM_REGS,
+ amd64_regmap,
+ amd64_cannot_fetch_register,
+ amd64_cannot_store_register,
+ amd64_get_pc,
+ amd64_set_pc,
+ amd64_breakpoint,
+ AMD64_BP_LEN,
+ NULL,
+ 1,
+ amd64_breakpoint_at,
+};
diff --git a/gnu/usr.bin/gdb/gdbserver/reg-x86-64.c b/gnu/usr.bin/gdb/gdbserver/reg-x86-64.c
new file mode 100644
index 0000000..7b0534f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdbserver/reg-x86-64.c
@@ -0,0 +1,99 @@
+/* *INDENT-OFF* */ /* THIS FILE IS GENERATED */
+
+/* A register protocol for GDB, the GNU debugger.
+ Copyright 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* This file was created with the aid of ``regdat.sh'' and ``../../../../contrib/gdb/gdb/regformats/reg-x86-64.dat''. */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "regdef.h"
+#include "regcache.h"
+
+struct reg regs_x86_64[] = {
+ { "rax", 0, 64 },
+ { "rbx", 64, 64 },
+ { "rcx", 128, 64 },
+ { "rdx", 192, 64 },
+ { "rsi", 256, 64 },
+ { "rdi", 320, 64 },
+ { "rbp", 384, 64 },
+ { "rsp", 448, 64 },
+ { "r8", 512, 64 },
+ { "r9", 576, 64 },
+ { "r10", 640, 64 },
+ { "r11", 704, 64 },
+ { "r12", 768, 64 },
+ { "r13", 832, 64 },
+ { "r14", 896, 64 },
+ { "r15", 960, 64 },
+ { "rip", 1024, 64 },
+ { "eflags", 1088, 32 },
+ { "cs", 1120, 32 },
+ { "ss", 1152, 32 },
+ { "ds", 1184, 32 },
+ { "es", 1216, 32 },
+ { "fs", 1248, 32 },
+ { "gs", 1280, 32 },
+ { "st0", 1312, 80 },
+ { "st1", 1392, 80 },
+ { "st2", 1472, 80 },
+ { "st3", 1552, 80 },
+ { "st4", 1632, 80 },
+ { "st5", 1712, 80 },
+ { "st6", 1792, 80 },
+ { "st7", 1872, 80 },
+ { "fctrl", 1952, 32 },
+ { "fstat", 1984, 32 },
+ { "ftag", 2016, 32 },
+ { "fiseg", 2048, 32 },
+ { "fioff", 2080, 32 },
+ { "foseg", 2112, 32 },
+ { "fooff", 2144, 32 },
+ { "fop", 2176, 32 },
+ { "xmm0", 2208, 128 },
+ { "xmm1", 2336, 128 },
+ { "xmm2", 2464, 128 },
+ { "xmm3", 2592, 128 },
+ { "xmm4", 2720, 128 },
+ { "xmm5", 2848, 128 },
+ { "xmm6", 2976, 128 },
+ { "xmm7", 3104, 128 },
+ { "xmm8", 3232, 128 },
+ { "xmm9", 3360, 128 },
+ { "xmm10", 3488, 128 },
+ { "xmm11", 3616, 128 },
+ { "xmm12", 3744, 128 },
+ { "xmm13", 3872, 128 },
+ { "xmm14", 4000, 128 },
+ { "xmm15", 4128, 128 },
+ { "mxcsr", 4256, 32 },
+};
+
+const char *expedite_regs_x86_64[] = { "rbp", "rsp", "rip", 0 };
+
+void
+init_registers ()
+{
+ set_register_cache (regs_x86_64,
+ sizeof (regs_x86_64) / sizeof (regs_x86_64[0]));
+ gdbserver_expedite_regs = expedite_regs_x86_64;
+}
diff --git a/gnu/usr.bin/gdb/kgdb/trgt_mips.c b/gnu/usr.bin/gdb/kgdb/trgt_mips.c
index 92d6f23..9782222 100644
--- a/gnu/usr.bin/gdb/kgdb/trgt_mips.c
+++ b/gnu/usr.bin/gdb/kgdb/trgt_mips.c
@@ -61,18 +61,17 @@ kgdb_trgt_fetch_registers(int regno __unused)
warnx("kvm_read: %s", kvm_geterr(kvm));
memset(&pcb, 0, sizeof(pcb));
}
- supply_register(MIPS_S0_REGNUM, (char *)&pcb.pcb_context.val[0]);
- supply_register(MIPS_S1_REGNUM, (char *)&pcb.pcb_context.val[1]);
- supply_register(MIPS_S2_REGNUM, (char *)&pcb.pcb_context.val[2]);
- supply_register(MIPS_S3_REGNUM, (char *)&pcb.pcb_context.val[3]);
- supply_register(MIPS_S4_REGNUM, (char *)&pcb.pcb_context.val[4]);
- supply_register(MIPS_S5_REGNUM, (char *)&pcb.pcb_context.val[5]);
- supply_register(MIPS_S6_REGNUM, (char *)&pcb.pcb_context.val[6]);
- supply_register(MIPS_S7_REGNUM, (char *)&pcb.pcb_context.val[7]);
- supply_register(MIPS_SP_REGNUM, (char *)&pcb.pcb_context.val[8]);
- supply_register(MIPS_SP_REGNUM, (char *)&pcb.pcb_context.val[8]);
- supply_register(MIPS_FP_REGNUM, (char *)&pcb.pcb_context.val[9]);
- supply_register(MIPS_RA_REGNUM, (char *)&pcb.pcb_context.val[10]);
+ supply_register(MIPS_S0_REGNUM, (char *)&pcb.pcb_context[0]);
+ supply_register(MIPS_S1_REGNUM, (char *)&pcb.pcb_context[1]);
+ supply_register(MIPS_S2_REGNUM, (char *)&pcb.pcb_context[2]);
+ supply_register(MIPS_S3_REGNUM, (char *)&pcb.pcb_context[3]);
+ supply_register(MIPS_S4_REGNUM, (char *)&pcb.pcb_context[4]);
+ supply_register(MIPS_S5_REGNUM, (char *)&pcb.pcb_context[5]);
+ supply_register(MIPS_S6_REGNUM, (char *)&pcb.pcb_context[6]);
+ supply_register(MIPS_S7_REGNUM, (char *)&pcb.pcb_context[7]);
+ supply_register(MIPS_SP_REGNUM, (char *)&pcb.pcb_context[8]);
+ supply_register(MIPS_FP_REGNUM, (char *)&pcb.pcb_context[9]);
+ supply_register(MIPS_RA_REGNUM, (char *)&pcb.pcb_context[10]);
}
void
diff --git a/gnu/usr.bin/sdiff/Makefile b/gnu/usr.bin/sdiff/Makefile
index c40cd4d..efadcf2 100644
--- a/gnu/usr.bin/sdiff/Makefile
+++ b/gnu/usr.bin/sdiff/Makefile
@@ -21,7 +21,7 @@ CFLAGS+=-DDEFAULT_DIFF_PROGRAM=\"/usr/bin/diff\"
.for f in sdiff.c
${f}: ${DIFFSRC}/${f} ${.CURDIR}/${f}.diff
- patch -s -b .orig -o ${.TARGET} < ${.CURDIR}/${f}.diff ${DIFFSRC}/${f}
+ patch -s -o ${.TARGET} < ${.CURDIR}/${f}.diff ${DIFFSRC}/${f}
CLEANFILES+= ${f}
.endfor
diff --git a/lib/libalias/Makefile.inc b/lib/libalias/Makefile.inc
new file mode 100644
index 0000000..265f86d
--- /dev/null
+++ b/lib/libalias/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+.include "../Makefile.inc"
diff --git a/lib/libalias/libalias/Makefile b/lib/libalias/libalias/Makefile
index a3f9889..00b4ed8 100644
--- a/lib/libalias/libalias/Makefile
+++ b/lib/libalias/libalias/Makefile
@@ -8,7 +8,6 @@ SHLIB_MAJOR= 7
MAN= libalias.3
SRCS= alias.c alias_db.c alias_proxy.c alias_util.c alias_mod.c
INCS= alias.h
-WARNS?= 6
NO_WERROR=
.include <bsd.lib.mk>
diff --git a/lib/libarchive/archive_write_disk.3 b/lib/libarchive/archive_write_disk.3
index f0ee011..2bdc0f5 100644
--- a/lib/libarchive/archive_write_disk.3
+++ b/lib/libarchive/archive_write_disk.3
@@ -339,7 +339,7 @@ In particular, the directory
.Pa aa
is created as well as the final object
.Pa bb .
-In theory, this can be exploited to create an entire directory heirarchy
+In theory, this can be exploited to create an entire directory hierarchy
with a single request.
Of course, this does not work if the
.Cm ARCHIVE_EXTRACT_NODOTDOT
@@ -371,5 +371,5 @@ compact implementation when appropriate.
.Pp
There should be a corresponding
.Nm archive_read_disk
-interface that walks a directory heirarchy and returns archive
+interface that walks a directory hierarchy and returns archive
entry objects.
diff --git a/lib/libarchive/test/Makefile b/lib/libarchive/test/Makefile
index ab65da3..c721f57 100644
--- a/lib/libarchive/test/Makefile
+++ b/lib/libarchive/test/Makefile
@@ -137,7 +137,6 @@ CFLAGS+= -I${LA_SRCDIR} -I.
# Uncomment to link against dmalloc
#LDADD+= -L/usr/local/lib -ldmalloc
#CFLAGS+= -I/usr/local/include -DUSE_DMALLOC
-#WARNS=6
# Build libarchive_test and run it.
check test: libarchive_test
diff --git a/lib/libbsnmp/Makefile.inc b/lib/libbsnmp/Makefile.inc
index 566274c..82f48ac 100644
--- a/lib/libbsnmp/Makefile.inc
+++ b/lib/libbsnmp/Makefile.inc
@@ -1,6 +1,6 @@
# $FreeBSD$
-SHLIB_MAJOR= 5
-WARNS?= 6
NO_WERROR=
INCSDIR= ${INCLUDEDIR}/bsnmp
+
+.include "../Makefile.inc"
diff --git a/lib/libbsnmp/libbsnmp/Makefile b/lib/libbsnmp/libbsnmp/Makefile
index 91351c0..a0ceecd 100644
--- a/lib/libbsnmp/libbsnmp/Makefile
+++ b/lib/libbsnmp/libbsnmp/Makefile
@@ -5,9 +5,8 @@
CONTRIB= ${.CURDIR}/../../../contrib/bsnmp/lib
.PATH: ${CONTRIB}
-LIB = bsnmp
-SHLIBDIR ?= /lib
-WARNS ?= 6
+LIB= bsnmp
+SHLIBDIR?= /lib
CFLAGS+= -I${CONTRIB} -DHAVE_ERR_H -DHAVE_GETADDRINFO -DHAVE_STRLCPY
CFLAGS+= -DHAVE_STDINT_H -DHAVE_INTTYPES_H -DQUADFMT='"llu"' -DQUADXFMT='"llx"'
diff --git a/lib/libc/gen/fmtcheck.3 b/lib/libc/gen/fmtcheck.3
index 782526d..ecd70fb 100644
--- a/lib/libc/gen/fmtcheck.3
+++ b/lib/libc/gen/fmtcheck.3
@@ -11,13 +11,6 @@
.\" 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.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the NetBSD
-.\" Foundation, Inc. and its contributors.
-.\" 4. Neither the name of The NetBSD Foundation nor the names of its
-.\" contributors may be used to endorse or promote products derived
-.\" from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/lib/libc/gen/pause.c b/lib/libc/gen/pause.c
index 00bf833..51706cf 100644
--- a/lib/libc/gen/pause.c
+++ b/lib/libc/gen/pause.c
@@ -33,8 +33,10 @@ static char sccsid[] = "@(#)pause.c 8.1 (Berkeley) 6/4/93";
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "namespace.h"
#include <signal.h>
#include <unistd.h>
+#include "un-namespace.h"
/*
* Backwards compatible pause.
@@ -42,7 +44,11 @@ __FBSDID("$FreeBSD$");
int
__pause(void)
{
- return sigpause(sigblock(0L));
+ sigset_t oset;
+
+ if (_sigprocmask(SIG_BLOCK, NULL, &oset) == -1)
+ return (-1);
+ return (_sigsuspend(&oset));
}
__weak_reference(__pause, pause);
__weak_reference(__pause, _pause);
diff --git a/lib/libc/gen/stringlist.3 b/lib/libc/gen/stringlist.3
index 30dd299..44d2a36 100644
--- a/lib/libc/gen/stringlist.3
+++ b/lib/libc/gen/stringlist.3
@@ -13,13 +13,6 @@
.\" 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.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the NetBSD
-.\" Foundation, Inc. and its contributors.
-.\" 4. Neither the name of The NetBSD Foundation nor the names of its
-.\" contributors may be used to endorse or promote products derived
-.\" from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/lib/libc/gen/sysconf.c b/lib/libc/gen/sysconf.c
index 3c342ee..4618f32 100644
--- a/lib/libc/gen/sysconf.c
+++ b/lib/libc/gen/sysconf.c
@@ -50,7 +50,7 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include "../stdlib/atexit.h"
-#include "../stdtime/tzfile.h"
+#include "tzfile.h" /* from ../../../contrib/tzcode/stdtime */
#define _PATH_ZONEINFO TZDIR /* from tzfile.h */
diff --git a/lib/libc/gen/sysctl.3 b/lib/libc/gen/sysctl.3
index 75f8668..143be16 100644
--- a/lib/libc/gen/sysctl.3
+++ b/lib/libc/gen/sysctl.3
@@ -28,7 +28,7 @@
.\" @(#)sysctl.3 8.4 (Berkeley) 5/9/95
.\" $FreeBSD$
.\"
-.Dd January 28, 2009
+.Dd February 21, 2010
.Dt SYSCTL 3
.Os
.Sh NAME
@@ -42,9 +42,9 @@
.In sys/types.h
.In sys/sysctl.h
.Ft int
-.Fn sysctl "int *name" "u_int namelen" "void *oldp" "size_t *oldlenp" "void *newp" "size_t newlen"
+.Fn sysctl "const int *name" "u_int namelen" "void *oldp" "size_t *oldlenp" "const void *newp" "size_t newlen"
.Ft int
-.Fn sysctlbyname "const char *name" "void *oldp" "size_t *oldlenp" "void *newp" "size_t newlen"
+.Fn sysctlbyname "const char *name" "void *oldp" "size_t *oldlenp" "const void *newp" "size_t newlen"
.Ft int
.Fn sysctlnametomib "const char *name" "int *mibp" "size_t *sizep"
.Sh DESCRIPTION
diff --git a/lib/libc/gen/sysctl.c b/lib/libc/gen/sysctl.c
index eb6418e..fbc2c0c 100644
--- a/lib/libc/gen/sysctl.c
+++ b/lib/libc/gen/sysctl.c
@@ -43,15 +43,12 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include <string.h>
-extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
- void *newp, size_t newlen);
+extern int __sysctl(const int *name, u_int namelen, void *oldp,
+ size_t *oldlenp, const void *newp, size_t newlen);
int
-sysctl(name, namelen, oldp, oldlenp, newp, newlen)
- int *name;
- u_int namelen;
- void *oldp, *newp;
- size_t *oldlenp, newlen;
+sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp,
+ const void *newp, size_t newlen)
{
if (name[0] != CTL_USER)
return (__sysctl(name, namelen, oldp, oldlenp, newp, newlen));
diff --git a/lib/libc/gen/sysctlbyname.c b/lib/libc/gen/sysctlbyname.c
index 4510fe0..a2e0d5f 100644
--- a/lib/libc/gen/sysctlbyname.c
+++ b/lib/libc/gen/sysctlbyname.c
@@ -13,27 +13,19 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/sysctl.h>
-#include <string.h>
int
-sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
- size_t newlen)
+sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
+ const void *newp, size_t newlen)
{
- int name2oid_oid[2];
int real_oid[CTL_MAXNAME+2];
int error;
size_t oidlen;
- name2oid_oid[0] = 0; /* This is magic & undocumented! */
- name2oid_oid[1] = 3;
-
- oidlen = sizeof(real_oid);
- error = sysctl(name2oid_oid, 2, real_oid, &oidlen, (void *)name,
- strlen(name));
+ oidlen = sizeof(real_oid) / sizeof(int);
+ error = sysctlnametomib(name, real_oid, &oidlen);
if (error < 0)
- return error;
- oidlen /= sizeof (int);
+ return (error);
error = sysctl(real_oid, oidlen, oldp, oldlenp, newp, newlen);
return (error);
}
-
diff --git a/lib/libc/gen/sysctlnametomib.c b/lib/libc/gen/sysctlnametomib.c
index 1515784..afca95d 100644
--- a/lib/libc/gen/sysctlnametomib.c
+++ b/lib/libc/gen/sysctlnametomib.c
@@ -48,8 +48,8 @@ sysctlnametomib(const char *name, int *mibp, size_t *sizep)
oid[0] = 0;
oid[1] = 3;
- *sizep *= sizeof (int);
- error = sysctl(oid, 2, mibp, sizep, (void *)name, strlen(name));
- *sizep /= sizeof (int);
+ *sizep *= sizeof(int);
+ error = sysctl(oid, 2, mibp, sizep, name, strlen(name));
+ *sizep /= sizeof(int);
return (error);
}
diff --git a/lib/libc/include/reentrant.h b/lib/libc/include/reentrant.h
index 8ab328b..22a2325 100644
--- a/lib/libc/include/reentrant.h
+++ b/lib/libc/include/reentrant.h
@@ -13,13 +13,6 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/lib/libc/nls/msgcat.c b/lib/libc/nls/msgcat.c
index 910c185..4532e90 100644
--- a/lib/libc/nls/msgcat.c
+++ b/lib/libc/nls/msgcat.c
@@ -60,34 +60,35 @@ __FBSDID("$FreeBSD$");
#define _DEFAULT_NLS_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L:/usr/local/share/nls/%L/%N.cat:/usr/local/share/nls/%N/%L"
-#define RLOCK(fail) { int ret; \
- if (__isthreaded && \
- ((ret = _pthread_rwlock_rdlock(&rwlock)) != 0)) { \
- errno = ret; \
- return (fail); \
+#define RLOCK(fail) { int ret; \
+ if (__isthreaded && \
+ ((ret = _pthread_rwlock_rdlock(&rwlock)) != 0)) { \
+ errno = ret; \
+ return (fail); \
}}
-#define WLOCK(fail) { int ret; \
- if (__isthreaded && \
- ((ret = _pthread_rwlock_wrlock(&rwlock)) != 0)) { \
- errno = ret; \
- return (fail); \
+#define WLOCK(fail) { int ret; \
+ if (__isthreaded && \
+ ((ret = _pthread_rwlock_wrlock(&rwlock)) != 0)) { \
+ errno = ret; \
+ return (fail); \
}}
-#define UNLOCK { if (__isthreaded) \
+#define UNLOCK { if (__isthreaded) \
_pthread_rwlock_unlock(&rwlock); }
#define NLERR ((nl_catd) -1)
#define NLRETERR(errc) { errno = errc; return (NLERR); }
-#define SAVEFAIL(n, l, e) { WLOCK(NLERR); \
- np = malloc(sizeof(struct catentry)); \
- if (np != NULL) { \
- np->name = strdup(n); \
- np->path = NULL; \
- np->lang = (l == NULL) ? NULL : strdup(l); \
- np->caterrno = e; \
- SLIST_INSERT_HEAD(&cache, np, list); \
- } \
- UNLOCK; \
- errno = e; \
+#define SAVEFAIL(n, l, e) { WLOCK(NLERR); \
+ np = malloc(sizeof(struct catentry)); \
+ if (np != NULL) { \
+ np->name = strdup(n); \
+ np->path = NULL; \
+ np->lang = (l == NULL) ? NULL : \
+ strdup(l); \
+ np->caterrno = e; \
+ SLIST_INSERT_HEAD(&cache, np, list); \
+ } \
+ UNLOCK; \
+ errno = e; \
}
static nl_catd load_msgcat(const char *, const char *, const char *);
@@ -209,7 +210,7 @@ catopen(const char *name, int type)
break;
case '%':
++nlspath;
- /* fallthrough */
+ /* FALLTHROUGH */
default:
if (pathP - path >=
sizeof(path) - 1)
@@ -369,7 +370,8 @@ load_msgcat(const char *path, const char *name, const char *lang)
/* path/name will never be NULL here */
- /* One more try in cache; if it was not found by name,
+ /*
+ * One more try in cache; if it was not found by name,
* it might still be found by absolute path.
*/
RLOCK(NLERR);
@@ -393,8 +395,9 @@ load_msgcat(const char *path, const char *name, const char *lang)
NLRETERR(EFTYPE);
}
- /* If the file size cannot be held in size_t we cannot mmap()
- * it to the memory. Probably, this will not be a problem given
+ /*
+ * If the file size cannot be held in size_t we cannot mmap()
+ * it to the memory. Probably, this will not be a problem given
* that catalog files are usually small.
*/
if (st.st_size > SIZE_T_MAX) {
diff --git a/lib/libc/stdio/mktemp.c b/lib/libc/stdio/mktemp.c
index 3f1e699..a30b930 100644
--- a/lib/libc/stdio/mktemp.c
+++ b/lib/libc/stdio/mktemp.c
@@ -116,6 +116,10 @@ _gettemp(path, doopen, domkdir, slen)
for (trv = path; *trv != '\0'; ++trv)
;
+ if (trv - path >= MAXPATHLEN) {
+ errno = ENAMETOOLONG;
+ return (0);
+ }
trv -= slen;
suffp = trv;
--trv;
diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c
index de7a4c0..295a168 100644
--- a/lib/libc/stdlib/malloc.c
+++ b/lib/libc/stdlib/malloc.c
@@ -194,6 +194,7 @@ __FBSDID("$FreeBSD$");
#include "un-namespace.h"
+#define RB_COMPACT
#include "rb.h"
#if (defined(MALLOC_TCACHE) && defined(MALLOC_STATS))
#include "qr.h"
@@ -1746,7 +1747,7 @@ extent_szad_comp(extent_node_t *a, extent_node_t *b)
}
/* Wrap red-black tree macros in functions. */
-rb_wrap(__unused static, extent_tree_szad_, extent_tree_t, extent_node_t,
+rb_gen(__unused static, extent_tree_szad_, extent_tree_t, extent_node_t,
link_szad, extent_szad_comp)
#endif
@@ -1760,7 +1761,7 @@ extent_ad_comp(extent_node_t *a, extent_node_t *b)
}
/* Wrap red-black tree macros in functions. */
-rb_wrap(__unused static, extent_tree_ad_, extent_tree_t, extent_node_t, link_ad,
+rb_gen(__unused static, extent_tree_ad_, extent_tree_t, extent_node_t, link_ad,
extent_ad_comp)
/*
@@ -2346,7 +2347,7 @@ arena_chunk_comp(arena_chunk_t *a, arena_chunk_t *b)
}
/* Wrap red-black tree macros in functions. */
-rb_wrap(__unused static, arena_chunk_tree_dirty_, arena_chunk_tree_t,
+rb_gen(__unused static, arena_chunk_tree_dirty_, arena_chunk_tree_t,
arena_chunk_t, link_dirty, arena_chunk_comp)
static inline int
@@ -2362,7 +2363,7 @@ arena_run_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
}
/* Wrap red-black tree macros in functions. */
-rb_wrap(__unused static, arena_run_tree_, arena_run_tree_t, arena_chunk_map_t,
+rb_gen(__unused static, arena_run_tree_, arena_run_tree_t, arena_chunk_map_t,
link, arena_run_comp)
static inline int
@@ -2394,7 +2395,7 @@ arena_avail_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
}
/* Wrap red-black tree macros in functions. */
-rb_wrap(__unused static, arena_avail_tree_, arena_avail_tree_t,
+rb_gen(__unused static, arena_avail_tree_, arena_avail_tree_t,
arena_chunk_map_t, link, arena_avail_comp)
static inline void
@@ -2824,6 +2825,18 @@ arena_run_alloc(arena_t *arena, size_t size, bool large, bool zero)
return (run);
}
+#ifdef MALLOC_DEBUG
+static arena_chunk_t *
+chunks_dirty_iter_cb(arena_chunk_tree_t *tree, arena_chunk_t *chunk, void *arg)
+{
+ size_t *ndirty = (size_t *)arg;
+
+ assert(chunk->dirtied);
+ *ndirty += chunk->ndirty;
+ return (NULL);
+}
+#endif
+
static void
arena_purge(arena_t *arena)
{
@@ -2832,11 +2845,8 @@ arena_purge(arena_t *arena)
#ifdef MALLOC_DEBUG
size_t ndirty = 0;
- rb_foreach_begin(arena_chunk_t, link_dirty, &arena->chunks_dirty,
- chunk) {
- assert(chunk->dirtied);
- ndirty += chunk->ndirty;
- } rb_foreach_end(arena_chunk_t, link_dirty, &arena->chunks_dirty, chunk)
+ arena_chunk_tree_dirty_iter(&arena->chunks_dirty, NULL,
+ chunks_dirty_iter_cb, (void *)&ndirty);
assert(ndirty == arena->ndirty);
#endif
assert((arena->nactive >> opt_lg_dirty_mult) < arena->ndirty);
diff --git a/lib/libc/stdlib/rb.h b/lib/libc/stdlib/rb.h
index 80875b0..baaec7f 100644
--- a/lib/libc/stdlib/rb.h
+++ b/lib/libc/stdlib/rb.h
@@ -1,6 +1,7 @@
-/******************************************************************************
+/*-
+ *******************************************************************************
*
- * Copyright (C) 2008 Jason Evans <jasone@FreeBSD.org>.
+ * Copyright (C) 2008-2010 Jason Evans <jasone@FreeBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,40 +30,23 @@
*
******************************************************************************
*
- * cpp macro implementation of left-leaning red-black trees.
+ * cpp macro implementation of left-leaning 2-3 red-black trees. Parent
+ * pointers are not used, and color bits are stored in the least significant
+ * bit of right-child pointers (if RB_COMPACT is defined), thus making node
+ * linkage as compact as is possible for red-black trees.
*
* Usage:
*
- * (Optional, see assert(3).)
- * #define NDEBUG
- *
- * (Required.)
+ * #include <stdint.h>
+ * #include <stdbool.h>
+ * #define NDEBUG // (Optional, see assert(3).)
* #include <assert.h>
+ * #define RB_COMPACT // (Optional, embed color bits in right-child pointers.)
* #include <rb.h>
* ...
*
- * All operations are done non-recursively. Parent pointers are not used, and
- * color bits are stored in the least significant bit of right-child pointers,
- * thus making node linkage as compact as is possible for red-black trees.
- *
- * Some macros use a comparison function pointer, which is expected to have the
- * following prototype:
- *
- * int (a_cmp *)(a_type *a_node, a_type *a_other);
- * ^^^^^^
- * or a_key
- *
- * Interpretation of comparision function return values:
- *
- * -1 : a_node < a_other
- * 0 : a_node == a_other
- * 1 : a_node > a_other
- *
- * In all cases, the a_node or a_key macro argument is the first argument to the
- * comparison function, which makes it possible to write comparison functions
- * that treat the first argument specially.
- *
- ******************************************************************************/
+ *******************************************************************************
+ */
#ifndef RB_H_
#define RB_H_
@@ -70,12 +54,21 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#ifdef RB_COMPACT
/* Node structure. */
#define rb_node(a_type) \
struct { \
a_type *rbn_left; \
a_type *rbn_right_red; \
}
+#else
+#define rb_node(a_type) \
+struct { \
+ a_type *rbn_left; \
+ a_type *rbn_right; \
+ bool rbn_red; \
+}
+#endif
/* Root structure. */
#define rb_tree(a_type) \
@@ -85,863 +78,925 @@ struct { \
}
/* Left accessors. */
-#define rbp_left_get(a_type, a_field, a_node) \
+#define rbtn_left_get(a_type, a_field, a_node) \
((a_node)->a_field.rbn_left)
-#define rbp_left_set(a_type, a_field, a_node, a_left) do { \
+#define rbtn_left_set(a_type, a_field, a_node, a_left) do { \
(a_node)->a_field.rbn_left = a_left; \
} while (0)
+#ifdef RB_COMPACT
/* Right accessors. */
-#define rbp_right_get(a_type, a_field, a_node) \
+#define rbtn_right_get(a_type, a_field, a_node) \
((a_type *) (((intptr_t) (a_node)->a_field.rbn_right_red) \
& ((ssize_t)-2)))
-#define rbp_right_set(a_type, a_field, a_node, a_right) do { \
+#define rbtn_right_set(a_type, a_field, a_node, a_right) do { \
(a_node)->a_field.rbn_right_red = (a_type *) (((uintptr_t) a_right) \
| (((uintptr_t) (a_node)->a_field.rbn_right_red) & ((size_t)1))); \
} while (0)
/* Color accessors. */
-#define rbp_red_get(a_type, a_field, a_node) \
+#define rbtn_red_get(a_type, a_field, a_node) \
((bool) (((uintptr_t) (a_node)->a_field.rbn_right_red) \
& ((size_t)1)))
-#define rbp_color_set(a_type, a_field, a_node, a_red) do { \
+#define rbtn_color_set(a_type, a_field, a_node, a_red) do { \
(a_node)->a_field.rbn_right_red = (a_type *) ((((intptr_t) \
(a_node)->a_field.rbn_right_red) & ((ssize_t)-2)) \
| ((ssize_t)a_red)); \
} while (0)
-#define rbp_red_set(a_type, a_field, a_node) do { \
+#define rbtn_red_set(a_type, a_field, a_node) do { \
(a_node)->a_field.rbn_right_red = (a_type *) (((uintptr_t) \
(a_node)->a_field.rbn_right_red) | ((size_t)1)); \
} while (0)
-#define rbp_black_set(a_type, a_field, a_node) do { \
+#define rbtn_black_set(a_type, a_field, a_node) do { \
(a_node)->a_field.rbn_right_red = (a_type *) (((intptr_t) \
(a_node)->a_field.rbn_right_red) & ((ssize_t)-2)); \
} while (0)
+#else
+/* Right accessors. */
+#define rbtn_right_get(a_type, a_field, a_node) \
+ ((a_node)->a_field.rbn_right)
+#define rbtn_right_set(a_type, a_field, a_node, a_right) do { \
+ (a_node)->a_field.rbn_right = a_right; \
+} while (0)
+
+/* Color accessors. */
+#define rbtn_red_get(a_type, a_field, a_node) \
+ ((a_node)->a_field.rbn_red)
+#define rbtn_color_set(a_type, a_field, a_node, a_red) do { \
+ (a_node)->a_field.rbn_red = (a_red); \
+} while (0)
+#define rbtn_red_set(a_type, a_field, a_node) do { \
+ (a_node)->a_field.rbn_red = true; \
+} while (0)
+#define rbtn_black_set(a_type, a_field, a_node) do { \
+ (a_node)->a_field.rbn_red = false; \
+} while (0)
+#endif
/* Node initializer. */
-#define rbp_node_new(a_type, a_field, a_tree, a_node) do { \
- rbp_left_set(a_type, a_field, (a_node), &(a_tree)->rbt_nil); \
- rbp_right_set(a_type, a_field, (a_node), &(a_tree)->rbt_nil); \
- rbp_red_set(a_type, a_field, (a_node)); \
+#define rbt_node_new(a_type, a_field, a_rbt, a_node) do { \
+ rbtn_left_set(a_type, a_field, (a_node), &(a_rbt)->rbt_nil); \
+ rbtn_right_set(a_type, a_field, (a_node), &(a_rbt)->rbt_nil); \
+ rbtn_red_set(a_type, a_field, (a_node)); \
} while (0)
/* Tree initializer. */
-#define rb_new(a_type, a_field, a_tree) do { \
- (a_tree)->rbt_root = &(a_tree)->rbt_nil; \
- rbp_node_new(a_type, a_field, a_tree, &(a_tree)->rbt_nil); \
- rbp_black_set(a_type, a_field, &(a_tree)->rbt_nil); \
+#define rb_new(a_type, a_field, a_rbt) do { \
+ (a_rbt)->rbt_root = &(a_rbt)->rbt_nil; \
+ rbt_node_new(a_type, a_field, a_rbt, &(a_rbt)->rbt_nil); \
+ rbtn_black_set(a_type, a_field, &(a_rbt)->rbt_nil); \
} while (0)
-/* Tree operations. */
-#define rbp_black_height(a_type, a_field, a_tree, r_height) do { \
- a_type *rbp_bh_t; \
- for (rbp_bh_t = (a_tree)->rbt_root, (r_height) = 0; \
- rbp_bh_t != &(a_tree)->rbt_nil; \
- rbp_bh_t = rbp_left_get(a_type, a_field, rbp_bh_t)) { \
- if (rbp_red_get(a_type, a_field, rbp_bh_t) == false) { \
- (r_height)++; \
+/* Internal utility macros. */
+#define rbtn_first(a_type, a_field, a_rbt, a_root, r_node) do { \
+ (r_node) = (a_root); \
+ if ((r_node) != &(a_rbt)->rbt_nil) { \
+ for (; \
+ rbtn_left_get(a_type, a_field, (r_node)) != &(a_rbt)->rbt_nil;\
+ (r_node) = rbtn_left_get(a_type, a_field, (r_node))) { \
} \
} \
} while (0)
-#define rbp_first(a_type, a_field, a_tree, a_root, r_node) do { \
- for ((r_node) = (a_root); \
- rbp_left_get(a_type, a_field, (r_node)) != &(a_tree)->rbt_nil; \
- (r_node) = rbp_left_get(a_type, a_field, (r_node))) { \
+#define rbtn_last(a_type, a_field, a_rbt, a_root, r_node) do { \
+ (r_node) = (a_root); \
+ if ((r_node) != &(a_rbt)->rbt_nil) { \
+ for (; rbtn_right_get(a_type, a_field, (r_node)) != \
+ &(a_rbt)->rbt_nil; (r_node) = rbtn_right_get(a_type, a_field, \
+ (r_node))) { \
+ } \
} \
} while (0)
-#define rbp_last(a_type, a_field, a_tree, a_root, r_node) do { \
- for ((r_node) = (a_root); \
- rbp_right_get(a_type, a_field, (r_node)) != &(a_tree)->rbt_nil; \
- (r_node) = rbp_right_get(a_type, a_field, (r_node))) { \
- } \
+#define rbtn_rotate_left(a_type, a_field, a_node, r_node) do { \
+ (r_node) = rbtn_right_get(a_type, a_field, (a_node)); \
+ rbtn_right_set(a_type, a_field, (a_node), \
+ rbtn_left_get(a_type, a_field, (r_node))); \
+ rbtn_left_set(a_type, a_field, (r_node), (a_node)); \
} while (0)
-#define rbp_next(a_type, a_field, a_cmp, a_tree, a_node, r_node) do { \
- if (rbp_right_get(a_type, a_field, (a_node)) \
- != &(a_tree)->rbt_nil) { \
- rbp_first(a_type, a_field, a_tree, rbp_right_get(a_type, \
- a_field, (a_node)), (r_node)); \
+#define rbtn_rotate_right(a_type, a_field, a_node, r_node) do { \
+ (r_node) = rbtn_left_get(a_type, a_field, (a_node)); \
+ rbtn_left_set(a_type, a_field, (a_node), \
+ rbtn_right_get(a_type, a_field, (r_node))); \
+ rbtn_right_set(a_type, a_field, (r_node), (a_node)); \
+} while (0)
+
+/*
+ * The rb_proto() macro generates function prototypes that correspond to the
+ * functions generated by an equivalently parameterized call to rb_gen().
+ */
+
+#define rb_proto(a_attr, a_prefix, a_rbt_type, a_type) \
+a_attr void \
+a_prefix##new(a_rbt_type *rbtree); \
+a_attr a_type * \
+a_prefix##first(a_rbt_type *rbtree); \
+a_attr a_type * \
+a_prefix##last(a_rbt_type *rbtree); \
+a_attr a_type * \
+a_prefix##next(a_rbt_type *rbtree, a_type *node); \
+a_attr a_type * \
+a_prefix##prev(a_rbt_type *rbtree, a_type *node); \
+a_attr a_type * \
+a_prefix##search(a_rbt_type *rbtree, a_type *key); \
+a_attr a_type * \
+a_prefix##nsearch(a_rbt_type *rbtree, a_type *key); \
+a_attr a_type * \
+a_prefix##psearch(a_rbt_type *rbtree, a_type *key); \
+a_attr void \
+a_prefix##insert(a_rbt_type *rbtree, a_type *node); \
+a_attr void \
+a_prefix##remove(a_rbt_type *rbtree, a_type *node); \
+a_attr a_type * \
+a_prefix##iter(a_rbt_type *rbtree, a_type *start, a_type *(*cb)( \
+ a_rbt_type *, a_type *, void *), void *arg); \
+a_attr a_type * \
+a_prefix##reverse_iter(a_rbt_type *rbtree, a_type *start, \
+ a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg);
+
+/*
+ * The rb_gen() macro generates a type-specific red-black tree implementation,
+ * based on the above cpp macros.
+ *
+ * Arguments:
+ *
+ * a_attr : Function attribute for generated functions (ex: static).
+ * a_prefix : Prefix for generated functions (ex: extree_).
+ * a_rb_type : Type for red-black tree data structure (ex: extree_t).
+ * a_type : Type for red-black tree node data structure (ex:
+ * extree_node_t).
+ * a_field : Name of red-black tree node linkage (ex: extree_link).
+ * a_cmp : Node comparison function name, with the following prototype:
+ * int (a_cmp *)(a_type *a_node, a_type *a_other);
+ * ^^^^^^
+ * or a_key
+ * Interpretation of comparision function return values:
+ * -1 : a_node < a_other
+ * 0 : a_node == a_other
+ * 1 : a_node > a_other
+ * In all cases, the a_node or a_key macro argument is the first
+ * argument to the comparison function, which makes it possible
+ * to write comparison functions that treat the first argument
+ * specially.
+ *
+ * Assuming the following setup:
+ *
+ * typedef struct ex_node_s ex_node_t;
+ * struct ex_node_s {
+ * rb_node(ex_node_t) ex_link;
+ * };
+ * typedef rb(ex_node_t) ex_t;
+ * rb_gen(static, ex_, ex_t, ex_node_t, ex_link, ex_cmp, 1297, 1301)
+ *
+ * The following API is generated:
+ *
+ * static void
+ * ex_new(ex_t *extree);
+ * Description: Initialize a red-black tree structure.
+ * Args:
+ * extree: Pointer to an uninitialized red-black tree object.
+ *
+ * static ex_node_t *
+ * ex_first(ex_t *extree);
+ * static ex_node_t *
+ * ex_last(ex_t *extree);
+ * Description: Get the first/last node in extree.
+ * Args:
+ * extree: Pointer to an initialized red-black tree object.
+ * Ret: First/last node in extree, or NULL if extree is empty.
+ *
+ * static ex_node_t *
+ * ex_next(ex_t *extree, ex_node_t *node);
+ * static ex_node_t *
+ * ex_prev(ex_t *extree, ex_node_t *node);
+ * Description: Get node's successor/predecessor.
+ * Args:
+ * extree: Pointer to an initialized red-black tree object.
+ * node : A node in extree.
+ * Ret: node's successor/predecessor in extree, or NULL if node is
+ * last/first.
+ *
+ * static ex_node_t *
+ * ex_search(ex_t *extree, ex_node_t *key);
+ * Description: Search for node that matches key.
+ * Args:
+ * extree: Pointer to an initialized red-black tree object.
+ * key : Search key.
+ * Ret: Node in extree that matches key, or NULL if no match.
+ *
+ * static ex_node_t *
+ * ex_nsearch(ex_t *extree, ex_node_t *key);
+ * static ex_node_t *
+ * ex_psearch(ex_t *extree, ex_node_t *key);
+ * Description: Search for node that matches key. If no match is found,
+ * return what would be key's successor/predecessor, were
+ * key in extree.
+ * Args:
+ * extree: Pointer to an initialized red-black tree object.
+ * key : Search key.
+ * Ret: Node in extree that matches key, or if no match, hypothetical
+ * node's successor/predecessor (NULL if no successor/predecessor).
+ *
+ * static void
+ * ex_insert(ex_t *extree, ex_node_t *node);
+ * Description: Insert node into extree.
+ * Args:
+ * extree: Pointer to an initialized red-black tree object.
+ * node : Node to be inserted into extree.
+ *
+ * static void
+ * ex_remove(ex_t *extree, ex_node_t *node);
+ * Description: Remove node from extree.
+ * Args:
+ * extree: Pointer to an initialized red-black tree object.
+ * node : Node in extree to be removed.
+ *
+ * static ex_node_t *
+ * ex_iter(ex_t *extree, ex_node_t *start, ex_node_t *(*cb)(ex_t *,
+ * ex_node_t *, void *), void *arg);
+ * static ex_node_t *
+ * ex_reverse_iter(ex_t *extree, ex_node_t *start, ex_node *(*cb)(ex_t *,
+ * ex_node_t *, void *), void *arg);
+ * Description: Iterate forward/backward over extree, starting at node.
+ * If extree is modified, iteration must be immediately
+ * terminated by the callback function that causes the
+ * modification.
+ * Args:
+ * extree: Pointer to an initialized red-black tree object.
+ * start : Node at which to start iteration, or NULL to start at
+ * first/last node.
+ * cb : Callback function, which is called for each node during
+ * iteration. Under normal circumstances the callback function
+ * should return NULL, which causes iteration to continue. If a
+ * callback function returns non-NULL, iteration is immediately
+ * terminated and the non-NULL return value is returned by the
+ * iterator. This is useful for re-starting iteration after
+ * modifying extree.
+ * arg : Opaque pointer passed to cb().
+ * Ret: NULL if iteration completed, or the non-NULL callback return value
+ * that caused termination of the iteration.
+ */
+#define rb_gen(a_attr, a_prefix, a_rbt_type, a_type, a_field, a_cmp) \
+a_attr void \
+a_prefix##new(a_rbt_type *rbtree) { \
+ rb_new(a_type, a_field, rbtree); \
+} \
+a_attr a_type * \
+a_prefix##first(a_rbt_type *rbtree) { \
+ a_type *ret; \
+ rbtn_first(a_type, a_field, rbtree, rbtree->rbt_root, ret); \
+ if (ret == &rbtree->rbt_nil) { \
+ ret = NULL; \
+ } \
+ return (ret); \
+} \
+a_attr a_type * \
+a_prefix##last(a_rbt_type *rbtree) { \
+ a_type *ret; \
+ rbtn_last(a_type, a_field, rbtree, rbtree->rbt_root, ret); \
+ if (ret == &rbtree->rbt_nil) { \
+ ret = NULL; \
+ } \
+ return (ret); \
+} \
+a_attr a_type * \
+a_prefix##next(a_rbt_type *rbtree, a_type *node) { \
+ a_type *ret; \
+ if (rbtn_right_get(a_type, a_field, node) != &rbtree->rbt_nil) { \
+ rbtn_first(a_type, a_field, rbtree, rbtn_right_get(a_type, \
+ a_field, node), ret); \
} else { \
- a_type *rbp_n_t = (a_tree)->rbt_root; \
- assert(rbp_n_t != &(a_tree)->rbt_nil); \
- (r_node) = &(a_tree)->rbt_nil; \
+ a_type *tnode = rbtree->rbt_root; \
+ assert(tnode != &rbtree->rbt_nil); \
+ ret = &rbtree->rbt_nil; \
while (true) { \
- int rbp_n_cmp = (a_cmp)((a_node), rbp_n_t); \
- if (rbp_n_cmp < 0) { \
- (r_node) = rbp_n_t; \
- rbp_n_t = rbp_left_get(a_type, a_field, rbp_n_t); \
- } else if (rbp_n_cmp > 0) { \
- rbp_n_t = rbp_right_get(a_type, a_field, rbp_n_t); \
+ int cmp = (a_cmp)(node, tnode); \
+ if (cmp < 0) { \
+ ret = tnode; \
+ tnode = rbtn_left_get(a_type, a_field, tnode); \
+ } else if (cmp > 0) { \
+ tnode = rbtn_right_get(a_type, a_field, tnode); \
} else { \
break; \
} \
- assert(rbp_n_t != &(a_tree)->rbt_nil); \
+ assert(tnode != &rbtree->rbt_nil); \
} \
} \
-} while (0)
-
-#define rbp_prev(a_type, a_field, a_cmp, a_tree, a_node, r_node) do { \
- if (rbp_left_get(a_type, a_field, (a_node)) != &(a_tree)->rbt_nil) {\
- rbp_last(a_type, a_field, a_tree, rbp_left_get(a_type, \
- a_field, (a_node)), (r_node)); \
+ if (ret == &rbtree->rbt_nil) { \
+ ret = (NULL); \
+ } \
+ return (ret); \
+} \
+a_attr a_type * \
+a_prefix##prev(a_rbt_type *rbtree, a_type *node) { \
+ a_type *ret; \
+ if (rbtn_left_get(a_type, a_field, node) != &rbtree->rbt_nil) { \
+ rbtn_last(a_type, a_field, rbtree, rbtn_left_get(a_type, \
+ a_field, node), ret); \
} else { \
- a_type *rbp_p_t = (a_tree)->rbt_root; \
- assert(rbp_p_t != &(a_tree)->rbt_nil); \
- (r_node) = &(a_tree)->rbt_nil; \
+ a_type *tnode = rbtree->rbt_root; \
+ assert(tnode != &rbtree->rbt_nil); \
+ ret = &rbtree->rbt_nil; \
while (true) { \
- int rbp_p_cmp = (a_cmp)((a_node), rbp_p_t); \
- if (rbp_p_cmp < 0) { \
- rbp_p_t = rbp_left_get(a_type, a_field, rbp_p_t); \
- } else if (rbp_p_cmp > 0) { \
- (r_node) = rbp_p_t; \
- rbp_p_t = rbp_right_get(a_type, a_field, rbp_p_t); \
+ int cmp = (a_cmp)(node, tnode); \
+ if (cmp < 0) { \
+ tnode = rbtn_left_get(a_type, a_field, tnode); \
+ } else if (cmp > 0) { \
+ ret = tnode; \
+ tnode = rbtn_right_get(a_type, a_field, tnode); \
} else { \
break; \
} \
- assert(rbp_p_t != &(a_tree)->rbt_nil); \
+ assert(tnode != &rbtree->rbt_nil); \
} \
} \
-} while (0)
-
-#define rb_first(a_type, a_field, a_tree, r_node) do { \
- rbp_first(a_type, a_field, a_tree, (a_tree)->rbt_root, (r_node)); \
- if ((r_node) == &(a_tree)->rbt_nil) { \
- (r_node) = NULL; \
- } \
-} while (0)
-
-#define rb_last(a_type, a_field, a_tree, r_node) do { \
- rbp_last(a_type, a_field, a_tree, (a_tree)->rbt_root, r_node); \
- if ((r_node) == &(a_tree)->rbt_nil) { \
- (r_node) = NULL; \
+ if (ret == &rbtree->rbt_nil) { \
+ ret = (NULL); \
} \
-} while (0)
-
-#define rb_next(a_type, a_field, a_cmp, a_tree, a_node, r_node) do { \
- rbp_next(a_type, a_field, a_cmp, a_tree, (a_node), (r_node)); \
- if ((r_node) == &(a_tree)->rbt_nil) { \
- (r_node) = NULL; \
- } \
-} while (0)
-
-#define rb_prev(a_type, a_field, a_cmp, a_tree, a_node, r_node) do { \
- rbp_prev(a_type, a_field, a_cmp, a_tree, (a_node), (r_node)); \
- if ((r_node) == &(a_tree)->rbt_nil) { \
- (r_node) = NULL; \
- } \
-} while (0)
-
-#define rb_search(a_type, a_field, a_cmp, a_tree, a_key, r_node) do { \
- int rbp_se_cmp; \
- (r_node) = (a_tree)->rbt_root; \
- while ((r_node) != &(a_tree)->rbt_nil \
- && (rbp_se_cmp = (a_cmp)((a_key), (r_node))) != 0) { \
- if (rbp_se_cmp < 0) { \
- (r_node) = rbp_left_get(a_type, a_field, (r_node)); \
+ return (ret); \
+} \
+a_attr a_type * \
+a_prefix##search(a_rbt_type *rbtree, a_type *key) { \
+ a_type *ret; \
+ int cmp; \
+ ret = rbtree->rbt_root; \
+ while (ret != &rbtree->rbt_nil \
+ && (cmp = (a_cmp)(key, ret)) != 0) { \
+ if (cmp < 0) { \
+ ret = rbtn_left_get(a_type, a_field, ret); \
} else { \
- (r_node) = rbp_right_get(a_type, a_field, (r_node)); \
+ ret = rbtn_right_get(a_type, a_field, ret); \
} \
} \
- if ((r_node) == &(a_tree)->rbt_nil) { \
- (r_node) = NULL; \
+ if (ret == &rbtree->rbt_nil) { \
+ ret = (NULL); \
} \
-} while (0)
-
-/*
- * Find a match if it exists. Otherwise, find the next greater node, if one
- * exists.
- */
-#define rb_nsearch(a_type, a_field, a_cmp, a_tree, a_key, r_node) do { \
- a_type *rbp_ns_t = (a_tree)->rbt_root; \
- (r_node) = NULL; \
- while (rbp_ns_t != &(a_tree)->rbt_nil) { \
- int rbp_ns_cmp = (a_cmp)((a_key), rbp_ns_t); \
- if (rbp_ns_cmp < 0) { \
- (r_node) = rbp_ns_t; \
- rbp_ns_t = rbp_left_get(a_type, a_field, rbp_ns_t); \
- } else if (rbp_ns_cmp > 0) { \
- rbp_ns_t = rbp_right_get(a_type, a_field, rbp_ns_t); \
+ return (ret); \
+} \
+a_attr a_type * \
+a_prefix##nsearch(a_rbt_type *rbtree, a_type *key) { \
+ a_type *ret; \
+ a_type *tnode = rbtree->rbt_root; \
+ ret = &rbtree->rbt_nil; \
+ while (tnode != &rbtree->rbt_nil) { \
+ int cmp = (a_cmp)(key, tnode); \
+ if (cmp < 0) { \
+ ret = tnode; \
+ tnode = rbtn_left_get(a_type, a_field, tnode); \
+ } else if (cmp > 0) { \
+ tnode = rbtn_right_get(a_type, a_field, tnode); \
} else { \
- (r_node) = rbp_ns_t; \
+ ret = tnode; \
break; \
} \
} \
-} while (0)
-
-/*
- * Find a match if it exists. Otherwise, find the previous lesser node, if one
- * exists.
- */
-#define rb_psearch(a_type, a_field, a_cmp, a_tree, a_key, r_node) do { \
- a_type *rbp_ps_t = (a_tree)->rbt_root; \
- (r_node) = NULL; \
- while (rbp_ps_t != &(a_tree)->rbt_nil) { \
- int rbp_ps_cmp = (a_cmp)((a_key), rbp_ps_t); \
- if (rbp_ps_cmp < 0) { \
- rbp_ps_t = rbp_left_get(a_type, a_field, rbp_ps_t); \
- } else if (rbp_ps_cmp > 0) { \
- (r_node) = rbp_ps_t; \
- rbp_ps_t = rbp_right_get(a_type, a_field, rbp_ps_t); \
+ if (ret == &rbtree->rbt_nil) { \
+ ret = (NULL); \
+ } \
+ return (ret); \
+} \
+a_attr a_type * \
+a_prefix##psearch(a_rbt_type *rbtree, a_type *key) { \
+ a_type *ret; \
+ a_type *tnode = rbtree->rbt_root; \
+ ret = &rbtree->rbt_nil; \
+ while (tnode != &rbtree->rbt_nil) { \
+ int cmp = (a_cmp)(key, tnode); \
+ if (cmp < 0) { \
+ tnode = rbtn_left_get(a_type, a_field, tnode); \
+ } else if (cmp > 0) { \
+ ret = tnode; \
+ tnode = rbtn_right_get(a_type, a_field, tnode); \
} else { \
- (r_node) = rbp_ps_t; \
+ ret = tnode; \
break; \
} \
} \
-} while (0)
-
-#define rbp_rotate_left(a_type, a_field, a_node, r_node) do { \
- (r_node) = rbp_right_get(a_type, a_field, (a_node)); \
- rbp_right_set(a_type, a_field, (a_node), \
- rbp_left_get(a_type, a_field, (r_node))); \
- rbp_left_set(a_type, a_field, (r_node), (a_node)); \
-} while (0)
-
-#define rbp_rotate_right(a_type, a_field, a_node, r_node) do { \
- (r_node) = rbp_left_get(a_type, a_field, (a_node)); \
- rbp_left_set(a_type, a_field, (a_node), \
- rbp_right_get(a_type, a_field, (r_node))); \
- rbp_right_set(a_type, a_field, (r_node), (a_node)); \
-} while (0)
-
-#define rbp_lean_left(a_type, a_field, a_node, r_node) do { \
- bool rbp_ll_red; \
- rbp_rotate_left(a_type, a_field, (a_node), (r_node)); \
- rbp_ll_red = rbp_red_get(a_type, a_field, (a_node)); \
- rbp_color_set(a_type, a_field, (r_node), rbp_ll_red); \
- rbp_red_set(a_type, a_field, (a_node)); \
-} while (0)
-
-#define rbp_lean_right(a_type, a_field, a_node, r_node) do { \
- bool rbp_lr_red; \
- rbp_rotate_right(a_type, a_field, (a_node), (r_node)); \
- rbp_lr_red = rbp_red_get(a_type, a_field, (a_node)); \
- rbp_color_set(a_type, a_field, (r_node), rbp_lr_red); \
- rbp_red_set(a_type, a_field, (a_node)); \
-} while (0)
-
-#define rbp_move_red_left(a_type, a_field, a_node, r_node) do { \
- a_type *rbp_mrl_t, *rbp_mrl_u; \
- rbp_mrl_t = rbp_left_get(a_type, a_field, (a_node)); \
- rbp_red_set(a_type, a_field, rbp_mrl_t); \
- rbp_mrl_t = rbp_right_get(a_type, a_field, (a_node)); \
- rbp_mrl_u = rbp_left_get(a_type, a_field, rbp_mrl_t); \
- if (rbp_red_get(a_type, a_field, rbp_mrl_u)) { \
- rbp_rotate_right(a_type, a_field, rbp_mrl_t, rbp_mrl_u); \
- rbp_right_set(a_type, a_field, (a_node), rbp_mrl_u); \
- rbp_rotate_left(a_type, a_field, (a_node), (r_node)); \
- rbp_mrl_t = rbp_right_get(a_type, a_field, (a_node)); \
- if (rbp_red_get(a_type, a_field, rbp_mrl_t)) { \
- rbp_black_set(a_type, a_field, rbp_mrl_t); \
- rbp_red_set(a_type, a_field, (a_node)); \
- rbp_rotate_left(a_type, a_field, (a_node), rbp_mrl_t); \
- rbp_left_set(a_type, a_field, (r_node), rbp_mrl_t); \
- } else { \
- rbp_black_set(a_type, a_field, (a_node)); \
- } \
- } else { \
- rbp_red_set(a_type, a_field, (a_node)); \
- rbp_rotate_left(a_type, a_field, (a_node), (r_node)); \
+ if (ret == &rbtree->rbt_nil) { \
+ ret = (NULL); \
} \
-} while (0)
-
-#define rbp_move_red_right(a_type, a_field, a_node, r_node) do { \
- a_type *rbp_mrr_t; \
- rbp_mrr_t = rbp_left_get(a_type, a_field, (a_node)); \
- if (rbp_red_get(a_type, a_field, rbp_mrr_t)) { \
- a_type *rbp_mrr_u, *rbp_mrr_v; \
- rbp_mrr_u = rbp_right_get(a_type, a_field, rbp_mrr_t); \
- rbp_mrr_v = rbp_left_get(a_type, a_field, rbp_mrr_u); \
- if (rbp_red_get(a_type, a_field, rbp_mrr_v)) { \
- rbp_color_set(a_type, a_field, rbp_mrr_u, \
- rbp_red_get(a_type, a_field, (a_node))); \
- rbp_black_set(a_type, a_field, rbp_mrr_v); \
- rbp_rotate_left(a_type, a_field, rbp_mrr_t, rbp_mrr_u); \
- rbp_left_set(a_type, a_field, (a_node), rbp_mrr_u); \
- rbp_rotate_right(a_type, a_field, (a_node), (r_node)); \
- rbp_rotate_left(a_type, a_field, (a_node), rbp_mrr_t); \
- rbp_right_set(a_type, a_field, (r_node), rbp_mrr_t); \
- } else { \
- rbp_color_set(a_type, a_field, rbp_mrr_t, \
- rbp_red_get(a_type, a_field, (a_node))); \
- rbp_red_set(a_type, a_field, rbp_mrr_u); \
- rbp_rotate_right(a_type, a_field, (a_node), (r_node)); \
- rbp_rotate_left(a_type, a_field, (a_node), rbp_mrr_t); \
- rbp_right_set(a_type, a_field, (r_node), rbp_mrr_t); \
- } \
- rbp_red_set(a_type, a_field, (a_node)); \
- } else { \
- rbp_red_set(a_type, a_field, rbp_mrr_t); \
- rbp_mrr_t = rbp_left_get(a_type, a_field, rbp_mrr_t); \
- if (rbp_red_get(a_type, a_field, rbp_mrr_t)) { \
- rbp_black_set(a_type, a_field, rbp_mrr_t); \
- rbp_rotate_right(a_type, a_field, (a_node), (r_node)); \
- rbp_rotate_left(a_type, a_field, (a_node), rbp_mrr_t); \
- rbp_right_set(a_type, a_field, (r_node), rbp_mrr_t); \
+ return (ret); \
+} \
+a_attr void \
+a_prefix##insert(a_rbt_type *rbtree, a_type *node) { \
+ struct { \
+ a_type *node; \
+ int cmp; \
+ } path[sizeof(void *) << 4], *pathp; \
+ rbt_node_new(a_type, a_field, rbtree, node); \
+ /* Wind. */ \
+ path->node = rbtree->rbt_root; \
+ for (pathp = path; pathp->node != &rbtree->rbt_nil; pathp++) { \
+ int cmp = pathp->cmp = a_cmp(node, pathp->node); \
+ assert(cmp != 0); \
+ if (cmp < 0) { \
+ pathp[1].node = rbtn_left_get(a_type, a_field, \
+ pathp->node); \
} else { \
- rbp_rotate_left(a_type, a_field, (a_node), (r_node)); \
+ pathp[1].node = rbtn_right_get(a_type, a_field, \
+ pathp->node); \
} \
} \
-} while (0)
-
-#define rb_insert(a_type, a_field, a_cmp, a_tree, a_node) do { \
- a_type rbp_i_s; \
- a_type *rbp_i_g, *rbp_i_p, *rbp_i_c, *rbp_i_t, *rbp_i_u; \
- int rbp_i_cmp = 0; \
- rbp_i_g = &(a_tree)->rbt_nil; \
- rbp_left_set(a_type, a_field, &rbp_i_s, (a_tree)->rbt_root); \
- rbp_right_set(a_type, a_field, &rbp_i_s, &(a_tree)->rbt_nil); \
- rbp_black_set(a_type, a_field, &rbp_i_s); \
- rbp_i_p = &rbp_i_s; \
- rbp_i_c = (a_tree)->rbt_root; \
- /* Iteratively search down the tree for the insertion point, */\
- /* splitting 4-nodes as they are encountered. At the end of each */\
- /* iteration, rbp_i_g->rbp_i_p->rbp_i_c is a 3-level path down */\
- /* the tree, assuming a sufficiently deep tree. */\
- while (rbp_i_c != &(a_tree)->rbt_nil) { \
- rbp_i_t = rbp_left_get(a_type, a_field, rbp_i_c); \
- rbp_i_u = rbp_left_get(a_type, a_field, rbp_i_t); \
- if (rbp_red_get(a_type, a_field, rbp_i_t) \
- && rbp_red_get(a_type, a_field, rbp_i_u)) { \
- /* rbp_i_c is the top of a logical 4-node, so split it. */\
- /* This iteration does not move down the tree, due to the */\
- /* disruptiveness of node splitting. */\
- /* */\
- /* Rotate right. */\
- rbp_rotate_right(a_type, a_field, rbp_i_c, rbp_i_t); \
- /* Pass red links up one level. */\
- rbp_i_u = rbp_left_get(a_type, a_field, rbp_i_t); \
- rbp_black_set(a_type, a_field, rbp_i_u); \
- if (rbp_left_get(a_type, a_field, rbp_i_p) == rbp_i_c) { \
- rbp_left_set(a_type, a_field, rbp_i_p, rbp_i_t); \
- rbp_i_c = rbp_i_t; \
- } else { \
- /* rbp_i_c was the right child of rbp_i_p, so rotate */\
- /* left in order to maintain the left-leaning */\
- /* invariant. */\
- assert(rbp_right_get(a_type, a_field, rbp_i_p) \
- == rbp_i_c); \
- rbp_right_set(a_type, a_field, rbp_i_p, rbp_i_t); \
- rbp_lean_left(a_type, a_field, rbp_i_p, rbp_i_u); \
- if (rbp_left_get(a_type, a_field, rbp_i_g) == rbp_i_p) {\
- rbp_left_set(a_type, a_field, rbp_i_g, rbp_i_u); \
- } else { \
- assert(rbp_right_get(a_type, a_field, rbp_i_g) \
- == rbp_i_p); \
- rbp_right_set(a_type, a_field, rbp_i_g, rbp_i_u); \
+ pathp->node = node; \
+ /* Unwind. */ \
+ for (pathp--; (uintptr_t)pathp >= (uintptr_t)path; pathp--) { \
+ a_type *cnode = pathp->node; \
+ if (pathp->cmp < 0) { \
+ a_type *left = pathp[1].node; \
+ rbtn_left_set(a_type, a_field, cnode, left); \
+ if (rbtn_red_get(a_type, a_field, left)) { \
+ a_type *leftleft = rbtn_left_get(a_type, a_field, left);\
+ if (rbtn_red_get(a_type, a_field, leftleft)) { \
+ /* Fix up 4-node. */ \
+ a_type *tnode; \
+ rbtn_black_set(a_type, a_field, leftleft); \
+ rbtn_rotate_right(a_type, a_field, cnode, tnode); \
+ cnode = tnode; \
} \
- rbp_i_p = rbp_i_u; \
- rbp_i_cmp = (a_cmp)((a_node), rbp_i_p); \
- if (rbp_i_cmp < 0) { \
- rbp_i_c = rbp_left_get(a_type, a_field, rbp_i_p); \
+ } else { \
+ return; \
+ } \
+ } else { \
+ a_type *right = pathp[1].node; \
+ rbtn_right_set(a_type, a_field, cnode, right); \
+ if (rbtn_red_get(a_type, a_field, right)) { \
+ a_type *left = rbtn_left_get(a_type, a_field, cnode); \
+ if (rbtn_red_get(a_type, a_field, left)) { \
+ /* Split 4-node. */ \
+ rbtn_black_set(a_type, a_field, left); \
+ rbtn_black_set(a_type, a_field, right); \
+ rbtn_red_set(a_type, a_field, cnode); \
} else { \
- assert(rbp_i_cmp > 0); \
- rbp_i_c = rbp_right_get(a_type, a_field, rbp_i_p); \
+ /* Lean left. */ \
+ a_type *tnode; \
+ bool tred = rbtn_red_get(a_type, a_field, cnode); \
+ rbtn_rotate_left(a_type, a_field, cnode, tnode); \
+ rbtn_color_set(a_type, a_field, tnode, tred); \
+ rbtn_red_set(a_type, a_field, cnode); \
+ cnode = tnode; \
} \
- continue; \
+ } else { \
+ return; \
} \
} \
- rbp_i_g = rbp_i_p; \
- rbp_i_p = rbp_i_c; \
- rbp_i_cmp = (a_cmp)((a_node), rbp_i_c); \
- if (rbp_i_cmp < 0) { \
- rbp_i_c = rbp_left_get(a_type, a_field, rbp_i_c); \
- } else { \
- assert(rbp_i_cmp > 0); \
- rbp_i_c = rbp_right_get(a_type, a_field, rbp_i_c); \
- } \
+ pathp->node = cnode; \
} \
- /* rbp_i_p now refers to the node under which to insert. */\
- rbp_node_new(a_type, a_field, a_tree, (a_node)); \
- if (rbp_i_cmp > 0) { \
- rbp_right_set(a_type, a_field, rbp_i_p, (a_node)); \
- rbp_lean_left(a_type, a_field, rbp_i_p, rbp_i_t); \
- if (rbp_left_get(a_type, a_field, rbp_i_g) == rbp_i_p) { \
- rbp_left_set(a_type, a_field, rbp_i_g, rbp_i_t); \
- } else if (rbp_right_get(a_type, a_field, rbp_i_g) == rbp_i_p) {\
- rbp_right_set(a_type, a_field, rbp_i_g, rbp_i_t); \
+ /* Set root, and make it black. */ \
+ rbtree->rbt_root = path->node; \
+ rbtn_black_set(a_type, a_field, rbtree->rbt_root); \
+} \
+a_attr void \
+a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \
+ struct { \
+ a_type *node; \
+ int cmp; \
+ } *pathp, *nodep, path[sizeof(void *) << 4]; \
+ /* Wind. */ \
+ nodep = NULL; /* Silence compiler warning. */ \
+ path->node = rbtree->rbt_root; \
+ for (pathp = path; pathp->node != &rbtree->rbt_nil; pathp++) { \
+ int cmp = pathp->cmp = a_cmp(node, pathp->node); \
+ if (cmp < 0) { \
+ pathp[1].node = rbtn_left_get(a_type, a_field, \
+ pathp->node); \
+ } else { \
+ pathp[1].node = rbtn_right_get(a_type, a_field, \
+ pathp->node); \
+ if (cmp == 0) { \
+ /* Find node's successor, in preparation for swap. */ \
+ pathp->cmp = 1; \
+ nodep = pathp; \
+ for (pathp++; pathp->node != &rbtree->rbt_nil; \
+ pathp++) { \
+ pathp->cmp = -1; \
+ pathp[1].node = rbtn_left_get(a_type, a_field, \
+ pathp->node); \
+ } \
+ break; \
+ } \
} \
- } else { \
- rbp_left_set(a_type, a_field, rbp_i_p, (a_node)); \
} \
- /* Update the root and make sure that it is black. */\
- (a_tree)->rbt_root = rbp_left_get(a_type, a_field, &rbp_i_s); \
- rbp_black_set(a_type, a_field, (a_tree)->rbt_root); \
-} while (0)
-
-#define rb_remove(a_type, a_field, a_cmp, a_tree, a_node) do { \
- a_type rbp_r_s; \
- a_type *rbp_r_p, *rbp_r_c, *rbp_r_xp, *rbp_r_t, *rbp_r_u; \
- int rbp_r_cmp; \
- rbp_left_set(a_type, a_field, &rbp_r_s, (a_tree)->rbt_root); \
- rbp_right_set(a_type, a_field, &rbp_r_s, &(a_tree)->rbt_nil); \
- rbp_black_set(a_type, a_field, &rbp_r_s); \
- rbp_r_p = &rbp_r_s; \
- rbp_r_c = (a_tree)->rbt_root; \
- rbp_r_xp = &(a_tree)->rbt_nil; \
- /* Iterate down the tree, but always transform 2-nodes to 3- or */\
- /* 4-nodes in order to maintain the invariant that the current */\
- /* node is not a 2-node. This allows simple deletion once a leaf */\
- /* is reached. Handle the root specially though, since there may */\
- /* be no way to convert it from a 2-node to a 3-node. */\
- rbp_r_cmp = (a_cmp)((a_node), rbp_r_c); \
- if (rbp_r_cmp < 0) { \
- rbp_r_t = rbp_left_get(a_type, a_field, rbp_r_c); \
- rbp_r_u = rbp_left_get(a_type, a_field, rbp_r_t); \
- if (rbp_red_get(a_type, a_field, rbp_r_t) == false \
- && rbp_red_get(a_type, a_field, rbp_r_u) == false) { \
- /* Apply standard transform to prepare for left move. */\
- rbp_move_red_left(a_type, a_field, rbp_r_c, rbp_r_t); \
- rbp_black_set(a_type, a_field, rbp_r_t); \
- rbp_left_set(a_type, a_field, rbp_r_p, rbp_r_t); \
- rbp_r_c = rbp_r_t; \
+ assert(nodep->node == node); \
+ pathp--; \
+ if (pathp->node != node) { \
+ /* Swap node with its successor. */ \
+ bool tred = rbtn_red_get(a_type, a_field, pathp->node); \
+ rbtn_color_set(a_type, a_field, pathp->node, \
+ rbtn_red_get(a_type, a_field, node)); \
+ rbtn_left_set(a_type, a_field, pathp->node, \
+ rbtn_left_get(a_type, a_field, node)); \
+ /* If node's successor is its right child, the following code */\
+ /* will do the wrong thing for the right child pointer. */\
+ /* However, it doesn't matter, because the pointer will be */\
+ /* properly set when the successor is pruned. */\
+ rbtn_right_set(a_type, a_field, pathp->node, \
+ rbtn_right_get(a_type, a_field, node)); \
+ rbtn_color_set(a_type, a_field, node, tred); \
+ /* The pruned leaf node's child pointers are never accessed */\
+ /* again, so don't bother setting them to nil. */\
+ nodep->node = pathp->node; \
+ pathp->node = node; \
+ if (nodep == path) { \
+ rbtree->rbt_root = nodep->node; \
} else { \
- /* Move left. */\
- rbp_r_p = rbp_r_c; \
- rbp_r_c = rbp_left_get(a_type, a_field, rbp_r_c); \
+ if (nodep[-1].cmp < 0) { \
+ rbtn_left_set(a_type, a_field, nodep[-1].node, \
+ nodep->node); \
+ } else { \
+ rbtn_right_set(a_type, a_field, nodep[-1].node, \
+ nodep->node); \
+ } \
} \
} else { \
- if (rbp_r_cmp == 0) { \
- assert((a_node) == rbp_r_c); \
- if (rbp_right_get(a_type, a_field, rbp_r_c) \
- == &(a_tree)->rbt_nil) { \
- /* Delete root node (which is also a leaf node). */\
- if (rbp_left_get(a_type, a_field, rbp_r_c) \
- != &(a_tree)->rbt_nil) { \
- rbp_lean_right(a_type, a_field, rbp_r_c, rbp_r_t); \
- rbp_right_set(a_type, a_field, rbp_r_t, \
- &(a_tree)->rbt_nil); \
+ a_type *left = rbtn_left_get(a_type, a_field, node); \
+ if (left != &rbtree->rbt_nil) { \
+ /* node has no successor, but it has a left child. */\
+ /* Splice node out, without losing the left child. */\
+ assert(rbtn_red_get(a_type, a_field, node) == false); \
+ assert(rbtn_red_get(a_type, a_field, left)); \
+ rbtn_black_set(a_type, a_field, left); \
+ if (pathp == path) { \
+ rbtree->rbt_root = left; \
+ } else { \
+ if (pathp[-1].cmp < 0) { \
+ rbtn_left_set(a_type, a_field, pathp[-1].node, \
+ left); \
} else { \
- rbp_r_t = &(a_tree)->rbt_nil; \
+ rbtn_right_set(a_type, a_field, pathp[-1].node, \
+ left); \
} \
- rbp_left_set(a_type, a_field, rbp_r_p, rbp_r_t); \
- } else { \
- /* This is the node we want to delete, but we will */\
- /* instead swap it with its successor and delete the */\
- /* successor. Record enough information to do the */\
- /* swap later. rbp_r_xp is the a_node's parent. */\
- rbp_r_xp = rbp_r_p; \
- rbp_r_cmp = 1; /* Note that deletion is incomplete. */\
} \
+ return; \
+ } else if (pathp == path) { \
+ /* The tree only contained one node. */ \
+ rbtree->rbt_root = &rbtree->rbt_nil; \
+ return; \
} \
- if (rbp_r_cmp == 1) { \
- if (rbp_red_get(a_type, a_field, rbp_left_get(a_type, \
- a_field, rbp_right_get(a_type, a_field, rbp_r_c))) \
- == false) { \
- rbp_r_t = rbp_left_get(a_type, a_field, rbp_r_c); \
- if (rbp_red_get(a_type, a_field, rbp_r_t)) { \
- /* Standard transform. */\
- rbp_move_red_right(a_type, a_field, rbp_r_c, \
- rbp_r_t); \
+ } \
+ if (rbtn_red_get(a_type, a_field, pathp->node)) { \
+ /* Prune red node, which requires no fixup. */ \
+ assert(pathp[-1].cmp < 0); \
+ rbtn_left_set(a_type, a_field, pathp[-1].node, \
+ &rbtree->rbt_nil); \
+ return; \
+ } \
+ /* The node to be pruned is black, so unwind until balance is */\
+ /* restored. */\
+ pathp->node = &rbtree->rbt_nil; \
+ for (pathp--; (uintptr_t)pathp >= (uintptr_t)path; pathp--) { \
+ assert(pathp->cmp != 0); \
+ if (pathp->cmp < 0) { \
+ rbtn_left_set(a_type, a_field, pathp->node, \
+ pathp[1].node); \
+ assert(rbtn_red_get(a_type, a_field, pathp[1].node) \
+ == false); \
+ if (rbtn_red_get(a_type, a_field, pathp->node)) { \
+ a_type *right = rbtn_right_get(a_type, a_field, \
+ pathp->node); \
+ a_type *rightleft = rbtn_left_get(a_type, a_field, \
+ right); \
+ a_type *tnode; \
+ if (rbtn_red_get(a_type, a_field, rightleft)) { \
+ /* In the following diagrams, ||, //, and \\ */\
+ /* indicate the path to the removed node. */\
+ /* */\
+ /* || */\
+ /* pathp(r) */\
+ /* // \ */\
+ /* (b) (b) */\
+ /* / */\
+ /* (r) */\
+ /* */\
+ rbtn_black_set(a_type, a_field, pathp->node); \
+ rbtn_rotate_right(a_type, a_field, right, tnode); \
+ rbtn_right_set(a_type, a_field, pathp->node, tnode);\
+ rbtn_rotate_left(a_type, a_field, pathp->node, \
+ tnode); \
} else { \
- /* Root-specific transform. */\
- rbp_red_set(a_type, a_field, rbp_r_c); \
- rbp_r_u = rbp_left_get(a_type, a_field, rbp_r_t); \
- if (rbp_red_get(a_type, a_field, rbp_r_u)) { \
- rbp_black_set(a_type, a_field, rbp_r_u); \
- rbp_rotate_right(a_type, a_field, rbp_r_c, \
- rbp_r_t); \
- rbp_rotate_left(a_type, a_field, rbp_r_c, \
- rbp_r_u); \
- rbp_right_set(a_type, a_field, rbp_r_t, \
- rbp_r_u); \
- } else { \
- rbp_red_set(a_type, a_field, rbp_r_t); \
- rbp_rotate_left(a_type, a_field, rbp_r_c, \
- rbp_r_t); \
- } \
+ /* || */\
+ /* pathp(r) */\
+ /* // \ */\
+ /* (b) (b) */\
+ /* / */\
+ /* (b) */\
+ /* */\
+ rbtn_rotate_left(a_type, a_field, pathp->node, \
+ tnode); \
+ } \
+ /* Balance restored, but rotation modified subtree */\
+ /* root. */\
+ assert((uintptr_t)pathp > (uintptr_t)path); \
+ if (pathp[-1].cmp < 0) { \
+ rbtn_left_set(a_type, a_field, pathp[-1].node, \
+ tnode); \
+ } else { \
+ rbtn_right_set(a_type, a_field, pathp[-1].node, \
+ tnode); \
} \
- rbp_left_set(a_type, a_field, rbp_r_p, rbp_r_t); \
- rbp_r_c = rbp_r_t; \
+ return; \
} else { \
- /* Move right. */\
- rbp_r_p = rbp_r_c; \
- rbp_r_c = rbp_right_get(a_type, a_field, rbp_r_c); \
- } \
- } \
- } \
- if (rbp_r_cmp != 0) { \
- while (true) { \
- assert(rbp_r_p != &(a_tree)->rbt_nil); \
- rbp_r_cmp = (a_cmp)((a_node), rbp_r_c); \
- if (rbp_r_cmp < 0) { \
- rbp_r_t = rbp_left_get(a_type, a_field, rbp_r_c); \
- if (rbp_r_t == &(a_tree)->rbt_nil) { \
- /* rbp_r_c now refers to the successor node to */\
- /* relocate, and rbp_r_xp/a_node refer to the */\
- /* context for the relocation. */\
- if (rbp_left_get(a_type, a_field, rbp_r_xp) \
- == (a_node)) { \
- rbp_left_set(a_type, a_field, rbp_r_xp, \
- rbp_r_c); \
+ a_type *right = rbtn_right_get(a_type, a_field, \
+ pathp->node); \
+ a_type *rightleft = rbtn_left_get(a_type, a_field, \
+ right); \
+ if (rbtn_red_get(a_type, a_field, rightleft)) { \
+ /* || */\
+ /* pathp(b) */\
+ /* // \ */\
+ /* (b) (b) */\
+ /* / */\
+ /* (r) */\
+ a_type *tnode; \
+ rbtn_black_set(a_type, a_field, rightleft); \
+ rbtn_rotate_right(a_type, a_field, right, tnode); \
+ rbtn_right_set(a_type, a_field, pathp->node, tnode);\
+ rbtn_rotate_left(a_type, a_field, pathp->node, \
+ tnode); \
+ /* Balance restored, but rotation modified */\
+ /* subree root, which may actually be the tree */\
+ /* root. */\
+ if (pathp == path) { \
+ /* Set root. */ \
+ rbtree->rbt_root = tnode; \
} else { \
- assert(rbp_right_get(a_type, a_field, \
- rbp_r_xp) == (a_node)); \
- rbp_right_set(a_type, a_field, rbp_r_xp, \
- rbp_r_c); \
+ if (pathp[-1].cmp < 0) { \
+ rbtn_left_set(a_type, a_field, \
+ pathp[-1].node, tnode); \
+ } else { \
+ rbtn_right_set(a_type, a_field, \
+ pathp[-1].node, tnode); \
+ } \
} \
- rbp_left_set(a_type, a_field, rbp_r_c, \
- rbp_left_get(a_type, a_field, (a_node))); \
- rbp_right_set(a_type, a_field, rbp_r_c, \
- rbp_right_get(a_type, a_field, (a_node))); \
- rbp_color_set(a_type, a_field, rbp_r_c, \
- rbp_red_get(a_type, a_field, (a_node))); \
- if (rbp_left_get(a_type, a_field, rbp_r_p) \
- == rbp_r_c) { \
- rbp_left_set(a_type, a_field, rbp_r_p, \
- &(a_tree)->rbt_nil); \
+ return; \
+ } else { \
+ /* || */\
+ /* pathp(b) */\
+ /* // \ */\
+ /* (b) (b) */\
+ /* / */\
+ /* (b) */\
+ a_type *tnode; \
+ rbtn_red_set(a_type, a_field, pathp->node); \
+ rbtn_rotate_left(a_type, a_field, pathp->node, \
+ tnode); \
+ pathp->node = tnode; \
+ } \
+ } \
+ } else { \
+ a_type *left; \
+ rbtn_right_set(a_type, a_field, pathp->node, \
+ pathp[1].node); \
+ left = rbtn_left_get(a_type, a_field, pathp->node); \
+ if (rbtn_red_get(a_type, a_field, left)) { \
+ a_type *tnode; \
+ a_type *leftright = rbtn_right_get(a_type, a_field, \
+ left); \
+ a_type *leftrightleft = rbtn_left_get(a_type, a_field, \
+ leftright); \
+ if (rbtn_red_get(a_type, a_field, leftrightleft)) { \
+ /* || */\
+ /* pathp(b) */\
+ /* / \\ */\
+ /* (r) (b) */\
+ /* \ */\
+ /* (b) */\
+ /* / */\
+ /* (r) */\
+ a_type *unode; \
+ rbtn_black_set(a_type, a_field, leftrightleft); \
+ rbtn_rotate_right(a_type, a_field, pathp->node, \
+ unode); \
+ rbtn_rotate_right(a_type, a_field, pathp->node, \
+ tnode); \
+ rbtn_right_set(a_type, a_field, unode, tnode); \
+ rbtn_rotate_left(a_type, a_field, unode, tnode); \
+ } else { \
+ /* || */\
+ /* pathp(b) */\
+ /* / \\ */\
+ /* (r) (b) */\
+ /* \ */\
+ /* (b) */\
+ /* / */\
+ /* (b) */\
+ assert(leftright != &rbtree->rbt_nil); \
+ rbtn_red_set(a_type, a_field, leftright); \
+ rbtn_rotate_right(a_type, a_field, pathp->node, \
+ tnode); \
+ rbtn_black_set(a_type, a_field, tnode); \
+ } \
+ /* Balance restored, but rotation modified subtree */\
+ /* root, which may actually be the tree root. */\
+ if (pathp == path) { \
+ /* Set root. */ \
+ rbtree->rbt_root = tnode; \
+ } else { \
+ if (pathp[-1].cmp < 0) { \
+ rbtn_left_set(a_type, a_field, pathp[-1].node, \
+ tnode); \
} else { \
- assert(rbp_right_get(a_type, a_field, rbp_r_p) \
- == rbp_r_c); \
- rbp_right_set(a_type, a_field, rbp_r_p, \
- &(a_tree)->rbt_nil); \
+ rbtn_right_set(a_type, a_field, pathp[-1].node, \
+ tnode); \
} \
- break; \
} \
- rbp_r_u = rbp_left_get(a_type, a_field, rbp_r_t); \
- if (rbp_red_get(a_type, a_field, rbp_r_t) == false \
- && rbp_red_get(a_type, a_field, rbp_r_u) == false) { \
- rbp_move_red_left(a_type, a_field, rbp_r_c, \
- rbp_r_t); \
- if (rbp_left_get(a_type, a_field, rbp_r_p) \
- == rbp_r_c) { \
- rbp_left_set(a_type, a_field, rbp_r_p, rbp_r_t);\
+ return; \
+ } else if (rbtn_red_get(a_type, a_field, pathp->node)) { \
+ a_type *leftleft = rbtn_left_get(a_type, a_field, left);\
+ if (rbtn_red_get(a_type, a_field, leftleft)) { \
+ /* || */\
+ /* pathp(r) */\
+ /* / \\ */\
+ /* (b) (b) */\
+ /* / */\
+ /* (r) */\
+ a_type *tnode; \
+ rbtn_black_set(a_type, a_field, pathp->node); \
+ rbtn_red_set(a_type, a_field, left); \
+ rbtn_black_set(a_type, a_field, leftleft); \
+ rbtn_rotate_right(a_type, a_field, pathp->node, \
+ tnode); \
+ /* Balance restored, but rotation modified */\
+ /* subtree root. */\
+ assert((uintptr_t)pathp > (uintptr_t)path); \
+ if (pathp[-1].cmp < 0) { \
+ rbtn_left_set(a_type, a_field, pathp[-1].node, \
+ tnode); \
} else { \
- rbp_right_set(a_type, a_field, rbp_r_p, \
- rbp_r_t); \
+ rbtn_right_set(a_type, a_field, pathp[-1].node, \
+ tnode); \
} \
- rbp_r_c = rbp_r_t; \
+ return; \
} else { \
- rbp_r_p = rbp_r_c; \
- rbp_r_c = rbp_left_get(a_type, a_field, rbp_r_c); \
+ /* || */\
+ /* pathp(r) */\
+ /* / \\ */\
+ /* (b) (b) */\
+ /* / */\
+ /* (b) */\
+ rbtn_red_set(a_type, a_field, left); \
+ rbtn_black_set(a_type, a_field, pathp->node); \
+ /* Balance restored. */ \
+ return; \
} \
} else { \
- /* Check whether to delete this node (it has to be */\
- /* the correct node and a leaf node). */\
- if (rbp_r_cmp == 0) { \
- assert((a_node) == rbp_r_c); \
- if (rbp_right_get(a_type, a_field, rbp_r_c) \
- == &(a_tree)->rbt_nil) { \
- /* Delete leaf node. */\
- if (rbp_left_get(a_type, a_field, rbp_r_c) \
- != &(a_tree)->rbt_nil) { \
- rbp_lean_right(a_type, a_field, rbp_r_c, \
- rbp_r_t); \
- rbp_right_set(a_type, a_field, rbp_r_t, \
- &(a_tree)->rbt_nil); \
- } else { \
- rbp_r_t = &(a_tree)->rbt_nil; \
- } \
- if (rbp_left_get(a_type, a_field, rbp_r_p) \
- == rbp_r_c) { \
- rbp_left_set(a_type, a_field, rbp_r_p, \
- rbp_r_t); \
+ a_type *leftleft = rbtn_left_get(a_type, a_field, left);\
+ if (rbtn_red_get(a_type, a_field, leftleft)) { \
+ /* || */\
+ /* pathp(b) */\
+ /* / \\ */\
+ /* (b) (b) */\
+ /* / */\
+ /* (r) */\
+ a_type *tnode; \
+ rbtn_black_set(a_type, a_field, leftleft); \
+ rbtn_rotate_right(a_type, a_field, pathp->node, \
+ tnode); \
+ /* Balance restored, but rotation modified */\
+ /* subtree root, which may actually be the tree */\
+ /* root. */\
+ if (pathp == path) { \
+ /* Set root. */ \
+ rbtree->rbt_root = tnode; \
+ } else { \
+ if (pathp[-1].cmp < 0) { \
+ rbtn_left_set(a_type, a_field, \
+ pathp[-1].node, tnode); \
} else { \
- rbp_right_set(a_type, a_field, rbp_r_p, \
- rbp_r_t); \
+ rbtn_right_set(a_type, a_field, \
+ pathp[-1].node, tnode); \
} \
- break; \
- } else { \
- /* This is the node we want to delete, but we */\
- /* will instead swap it with its successor */\
- /* and delete the successor. Record enough */\
- /* information to do the swap later. */\
- /* rbp_r_xp is a_node's parent. */\
- rbp_r_xp = rbp_r_p; \
} \
- } \
- rbp_r_t = rbp_right_get(a_type, a_field, rbp_r_c); \
- rbp_r_u = rbp_left_get(a_type, a_field, rbp_r_t); \
- if (rbp_red_get(a_type, a_field, rbp_r_u) == false) { \
- rbp_move_red_right(a_type, a_field, rbp_r_c, \
- rbp_r_t); \
- if (rbp_left_get(a_type, a_field, rbp_r_p) \
- == rbp_r_c) { \
- rbp_left_set(a_type, a_field, rbp_r_p, rbp_r_t);\
- } else { \
- rbp_right_set(a_type, a_field, rbp_r_p, \
- rbp_r_t); \
- } \
- rbp_r_c = rbp_r_t; \
+ return; \
} else { \
- rbp_r_p = rbp_r_c; \
- rbp_r_c = rbp_right_get(a_type, a_field, rbp_r_c); \
+ /* || */\
+ /* pathp(b) */\
+ /* / \\ */\
+ /* (b) (b) */\
+ /* / */\
+ /* (b) */\
+ rbtn_red_set(a_type, a_field, left); \
} \
} \
} \
} \
- /* Update root. */\
- (a_tree)->rbt_root = rbp_left_get(a_type, a_field, &rbp_r_s); \
-} while (0)
-
-/*
- * The rb_wrap() macro provides a convenient way to wrap functions around the
- * cpp macros. The main benefits of wrapping are that 1) repeated macro
- * expansion can cause code bloat, especially for rb_{insert,remove)(), and
- * 2) type, linkage, comparison functions, etc. need not be specified at every
- * call point.
- */
-
-#define rb_wrap(a_attr, a_prefix, a_tree_type, a_type, a_field, a_cmp) \
-a_attr void \
-a_prefix##new(a_tree_type *tree) { \
- rb_new(a_type, a_field, tree); \
-} \
-a_attr a_type * \
-a_prefix##first(a_tree_type *tree) { \
- a_type *ret; \
- rb_first(a_type, a_field, tree, ret); \
- return (ret); \
+ /* Set root. */ \
+ rbtree->rbt_root = path->node; \
+ assert(rbtn_red_get(a_type, a_field, rbtree->rbt_root) == false); \
} \
a_attr a_type * \
-a_prefix##last(a_tree_type *tree) { \
- a_type *ret; \
- rb_last(a_type, a_field, tree, ret); \
- return (ret); \
+a_prefix##iter_recurse(a_rbt_type *rbtree, a_type *node, \
+ a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \
+ if (node == &rbtree->rbt_nil) { \
+ return (&rbtree->rbt_nil); \
+ } else { \
+ a_type *ret; \
+ if ((ret = a_prefix##iter_recurse(rbtree, rbtn_left_get(a_type, \
+ a_field, node), cb, arg)) != &rbtree->rbt_nil \
+ || (ret = cb(rbtree, node, arg)) != NULL) { \
+ return (ret); \
+ } \
+ return (a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \
+ a_field, node), cb, arg)); \
+ } \
} \
a_attr a_type * \
-a_prefix##next(a_tree_type *tree, a_type *node) { \
- a_type *ret; \
- rb_next(a_type, a_field, a_cmp, tree, node, ret); \
- return (ret); \
+a_prefix##iter_start(a_rbt_type *rbtree, a_type *start, a_type *node, \
+ a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \
+ int cmp = a_cmp(start, node); \
+ if (cmp < 0) { \
+ a_type *ret; \
+ if ((ret = a_prefix##iter_start(rbtree, start, \
+ rbtn_left_get(a_type, a_field, node), cb, arg)) != \
+ &rbtree->rbt_nil || (ret = cb(rbtree, node, arg)) != NULL) { \
+ return (ret); \
+ } \
+ return (a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \
+ a_field, node), cb, arg)); \
+ } else if (cmp > 0) { \
+ return (a_prefix##iter_start(rbtree, start, \
+ rbtn_right_get(a_type, a_field, node), cb, arg)); \
+ } else { \
+ a_type *ret; \
+ if ((ret = cb(rbtree, node, arg)) != NULL) { \
+ return (ret); \
+ } \
+ return (a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \
+ a_field, node), cb, arg)); \
+ } \
} \
a_attr a_type * \
-a_prefix##prev(a_tree_type *tree, a_type *node) { \
+a_prefix##iter(a_rbt_type *rbtree, a_type *start, a_type *(*cb)( \
+ a_rbt_type *, a_type *, void *), void *arg) { \
a_type *ret; \
- rb_prev(a_type, a_field, a_cmp, tree, node, ret); \
+ if (start != NULL) { \
+ ret = a_prefix##iter_start(rbtree, start, rbtree->rbt_root, \
+ cb, arg); \
+ } else { \
+ ret = a_prefix##iter_recurse(rbtree, rbtree->rbt_root, cb, arg);\
+ } \
+ if (ret == &rbtree->rbt_nil) { \
+ ret = NULL; \
+ } \
return (ret); \
} \
a_attr a_type * \
-a_prefix##search(a_tree_type *tree, a_type *key) { \
- a_type *ret; \
- rb_search(a_type, a_field, a_cmp, tree, key, ret); \
- return (ret); \
+a_prefix##reverse_iter_recurse(a_rbt_type *rbtree, a_type *node, \
+ a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \
+ if (node == &rbtree->rbt_nil) { \
+ return (&rbtree->rbt_nil); \
+ } else { \
+ a_type *ret; \
+ if ((ret = a_prefix##reverse_iter_recurse(rbtree, \
+ rbtn_right_get(a_type, a_field, node), cb, arg)) != \
+ &rbtree->rbt_nil || (ret = cb(rbtree, node, arg)) != NULL) { \
+ return (ret); \
+ } \
+ return (a_prefix##reverse_iter_recurse(rbtree, \
+ rbtn_left_get(a_type, a_field, node), cb, arg)); \
+ } \
} \
a_attr a_type * \
-a_prefix##nsearch(a_tree_type *tree, a_type *key) { \
- a_type *ret; \
- rb_nsearch(a_type, a_field, a_cmp, tree, key, ret); \
- return (ret); \
+a_prefix##reverse_iter_start(a_rbt_type *rbtree, a_type *start, \
+ a_type *node, a_type *(*cb)(a_rbt_type *, a_type *, void *), \
+ void *arg) { \
+ int cmp = a_cmp(start, node); \
+ if (cmp > 0) { \
+ a_type *ret; \
+ if ((ret = a_prefix##reverse_iter_start(rbtree, start, \
+ rbtn_right_get(a_type, a_field, node), cb, arg)) != \
+ &rbtree->rbt_nil || (ret = cb(rbtree, node, arg)) != NULL) { \
+ return (ret); \
+ } \
+ return (a_prefix##reverse_iter_recurse(rbtree, \
+ rbtn_left_get(a_type, a_field, node), cb, arg)); \
+ } else if (cmp < 0) { \
+ return (a_prefix##reverse_iter_start(rbtree, start, \
+ rbtn_left_get(a_type, a_field, node), cb, arg)); \
+ } else { \
+ a_type *ret; \
+ if ((ret = cb(rbtree, node, arg)) != NULL) { \
+ return (ret); \
+ } \
+ return (a_prefix##reverse_iter_recurse(rbtree, \
+ rbtn_left_get(a_type, a_field, node), cb, arg)); \
+ } \
} \
a_attr a_type * \
-a_prefix##psearch(a_tree_type *tree, a_type *key) { \
+a_prefix##reverse_iter(a_rbt_type *rbtree, a_type *start, \
+ a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \
a_type *ret; \
- rb_psearch(a_type, a_field, a_cmp, tree, key, ret); \
- return (ret); \
-} \
-a_attr void \
-a_prefix##insert(a_tree_type *tree, a_type *node) { \
- rb_insert(a_type, a_field, a_cmp, tree, node); \
-} \
-a_attr void \
-a_prefix##remove(a_tree_type *tree, a_type *node) { \
- rb_remove(a_type, a_field, a_cmp, tree, node); \
-}
-
-/*
- * The iterators simulate recursion via an array of pointers that store the
- * current path. This is critical to performance, since a series of calls to
- * rb_{next,prev}() would require time proportional to (n lg n), whereas this
- * implementation only requires time proportional to (n).
- *
- * Since the iterators cache a path down the tree, any tree modification may
- * cause the cached path to become invalid. In order to continue iteration,
- * use something like the following sequence:
- *
- * {
- * a_type *node, *tnode;
- *
- * rb_foreach_begin(a_type, a_field, a_tree, node) {
- * ...
- * rb_next(a_type, a_field, a_cmp, a_tree, node, tnode);
- * rb_remove(a_type, a_field, a_cmp, a_tree, node);
- * rb_foreach_next(a_type, a_field, a_cmp, a_tree, tnode);
- * ...
- * } rb_foreach_end(a_type, a_field, a_tree, node)
- * }
- *
- * Note that this idiom is not advised if every iteration modifies the tree,
- * since in that case there is no algorithmic complexity improvement over a
- * series of rb_{next,prev}() calls, thus making the setup overhead wasted
- * effort.
- */
-
-#define rb_foreach_begin(a_type, a_field, a_tree, a_var) { \
- /* Compute the maximum possible tree depth (3X the black height). */\
- unsigned rbp_f_height; \
- rbp_black_height(a_type, a_field, a_tree, rbp_f_height); \
- rbp_f_height *= 3; \
- { \
- /* Initialize the path to contain the left spine. */\
- a_type *rbp_f_path[rbp_f_height]; \
- a_type *rbp_f_node; \
- bool rbp_f_synced = false; \
- unsigned rbp_f_depth = 0; \
- if ((a_tree)->rbt_root != &(a_tree)->rbt_nil) { \
- rbp_f_path[rbp_f_depth] = (a_tree)->rbt_root; \
- rbp_f_depth++; \
- while ((rbp_f_node = rbp_left_get(a_type, a_field, \
- rbp_f_path[rbp_f_depth-1])) != &(a_tree)->rbt_nil) { \
- rbp_f_path[rbp_f_depth] = rbp_f_node; \
- rbp_f_depth++; \
- } \
- } \
- /* While the path is non-empty, iterate. */\
- while (rbp_f_depth > 0) { \
- (a_var) = rbp_f_path[rbp_f_depth-1];
-
-/* Only use if modifying the tree during iteration. */
-#define rb_foreach_next(a_type, a_field, a_cmp, a_tree, a_node) \
- /* Re-initialize the path to contain the path to a_node. */\
- rbp_f_depth = 0; \
- if (a_node != NULL) { \
- if ((a_tree)->rbt_root != &(a_tree)->rbt_nil) { \
- rbp_f_path[rbp_f_depth] = (a_tree)->rbt_root; \
- rbp_f_depth++; \
- rbp_f_node = rbp_f_path[0]; \
- while (true) { \
- int rbp_f_cmp = (a_cmp)((a_node), \
- rbp_f_path[rbp_f_depth-1]); \
- if (rbp_f_cmp < 0) { \
- rbp_f_node = rbp_left_get(a_type, a_field, \
- rbp_f_path[rbp_f_depth-1]); \
- } else if (rbp_f_cmp > 0) { \
- rbp_f_node = rbp_right_get(a_type, a_field, \
- rbp_f_path[rbp_f_depth-1]); \
- } else { \
- break; \
- } \
- assert(rbp_f_node != &(a_tree)->rbt_nil); \
- rbp_f_path[rbp_f_depth] = rbp_f_node; \
- rbp_f_depth++; \
- } \
- } \
- } \
- rbp_f_synced = true;
-
-#define rb_foreach_end(a_type, a_field, a_tree, a_var) \
- if (rbp_f_synced) { \
- rbp_f_synced = false; \
- continue; \
- } \
- /* Find the successor. */\
- if ((rbp_f_node = rbp_right_get(a_type, a_field, \
- rbp_f_path[rbp_f_depth-1])) != &(a_tree)->rbt_nil) { \
- /* The successor is the left-most node in the right */\
- /* subtree. */\
- rbp_f_path[rbp_f_depth] = rbp_f_node; \
- rbp_f_depth++; \
- while ((rbp_f_node = rbp_left_get(a_type, a_field, \
- rbp_f_path[rbp_f_depth-1])) != &(a_tree)->rbt_nil) { \
- rbp_f_path[rbp_f_depth] = rbp_f_node; \
- rbp_f_depth++; \
- } \
- } else { \
- /* The successor is above the current node. Unwind */\
- /* until a left-leaning edge is removed from the */\
- /* path, or the path is empty. */\
- for (rbp_f_depth--; rbp_f_depth > 0; rbp_f_depth--) { \
- if (rbp_left_get(a_type, a_field, \
- rbp_f_path[rbp_f_depth-1]) \
- == rbp_f_path[rbp_f_depth]) { \
- break; \
- } \
- } \
- } \
- } \
+ if (start != NULL) { \
+ ret = a_prefix##reverse_iter_start(rbtree, start, \
+ rbtree->rbt_root, cb, arg); \
+ } else { \
+ ret = a_prefix##reverse_iter_recurse(rbtree, rbtree->rbt_root, \
+ cb, arg); \
} \
-}
-
-#define rb_foreach_reverse_begin(a_type, a_field, a_tree, a_var) { \
- /* Compute the maximum possible tree depth (3X the black height). */\
- unsigned rbp_fr_height; \
- rbp_black_height(a_type, a_field, a_tree, rbp_fr_height); \
- rbp_fr_height *= 3; \
- { \
- /* Initialize the path to contain the right spine. */\
- a_type *rbp_fr_path[rbp_fr_height]; \
- a_type *rbp_fr_node; \
- bool rbp_fr_synced = false; \
- unsigned rbp_fr_depth = 0; \
- if ((a_tree)->rbt_root != &(a_tree)->rbt_nil) { \
- rbp_fr_path[rbp_fr_depth] = (a_tree)->rbt_root; \
- rbp_fr_depth++; \
- while ((rbp_fr_node = rbp_right_get(a_type, a_field, \
- rbp_fr_path[rbp_fr_depth-1])) != &(a_tree)->rbt_nil) { \
- rbp_fr_path[rbp_fr_depth] = rbp_fr_node; \
- rbp_fr_depth++; \
- } \
- } \
- /* While the path is non-empty, iterate. */\
- while (rbp_fr_depth > 0) { \
- (a_var) = rbp_fr_path[rbp_fr_depth-1];
-
-/* Only use if modifying the tree during iteration. */
-#define rb_foreach_reverse_prev(a_type, a_field, a_cmp, a_tree, a_node) \
- /* Re-initialize the path to contain the path to a_node. */\
- rbp_fr_depth = 0; \
- if (a_node != NULL) { \
- if ((a_tree)->rbt_root != &(a_tree)->rbt_nil) { \
- rbp_fr_path[rbp_fr_depth] = (a_tree)->rbt_root; \
- rbp_fr_depth++; \
- rbp_fr_node = rbp_fr_path[0]; \
- while (true) { \
- int rbp_fr_cmp = (a_cmp)((a_node), \
- rbp_fr_path[rbp_fr_depth-1]); \
- if (rbp_fr_cmp < 0) { \
- rbp_fr_node = rbp_left_get(a_type, a_field, \
- rbp_fr_path[rbp_fr_depth-1]); \
- } else if (rbp_fr_cmp > 0) { \
- rbp_fr_node = rbp_right_get(a_type, a_field,\
- rbp_fr_path[rbp_fr_depth-1]); \
- } else { \
- break; \
- } \
- assert(rbp_fr_node != &(a_tree)->rbt_nil); \
- rbp_fr_path[rbp_fr_depth] = rbp_fr_node; \
- rbp_fr_depth++; \
- } \
- } \
- } \
- rbp_fr_synced = true;
-
-#define rb_foreach_reverse_end(a_type, a_field, a_tree, a_var) \
- if (rbp_fr_synced) { \
- rbp_fr_synced = false; \
- continue; \
- } \
- if (rbp_fr_depth == 0) { \
- /* rb_foreach_reverse_sync() was called with a NULL */\
- /* a_node. */\
- break; \
- } \
- /* Find the predecessor. */\
- if ((rbp_fr_node = rbp_left_get(a_type, a_field, \
- rbp_fr_path[rbp_fr_depth-1])) != &(a_tree)->rbt_nil) { \
- /* The predecessor is the right-most node in the left */\
- /* subtree. */\
- rbp_fr_path[rbp_fr_depth] = rbp_fr_node; \
- rbp_fr_depth++; \
- while ((rbp_fr_node = rbp_right_get(a_type, a_field, \
- rbp_fr_path[rbp_fr_depth-1])) != &(a_tree)->rbt_nil) {\
- rbp_fr_path[rbp_fr_depth] = rbp_fr_node; \
- rbp_fr_depth++; \
- } \
- } else { \
- /* The predecessor is above the current node. Unwind */\
- /* until a right-leaning edge is removed from the */\
- /* path, or the path is empty. */\
- for (rbp_fr_depth--; rbp_fr_depth > 0; rbp_fr_depth--) {\
- if (rbp_right_get(a_type, a_field, \
- rbp_fr_path[rbp_fr_depth-1]) \
- == rbp_fr_path[rbp_fr_depth]) { \
- break; \
- } \
- } \
- } \
- } \
+ if (ret == &rbtree->rbt_nil) { \
+ ret = NULL; \
} \
+ return (ret); \
}
#endif /* RB_H_ */
diff --git a/lib/libc/stdtime/Makefile.inc b/lib/libc/stdtime/Makefile.inc
index a58a8a2..a039bc9 100644
--- a/lib/libc/stdtime/Makefile.inc
+++ b/lib/libc/stdtime/Makefile.inc
@@ -1,13 +1,16 @@
# Makefile.inc,v 1.2 1994/09/13 21:26:01 wollman Exp
# $FreeBSD$
-.PATH: ${.CURDIR}/stdtime ${.CURDIR}/../locale
+.PATH: ${.CURDIR}/stdtime ${.CURDIR}/../locale \
+ ${.CURDIR}/../../contrib/tzcode/stdtime
SRCS+= asctime.c difftime.c localtime.c strftime.c strptime.c timelocal.c \
time32.c
SYM_MAPS+= ${.CURDIR}/stdtime/Symbol.map
+CFLAGS+= -I${.CURDIR}/../../contrib/tzcode/stdtime -I${.CURDIR}/stdtime
+
MAN+= ctime.3 strftime.3 strptime.3 time2posix.3
MAN+= tzfile.5
diff --git a/lib/libc/sys/mlockall.2 b/lib/libc/sys/mlockall.2
index db4c4a9..d09ce27 100644
--- a/lib/libc/sys/mlockall.2
+++ b/lib/libc/sys/mlockall.2
@@ -15,13 +15,6 @@
.\" 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.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the NetBSD
-.\" Foundation, Inc. and its contributors.
-.\" 4. Neither the name of The NetBSD Foundation nor the names of its
-.\" contributors may be used to endorse or promote products derived
-.\" from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/lib/libc/sys/ntp_adjtime.2 b/lib/libc/sys/ntp_adjtime.2
index 5f5185f..65ff8a3 100644
--- a/lib/libc/sys/ntp_adjtime.2
+++ b/lib/libc/sys/ntp_adjtime.2
@@ -14,13 +14,6 @@
.\" 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.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the NetBSD
-.\" Foundation, Inc. and its contributors.
-.\" 4. Neither the name of The NetBSD Foundation nor the names of its
-.\" contributors may be used to endorse or promote products derived
-.\" from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
diff --git a/lib/libc/sys/utrace.2 b/lib/libc/sys/utrace.2
index a83c185..5177288 100644
--- a/lib/libc/sys/utrace.2
+++ b/lib/libc/sys/utrace.2
@@ -14,13 +14,6 @@
.\" 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.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the NetBSD
-.\" Foundation, Inc. and its contributors.
-.\" 4. Neither the name of The NetBSD Foundation nor the names of its
-.\" contributors may be used to endorse or promote products derived
-.\" from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
diff --git a/lib/libdwarf/Makefile b/lib/libdwarf/Makefile
index 86c707a..1375a92 100644
--- a/lib/libdwarf/Makefile
+++ b/lib/libdwarf/Makefile
@@ -19,10 +19,10 @@ SRCS= \
INCS= dwarf.h libdwarf.h
-CFLAGS+= -I. -I${.CURDIR}
+CFLAGS+= -I${.CURDIR}
SHLIB_MAJOR= 2
-WITHOUT_MAN= yes
+WITHOUT_MAN=
.include <bsd.lib.mk>
diff --git a/lib/libedit/editline.3 b/lib/libedit/editline.3
index 7ed5e38..d5dfff5 100644
--- a/lib/libedit/editline.3
+++ b/lib/libedit/editline.3
@@ -13,9 +13,6 @@
.\" 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.
-.\" 3. Neither the name of The NetBSD Foundation nor the names of its
-.\" contributors may be used to endorse or promote products derived
-.\" from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/lib/libedit/editrc.5 b/lib/libedit/editrc.5
index 8428fea..4b1d414 100644
--- a/lib/libedit/editrc.5
+++ b/lib/libedit/editrc.5
@@ -13,9 +13,6 @@
.\" 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.
-.\" 3. Neither the name of The NetBSD Foundation nor the names of its
-.\" contributors may be used to endorse or promote products derived
-.\" from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/lib/libedit/read.h b/lib/libedit/read.h
index 18de818..1dcf164 100644
--- a/lib/libedit/read.h
+++ b/lib/libedit/read.h
@@ -13,9 +13,6 @@
* 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.
- * 3. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/lib/libkvm/Makefile b/lib/libkvm/Makefile
index bca05b0..bf464ed 100644
--- a/lib/libkvm/Makefile
+++ b/lib/libkvm/Makefile
@@ -24,6 +24,7 @@ MAN= kvm.3 kvm_getcptime.3 kvm_geterr.3 kvm_getfiles.3 kvm_getloadavg.3 \
kvm_read.3
MLINKS+=kvm_getpcpu.3 kvm_getmaxcpu.3
+MLINKS+=kvm_getpcpu.3 kvm_dpcpu_setcpu.3
MLINKS+=kvm_getprocs.3 kvm_getargv.3 kvm_getprocs.3 kvm_getenvv.3
MLINKS+=kvm_open.3 kvm_close.3 kvm_open.3 kvm_openfiles.3
MLINKS+=kvm_read.3 kvm_write.3
diff --git a/lib/libkvm/kvm.c b/lib/libkvm/kvm.c
index 50f752a..37f6a72 100644
--- a/lib/libkvm/kvm.c
+++ b/lib/libkvm/kvm.c
@@ -416,6 +416,8 @@ _kvm_nlist(kvm_t *kd, struct nlist *nl, int initialize)
struct kld_sym_lookup lookup;
int error;
char *prefix = "", symname[1024]; /* XXX-BZ symbol name length limit? */
+ int tried_vnet, tried_dpcpu;
+
/*
* If we can't use the kld symbol lookup, revert to the
* slow library call.
@@ -429,6 +431,10 @@ _kvm_nlist(kvm_t *kd, struct nlist *nl, int initialize)
error = kvm_fdnlist_prefix(kd, nl, error,
VNET_SYMPREFIX, _kvm_vnet_validaddr);
+ if (error > 0 && _kvm_dpcpu_initialized(kd, initialize))
+ error = kvm_fdnlist_prefix(kd, nl, error,
+ "pcpu_entry_", _kvm_dpcpu_validaddr);
+
return (error);
}
@@ -437,6 +443,8 @@ _kvm_nlist(kvm_t *kd, struct nlist *nl, int initialize)
* and look it up with a kldsym(2) syscall.
*/
nvalid = 0;
+ tried_vnet = 0;
+ tried_dpcpu = 0;
again:
for (p = nl; p->n_name && p->n_name[0]; ++p) {
if (p->n_type != N_UNDF)
@@ -464,6 +472,10 @@ again:
!strcmp(prefix, VNET_SYMPREFIX))
p->n_value =
_kvm_vnet_validaddr(kd, lookup.symvalue);
+ else if (_kvm_dpcpu_initialized(kd, initialize) &&
+ !strcmp(prefix, "pcpu_entry_"))
+ p->n_value =
+ _kvm_dpcpu_validaddr(kd, lookup.symvalue);
else
p->n_value = lookup.symvalue;
++nvalid;
@@ -473,14 +485,19 @@ again:
/*
* Check the number of entries that weren't found. If they exist,
- * try again with a prefix for virtualized symbol names.
+ * try again with a prefix for virtualized or DPCPU symbol names.
*/
error = ((p - nl) - nvalid);
- if (error && _kvm_vnet_initialized(kd, initialize) &&
- strcmp(prefix, VNET_SYMPREFIX)) {
+ if (error && _kvm_vnet_initialized(kd, initialize) && !tried_vnet) {
+ tried_vnet = 1;
prefix = VNET_SYMPREFIX;
goto again;
}
+ if (error && _kvm_dpcpu_initialized(kd, initialize) && !tried_dpcpu) {
+ tried_dpcpu = 1;
+ prefix = "pcpu_entry_";
+ goto again;
+ }
/*
* Return the number of entries that weren't found. If they exist,
diff --git a/lib/libkvm/kvm.h b/lib/libkvm/kvm.h
index 0427bd1..6c8fdce 100644
--- a/lib/libkvm/kvm.h
+++ b/lib/libkvm/kvm.h
@@ -69,6 +69,7 @@ struct kvm_swap {
__BEGIN_DECLS
int kvm_close(kvm_t *);
+int kvm_dpcpu_setcpu(kvm_t *, unsigned int);
char **kvm_getargv(kvm_t *, const struct kinfo_proc *, int);
int kvm_getcptime(kvm_t *, long *);
char **kvm_getenvv(kvm_t *, const struct kinfo_proc *, int);
diff --git a/lib/libkvm/kvm_getpcpu.3 b/lib/libkvm/kvm_getpcpu.3
index 40f16ac..f2deda9 100644
--- a/lib/libkvm/kvm_getpcpu.3
+++ b/lib/libkvm/kvm_getpcpu.3
@@ -28,10 +28,11 @@
.\"
.\" $FreeBSD$
.\"
-.Dd August 19, 2008
+.Dd February 28, 2010
.Dt KVM_GETPCPU 3
.Os
.Sh NAME
+.Nm kvm_dpcpu_setcpu
.Nm kvm_getmaxcpu ,
.Nm kvm_getpcpu
.Nd access per-CPU data
@@ -43,20 +44,30 @@
.In sys/sysctl.h
.In kvm.h
.Ft int
+.Fn kvm_dpcpu_setcpu "kvm_t *kd" "u_int cpu"
+.Ft int
.Fn kvm_getmaxcpu "kvm_t *kd"
.Ft void *
.Fn kvm_getpcpu "kvm_t *kd" "int cpu"
.Sh DESCRIPTION
The
-.Fn kvm_getmaxcpu
+.Fn kvm_dpcpu_setcpu ,
+.Fn kvm_getmaxcpu ,
and
.Fn kvm_getpcpu
functions are used to access the per-CPU data of active processors in the
kernel indicated by
.Fa kd .
+Per-CPU storage comes in two flavours: data stored directly in a
+.Vt "struct pcpu"
+associated with each CPU, and dynamic per-CPU storage (DPCPU), in which a
+single kernel symbol refers to different data depending on what CPU it is
+accessed from.
+.Pp
The
.Fn kvm_getmaxcpu
function returns the maximum number of CPUs supported by the kernel.
+.Pp
The
.Fn kvm_getpcpu
function returns a buffer holding the per-CPU data for a single CPU.
@@ -71,8 +82,22 @@ If
is not active, then
.Dv NULL
is returned instead.
+.Pp
+Symbols for dynamic per-CPU data are accessed via
+.Xr kvm_nlist 3
+as with other symbols.
+.Nm libkvm
+maintains a notion of the "current CPU", set by
+.Xr kvm_dpcpu_setcpu ,
+which defaults to 0.
+Once another CPU is selected,
+.Xr kvm_nlist 3
+will return pointers to that data on the appropriate CPU.
.Sh CACHING
-These functions cache the nlist values for various kernel variables which are
+.Fn kvm_getmaxcpu
+and
+.Vn kvm_getpcpu
+cache the nlist values for various kernel variables which are
reused in successive calls.
You may call either function with
.Fa kd
@@ -93,7 +118,11 @@ function returns a pointer to an allocated buffer or
If an error occurs,
it returns -1 instead.
.Pp
-If either function encounters an error,
+On success, the
+.Fn kvm_dpcpu_setcpu
+call returns 0; if an error occurs, it returns -1 instead.
+.Pp
+If any function encounters an error,
then an error message may be retrieved via
.Xr kvm_geterr 3.
.Sh SEE ALSO
diff --git a/lib/libkvm/kvm_pcpu.c b/lib/libkvm/kvm_pcpu.c
index e4f8909..484d2ea 100644
--- a/lib/libkvm/kvm_pcpu.c
+++ b/lib/libkvm/kvm_pcpu.c
@@ -1,8 +1,15 @@
/*-
+ * Copyright (c) 2010 Juniper Networks, Inc.
+ * Copyright (c) 2009 Robert N. M. Watson
+ * Copyright (c) 2009 Bjoern A. Zeeb <bz@FreeBSD.org>
* Copyright (c) 2008 Yahoo!, Inc.
* All rights reserved.
+ *
* Written by: John Baldwin <jhb@FreeBSD.org>
*
+ * This software was developed by Robert N. M. Watson under contract
+ * to Juniper Networks, Inc.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -49,6 +56,10 @@ static struct nlist kvm_pcpu_nl[] = {
/*
* Kernel per-CPU data state. We cache this stuff on the first
* access.
+ *
+ * XXXRW: Possibly, this (and kvmpcpu_nl) should be per-kvm_t, in case the
+ * consumer has multiple handles in flight to differently configured
+ * kernels/crashdumps.
*/
static void **pcpu_data;
static int maxcpu;
@@ -150,3 +161,132 @@ kvm_getmaxcpu(kvm_t *kd)
return (-1);
return (maxcpu);
}
+
+static int
+_kvm_dpcpu_setcpu(kvm_t *kd, u_int cpu, int report_error)
+{
+
+ if (!kd->dpcpu_initialized) {
+ if (report_error)
+ _kvm_err(kd, kd->program, "%s: not initialized",
+ __func__);
+ return (-1);
+ }
+ if (cpu >= kd->dpcpu_maxcpus) {
+ if (report_error)
+ _kvm_err(kd, kd->program, "%s: CPU %u too big",
+ __func__, cpu);
+ return (-1);
+ }
+ if (kd->dpcpu_off[cpu] == 0) {
+ if (report_error)
+ _kvm_err(kd, kd->program, "%s: CPU %u not found",
+ __func__, cpu);
+ return (-1);
+ }
+ kd->dpcpu_curcpu = cpu;
+ kd->dpcpu_curoff = kd->dpcpu_off[cpu];
+ return (0);
+}
+
+/*
+ * Set up libkvm to handle dynamic per-CPU memory.
+ */
+static int
+_kvm_dpcpu_init(kvm_t *kd)
+{
+ struct nlist nl[] = {
+#define NLIST_START_SET_PCPU 0
+ { "___start_set_pcpu" },
+#define NLIST_STOP_SET_PCPU 1
+ { "___stop_set_pcpu" },
+#define NLIST_DPCPU_OFF 2
+ { "_dpcpu_off" },
+#define NLIST_MP_MAXCPUS 3
+ { "_mp_maxcpus" },
+ { NULL },
+ };
+ uintptr_t *dpcpu_off_buf;
+ size_t len;
+ u_int dpcpu_maxcpus;
+
+ /*
+ * Locate and cache locations of important symbols using the internal
+ * version of _kvm_nlist, turning off initialization to avoid
+ * recursion in case of unresolveable symbols.
+ */
+ if (_kvm_nlist(kd, nl, 0) != 0)
+ return (-1);
+ if (kvm_read(kd, nl[NLIST_MP_MAXCPUS].n_value, &dpcpu_maxcpus,
+ sizeof(dpcpu_maxcpus)) != sizeof(dpcpu_maxcpus))
+ return (-1);
+ len = dpcpu_maxcpus * sizeof(*dpcpu_off_buf);
+ dpcpu_off_buf = malloc(len);
+ if (dpcpu_off_buf == NULL)
+ return (-1);
+ if (kvm_read(kd, nl[NLIST_DPCPU_OFF].n_value, dpcpu_off_buf, len) !=
+ len) {
+ free(dpcpu_off_buf);
+ return (-1);
+ }
+ kd->dpcpu_start = nl[NLIST_START_SET_PCPU].n_value;
+ kd->dpcpu_stop = nl[NLIST_STOP_SET_PCPU].n_value;
+ kd->dpcpu_maxcpus = dpcpu_maxcpus;
+ kd->dpcpu_off = dpcpu_off_buf;
+ kd->dpcpu_initialized = 1;
+ (void)_kvm_dpcpu_setcpu(kd, 0, 0);
+ return (0);
+}
+
+/*
+ * Check whether the dpcpu module has been initialized sucessfully or not,
+ * initialize it if permitted.
+ */
+int
+_kvm_dpcpu_initialized(kvm_t *kd, int intialize)
+{
+
+ if (kd->dpcpu_initialized || !intialize)
+ return (kd->dpcpu_initialized);
+
+ (void)_kvm_dpcpu_init(kd);
+
+ return (kd->dpcpu_initialized);
+}
+
+/*
+ * Check whether the value is within the dpcpu symbol range and only if so
+ * adjust the offset relative to the current offset.
+ */
+uintptr_t
+_kvm_dpcpu_validaddr(kvm_t *kd, uintptr_t value)
+{
+
+ if (value == 0)
+ return (value);
+
+ if (!kd->dpcpu_initialized)
+ return (value);
+
+ if (value < kd->dpcpu_start || value >= kd->dpcpu_stop)
+ return (value);
+
+ return (kd->dpcpu_curoff + value);
+}
+
+int
+kvm_dpcpu_setcpu(kvm_t *kd, u_int cpu)
+{
+ int ret;
+
+ if (!kd->dpcpu_initialized) {
+ ret = _kvm_dpcpu_init(kd);
+ if (ret != 0) {
+ _kvm_err(kd, kd->program, "%s: init failed",
+ __func__);
+ return (ret);
+ }
+ }
+
+ return (_kvm_dpcpu_setcpu(kd, cpu, 1));
+}
diff --git a/lib/libkvm/kvm_private.h b/lib/libkvm/kvm_private.h
index cc073db..69b1658 100644
--- a/lib/libkvm/kvm_private.h
+++ b/lib/libkvm/kvm_private.h
@@ -68,6 +68,19 @@ struct __kvm {
uintptr_t vnet_stop; /* stop of kernel's vnet region */
uintptr_t vnet_current; /* vnet we're working with */
uintptr_t vnet_base; /* vnet base of current vnet */
+
+ /*
+ * Dynamic per-CPU kernel memory. We translate symbols, on-demand,
+ * to the data associated with dpcpu_curcpu, set with
+ * kvm_dpcpu_setcpu().
+ */
+ int dpcpu_initialized; /* dpcpu fields set up */
+ uintptr_t dpcpu_start; /* start of kernel's dpcpu region */
+ uintptr_t dpcpu_stop; /* stop of kernel's dpcpu region */
+ u_int dpcpu_maxcpus; /* size of base array */
+ uintptr_t *dpcpu_off; /* base array, indexed by CPU ID */
+ u_int dpcpu_curcpu; /* CPU we're currently working with */
+ uintptr_t dpcpu_curoff; /* dpcpu base of current CPU */
};
/*
@@ -88,6 +101,8 @@ int _kvm_uvatop(kvm_t *, const struct proc *, u_long, u_long *);
int _kvm_vnet_selectpid(kvm_t *, pid_t);
int _kvm_vnet_initialized(kvm_t *, int);
uintptr_t _kvm_vnet_validaddr(kvm_t *, uintptr_t);
+int _kvm_dpcpu_initialized(kvm_t *, int);
+uintptr_t _kvm_dpcpu_validaddr(kvm_t *, uintptr_t);
#if defined(__amd64__) || defined(__i386__) || defined(__arm__)
void _kvm_minidump_freevtop(kvm_t *);
diff --git a/lib/libkvm/kvm_vnet.c b/lib/libkvm/kvm_vnet.c
index d192c67..a5c8aad 100644
--- a/lib/libkvm/kvm_vnet.c
+++ b/lib/libkvm/kvm_vnet.c
@@ -117,8 +117,8 @@ _kvm_vnet_selectpid(kvm_t *kd, pid_t pid)
}
/*
- * First, find the process for this pid. If we are workig on a dump,
- * either locate the thread dumptid is refering to or proc0.
+ * First, find the process for this pid. If we are working on a
+ * dump, either locate the thread dumptid is refering to or proc0.
* Based on either, take the address of the ucred.
*/
credp = 0;
diff --git a/lib/libpam/Makefile.inc b/lib/libpam/Makefile.inc
index 1fe2f12..1c1e513 100644
--- a/lib/libpam/Makefile.inc
+++ b/lib/libpam/Makefile.inc
@@ -30,3 +30,5 @@ DEBUG_FLAGS+= -DDEBUG
SHLIB_MAJOR= 5
PAM_MOD_DIR= ${LIBDIR}
+
+.include "../Makefile.inc"
diff --git a/lib/libpam/modules/Makefile.inc b/lib/libpam/modules/Makefile.inc
index c352f42..feb5da0 100644
--- a/lib/libpam/modules/Makefile.inc
+++ b/lib/libpam/modules/Makefile.inc
@@ -6,7 +6,6 @@ NO_INSTALLLIB=
NO_PROFILE=
CFLAGS+= -I${PAMDIR}/include -I${.CURDIR}/../../libpam
-WARNS?= 6
# This is nasty.
# For the static case, libpam.a depends on the modules.
diff --git a/lib/libpam/modules/pam_krb5/Makefile b/lib/libpam/modules/pam_krb5/Makefile
index 500801b..85f3421 100644
--- a/lib/libpam/modules/pam_krb5/Makefile
+++ b/lib/libpam/modules/pam_krb5/Makefile
@@ -29,7 +29,7 @@ SRCS= pam_krb5.c
MAN= pam_krb5.8
.if defined(_FREEFALL_CONFIG)
CFLAGS+=-D_FREEFALL_CONFIG
-WARNS= 3
+WARNS?= 3
.endif
DPADD= ${LIBKRB5} ${LIBHX509} ${LIBASN1} ${LIBROKEN} ${LIBCOM_ERR} ${LIBCRYPT} ${LIBCRYPTO}
diff --git a/lib/libproc/Makefile b/lib/libproc/Makefile
index 1c5be4e7..edb19bb 100644
--- a/lib/libproc/Makefile
+++ b/lib/libproc/Makefile
@@ -9,10 +9,10 @@ SRCS= \
INCS= libproc.h
-CFLAGS+= -I. -I${.CURDIR}
+CFLAGS+= -I${.CURDIR}
SHLIB_MAJOR= 2
-WITHOUT_MAN= yes
+WITHOUT_MAN=
.include <bsd.lib.mk>
diff --git a/lib/librt/Makefile b/lib/librt/Makefile
index e2ac374..f98d94e 100644
--- a/lib/librt/Makefile
+++ b/lib/librt/Makefile
@@ -4,7 +4,8 @@ LIB=rt
SHLIB_MAJOR= 1
CFLAGS+=-I${.CURDIR}/../libc/include -I${.CURDIR}
CFLAGS+=-Winline -Wall -g
-LDADD+=-lpthread
+DPADD= ${LIBPTHREAD}
+LDADD= -lpthread
WARNS?= 2
diff --git a/lib/libutil/humanize_number.3 b/lib/libutil/humanize_number.3
index 76d5677..a4c3140 100644
--- a/lib/libutil/humanize_number.3
+++ b/lib/libutil/humanize_number.3
@@ -15,13 +15,6 @@
.\" 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.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the NetBSD
-.\" Foundation, Inc. and its contributors.
-.\" 4. Neither the name of The NetBSD Foundation nor the names of its
-.\" contributors may be used to endorse or promote products derived
-.\" from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/libexec/rpc.rstatd/Makefile b/libexec/rpc.rstatd/Makefile
index d1a12ea..a42225f 100644
--- a/libexec/rpc.rstatd/Makefile
+++ b/libexec/rpc.rstatd/Makefile
@@ -4,8 +4,8 @@ PROG = rpc.rstatd
SRCS = rstatd.c rstat_proc.c
MAN = rpc.rstatd.8
-DPADD= ${LIBRPCSVC} ${LIBUTIL} ${LIBDEVSTAT}
-LDADD= -lrpcsvc -lutil -ldevstat
+DPADD= ${LIBRPCSVC} ${LIBUTIL} ${LIBDEVSTAT} ${LIBKVM}
+LDADD= -lrpcsvc -lutil -ldevstat -lkvm
WARNS?= 1
diff --git a/libexec/rtld-elf/powerpc/reloc.c b/libexec/rtld-elf/powerpc/reloc.c
index 2252428..ccdcd90 100644
--- a/libexec/rtld-elf/powerpc/reloc.c
+++ b/libexec/rtld-elf/powerpc/reloc.c
@@ -47,6 +47,13 @@
((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
#define _ppc_la(x) ((u_int32_t)(x) & 0xffff)
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+
+#define PLT_EXTENDED_BEGIN (1 << 13)
+#define JMPTAB_BASE(N) (18 + N*2 + ((N > PLT_EXTENDED_BEGIN) ? \
+ (N - PLT_EXTENDED_BEGIN)*2 : 0))
+
/*
* Process the R_PPC_COPY relocations
*/
@@ -313,7 +320,6 @@ done:
return (r);
}
-
/*
* Initialise a PLT slot to the resolving trampoline
*/
@@ -321,27 +327,43 @@ static int
reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela)
{
Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
- Elf_Addr *pltresolve;
+ Elf_Addr *pltresolve, *pltlongresolve, *jmptab;
Elf_Addr distance;
+ int N = obj->pltrelasize / sizeof(Elf_Rela);
int reloff;
reloff = rela - obj->pltrela;
- if ((reloff < 0) || (reloff >= 0x8000)) {
+ if (reloff < 0)
return (-1);
- }
- pltresolve = obj->pltgot + 8;
+ pltlongresolve = obj->pltgot + 5;
+ pltresolve = pltlongresolve + 5;
distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1);
dbg(" reloc_plt_object: where=%p,pltres=%p,reloff=%x,distance=%x",
(void *)where, (void *)pltresolve, reloff, distance);
- /* li r11,reloff */
- /* b pltresolve */
- where[0] = 0x39600000 | reloff;
- where[1] = 0x48000000 | (distance & 0x03fffffc);
+ if (reloff < PLT_EXTENDED_BEGIN) {
+ /* li r11,reloff */
+ /* b pltresolve */
+ where[0] = 0x39600000 | reloff;
+ where[1] = 0x48000000 | (distance & 0x03fffffc);
+ } else {
+ jmptab = obj->pltgot + JMPTAB_BASE(N);
+ jmptab[reloff] = (u_int)pltlongresolve;
+
+ /* lis r11,jmptab[reloff]@ha */
+ /* lwzu r12,jmptab[reloff]@l(r11) */
+ /* mtctr r12 */
+ /* bctr */
+ where[0] = 0x3d600000 | _ppc_ha(&jmptab[reloff]);
+ where[1] = 0x858b0000 | _ppc_la(&jmptab[reloff]);
+ where[2] = 0x7d8903a6;
+ where[3] = 0x4e800420;
+ }
+
/*
* The icache will be sync'd in init_pltgot, which is called
@@ -453,25 +475,28 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
int N = obj->pltrelasize / sizeof(Elf_Rela);
int reloff = rela - obj->pltrela;
- if ((reloff < 0) || (reloff >= 0x8000)) {
+ if (reloff < 0)
return (-1);
- }
pltcall = obj->pltgot;
- dbg(" reloc_jmpslot: indir, reloff=%d, N=%d\n",
+ dbg(" reloc_jmpslot: indir, reloff=%x, N=%x\n",
reloff, N);
- jmptab = obj->pltgot + 18 + N * 2;
+ jmptab = obj->pltgot + JMPTAB_BASE(N);
jmptab[reloff] = target;
- distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1);
+ if (reloff < PLT_EXTENDED_BEGIN) {
+ /* for extended PLT entries, we keep the old code */
+
+ distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1);
- /* li r11,reloff */
- /* b pltcall # use indirect pltcall routine */
- wherep[0] = 0x39600000 | reloff;
- wherep[1] = 0x48000000 | (distance & 0x03fffffc);
- __syncicache(wherep, 8);
+ /* li r11,reloff */
+ /* b pltcall # use indirect pltcall routine */
+ wherep[0] = 0x39600000 | reloff;
+ wherep[1] = 0x48000000 | (distance & 0x03fffffc);
+ __syncicache(wherep, 8);
+ }
}
return (target);
@@ -481,13 +506,14 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
/*
* Setup the plt glue routines.
*/
-#define PLTCALL_SIZE 20
-#define PLTRESOLVE_SIZE 24
+#define PLTCALL_SIZE 20
+#define PLTLONGRESOLVE_SIZE 20
+#define PLTRESOLVE_SIZE 24
void
init_pltgot(Obj_Entry *obj)
{
- Elf_Word *pltcall, *pltresolve;
+ Elf_Word *pltcall, *pltresolve, *pltlongresolve;
Elf_Word *jmptab;
int N = obj->pltrelasize / sizeof(Elf_Rela);
@@ -524,18 +550,27 @@ init_pltgot(Obj_Entry *obj)
* of the jumptable into the absolute-call assembler code so it
* can determine this address.
*/
- jmptab = pltcall + 18 + N * 2;
+ jmptab = obj->pltgot + JMPTAB_BASE(N);
pltcall[1] |= _ppc_ha(jmptab); /* addis 11,11,jmptab@ha */
pltcall[2] |= _ppc_la(jmptab); /* lwz 11,jmptab@l(11) */
/*
- * Skip down 32 bytes into the initial reserved area and copy
+ * Skip down 20 bytes into the initial reserved area and copy
* in the standard resolving assembler call. Into this assembler,
* insert the absolute address of the _rtld_bind_start routine
* and the address of the relocation object.
+ *
+ * We place pltlongresolve first, so it can fix up its arguments
+ * and then fall through to the regular PLT resolver.
*/
- pltresolve = obj->pltgot + 8;
+ pltlongresolve = obj->pltgot + 5;
+
+ memcpy(pltlongresolve, _rtld_powerpc_pltlongresolve,
+ PLTLONGRESOLVE_SIZE);
+ pltlongresolve[0] |= _ppc_ha(jmptab); /* lis 12,jmptab@ha */
+ pltlongresolve[1] |= _ppc_la(jmptab); /* addi 12,12,jmptab@l */
+ pltresolve = pltlongresolve + PLTLONGRESOLVE_SIZE/sizeof(uint32_t);
memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE);
pltresolve[0] |= _ppc_ha(_rtld_bind_start);
pltresolve[1] |= _ppc_la(_rtld_bind_start);
diff --git a/libexec/rtld-elf/powerpc/rtld_machdep.h b/libexec/rtld-elf/powerpc/rtld_machdep.h
index f5f21a4..bf589c5 100644
--- a/libexec/rtld-elf/powerpc/rtld_machdep.h
+++ b/libexec/rtld-elf/powerpc/rtld_machdep.h
@@ -57,6 +57,7 @@ void _rtld_bind_start(void);
* PLT functions. Not really correct prototypes, but the
* symbol values are needed.
*/
+void _rtld_powerpc_pltlongresolve(void);
void _rtld_powerpc_pltresolve(void);
void _rtld_powerpc_pltcall(void);
diff --git a/libexec/rtld-elf/powerpc/rtld_start.S b/libexec/rtld-elf/powerpc/rtld_start.S
index 86f76e6..00692d2 100644
--- a/libexec/rtld-elf/powerpc/rtld_start.S
+++ b/libexec/rtld-elf/powerpc/rtld_start.S
@@ -163,6 +163,12 @@ _ENTRY(_rtld_bind_start)
* The ELF object is shifted into %r11, and _rtld_bind_start is called
* to complete the binding.
*/
+_ENTRY(_rtld_powerpc_pltlongresolve)
+ lis %r12,0 # lis 12,jmptab@ha
+ addi %r12,%r12,0 # addi 12,12,jmptab@l
+ subf %r11,%r12,%r11 # reloff
+ li %r12,2
+ srw %r11,%r11,%r12 # index = reloff/sizeof(Elf_Addr)
_ENTRY(_rtld_powerpc_pltresolve)
lis %r12,0 # lis 12,_rtld_bind_start@ha
addi %r12,%r12,0 # addi 12,12,_rtld_bind_start@l
diff --git a/libexec/ulog-helper/Makefile b/libexec/ulog-helper/Makefile
index c1697c8..3c1770c 100644
--- a/libexec/ulog-helper/Makefile
+++ b/libexec/ulog-helper/Makefile
@@ -5,7 +5,7 @@ BINOWN= root
BINMODE=4555
NO_MAN=
-DPADD= ${LIBULOG}
-LDADD= -lulog
+DPADD= ${LIBULOG} ${LIBMD}
+LDADD= -lulog -lmd
.include <bsd.prog.mk>
diff --git a/sbin/Makefile b/sbin/Makefile
index ce3895e..0623574 100644
--- a/sbin/Makefile
+++ b/sbin/Makefile
@@ -31,6 +31,8 @@ SUBDIR=adjkerntz \
ggate \
growfs \
gvinum \
+ hastctl \
+ hastd \
ifconfig \
init \
iscontrol \
diff --git a/sbin/atacontrol/atacontrol.c b/sbin/atacontrol/atacontrol.c
index 29599eb..4354ddf 100644
--- a/sbin/atacontrol/atacontrol.c
+++ b/sbin/atacontrol/atacontrol.c
@@ -72,6 +72,7 @@ satarev2str(int mode)
case 1: return "SATA 1.5Gb/s";
case 2: return "SATA 3Gb/s";
case 3: return "SATA 6Gb/s";
+ case 0xff: return "SATA";
default: return "???";
}
}
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c
index 8a00f75..8e0605f 100644
--- a/sbin/camcontrol/camcontrol.c
+++ b/sbin/camcontrol/camcontrol.c
@@ -1022,6 +1022,8 @@ camxferrate(struct cam_device *device)
printf(" (");
if (sata->valid & CTS_SATA_VALID_REVISION)
printf("SATA %d.x, ", sata->revision);
+ else
+ printf("SATA, ");
if (sata->valid & CTS_SATA_VALID_MODE)
printf("%s, ", ata_mode2string(sata->mode));
if ((sata->valid & CTS_SATA_VALID_ATAPI) && sata->atapi != 0)
diff --git a/sbin/ddb/Makefile b/sbin/ddb/Makefile
index b9189c1..c556be1 100644
--- a/sbin/ddb/Makefile
+++ b/sbin/ddb/Makefile
@@ -3,7 +3,7 @@
PROG= ddb
SRCS= ddb.c ddb_capture.c ddb_script.c
MAN= ddb.8
-WARNS= 3
+WARNS?= 3
DPADD= ${LIBKVM}
LDADD= -lkvm
diff --git a/sbin/devfs/devfs.8 b/sbin/devfs/devfs.8
index 62e10d9..7a744d4 100644
--- a/sbin/devfs/devfs.8
+++ b/sbin/devfs/devfs.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 27, 2008
+.Dd February 21, 2010
.Dt DEVFS 8
.Os
.Sh NAME
@@ -196,6 +196,9 @@ Apply all the rules in ruleset number
to the node.
This does not necessarily result in any changes to the node
(e.g., if none of the rules in the included ruleset match).
+Include commands in the referenced
+.Ar ruleset
+are not resolved.
.It Cm mode Ar filemode
Set the file mode to
.Ar filemode ,
@@ -243,7 +246,9 @@ configuration file.
.It Pa /etc/devfs.rules
Local
.Nm
-configuration file.
+configuration file. Rulesets in here override those in
+.Pa /etc/defaults/devfs.rules
+with the same ruleset number, otherwise the two files are effectively merged.
.It Pa /etc/devfs.conf
Boot-time
.Nm
diff --git a/sbin/geom/class/part/Makefile b/sbin/geom/class/part/Makefile
index 8e7d0ff..7fe221a 100644
--- a/sbin/geom/class/part/Makefile
+++ b/sbin/geom/class/part/Makefile
@@ -4,6 +4,7 @@
CLASS= part
+DPADD= ${LIBUTIL}
LDADD= -lutil
.include <bsd.lib.mk>
diff --git a/sbin/ggate/ggatec/ggatec.c b/sbin/ggate/ggatec/ggatec.c
index e421614..660bd8a 100644
--- a/sbin/ggate/ggatec/ggatec.c
+++ b/sbin/ggate/ggatec/ggatec.c
@@ -59,7 +59,7 @@ enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET;
static const char *path = NULL;
static const char *host = NULL;
-static int unit = -1;
+static int unit = G_GATE_UNIT_AUTO;
static unsigned flags = 0;
static int force = 0;
static unsigned queue_size = G_GATE_QUEUE_SIZE;
diff --git a/sbin/ggate/ggated/ggated.c b/sbin/ggate/ggated/ggated.c
index 3b2a0a5..2997a9c 100644
--- a/sbin/ggate/ggated/ggated.c
+++ b/sbin/ggate/ggated/ggated.c
@@ -10,7 +10,7 @@
* 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 AUTHORS 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
diff --git a/sbin/ggate/ggatel/ggatel.c b/sbin/ggate/ggatel/ggatel.c
index 03979c3..6a3f26e 100644
--- a/sbin/ggate/ggatel/ggatel.c
+++ b/sbin/ggate/ggatel/ggatel.c
@@ -50,7 +50,7 @@
enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET;
static const char *path = NULL;
-static int unit = -1;
+static int unit = G_GATE_UNIT_AUTO;
static unsigned flags = 0;
static int force = 0;
static unsigned queue_size = G_GATE_QUEUE_SIZE;
diff --git a/sbin/ggate/shared/ggate.c b/sbin/ggate/shared/ggate.c
index dd40790..cf9b9ca 100644
--- a/sbin/ggate/shared/ggate.c
+++ b/sbin/ggate/shared/ggate.c
@@ -10,7 +10,7 @@
* 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 AUTHORS 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
@@ -159,7 +159,7 @@ g_gate_sectorsize(int fd)
g_gate_xlog("fstat(): %s.", strerror(errno));
if (S_ISCHR(sb.st_mode)) {
if (ioctl(fd, DIOCGSECTORSIZE, &secsize) == -1) {
- g_gate_xlog("Can't get sector size: %s.",
+ g_gate_xlog("Can't get sector size: %s.",
strerror(errno));
}
} else if (S_ISREG(sb.st_mode)) {
@@ -174,7 +174,7 @@ void
g_gate_open_device(void)
{
- g_gate_devfd = open("/dev/" G_GATE_CTL_NAME, O_RDWR, 0);
+ g_gate_devfd = open("/dev/" G_GATE_CTL_NAME, O_RDWR);
if (g_gate_devfd == -1)
err(EXIT_FAILURE, "open(/dev/%s)", G_GATE_CTL_NAME);
}
@@ -281,7 +281,7 @@ g_gate_socket_settings(int sfd)
/* Socket settings. */
on = 1;
if (nagle) {
- if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &on,
+ if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &on,
sizeof(on)) == -1) {
g_gate_xlog("setsockopt() error: %s.", strerror(errno));
}
diff --git a/sbin/hastctl/Makefile b/sbin/hastctl/Makefile
new file mode 100644
index 0000000..e0d6b5b
--- /dev/null
+++ b/sbin/hastctl/Makefile
@@ -0,0 +1,35 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+.PATH: ${.CURDIR}/../hastd
+
+PROG= hastctl
+SRCS= activemap.c
+SRCS+= ebuf.c
+SRCS+= hast_proto.c hastctl.c
+SRCS+= metadata.c
+SRCS+= nv.c
+SRCS+= parse.y pjdlog.c
+SRCS+= proto.c proto_common.c proto_tcp4.c proto_uds.c
+SRCS+= token.l
+SRCS+= subr.c
+SRCS+= y.tab.h
+MAN= hastctl.8
+
+CFLAGS+=-I${.CURDIR}/../hastd
+CFLAGS+=-DINET
+.if ${MK_INET6_SUPPORT} != "no"
+CFLAGS+=-DINET6
+.endif
+# This is needed to have WARNS > 1.
+CFLAGS+=-DYY_NO_UNPUT
+
+DPADD= ${LIBCRYPTO} ${LIBL}
+LDADD= -lcrypto -ll
+
+YFLAGS+=-v
+
+CLEANFILES=y.tab.c y.tab.h y.output
+
+.include <bsd.prog.mk>
diff --git a/sbin/hastctl/hastctl.8 b/sbin/hastctl/hastctl.8
new file mode 100644
index 0000000..bf03c2e
--- /dev/null
+++ b/sbin/hastctl/hastctl.8
@@ -0,0 +1,217 @@
+.\" Copyright (c) 2010 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This software was developed by Pawel Jakub Dawidek under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 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 AUTHORS 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 AUTHORS 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$
+.\"
+.Dd February 1, 2010
+.Dt HASTCTL 8
+.Os
+.Sh NAME
+.Nm hastctl
+.Nd "Highly Available Storage control utility"
+.Sh SYNOPSIS
+.Nm
+.Cm create
+.Op Fl d
+.Op Fl c Ar config
+.Op Fl e Ar extentsize
+.Op Fl k Ar keepdirty
+.Op Fl m Ar mediasize
+.Ar name ...
+.Nm
+.Cm role
+.Op Fl d
+.Op Fl c Ar config
+.Aq init | primary | secondary
+.Ar all | name ...
+.Nm
+.Cm status
+.Op Fl d
+.Op Fl c Ar config
+.Op Ar all | name ...
+.Nm
+.Cm dump
+.Op Fl d
+.Op Fl c Ar config
+.Op Ar all | name ...
+.Sh DESCRIPTION
+The
+.Nm
+utility is used to control the behaviour of the
+.Xr hastd 8
+daemon.
+.Pp
+This utility should be used by HA software like
+.Nm heartbeat
+or
+.Nm ucarp
+to setup HAST resources role when changing from primary mode to
+secondary or vice versa.
+Be aware that if a file system like UFS exists on HAST provider and
+primary node dies, file system has to be checked for inconsistencies
+with the
+.Xr fsck 8
+utility after switching secondary node to primary role.
+.Pp
+The first argument to
+.Nm
+indicates an action to be performed:
+.Bl -tag -width ".Cm create"
+.It Cm create
+Initialize local provider configured for the given resource.
+Additional options include:
+.Bl -tag -width ".Fl e Ar extentsize"
+.It Fl e Ar extentsize
+Size of an extent.
+Extent is a block which is used for synchronization.
+.Nm
+maintains a map of dirty extents and extent is the smallest region that
+can be marked as dirty.
+If any part of an extent is modified, entire extent will be synchronized
+when nodes connect.
+If extent size is too small, there will be too much disk activity
+related to dirty map updates, which will degrade performance of the
+given resource.
+If extent size is too large, synchronization, even in case of short
+outage, can take a long time increasing the risk of loosing up-to-date
+node before synchronization process is completed.
+The default extent size is
+.Va 2MB .
+.It Fl k Ar keepdirty
+Maximum number of dirty extents to keep dirty all the time.
+Most recently used extents are kept dirty to reduce number of metadata
+updates.
+The default numer of most recently used extents which will be kept
+dirty is
+.Va 64 .
+.It Fl m Ar mediasize
+Size of the smaller provider used as backend storage on both nodes.
+This option can be omitted if node providers have the same size on both
+sides.
+.El
+.It Cm role
+Change role of the given resource.
+The role can be one of:
+.Bl -tag -width ".Cm secondary"
+.It Cm init
+Resource is turned off.
+.It Cm primary
+Local
+.Xr hastd 8
+daemon will act as primary node for the given resource.
+System on which resource role is set to primary can use
+.Pa /dev/hast/<name>
+GEOM provider.
+.It Cm secondary
+Local
+.Xr hastd 8
+daemon will act as secondary node for the given resource - it will wait
+for connection from the primary node and will handle I/O requests
+received from it.
+GEOM provider
+.Pa /dev/hast/<name>
+will not be created on secondary node.
+.El
+.It Cm status
+Present status of the configured resources.
+.It Cm dump
+Dump metadata stored on local component for the configured resources.
+.El
+.Pp
+In addition, every subcommand can be followed by the following options:
+.Bl -tag -width ".Fl c Ar config"
+.It Fl c Ar config
+Specify alternative location of the configuration file.
+The default location is
+.Pa /etc/hast.conf .
+.It Fl d
+Print debugging information.
+This option can be specified multiple times to raise the verbosity
+level.
+.El
+.Sh EXIT STATUS
+Exit status is 0 on success, or one of the values described in
+.Xr sysexits 3
+on failure.
+.Sh EXAMPLES
+Initialize HAST provider, create file system on it and mount it.
+.Bd -literal -offset indent
+nodeB# hastctl create shared
+nodeB# hastd
+nodeB# hastctl role secondary shared
+
+nodeB# hastctl create shared
+nodeA# hastd
+nodeA# hastctl role primary shared
+nodeA# newfs -U /dev/hast/shared
+nodeA# mount -o noatime /dev/hast/shared /shared
+nodeA# application_start
+.Ed
+.Pp
+Switch roles for the
+.Nm shared
+HAST resource.
+.Bd -literal -offset indent
+nodeA# application_stop
+nodeA# umount -f /shared
+nodeA# hastctl role secondary shared
+
+nodeB# hastctl role primary shared
+nodeB# fsck -t ufs /dev/hast/shared
+nodeB# mount -o noatime /dev/hast/shared /shared
+nodeB# application_start
+.Ed
+.Sh FILES
+.Bl -tag -width ".Pa /var/run/hastctl" -compact
+.It Pa /etc/hast.conf
+Configuration file for
+.Nm
+and
+.Xr hastd 8 .
+.It Pa /var/run/hastctl
+Control socket used by
+.Nm
+to communicate with the
+.Xr hastd 8
+daemon.
+.El
+.Sh SEE ALSO
+.Xr sysexits 3 ,
+.Xr geom 4 ,
+.Xr hast.conf 5 ,
+.Xr fsck 8 ,
+.Xr ggatec 8 ,
+.Xr ggatel 8 ,
+.Xr hastd 8 ,
+.Xr mount 8 ,
+.Xr newfs 8 .
+.Sh AUTHORS
+The
+.Nm
+was developed by
+.An Pawel Jakub Dawidek Aq pjd@FreeBSD.org
+under sponsorship of the FreeBSD Foundation.
diff --git a/sbin/hastctl/hastctl.c b/sbin/hastctl/hastctl.c
new file mode 100644
index 0000000..8499528
--- /dev/null
+++ b/sbin/hastctl/hastctl.c
@@ -0,0 +1,526 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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/disk.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <activemap.h>
+
+#include "hast.h"
+#include "hast_proto.h"
+#include "metadata.h"
+#include "nv.h"
+#include "pjdlog.h"
+#include "proto.h"
+#include "subr.h"
+
+/* Path to configuration file. */
+static const char *cfgpath = HAST_CONFIG;
+/* Hastd configuration. */
+static struct hastd_config *cfg;
+/* Control connection. */
+static struct proto_conn *controlconn;
+
+enum {
+ CMD_INVALID,
+ CMD_CREATE,
+ CMD_ROLE,
+ CMD_STATUS,
+ CMD_DUMP
+};
+
+static __dead2 void
+usage(void)
+{
+
+ fprintf(stderr,
+ "usage: %s create [-d] [-c config] [-e extentsize] [-k keepdirty]\n"
+ "\t\t[-m mediasize] name ...\n",
+ getprogname());
+ fprintf(stderr,
+ " %s role [-d] [-c config] <init | primary | secondary> all | name ...\n",
+ getprogname());
+ fprintf(stderr,
+ " %s status [-d] [-c config] [all | name ...]\n",
+ getprogname());
+ fprintf(stderr,
+ " %s dump [-d] [-c config] [all | name ...]\n",
+ getprogname());
+ exit(EX_USAGE);
+}
+
+static int
+create_one(struct hast_resource *res, intmax_t mediasize, intmax_t extentsize,
+ intmax_t keepdirty)
+{
+ unsigned char *buf;
+ size_t mapsize;
+ int ec;
+
+ ec = 0;
+ pjdlog_prefix_set("[%s] ", res->hr_name);
+
+ if (provinfo(res, true) < 0) {
+ ec = EX_NOINPUT;
+ goto end;
+ }
+ if (mediasize == 0)
+ mediasize = res->hr_local_mediasize;
+ else if (mediasize > res->hr_local_mediasize) {
+ pjdlog_error("Provided mediasize is larger than provider %s size.",
+ res->hr_localpath);
+ ec = EX_DATAERR;
+ goto end;
+ }
+ if (!powerof2(res->hr_local_sectorsize)) {
+ pjdlog_error("Sector size of provider %s is not power of 2 (%u).",
+ res->hr_localpath, res->hr_local_sectorsize);
+ ec = EX_DATAERR;
+ goto end;
+ }
+ if (extentsize == 0)
+ extentsize = HAST_EXTENTSIZE;
+ if (extentsize < res->hr_local_sectorsize) {
+ pjdlog_error("Extent size (%jd) is less than sector size (%u).",
+ (intmax_t)extentsize, res->hr_local_sectorsize);
+ ec = EX_DATAERR;
+ goto end;
+ }
+ if ((extentsize % res->hr_local_sectorsize) != 0) {
+ pjdlog_error("Extent size (%jd) is not multiple of sector size (%u).",
+ (intmax_t)extentsize, res->hr_local_sectorsize);
+ ec = EX_DATAERR;
+ goto end;
+ }
+ mapsize = activemap_calc_ondisk_size(mediasize - METADATA_SIZE,
+ extentsize, res->hr_local_sectorsize);
+ if (keepdirty == 0)
+ keepdirty = HAST_KEEPDIRTY;
+ res->hr_datasize = mediasize - METADATA_SIZE - mapsize;
+ res->hr_extentsize = extentsize;
+ res->hr_keepdirty = keepdirty;
+
+ res->hr_localoff = METADATA_SIZE + mapsize;
+
+ if (metadata_write(res) < 0) {
+ ec = EX_IOERR;
+ goto end;
+ }
+ buf = calloc(1, mapsize);
+ if (buf == NULL) {
+ pjdlog_error("Unable to allocate %zu bytes of memory for initial bitmap.",
+ mapsize);
+ ec = EX_TEMPFAIL;
+ goto end;
+ }
+ if (pwrite(res->hr_localfd, buf, mapsize, METADATA_SIZE) !=
+ (ssize_t)mapsize) {
+ pjdlog_errno(LOG_ERR, "Unable to store initial bitmap on %s",
+ res->hr_localpath);
+ free(buf);
+ ec = EX_IOERR;
+ goto end;
+ }
+ free(buf);
+end:
+ if (res->hr_localfd >= 0)
+ close(res->hr_localfd);
+ pjdlog_prefix_set("%s", "");
+ return (ec);
+}
+
+static void
+control_create(int argc, char *argv[], intmax_t mediasize, intmax_t extentsize,
+ intmax_t keepdirty)
+{
+ struct hast_resource *res;
+ int ec, ii, ret;
+
+ /* Initialize the given resources. */
+ if (argc < 1)
+ usage();
+ ec = 0;
+ for (ii = 0; ii < argc; ii++) {
+ TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) {
+ if (strcmp(argv[ii], res->hr_name) == 0)
+ break;
+ }
+ if (res == NULL) {
+ pjdlog_error("Unknown resource %s.", argv[ii]);
+ if (ec == 0)
+ ec = EX_DATAERR;
+ continue;
+ }
+ ret = create_one(res, mediasize, extentsize, keepdirty);
+ if (ret != 0 && ec == 0)
+ ec = ret;
+ }
+ exit(ec);
+}
+
+static int
+dump_one(struct hast_resource *res)
+{
+ int ret;
+
+ ret = metadata_read(res, false);
+ if (ret != 0)
+ return (ret);
+
+ printf("resource: %s\n", res->hr_name);
+ printf(" datasize: %ju\n", (uintmax_t)res->hr_datasize);
+ printf(" extentsize: %d\n", res->hr_extentsize);
+ printf(" keepdirty: %d\n", res->hr_keepdirty);
+ printf(" localoff: %ju\n", (uintmax_t)res->hr_localoff);
+ printf(" resuid: %ju\n", (uintmax_t)res->hr_resuid);
+ printf(" localcnt: %ju\n", (uintmax_t)res->hr_primary_localcnt);
+ printf(" remotecnt: %ju\n", (uintmax_t)res->hr_primary_remotecnt);
+ printf(" prevrole: %s\n", role2str(res->hr_previous_role));
+
+ return (0);
+}
+
+static void
+control_dump(int argc, char *argv[])
+{
+ struct hast_resource *res;
+ int ec, ret;
+
+ /* Dump metadata of the given resource(s). */
+
+ ec = 0;
+ if (argc == 0 || (argc == 1 && strcmp(argv[0], "all") == 0)) {
+ TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) {
+ ret = dump_one(res);
+ if (ret != 0 && ec == 0)
+ ec = ret;
+ }
+ } else {
+ int ii;
+
+ for (ii = 0; ii < argc; ii++) {
+ TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) {
+ if (strcmp(argv[ii], res->hr_name) == 0)
+ break;
+ }
+ if (res == NULL) {
+ pjdlog_error("Unknown resource %s.", argv[ii]);
+ if (ec == 0)
+ ec = EX_DATAERR;
+ continue;
+ }
+ ret = dump_one(res);
+ if (ret != 0 && ec == 0)
+ ec = ret;
+ }
+ }
+ exit(ec);
+}
+
+static int
+control_set_role(struct nv *nv, const char *newrole)
+{
+ const char *res, *oldrole;
+ unsigned int ii;
+ int error, ret;
+
+ ret = 0;
+
+ for (ii = 0; ; ii++) {
+ res = nv_get_string(nv, "resource%u", ii);
+ if (res == NULL)
+ break;
+ pjdlog_prefix_set("[%s] ", res);
+ error = nv_get_int16(nv, "error%u", ii);
+ if (error != 0) {
+ if (ret == 0)
+ ret = error;
+ pjdlog_warning("Received error %d from hastd.", error);
+ continue;
+ }
+ oldrole = nv_get_string(nv, "role%u", ii);
+ if (strcmp(oldrole, newrole) == 0)
+ pjdlog_debug(2, "Role unchanged (%s).", oldrole);
+ else {
+ pjdlog_debug(1, "Role changed from %s to %s.", oldrole,
+ newrole);
+ }
+ }
+ pjdlog_prefix_set("%s", "");
+ return (ret);
+}
+
+static int
+control_status(struct nv *nv)
+{
+ unsigned int ii;
+ const char *str;
+ int error, ret;
+
+ ret = 0;
+
+ for (ii = 0; ; ii++) {
+ str = nv_get_string(nv, "resource%u", ii);
+ if (str == NULL)
+ break;
+ printf("%s:\n", str);
+ error = nv_get_int16(nv, "error%u", ii);
+ if (error != 0) {
+ if (ret == 0)
+ ret = error;
+ printf(" error: %d\n", error);
+ continue;
+ }
+ printf(" role: %s\n", nv_get_string(nv, "role%u", ii));
+ printf(" provname: %s\n",
+ nv_get_string(nv, "provname%u", ii));
+ printf(" localpath: %s\n",
+ nv_get_string(nv, "localpath%u", ii));
+ printf(" extentsize: %u\n",
+ (unsigned int)nv_get_uint32(nv, "extentsize%u", ii));
+ printf(" keepdirty: %u\n",
+ (unsigned int)nv_get_uint32(nv, "keepdirty%u", ii));
+ printf(" remoteaddr: %s\n",
+ nv_get_string(nv, "remoteaddr%u", ii));
+ printf(" replication: %s\n",
+ nv_get_string(nv, "replication%u", ii));
+ str = nv_get_string(nv, "status%u", ii);
+ if (str != NULL)
+ printf(" status: %s\n", str);
+ printf(" dirty: %ju bytes\n",
+ (uintmax_t)nv_get_uint64(nv, "dirty%u", ii));
+ }
+ return (ret);
+}
+
+static int
+numfromstr(const char *str, intmax_t *nump)
+{
+ intmax_t num;
+ char *suffix;
+ int rerrno;
+
+ rerrno = errno;
+ errno = 0;
+ num = strtoimax(str, &suffix, 0);
+ if (errno == 0 && *suffix != '\0')
+ errno = EINVAL;
+ if (errno != 0)
+ return (-1);
+ *nump = num;
+ errno = rerrno;
+ return (0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct nv *nv;
+ intmax_t mediasize, extentsize, keepdirty;
+ int cmd, debug, error, ii;
+ const char *optstr;
+
+ debug = 0;
+ mediasize = extentsize = keepdirty = 0;
+
+ if (argc == 1)
+ usage();
+
+ if (strcmp(argv[1], "create") == 0) {
+ cmd = CMD_CREATE;
+ optstr = "c:de:k:m:h";
+ } else if (strcmp(argv[1], "role") == 0) {
+ cmd = CMD_ROLE;
+ optstr = "c:dh";
+ } else if (strcmp(argv[1], "status") == 0) {
+ cmd = CMD_STATUS;
+ optstr = "c:dh";
+ } else if (strcmp(argv[1], "dump") == 0) {
+ cmd = CMD_DUMP;
+ optstr = "c:dh";
+ } else
+ usage();
+
+ argc--;
+ argv++;
+
+ for (;;) {
+ int ch;
+
+ ch = getopt(argc, argv, optstr);
+ if (ch == -1)
+ break;
+ switch (ch) {
+ case 'c':
+ cfgpath = optarg;
+ break;
+ case 'd':
+ debug++;
+ break;
+ case 'e':
+ if (numfromstr(optarg, &extentsize) < 0)
+ err(1, "Invalid extentsize");
+ break;
+ case 'k':
+ if (numfromstr(optarg, &keepdirty) < 0)
+ err(1, "Invalid keepdirty");
+ break;
+ case 'm':
+ if (numfromstr(optarg, &mediasize) < 0)
+ err(1, "Invalid mediasize");
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch (cmd) {
+ case CMD_CREATE:
+ case CMD_ROLE:
+ if (argc == 0)
+ usage();
+ break;
+ }
+
+ pjdlog_debug_set(debug);
+
+ cfg = yy_config_parse(cfgpath);
+ assert(cfg != NULL);
+
+ switch (cmd) {
+ case CMD_CREATE:
+ control_create(argc, argv, mediasize, extentsize, keepdirty);
+ /* NOTREACHED */
+ assert(!"What are we doing here?!");
+ break;
+ case CMD_DUMP:
+ /* Dump metadata from local component of the given resource. */
+ control_dump(argc, argv);
+ /* NOTREACHED */
+ assert(!"What are we doing here?!");
+ break;
+ case CMD_ROLE:
+ /* Change role for the given resources. */
+ if (argc < 2)
+ usage();
+ nv = nv_alloc();
+ nv_add_uint8(nv, HASTCTL_CMD_SETROLE, "cmd");
+ if (strcmp(argv[0], "init") == 0)
+ nv_add_uint8(nv, HAST_ROLE_INIT, "role");
+ else if (strcmp(argv[0], "primary") == 0)
+ nv_add_uint8(nv, HAST_ROLE_PRIMARY, "role");
+ else if (strcmp(argv[0], "secondary") == 0)
+ nv_add_uint8(nv, HAST_ROLE_SECONDARY, "role");
+ else
+ usage();
+ for (ii = 0; ii < argc - 1; ii++)
+ nv_add_string(nv, argv[ii + 1], "resource%d", ii);
+ break;
+ case CMD_STATUS:
+ /* Obtain status of the given resources. */
+ nv = nv_alloc();
+ nv_add_uint8(nv, HASTCTL_CMD_STATUS, "cmd");
+ if (argc == 0)
+ nv_add_string(nv, "all", "resource%d", 0);
+ else {
+ for (ii = 0; ii < argc; ii++)
+ nv_add_string(nv, argv[ii], "resource%d", ii);
+ }
+ break;
+ default:
+ assert(!"Impossible role!");
+ }
+
+ /* Setup control connection... */
+ if (proto_client(cfg->hc_controladdr, &controlconn) < 0) {
+ pjdlog_exit(EX_OSERR,
+ "Unable to setup control connection to %s",
+ cfg->hc_controladdr);
+ }
+ /* ...and connect to hastd. */
+ if (proto_connect(controlconn) < 0) {
+ pjdlog_exit(EX_OSERR, "Unable to connect to hastd via %s",
+ cfg->hc_controladdr);
+ }
+ /* Send the command to the server... */
+ if (hast_proto_send(NULL, controlconn, nv, NULL, 0) < 0) {
+ pjdlog_exit(EX_UNAVAILABLE,
+ "Unable to send command to hastd via %s",
+ cfg->hc_controladdr);
+ }
+ nv_free(nv);
+ /* ...and receive reply. */
+ if (hast_proto_recv(NULL, controlconn, &nv, NULL, 0) < 0) {
+ pjdlog_exit(EX_UNAVAILABLE,
+ "cannot receive reply from hastd via %s",
+ cfg->hc_controladdr);
+ }
+
+ error = nv_get_int16(nv, "error");
+ if (error != 0) {
+ pjdlog_exitx(EX_SOFTWARE, "Error %d received from hastd.",
+ error);
+ }
+ nv_set_error(nv, 0);
+
+ switch (cmd) {
+ case CMD_ROLE:
+ error = control_set_role(nv, argv[0]);
+ break;
+ case CMD_STATUS:
+ error = control_status(nv);
+ break;
+ default:
+ assert(!"Impossible role!");
+ }
+
+ exit(error);
+}
diff --git a/sbin/hastd/Makefile b/sbin/hastd/Makefile
new file mode 100644
index 0000000..8153c3a
--- /dev/null
+++ b/sbin/hastd/Makefile
@@ -0,0 +1,37 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+PROG= hastd
+SRCS= activemap.c
+SRCS+= control.c
+SRCS+= ebuf.c
+SRCS+= hast_proto.c hastd.c hooks.c
+SRCS+= metadata.c
+SRCS+= nv.c
+SRCS+= secondary.c
+SRCS+= parse.y pjdlog.c primary.c
+SRCS+= proto.c proto_common.c proto_socketpair.c proto_tcp4.c proto_uds.c
+SRCS+= rangelock.c
+SRCS+= subr.c
+SRCS+= token.l
+SRCS+= y.tab.h
+MAN= hastd.8 hast.conf.5
+
+CFLAGS+=-I${.CURDIR}
+CFLAGS+=-DINET
+.if ${MK_INET6_SUPPORT} != "no"
+CFLAGS+=-DINET6
+.endif
+# This is needed to have WARNS > 1.
+CFLAGS+=-DYY_NO_UNPUT
+
+DPADD= ${LIBCRYPTO} ${LIBGEOM} ${LIBBSDXML} ${LIBSBUF} ${LIBL} \
+ ${LIBPTHREAD} ${LIBUTIL}
+LDADD= -lcrypto -lgeom -lbsdxml -lsbuf -ll -lpthread -lutil
+
+YFLAGS+=-v
+
+CLEANFILES=y.tab.c y.tab.h y.output
+
+.include <bsd.prog.mk>
diff --git a/sbin/hastd/activemap.c b/sbin/hastd/activemap.c
new file mode 100644
index 0000000..10eb641
--- /dev/null
+++ b/sbin/hastd/activemap.c
@@ -0,0 +1,691 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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> /* powerof2() */
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <bitstring.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <activemap.h>
+
+#define ACTIVEMAP_MAGIC 0xac71e4
+struct activemap {
+ int am_magic; /* Magic value. */
+ off_t am_mediasize; /* Media size in bytes. */
+ uint32_t am_extentsize; /* Extent size in bytes,
+ must be power of 2. */
+ uint8_t am_extentshift;/* 2 ^ extentbits == extentsize */
+ int am_nextents; /* Number of extents. */
+ size_t am_mapsize; /* Bitmap size in bytes. */
+ uint16_t *am_memtab; /* An array that holds number of pending
+ writes per extent. */
+ bitstr_t *am_diskmap; /* On-disk bitmap of dirty extents. */
+ bitstr_t *am_memmap; /* In-memory bitmap of dirty extents. */
+ size_t am_diskmapsize; /* Map size rounded up to sector size. */
+ uint64_t am_ndirty; /* Number of dirty regions. */
+ bitstr_t *am_syncmap; /* Bitmap of extents to sync. */
+ off_t am_syncoff; /* Next synchronization offset. */
+ TAILQ_HEAD(skeepdirty, keepdirty) am_keepdirty; /* List of extents that
+ we keep dirty to reduce bitmap
+ updates. */
+ int am_nkeepdirty; /* Number of am_keepdirty elements. */
+ int am_nkeepdirty_limit; /* Maximum number of am_keepdirty
+ elements. */
+};
+
+struct keepdirty {
+ int kd_extent;
+ TAILQ_ENTRY(keepdirty) kd_next;
+};
+
+/*
+ * Helper function taken from sys/systm.h to calculate extentshift.
+ */
+static uint32_t
+bitcount32(uint32_t x)
+{
+
+ x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1);
+ x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2);
+ x = (x + (x >> 4)) & 0x0f0f0f0f;
+ x = (x + (x >> 8));
+ x = (x + (x >> 16)) & 0x000000ff;
+ return (x);
+}
+
+static __inline int
+off2ext(const struct activemap *amp, off_t offset)
+{
+ int extent;
+
+ assert(offset >= 0 && offset < amp->am_mediasize);
+ extent = (offset >> amp->am_extentshift);
+ assert(extent >= 0 && extent < amp->am_nextents);
+ return (extent);
+}
+
+static __inline off_t
+ext2off(const struct activemap *amp, int extent)
+{
+ off_t offset;
+
+ assert(extent >= 0 && extent < amp->am_nextents);
+ offset = ((off_t)extent << amp->am_extentshift);
+ assert(offset >= 0 && offset < amp->am_mediasize);
+ return (offset);
+}
+
+/*
+ * Function calculates number of requests needed to synchronize the given
+ * extent.
+ */
+static __inline int
+ext2reqs(const struct activemap *amp, int ext)
+{
+ off_t left;
+
+ if (ext < amp->am_nextents - 1)
+ return (((amp->am_extentsize - 1) / MAXPHYS) + 1);
+
+ assert(ext == amp->am_nextents - 1);
+ left = amp->am_mediasize % amp->am_extentsize;
+ if (left == 0)
+ left = amp->am_extentsize;
+ return (((left - 1) / MAXPHYS) + 1);
+}
+
+/*
+ * Initialize activemap structure and allocate memory for internal needs.
+ * Function returns 0 on success and -1 if any of the allocations failed.
+ */
+int
+activemap_init(struct activemap **ampp, uint64_t mediasize, uint32_t extentsize,
+ uint32_t sectorsize, uint32_t keepdirty)
+{
+ struct activemap *amp;
+
+ assert(ampp != NULL);
+ assert(mediasize > 0);
+ assert(extentsize > 0);
+ assert(powerof2(extentsize));
+ assert(sectorsize > 0);
+ assert(powerof2(sectorsize));
+ assert(keepdirty > 0);
+
+ amp = malloc(sizeof(*amp));
+ if (amp == NULL)
+ return (-1);
+
+ amp->am_mediasize = mediasize;
+ amp->am_nkeepdirty_limit = keepdirty;
+ amp->am_extentsize = extentsize;
+ amp->am_extentshift = bitcount32(extentsize - 1);
+ amp->am_nextents = ((mediasize - 1) / extentsize) + 1;
+ amp->am_mapsize = sizeof(bitstr_t) * bitstr_size(amp->am_nextents);
+ amp->am_diskmapsize = roundup2(amp->am_mapsize, sectorsize);
+ amp->am_ndirty = 0;
+ amp->am_syncoff = -2;
+ TAILQ_INIT(&amp->am_keepdirty);
+ amp->am_nkeepdirty = 0;
+
+ amp->am_memtab = calloc(amp->am_nextents, sizeof(amp->am_memtab[0]));
+ amp->am_diskmap = calloc(1, amp->am_diskmapsize);
+ amp->am_memmap = bit_alloc(amp->am_nextents);
+ amp->am_syncmap = bit_alloc(amp->am_nextents);
+
+ /*
+ * Check to see if any of the allocations above failed.
+ */
+ if (amp->am_memtab == NULL || amp->am_diskmap == NULL ||
+ amp->am_memmap == NULL || amp->am_syncmap == NULL) {
+ if (amp->am_memtab != NULL)
+ free(amp->am_memtab);
+ if (amp->am_diskmap != NULL)
+ free(amp->am_diskmap);
+ if (amp->am_memmap != NULL)
+ free(amp->am_memmap);
+ if (amp->am_syncmap != NULL)
+ free(amp->am_syncmap);
+ amp->am_magic = 0;
+ free(amp);
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ amp->am_magic = ACTIVEMAP_MAGIC;
+ *ampp = amp;
+
+ return (0);
+}
+
+static struct keepdirty *
+keepdirty_find(struct activemap *amp, int extent)
+{
+ struct keepdirty *kd;
+
+ TAILQ_FOREACH(kd, &amp->am_keepdirty, kd_next) {
+ if (kd->kd_extent == extent)
+ break;
+ }
+ return (kd);
+}
+
+static void
+keepdirty_add(struct activemap *amp, int extent)
+{
+ struct keepdirty *kd;
+
+ kd = keepdirty_find(amp, extent);
+ if (kd != NULL) {
+ /*
+ * Only move element at the begining.
+ */
+ TAILQ_REMOVE(&amp->am_keepdirty, kd, kd_next);
+ TAILQ_INSERT_HEAD(&amp->am_keepdirty, kd, kd_next);
+ return;
+ }
+ /*
+ * Add new element, but first remove the most unused one if
+ * we have too many.
+ */
+ if (amp->am_nkeepdirty >= amp->am_nkeepdirty_limit) {
+ kd = TAILQ_LAST(&amp->am_keepdirty, skeepdirty);
+ assert(kd != NULL);
+ TAILQ_REMOVE(&amp->am_keepdirty, kd, kd_next);
+ amp->am_nkeepdirty--;
+ assert(amp->am_nkeepdirty > 0);
+ }
+ if (kd == NULL)
+ kd = malloc(sizeof(*kd));
+ /* We can ignore allocation failure. */
+ if (kd != NULL) {
+ kd->kd_extent = extent;
+ amp->am_nkeepdirty++;
+ TAILQ_INSERT_HEAD(&amp->am_keepdirty, kd, kd_next);
+ }
+}
+
+static void
+keepdirty_fill(struct activemap *amp)
+{
+ struct keepdirty *kd;
+
+ TAILQ_FOREACH(kd, &amp->am_keepdirty, kd_next)
+ bit_set(amp->am_diskmap, kd->kd_extent);
+}
+
+static void
+keepdirty_free(struct activemap *amp)
+{
+ struct keepdirty *kd;
+
+ while ((kd = TAILQ_FIRST(&amp->am_keepdirty)) != NULL) {
+ TAILQ_REMOVE(&amp->am_keepdirty, kd, kd_next);
+ amp->am_nkeepdirty--;
+ free(kd);
+ }
+ assert(amp->am_nkeepdirty == 0);
+}
+
+/*
+ * Function frees resources allocated by activemap_init() function.
+ */
+void
+activemap_free(struct activemap *amp)
+{
+
+ assert(amp->am_magic == ACTIVEMAP_MAGIC);
+
+ amp->am_magic = 0;
+
+ keepdirty_free(amp);
+ free(amp->am_memtab);
+ free(amp->am_diskmap);
+ free(amp->am_memmap);
+ free(amp->am_syncmap);
+}
+
+/*
+ * Function should be called before we handle write requests. It updates
+ * internal structures and returns true if on-disk metadata should be updated.
+ */
+bool
+activemap_write_start(struct activemap *amp, off_t offset, off_t length)
+{
+ bool modified;
+ off_t end;
+ int ext;
+
+ assert(amp->am_magic == ACTIVEMAP_MAGIC);
+ assert(length > 0);
+
+ modified = false;
+ end = offset + length - 1;
+
+ for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) {
+ /*
+ * If the number of pending writes is increased from 0,
+ * we have to mark the extent as dirty also in on-disk bitmap.
+ * By returning true we inform the caller that on-disk bitmap
+ * was modified and has to be flushed to disk.
+ */
+ if (amp->am_memtab[ext]++ == 0) {
+ assert(!bit_test(amp->am_memmap, ext));
+ bit_set(amp->am_memmap, ext);
+ amp->am_ndirty++;
+ modified = true;
+ }
+ keepdirty_add(amp, ext);
+ }
+
+ return (modified);
+}
+
+/*
+ * Function should be called after receiving write confirmation. It updates
+ * internal structures and returns true if on-disk metadata should be updated.
+ */
+bool
+activemap_write_complete(struct activemap *amp, off_t offset, off_t length)
+{
+ bool modified;
+ off_t end;
+ int ext;
+
+ assert(amp->am_magic == ACTIVEMAP_MAGIC);
+ assert(length > 0);
+
+ modified = false;
+ end = offset + length - 1;
+
+ for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) {
+ /*
+ * If the number of pending writes goes down to 0, we have to
+ * mark the extent as clean also in on-disk bitmap.
+ * By returning true we inform the caller that on-disk bitmap
+ * was modified and has to be flushed to disk.
+ */
+ assert(amp->am_memtab[ext] > 0);
+ assert(bit_test(amp->am_memmap, ext));
+ if (--amp->am_memtab[ext] == 0) {
+ bit_clear(amp->am_memmap, ext);
+ amp->am_ndirty--;
+ modified = true;
+ }
+ }
+
+ return (modified);
+}
+
+/*
+ * Function should be called after finishing synchronization of one extent.
+ * It returns true if on-disk metadata should be updated.
+ */
+bool
+activemap_extent_complete(struct activemap *amp, int extent)
+{
+ bool modified;
+ int reqs;
+
+ assert(amp->am_magic == ACTIVEMAP_MAGIC);
+ assert(extent >= 0 && extent < amp->am_nextents);
+
+ modified = false;
+
+ reqs = ext2reqs(amp, extent);
+ assert(amp->am_memtab[extent] >= reqs);
+ amp->am_memtab[extent] -= reqs;
+ assert(bit_test(amp->am_memmap, extent));
+ if (amp->am_memtab[extent] == 0) {
+ bit_clear(amp->am_memmap, extent);
+ amp->am_ndirty--;
+ modified = true;
+ }
+
+ return (modified);
+}
+
+/*
+ * Function returns number of dirty regions.
+ */
+uint64_t
+activemap_ndirty(const struct activemap *amp)
+{
+
+ assert(amp->am_magic == ACTIVEMAP_MAGIC);
+
+ return (amp->am_ndirty);
+}
+
+/*
+ * Function compare on-disk bitmap and in-memory bitmap and returns true if
+ * they differ and should be flushed to the disk.
+ */
+bool
+activemap_differ(const struct activemap *amp)
+{
+
+ assert(amp->am_magic == ACTIVEMAP_MAGIC);
+
+ return (memcmp(amp->am_diskmap, amp->am_memmap,
+ amp->am_mapsize) != 0);
+}
+
+/*
+ * Function returns number of bytes used by bitmap.
+ */
+size_t
+activemap_size(const struct activemap *amp)
+{
+
+ assert(amp->am_magic == ACTIVEMAP_MAGIC);
+
+ return (amp->am_mapsize);
+}
+
+/*
+ * Function returns number of bytes needed for storing on-disk bitmap.
+ * This is the same as activemap_size(), but rounded up to sector size.
+ */
+size_t
+activemap_ondisk_size(const struct activemap *amp)
+{
+
+ assert(amp->am_magic == ACTIVEMAP_MAGIC);
+
+ return (amp->am_diskmapsize);
+}
+
+/*
+ * Function copies the given buffer read from disk to the internal bitmap.
+ */
+void
+activemap_copyin(struct activemap *amp, const unsigned char *buf, size_t size)
+{
+ int ext;
+
+ assert(amp->am_magic == ACTIVEMAP_MAGIC);
+ assert(size >= amp->am_mapsize);
+
+ memcpy(amp->am_diskmap, buf, amp->am_mapsize);
+ memcpy(amp->am_memmap, buf, amp->am_mapsize);
+ memcpy(amp->am_syncmap, buf, amp->am_mapsize);
+
+ bit_ffs(amp->am_memmap, amp->am_nextents, &ext);
+ if (ext == -1) {
+ /* There are no dirty extents, so we can leave now. */
+ return;
+ }
+ /*
+ * Set synchronization offset to the first dirty extent.
+ */
+ activemap_sync_rewind(amp);
+ /*
+ * We have dirty extents and we want them to stay that way until
+ * we synchronize, so we set number of pending writes to number
+ * of requests needed to synchronize one extent.
+ */
+ amp->am_ndirty = 0;
+ for (; ext < amp->am_nextents; ext++) {
+ if (bit_test(amp->am_memmap, ext)) {
+ amp->am_memtab[ext] = ext2reqs(amp, ext);
+ amp->am_ndirty++;
+ }
+ }
+}
+
+/*
+ * Function merges the given bitmap with existng one.
+ */
+void
+activemap_merge(struct activemap *amp, const unsigned char *buf, size_t size)
+{
+ bitstr_t *remmap = __DECONST(bitstr_t *, buf);
+ int ext;
+
+ assert(amp->am_magic == ACTIVEMAP_MAGIC);
+ assert(size >= amp->am_mapsize);
+
+ bit_ffs(remmap, amp->am_nextents, &ext);
+ if (ext == -1) {
+ /* There are no dirty extents, so we can leave now. */
+ return;
+ }
+ /*
+ * We have dirty extents and we want them to stay that way until
+ * we synchronize, so we set number of pending writes to number
+ * of requests needed to synchronize one extent.
+ */
+ for (; ext < amp->am_nextents; ext++) {
+ /* Local extent already dirty. */
+ if (bit_test(amp->am_syncmap, ext))
+ continue;
+ /* Remote extent isn't dirty. */
+ if (!bit_test(remmap, ext))
+ continue;
+ bit_set(amp->am_syncmap, ext);
+ bit_set(amp->am_memmap, ext);
+ bit_set(amp->am_diskmap, ext);
+ if (amp->am_memtab[ext] == 0)
+ amp->am_ndirty++;
+ amp->am_memtab[ext] = ext2reqs(amp, ext);
+ }
+ /*
+ * Set synchronization offset to the first dirty extent.
+ */
+ activemap_sync_rewind(amp);
+}
+
+/*
+ * Function returns pointer to internal bitmap that should be written to disk.
+ */
+const unsigned char *
+activemap_bitmap(struct activemap *amp, size_t *sizep)
+{
+
+ assert(amp->am_magic == ACTIVEMAP_MAGIC);
+
+ if (sizep != NULL)
+ *sizep = amp->am_diskmapsize;
+ memcpy(amp->am_diskmap, amp->am_memmap, amp->am_mapsize);
+ keepdirty_fill(amp);
+ return ((const unsigned char *)amp->am_diskmap);
+}
+
+/*
+ * Function calculates size needed to store bitmap on disk.
+ */
+size_t
+activemap_calc_ondisk_size(uint64_t mediasize, uint32_t extentsize,
+ uint32_t sectorsize)
+{
+ uint64_t nextents, mapsize;
+
+ assert(mediasize > 0);
+ assert(extentsize > 0);
+ assert(powerof2(extentsize));
+ assert(sectorsize > 0);
+ assert(powerof2(sectorsize));
+
+ nextents = ((mediasize - 1) / extentsize) + 1;
+ mapsize = sizeof(bitstr_t) * bitstr_size(nextents);
+ return (roundup2(mapsize, sectorsize));
+}
+
+/*
+ * Set synchronization offset to the first dirty extent.
+ */
+void
+activemap_sync_rewind(struct activemap *amp)
+{
+ int ext;
+
+ assert(amp->am_magic == ACTIVEMAP_MAGIC);
+
+ bit_ffs(amp->am_syncmap, amp->am_nextents, &ext);
+ if (ext == -1) {
+ /* There are no extents to synchronize. */
+ amp->am_syncoff = -2;
+ return;
+ }
+ /*
+ * Mark that we want to start synchronization from the begining.
+ */
+ amp->am_syncoff = -1;
+}
+
+/*
+ * Return next offset of where we should synchronize.
+ */
+off_t
+activemap_sync_offset(struct activemap *amp, off_t *lengthp, int *syncextp)
+{
+ off_t syncoff, left;
+ int ext;
+
+ assert(amp->am_magic == ACTIVEMAP_MAGIC);
+ assert(lengthp != NULL);
+ assert(syncextp != NULL);
+
+ *syncextp = -1;
+
+ if (amp->am_syncoff == -2)
+ return (-1);
+
+ if (amp->am_syncoff >= 0 &&
+ (amp->am_syncoff + MAXPHYS >= amp->am_mediasize ||
+ off2ext(amp, amp->am_syncoff) !=
+ off2ext(amp, amp->am_syncoff + MAXPHYS))) {
+ /*
+ * We are about to change extent, so mark previous one as clean.
+ */
+ ext = off2ext(amp, amp->am_syncoff);
+ bit_clear(amp->am_syncmap, ext);
+ *syncextp = ext;
+ amp->am_syncoff = -1;
+ }
+
+ if (amp->am_syncoff == -1) {
+ /*
+ * Let's find first extent to synchronize.
+ */
+ bit_ffs(amp->am_syncmap, amp->am_nextents, &ext);
+ if (ext == -1) {
+ amp->am_syncoff = -2;
+ return (-1);
+ }
+ amp->am_syncoff = ext2off(amp, ext);
+ } else {
+ /*
+ * We don't change extent, so just increase offset.
+ */
+ amp->am_syncoff += MAXPHYS;
+ if (amp->am_syncoff >= amp->am_mediasize) {
+ amp->am_syncoff = -2;
+ return (-1);
+ }
+ }
+
+ syncoff = amp->am_syncoff;
+ left = ext2off(amp, off2ext(amp, syncoff)) +
+ amp->am_extentsize - syncoff;
+ if (syncoff + left > amp->am_mediasize)
+ left = amp->am_mediasize - syncoff;
+ if (left > MAXPHYS)
+ left = MAXPHYS;
+
+ assert(left >= 0 && left <= MAXPHYS);
+ assert(syncoff >= 0 && syncoff < amp->am_mediasize);
+ assert(syncoff + left >= 0 && syncoff + left <= amp->am_mediasize);
+
+ *lengthp = left;
+ return (syncoff);
+}
+
+/*
+ * Mark extent(s) containing the given region for synchronization.
+ * Most likely one of the components is unavailable.
+ */
+bool
+activemap_need_sync(struct activemap *amp, off_t offset, off_t length)
+{
+ bool modified;
+ off_t end;
+ int ext;
+
+ assert(amp->am_magic == ACTIVEMAP_MAGIC);
+
+ modified = false;
+ end = offset + length - 1;
+
+ for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) {
+ if (bit_test(amp->am_syncmap, ext)) {
+ /* Already marked for synchronization. */
+ assert(bit_test(amp->am_memmap, ext));
+ continue;
+ }
+ bit_set(amp->am_syncmap, ext);
+ if (!bit_test(amp->am_memmap, ext)) {
+ bit_set(amp->am_memmap, ext);
+ amp->am_ndirty++;
+ }
+ amp->am_memtab[ext] += ext2reqs(amp, ext);
+ modified = true;
+ }
+
+ return (modified);
+}
+
+void
+activemap_dump(const struct activemap *amp)
+{
+ int bit;
+
+ printf("M: ");
+ for (bit = 0; bit < amp->am_nextents; bit++)
+ printf("%d", bit_test(amp->am_memmap, bit) ? 1 : 0);
+ printf("\n");
+ printf("D: ");
+ for (bit = 0; bit < amp->am_nextents; bit++)
+ printf("%d", bit_test(amp->am_diskmap, bit) ? 1 : 0);
+ printf("\n");
+ printf("S: ");
+ for (bit = 0; bit < amp->am_nextents; bit++)
+ printf("%d", bit_test(amp->am_syncmap, bit) ? 1 : 0);
+ printf("\n");
+}
diff --git a/sbin/hastd/activemap.h b/sbin/hastd/activemap.h
new file mode 100644
index 0000000..42f0221
--- /dev/null
+++ b/sbin/hastd/activemap.h
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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 _ACTIVEMAP_H_
+#define _ACTIVEMAP_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct activemap;
+
+int activemap_init(struct activemap **ampp, uint64_t mediasize,
+ uint32_t extentsize, uint32_t sectorsize, uint32_t keepdirty);
+void activemap_free(struct activemap *amp);
+
+bool activemap_write_start(struct activemap *amp, off_t offset, off_t length);
+bool activemap_write_complete(struct activemap *amp, off_t offset,
+ off_t length);
+bool activemap_extent_complete(struct activemap *amp, int extent);
+uint64_t activemap_ndirty(const struct activemap *amp);
+
+bool activemap_differ(const struct activemap *amp);
+size_t activemap_size(const struct activemap *amp);
+size_t activemap_ondisk_size(const struct activemap *amp);
+void activemap_copyin(struct activemap *amp, const unsigned char *buf,
+ size_t size);
+void activemap_merge(struct activemap *amp, const unsigned char *buf,
+ size_t size);
+const unsigned char *activemap_bitmap(struct activemap *amp, size_t *sizep);
+
+size_t activemap_calc_ondisk_size(uint64_t mediasize, uint32_t extentsize,
+ uint32_t sectorsize);
+
+void activemap_sync_rewind(struct activemap *amp);
+off_t activemap_sync_offset(struct activemap *amp, off_t *lengthp,
+ int *syncextp);
+bool activemap_need_sync(struct activemap *amp, off_t offset, off_t length);
+
+void activemap_dump(const struct activemap *amp);
+
+#endif /* !_ACTIVEMAP_H_ */
diff --git a/sbin/hastd/control.c b/sbin/hastd/control.c
new file mode 100644
index 0000000..0ad39b4
--- /dev/null
+++ b/sbin/hastd/control.c
@@ -0,0 +1,426 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "hast.h"
+#include "hastd.h"
+#include "hast_proto.h"
+#include "nv.h"
+#include "pjdlog.h"
+#include "proto.h"
+#include "subr.h"
+
+#include "control.h"
+
+static void
+control_set_role(struct hastd_config *cfg, struct nv *nvout, uint8_t role,
+ struct hast_resource *res, const char *name, unsigned int no)
+{
+
+ assert(cfg != NULL);
+ assert(nvout != NULL);
+ assert(name != NULL);
+
+ /* Name is always needed. */
+ nv_add_string(nvout, name, "resource%u", no);
+
+ if (res == NULL) {
+ TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) {
+ if (strcmp(res->hr_name, name) == 0)
+ break;
+ }
+ if (res == NULL) {
+ nv_add_int16(nvout, EHAST_NOENTRY, "error%u", no);
+ return;
+ }
+ }
+ assert(res != NULL);
+
+ /* Send previous role back. */
+ nv_add_string(nvout, role2str(res->hr_role), "role%u", no);
+
+ /* Nothing changed, return here. */
+ if (role == res->hr_role)
+ return;
+
+ pjdlog_prefix_set("[%s] (%s) ", res->hr_name, role2str(res->hr_role));
+ pjdlog_info("Role changed to %s.", role2str(role));
+
+ /* Change role to the new one. */
+ res->hr_role = role;
+ pjdlog_prefix_set("[%s] (%s) ", res->hr_name, role2str(res->hr_role));
+
+ /*
+ * If previous role was primary or secondary we have to kill process
+ * doing that work.
+ */
+ if (res->hr_workerpid != 0) {
+ if (kill(res->hr_workerpid, SIGTERM) < 0) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to kill worker process %u",
+ (unsigned int)res->hr_workerpid);
+ } else if (waitpid(res->hr_workerpid, NULL, 0) !=
+ res->hr_workerpid) {
+ pjdlog_errno(LOG_WARNING,
+ "Error while waiting for worker process %u",
+ (unsigned int)res->hr_workerpid);
+ } else {
+ pjdlog_debug(1, "Worker process %u stopped.",
+ (unsigned int)res->hr_workerpid);
+ }
+ res->hr_workerpid = 0;
+ }
+
+ /* Start worker process if we are changing to primary. */
+ if (role == HAST_ROLE_PRIMARY)
+ hastd_primary(res);
+ pjdlog_prefix_set("%s", "");
+}
+
+static void
+control_status_worker(struct hast_resource *res, struct nv *nvout,
+ unsigned int no)
+{
+ struct nv *cnvin, *cnvout;
+ const char *str;
+ int error;
+
+ cnvin = cnvout = NULL;
+ error = 0;
+
+ /*
+ * Prepare and send command to worker process.
+ */
+ cnvout = nv_alloc();
+ nv_add_uint8(cnvout, HASTCTL_STATUS, "cmd");
+ error = nv_error(cnvout);
+ if (error != 0) {
+ /* LOG */
+ goto end;
+ }
+ if (hast_proto_send(res, res->hr_ctrl, cnvout, NULL, 0) < 0) {
+ error = errno;
+ /* LOG */
+ goto end;
+ }
+
+ /*
+ * Receive response.
+ */
+ if (hast_proto_recv_hdr(res->hr_ctrl, &cnvin) < 0) {
+ error = errno;
+ /* LOG */
+ goto end;
+ }
+
+ error = nv_get_int64(cnvin, "error");
+ if (error != 0)
+ goto end;
+
+ if ((str = nv_get_string(cnvin, "status")) == NULL) {
+ error = ENOENT;
+ /* LOG */
+ goto end;
+ }
+ nv_add_string(nvout, str, "status%u", no);
+ nv_add_uint64(nvout, nv_get_uint64(cnvin, "dirty"), "dirty%u", no);
+ nv_add_uint32(nvout, nv_get_uint32(cnvin, "extentsize"),
+ "extentsize%u", no);
+ nv_add_uint32(nvout, nv_get_uint32(cnvin, "keepdirty"),
+ "keepdirty%u", no);
+end:
+ if (cnvin != NULL)
+ nv_free(cnvin);
+ if (cnvout != NULL)
+ nv_free(cnvout);
+ if (error != 0)
+ nv_add_int16(nvout, error, "error");
+}
+
+static void
+control_status(struct hastd_config *cfg, struct nv *nvout,
+ struct hast_resource *res, const char *name, unsigned int no)
+{
+
+ assert(cfg != NULL);
+ assert(nvout != NULL);
+ assert(name != NULL);
+
+ /* Name is always needed. */
+ nv_add_string(nvout, name, "resource%u", no);
+
+ if (res == NULL) {
+ TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) {
+ if (strcmp(res->hr_name, name) == 0)
+ break;
+ }
+ if (res == NULL) {
+ nv_add_int16(nvout, EHAST_NOENTRY, "error%u", no);
+ return;
+ }
+ }
+ assert(res != NULL);
+ nv_add_string(nvout, res->hr_provname, "provname%u", no);
+ nv_add_string(nvout, res->hr_localpath, "localpath%u", no);
+ nv_add_string(nvout, res->hr_remoteaddr, "remoteaddr%u", no);
+ switch (res->hr_replication) {
+ case HAST_REPLICATION_FULLSYNC:
+ nv_add_string(nvout, "fullsync", "replication%u", no);
+ break;
+ case HAST_REPLICATION_MEMSYNC:
+ nv_add_string(nvout, "memsync", "replication%u", no);
+ break;
+ case HAST_REPLICATION_ASYNC:
+ nv_add_string(nvout, "async", "replication%u", no);
+ break;
+ default:
+ nv_add_string(nvout, "unknown", "replication%u", no);
+ break;
+ }
+ nv_add_string(nvout, role2str(res->hr_role), "role%u", no);
+
+ switch (res->hr_role) {
+ case HAST_ROLE_PRIMARY:
+ assert(res->hr_workerpid != 0);
+ /* FALLTHROUGH */
+ case HAST_ROLE_SECONDARY:
+ if (res->hr_workerpid != 0)
+ break;
+ /* FALLTHROUGH */
+ default:
+ return;
+ }
+
+ /*
+ * If we are here, it means that we have a worker process, which we
+ * want to ask some questions.
+ */
+ control_status_worker(res, nvout, no);
+}
+
+void
+control_handle(struct hastd_config *cfg)
+{
+ struct proto_conn *conn;
+ struct nv *nvin, *nvout;
+ unsigned int ii;
+ const char *str;
+ uint8_t cmd, role;
+ int error;
+
+ if (proto_accept(cfg->hc_controlconn, &conn) < 0) {
+ pjdlog_errno(LOG_ERR, "Unable to accept control connection");
+ return;
+ }
+
+ nvin = nvout = NULL;
+ role = HAST_ROLE_UNDEF;
+
+ if (hast_proto_recv_hdr(conn, &nvin) < 0) {
+ pjdlog_errno(LOG_ERR, "Unable to receive control header");
+ nvin = NULL;
+ goto close;
+ }
+
+ /* Obtain command code. 0 means that nv_get_uint8() failed. */
+ cmd = nv_get_uint8(nvin, "cmd");
+ if (cmd == 0) {
+ pjdlog_error("Control header is missing 'cmd' field.");
+ error = EHAST_INVALID;
+ goto close;
+ }
+
+ /* Allocate outgoing nv structure. */
+ nvout = nv_alloc();
+ if (nvout == NULL) {
+ pjdlog_error("Unable to allocate header for control response.");
+ error = EHAST_NOMEMORY;
+ goto close;
+ }
+
+ error = 0;
+
+ str = nv_get_string(nvin, "resource0");
+ if (str == NULL) {
+ pjdlog_error("Control header is missing 'resource0' field.");
+ error = EHAST_INVALID;
+ goto fail;
+ }
+ if (cmd == HASTCTL_SET_ROLE) {
+ role = nv_get_uint8(nvin, "role");
+ switch (role) {
+ case HAST_ROLE_INIT: /* Is that valid to set, hmm? */
+ case HAST_ROLE_PRIMARY:
+ case HAST_ROLE_SECONDARY:
+ break;
+ default:
+ pjdlog_error("Invalid role received (%hhu).", role);
+ error = EHAST_INVALID;
+ goto fail;
+ }
+ }
+ if (strcmp(str, "all") == 0) {
+ struct hast_resource *res;
+
+ /* All configured resources. */
+
+ ii = 0;
+ TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) {
+ switch (cmd) {
+ case HASTCTL_SET_ROLE:
+ control_set_role(cfg, nvout, role, res,
+ res->hr_name, ii++);
+ break;
+ case HASTCTL_STATUS:
+ control_status(cfg, nvout, res, res->hr_name,
+ ii++);
+ break;
+ default:
+ pjdlog_error("Invalid command received (%hhu).",
+ cmd);
+ error = EHAST_UNIMPLEMENTED;
+ goto fail;
+ }
+ }
+ } else {
+ /* Only selected resources. */
+
+ for (ii = 0; ; ii++) {
+ str = nv_get_string(nvin, "resource%u", ii);
+ if (str == NULL)
+ break;
+ switch (cmd) {
+ case HASTCTL_SET_ROLE:
+ control_set_role(cfg, nvout, role, NULL, str,
+ ii);
+ break;
+ case HASTCTL_STATUS:
+ control_status(cfg, nvout, NULL, str, ii);
+ break;
+ default:
+ pjdlog_error("Invalid command received (%hhu).",
+ cmd);
+ error = EHAST_UNIMPLEMENTED;
+ goto fail;
+ }
+ }
+ }
+ if (nv_error(nvout) != 0)
+ goto close;
+fail:
+ if (error != 0)
+ nv_add_int16(nvout, error, "error");
+
+ if (hast_proto_send(NULL, conn, nvout, NULL, 0) < 0)
+ pjdlog_errno(LOG_ERR, "Unable to send control response");
+close:
+ if (nvin != NULL)
+ nv_free(nvin);
+ if (nvout != NULL)
+ nv_free(nvout);
+ proto_close(conn);
+}
+
+/*
+ * Thread handles control requests from the parent.
+ */
+void *
+ctrl_thread(void *arg)
+{
+ struct hast_resource *res = arg;
+ struct nv *nvin, *nvout;
+ uint8_t cmd;
+
+ for (;;) {
+ if (hast_proto_recv_hdr(res->hr_ctrl, &nvin) < 0) {
+ if (sigexit_received)
+ pthread_exit(NULL);
+ pjdlog_errno(LOG_ERR,
+ "Unable to receive control message");
+ continue;
+ }
+ cmd = nv_get_uint8(nvin, "cmd");
+ if (cmd == 0) {
+ pjdlog_error("Control message is missing 'cmd' field.");
+ nv_free(nvin);
+ continue;
+ }
+ nv_free(nvin);
+ nvout = nv_alloc();
+ switch (cmd) {
+ case HASTCTL_STATUS:
+ if (res->hr_remotein != NULL &&
+ res->hr_remoteout != NULL) {
+ nv_add_string(nvout, "complete", "status");
+ } else {
+ nv_add_string(nvout, "degraded", "status");
+ }
+ nv_add_uint32(nvout, (uint32_t)res->hr_extentsize,
+ "extentsize");
+ if (res->hr_role == HAST_ROLE_PRIMARY) {
+ nv_add_uint32(nvout,
+ (uint32_t)res->hr_keepdirty, "keepdirty");
+ nv_add_uint64(nvout,
+ (uint64_t)(activemap_ndirty(res->hr_amp) *
+ res->hr_extentsize), "dirty");
+ } else {
+ nv_add_uint32(nvout, (uint32_t)0, "keepdirty");
+ nv_add_uint64(nvout, (uint64_t)0, "dirty");
+ }
+ break;
+ default:
+ nv_add_int16(nvout, EINVAL, "error");
+ break;
+ }
+ if (nv_error(nvout) != 0) {
+ pjdlog_error("Unable to create answer on control message.");
+ nv_free(nvout);
+ continue;
+ }
+ if (hast_proto_send(NULL, res->hr_ctrl, nvout, NULL, 0) < 0) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to send reply to control message");
+ }
+ nv_free(nvout);
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
diff --git a/sbin/hastd/control.h b/sbin/hastd/control.h
new file mode 100644
index 0000000..15ea290
--- /dev/null
+++ b/sbin/hastd/control.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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 _CONTROL_H_
+#define _CONTROL_H_
+
+#define HASTCTL_SET_ROLE 1
+#define HASTCTL_STATUS 2
+
+struct hastd_config;
+
+void control_handle(struct hastd_config *cfg);
+
+void *ctrl_thread(void *arg);
+
+#endif /* !_CONTROL_H_ */
diff --git a/sbin/hastd/ebuf.c b/sbin/hastd/ebuf.c
new file mode 100644
index 0000000..47b7530
--- /dev/null
+++ b/sbin/hastd/ebuf.c
@@ -0,0 +1,252 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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 <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "ebuf.h"
+
+#define EBUF_MAGIC 0xeb0f41c
+struct ebuf {
+ /* Magic to assert the caller uses valid structure. */
+ int eb_magic;
+ /* Address where we did the allocation. */
+ unsigned char *eb_start;
+ /* Allocation end address. */
+ unsigned char *eb_end;
+ /* Start of real data. */
+ unsigned char *eb_used;
+ /* Size of real data. */
+ size_t eb_size;
+};
+
+static int ebuf_head_extent(struct ebuf *eb, size_t size);
+static int ebuf_tail_extent(struct ebuf *eb, size_t size);
+
+struct ebuf *
+ebuf_alloc(size_t size)
+{
+ struct ebuf *eb;
+ int rerrno;
+
+ eb = malloc(sizeof(*eb));
+ if (eb == NULL)
+ return (NULL);
+ size += PAGE_SIZE;
+ eb->eb_start = malloc(size);
+ if (eb->eb_start == NULL) {
+ rerrno = errno;
+ free(eb);
+ errno = rerrno;
+ return (NULL);
+ }
+ eb->eb_end = eb->eb_start + size;
+ /*
+ * We set start address for real data not at the first entry, because
+ * we want to be able to add data at the front.
+ */
+ eb->eb_used = eb->eb_start + PAGE_SIZE / 4;
+ eb->eb_size = 0;
+ eb->eb_magic = EBUF_MAGIC;
+
+ return (eb);
+}
+
+void
+ebuf_free(struct ebuf *eb)
+{
+
+ assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
+
+ eb->eb_magic = 0;
+
+ free(eb->eb_start);
+ free(eb);
+}
+
+int
+ebuf_add_head(struct ebuf *eb, const void *data, size_t size)
+{
+
+ assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
+
+ if (size > (size_t)(eb->eb_used - eb->eb_start)) {
+ /*
+ * We can't add more entries at the front, so we have to extend
+ * our buffer.
+ */
+ if (ebuf_head_extent(eb, size) < 0)
+ return (-1);
+ }
+ assert(size <= (size_t)(eb->eb_used - eb->eb_start));
+
+ eb->eb_size += size;
+ eb->eb_used -= size;
+ /*
+ * If data is NULL the caller just wants to reserve place.
+ */
+ if (data != NULL)
+ bcopy(data, eb->eb_used, size);
+
+ return (0);
+}
+
+int
+ebuf_add_tail(struct ebuf *eb, const void *data, size_t size)
+{
+
+ assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
+
+ if (size > (size_t)(eb->eb_end - (eb->eb_used + eb->eb_size))) {
+ /*
+ * We can't add more entries at the back, so we have to extend
+ * our buffer.
+ */
+ if (ebuf_tail_extent(eb, size) < 0)
+ return (-1);
+ }
+ assert(size <= (size_t)(eb->eb_end - (eb->eb_used + eb->eb_size)));
+
+ /*
+ * If data is NULL the caller just wants to reserve place.
+ */
+ if (data != NULL)
+ bcopy(data, eb->eb_used + eb->eb_size, size);
+ eb->eb_size += size;
+
+ return (0);
+}
+
+void
+ebuf_del_head(struct ebuf *eb, size_t size)
+{
+
+ assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
+ assert(size <= eb->eb_size);
+
+ eb->eb_used += size;
+ eb->eb_size -= size;
+}
+
+void
+ebuf_del_tail(struct ebuf *eb, size_t size)
+{
+
+ assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
+ assert(size <= eb->eb_size);
+
+ eb->eb_size -= size;
+}
+
+/*
+ * Return pointer to the data and data size.
+ */
+void *
+ebuf_data(struct ebuf *eb, size_t *sizep)
+{
+
+ assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
+
+ if (sizep != NULL)
+ *sizep = eb->eb_size;
+ return (eb->eb_size > 0 ? eb->eb_used : NULL);
+}
+
+/*
+ * Return data size.
+ */
+size_t
+ebuf_size(struct ebuf *eb)
+{
+
+ assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
+
+ return (eb->eb_size);
+}
+
+/*
+ * Function adds size + (PAGE_SIZE / 4) bytes at the front of the buffer..
+ */
+static int
+ebuf_head_extent(struct ebuf *eb, size_t size)
+{
+ unsigned char *newstart, *newused;
+ size_t newsize;
+
+ assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
+
+ newsize = eb->eb_end - eb->eb_start + (PAGE_SIZE / 4) + size;
+
+ newstart = malloc(newsize);
+ if (newstart == NULL)
+ return (-1);
+ newused =
+ newstart + (PAGE_SIZE / 4) + size + (eb->eb_used - eb->eb_start);
+
+ bcopy(eb->eb_used, newused, eb->eb_size);
+
+ eb->eb_start = newstart;
+ eb->eb_used = newused;
+ eb->eb_end = newstart + newsize;
+
+ return (0);
+}
+
+/*
+ * Function adds size + ((3 * PAGE_SIZE) / 4) bytes at the back.
+ */
+static int
+ebuf_tail_extent(struct ebuf *eb, size_t size)
+{
+ unsigned char *newstart;
+ size_t newsize;
+
+ assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
+
+ newsize = eb->eb_end - eb->eb_start + size + ((3 * PAGE_SIZE) / 4);
+
+ newstart = realloc(eb->eb_start, newsize);
+ if (newstart == NULL)
+ return (-1);
+
+ eb->eb_used = newstart + (eb->eb_used - eb->eb_start);
+ eb->eb_start = newstart;
+ eb->eb_end = newstart + newsize;
+
+ return (0);
+}
diff --git a/sys/amd64/isa/icu.h b/sbin/hastd/ebuf.h
index c484ecc..06275e7 100644
--- a/sys/amd64/isa/icu.h
+++ b/sbin/hastd/ebuf.h
@@ -1,9 +1,9 @@
/*-
- * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
* All rights reserved.
*
- * This code is derived from software contributed to Berkeley by
- * William Jolitz.
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -13,14 +13,11 @@
* 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.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 REGENTS OR CONTRIBUTORS BE LIABLE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS 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)
@@ -29,21 +26,26 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * from: @(#)icu.h 5.6 (Berkeley) 5/9/91
* $FreeBSD$
*/
-/*
- * AT/386 Interrupt Control constants
- * W. Jolitz 8/89
- */
+#ifndef _EBUF_H_
+#define _EBUF_H_
+
+#include <stdlib.h> /* size_t */
+
+struct ebuf;
+
+struct ebuf *ebuf_alloc(size_t size);
+void ebuf_free(struct ebuf *eb);
-#ifndef _AMD64_ISA_ICU_H_
-#define _AMD64_ISA_ICU_H_
+int ebuf_add_head(struct ebuf *eb, const void *data, size_t size);
+int ebuf_add_tail(struct ebuf *eb, const void *data, size_t size);
-#define ICU_IMR_OFFSET 1
+void ebuf_del_head(struct ebuf *eb, size_t size);
+void ebuf_del_tail(struct ebuf *eb, size_t size);
-void atpic_handle_intr(u_int vector, struct trapframe *frame);
-void atpic_startup(void);
+void *ebuf_data(struct ebuf *eb, size_t *sizep);
+size_t ebuf_size(struct ebuf *eb);
-#endif /* !_AMD64_ISA_ICU_H_ */
+#endif /* !_EBUF_H_ */
diff --git a/sbin/hastd/hast.conf.5 b/sbin/hastd/hast.conf.5
new file mode 100644
index 0000000..5734ee8
--- /dev/null
+++ b/sbin/hastd/hast.conf.5
@@ -0,0 +1,267 @@
+.\" Copyright (c) 2010 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This software was developed by Pawel Jakub Dawidek under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 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 AUTHORS 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 AUTHORS 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$
+.\"
+.Dd February 1, 2010
+.Dt HAST.CONF 5
+.Os
+.Sh NAME
+.Nm hast.conf
+.Nd configuration file for the
+.Xr hastd 8
+deamon and the
+.Xr hastctl 8
+utility.
+.Sh DESCRIPTION
+The
+.Nm
+file is used by both
+.Xr hastd 8
+daemon
+and
+.Xr hastctl 8
+control utility.
+Configuration file is designed in a way that exactly the same file can be
+(and should be) used on both HAST nodes.
+Every line starting with # is treated as comment and ignored.
+.Sh CONFIGURATION FILE SYNTAX
+General syntax of the
+.Nm
+file is following:
+.Bd -literal -offset indent
+# Global section
+control <addr>
+listen <addr>
+replication <mode>
+
+on <node> {
+ # Node section
+ control <addr>
+ listen <addr>
+}
+
+on <node> {
+ # Node section
+ control <addr>
+ listen <addr>
+}
+
+resource <name> {
+ # Resource section
+ replication <mode>
+ name <name>
+ local <path>
+
+ on <node> {
+ # Resource-node section
+ name <name>
+ # Required
+ local <path>
+ # Required
+ remote <addr>
+ }
+ on <node> {
+ # Resource-node section
+ name <name>
+ # Required
+ local <path>
+ # Required
+ remote <addr>
+ }
+}
+.Ed
+.Pp
+Most of the various available configuration parameters are optional.
+If parameter is not defined in the particular section, it will be
+inherited from the parent section.
+For example, if the
+.Ic listen
+parameter is not defined in the node section, it will be inherited from
+the global section.
+In case the global section does not define the
+.Ic listen
+parameter at all, the default value will be used.
+.Sh CONFIGURATION FILE DESCRIPTION
+The
+.Aq node
+argument can be replaced either by a full hostname as obtained by
+.Xr gethostname 3 ,
+only first part of the hostname, or by node's UUID as found in the
+.Va kern.hostuuid
+.Xr sysctl 8
+variable.
+.Pp
+The following statements are available:
+.Bl -tag -width ".Ic xxxx"
+.It Ic control Aq addr
+.Pp
+Address for communication with
+.Xr hastctl 8 .
+Each of the following examples defines the same control address:
+.Bd -literal -offset indent
+uds:///var/run/hastctl
+unix:///var/run/hastctl
+/var/run/hastctl
+.Ed
+.Pp
+The default value is
+.Pa uds:///var/run/hastctl .
+.It Ic listen Aq addr
+.Pp
+Address to listen on in form of:
+.Bd -literal -offset indent
+protocol://protocol-specific-address
+.Ed
+.Pp
+Each of the following examples defines the same listen address:
+.Bd -literal -offset indent
+0.0.0.0
+0.0.0.0:8457
+tcp://0.0.0.0
+tcp://0.0.0.0:8457
+tcp4://0.0.0.0
+tcp4://0.0.0.0:8457
+.Ed
+.Pp
+The default value is
+.Pa tcp4://0.0.0.0:8457 .
+.It Ic replication Aq mode
+.Pp
+Replication mode should be one of the following:
+.Bl -tag -width ".Ic xxxx"
+.It Ic memsync
+.Pp
+Report the write operation as completed when local write completes and
+when the remote node acknowledges the data receipt, but before it
+actually stores the data.
+The data on remote node will be stored directly after sending
+acknowledgement.
+This mode is intended to reduce latency, but still provides a very good
+reliability.
+The only situation where some small amount of data could be lost is when
+the data is stored on primary node and sent to the secondary.
+Secondary node then acknowledges data receipt and primary reports
+success to an application.
+However, it may happen that the seconderay goes down before the received
+data is really stored locally.
+Before secondary node returns, primary node dies entirely.
+When the secondary node comes back to life it becomes the new primary.
+Unfortunately some small amount of data which was confirmed to be stored
+to the application was lost.
+The risk of such a situation is very small, which is the reason for this
+mode to be the default.
+.It Ic fullsync
+.Pp
+Mark the write operation as completed when local as well as remote
+write completes.
+This is the safest and the slowest replication mode.
+The
+.Ic fullsync
+replication mode is currently not implemented.
+.It Ic async
+.Pp
+The write operation is reported as complete right after the local write
+completes.
+This is the fastest and the most dangerous replication mode.
+This mode should be used when replicating to a distant node where
+latency is too high for other modes.
+The
+.Ic async
+replication mode is currently not implemented.
+.El
+.It Ic name Aq name
+.Pp
+GEOM provider name that will appear as
+.Pa /dev/hast/<name> .
+If name is not defined, resource name will be used as provider name.
+.It Ic local Aq path
+.Pp
+Path to the local component which will be used as backend provider for
+the resource.
+This can be either GEOM provider or regular file.
+.It Ic remote Aq addr
+.Pp
+Address of the remote
+.Nm hastd
+daemon.
+Format is the same as for the
+.Ic listen
+statement.
+When operating as a primary node this address will be used to connect to
+the secondary node.
+When operating as a secondary node only connections from this address
+will be accepted.
+.El
+.Sh EXAMPLES
+The example configuration file can look as follows:
+.Bd -literal -offset indent
+resource shared {
+ local /dev/da0
+
+ on hasta {
+ remote tcp4://10.0.0.2
+ }
+ on hastb {
+ remote tcp4://10.0.0.1
+ }
+}
+resource tank {
+ on hasta {
+ local /dev/mirror/tanka
+ remote tcp4://10.0.0.2
+ }
+ on hastb {
+ local /dev/mirror/tankb
+ remote tcp4://10.0.0.1
+ }
+}
+.Ed
+.Sh FILES
+.Bl -tag -width ".Pa /var/run/hastctl" -compact
+.It Pa /etc/hast.conf
+The default
+.Nm
+configuration file.
+.It Pa /var/run/hastctl
+Control socket used by the
+.Xr hastctl 8
+control utility to communicate with the
+.Xr hastd 8
+daemon.
+.El
+.Sh SEE ALSO
+.Xr gethostname 3 ,
+.Xr geom 4 ,
+.Xr hastctl 8 ,
+.Xr hastd 8 .
+.Sh AUTHORS
+The
+.Nm
+was written by
+.An Pawel Jakub Dawidek Aq pjd@FreeBSD.org
+under sponsorship of the FreeBSD Foundation.
diff --git a/sbin/hastd/hast.h b/sbin/hastd/hast.h
new file mode 100644
index 0000000..c5220b5
--- /dev/null
+++ b/sbin/hastd/hast.h
@@ -0,0 +1,190 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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 _HAST_H_
+#define _HAST_H_
+
+#include <sys/queue.h>
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+
+#include <limits.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <activemap.h>
+
+#include "proto.h"
+
+#define HAST_PROTO_VERSION 0
+
+#define EHAST_OK 0
+#define EHAST_NOENTRY 1
+#define EHAST_INVALID 2
+#define EHAST_NOMEMORY 3
+#define EHAST_UNIMPLEMENTED 4
+
+#define HASTCTL_CMD_UNKNOWN 0
+#define HASTCTL_CMD_SETROLE 1
+#define HASTCTL_CMD_STATUS 2
+
+#define HAST_ROLE_UNDEF 0
+#define HAST_ROLE_INIT 1
+#define HAST_ROLE_PRIMARY 2
+#define HAST_ROLE_SECONDARY 3
+
+#define HAST_SYNCSRC_UNDEF 0
+#define HAST_SYNCSRC_PRIMARY 1
+#define HAST_SYNCSRC_SECONDARY 2
+
+#define HIO_UNDEF 0
+#define HIO_READ 1
+#define HIO_WRITE 2
+#define HIO_DELETE 3
+#define HIO_FLUSH 4
+
+#define HAST_CONFIG "/etc/hast.conf"
+#define HAST_CONTROL "/var/run/hastctl"
+#define HASTD_PORT 8457
+#define HASTD_LISTEN "tcp4://0.0.0.0:8457"
+#define HASTD_PIDFILE "/var/run/hastd.pid"
+
+/* Default extent size. */
+#define HAST_EXTENTSIZE 2097152
+/* Default maximum number of extents that are kept dirty. */
+#define HAST_KEEPDIRTY 64
+
+#define HAST_ADDRSIZE 1024
+#define HAST_TOKEN_SIZE 16
+
+struct hastd_config {
+ /* Address to communicate with hastctl(8). */
+ char hc_controladdr[HAST_ADDRSIZE];
+ /* Protocol-specific data. */
+ struct proto_conn *hc_controlconn;
+ /* Address to listen on. */
+ char hc_listenaddr[HAST_ADDRSIZE];
+ /* Protocol-specific data. */
+ struct proto_conn *hc_listenconn;
+ /* List of resources. */
+ TAILQ_HEAD(, hast_resource) hc_resources;
+};
+
+#define HAST_REPLICATION_FULLSYNC 0
+#define HAST_REPLICATION_MEMSYNC 1
+#define HAST_REPLICATION_ASYNC 2
+
+/*
+ * Structure that describes single resource.
+ */
+struct hast_resource {
+ /* Resource name. */
+ char hr_name[NAME_MAX];
+ /* Replication mode (HAST_REPLICATION_*). */
+ int hr_replication;
+ /* Provider name that will appear in /dev/hast/. */
+ char hr_provname[NAME_MAX];
+ /* Synchronization extent size. */
+ int hr_extentsize;
+ /* Maximum number of extents that are kept dirty. */
+ int hr_keepdirty;
+
+ /* Path to local component. */
+ char hr_localpath[PATH_MAX];
+ /* Descriptor to access local component. */
+ int hr_localfd;
+ /* Offset into local component. */
+ off_t hr_localoff;
+ /* Size of usable space. */
+ off_t hr_datasize;
+ /* Size of entire local provider. */
+ off_t hr_local_mediasize;
+ /* Sector size of local provider. */
+ unsigned int hr_local_sectorsize;
+
+ /* Descriptor for /dev/ggctl communication. */
+ int hr_ggatefd;
+ /* Unit number for ggate communication. */
+ int hr_ggateunit;
+
+ /* Address of the remote component. */
+ char hr_remoteaddr[HAST_ADDRSIZE];
+ /* Connection for incoming data. */
+ struct proto_conn *hr_remotein;
+ /* Connection for outgoing data. */
+ struct proto_conn *hr_remoteout;
+ /* Token to verify both in and out connection are coming from
+ the same node (not necessarily from the same address). */
+ unsigned char hr_token[HAST_TOKEN_SIZE];
+
+ /* Resource unique identifier. */
+ uint64_t hr_resuid;
+ /* Primary's local modification count. */
+ uint64_t hr_primary_localcnt;
+ /* Primary's remote modification count. */
+ uint64_t hr_primary_remotecnt;
+ /* Secondary's local modification count. */
+ uint64_t hr_secondary_localcnt;
+ /* Secondary's remote modification count. */
+ uint64_t hr_secondary_remotecnt;
+ /* Synchronization source. */
+ uint8_t hr_syncsrc;
+
+ /* Resource role: HAST_ROLE_{INIT,PRIMARY,SECONDARY}. */
+ int hr_role;
+ /* Previous resource role: HAST_ROLE_{INIT,PRIMARY,SECONDARY}. */
+ int hr_previous_role;
+ /* PID of child worker process. 0 - no child. */
+ pid_t hr_workerpid;
+ /* Control connection between parent and child. */
+ struct proto_conn *hr_ctrl;
+
+ /* Activemap structure. */
+ struct activemap *hr_amp;
+ /* Locked used to synchronize access to hr_amp. */
+ pthread_mutex_t hr_amp_lock;
+
+ /* Next resource. */
+ TAILQ_ENTRY(hast_resource) hr_next;
+};
+
+struct hastd_config *yy_config_parse(const char *config);
+void yy_config_free(struct hastd_config *config);
+
+void yyerror(const char *);
+int yylex(void);
+int yyparse(void);
+
+#endif /* !_HAST_H_ */
diff --git a/sbin/hastd/hast_proto.c b/sbin/hastd/hast_proto.c
new file mode 100644
index 0000000..6e66006
--- /dev/null
+++ b/sbin/hastd/hast_proto.c
@@ -0,0 +1,401 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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/endian.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+
+#include <openssl/sha.h>
+
+#include <hast.h>
+#include <ebuf.h>
+#include <nv.h>
+#include <pjdlog.h>
+#include <proto.h>
+
+#include "hast_proto.h"
+
+struct hast_main_header {
+ /* Protocol version. */
+ uint8_t version;
+ /* Size of nv headers. */
+ uint32_t size;
+} __packed;
+
+typedef int hps_send_t(struct hast_resource *, struct nv *nv, void **, size_t *, bool *);
+typedef int hps_recv_t(struct hast_resource *, struct nv *nv, void **, size_t *, bool *);
+
+struct hast_pipe_stage {
+ const char *hps_name;
+ hps_send_t *hps_send;
+ hps_recv_t *hps_recv;
+};
+
+static int compression_send(struct hast_resource *res, struct nv *nv,
+ void **datap, size_t *sizep, bool *freedatap);
+static int compression_recv(struct hast_resource *res, struct nv *nv,
+ void **datap, size_t *sizep, bool *freedatap);
+static int checksum_send(struct hast_resource *res, struct nv *nv,
+ void **datap, size_t *sizep, bool *freedatap);
+static int checksum_recv(struct hast_resource *res, struct nv *nv,
+ void **datap, size_t *sizep, bool *freedatap);
+
+static struct hast_pipe_stage pipeline[] = {
+ { "compression", compression_send, compression_recv },
+ { "checksum", checksum_send, checksum_recv }
+};
+
+static int
+compression_send(struct hast_resource *res, struct nv *nv, void **datap,
+ size_t *sizep, bool *freedatap)
+{
+ unsigned char *newbuf;
+
+ res = res; /* TODO */
+
+ /*
+ * TODO: For now we emulate compression.
+ * At 80% probability we succeed to compress data, which means we
+ * allocate new buffer, copy the data over set *freedatap to true.
+ */
+
+ if (arc4random_uniform(100) < 80) {
+ uint32_t *origsize;
+
+ /*
+ * Compression succeeded (but we will grow by 4 bytes, not
+ * shrink for now).
+ */
+ newbuf = malloc(sizeof(uint32_t) + *sizep);
+ if (newbuf == NULL)
+ return (-1);
+ origsize = (void *)newbuf;
+ *origsize = htole32((uint32_t)*sizep);
+ nv_add_string(nv, "null", "compression");
+ if (nv_error(nv) != 0) {
+ free(newbuf);
+ errno = nv_error(nv);
+ return (-1);
+ }
+ bcopy(*datap, newbuf + sizeof(uint32_t), *sizep);
+ if (*freedatap)
+ free(*datap);
+ *freedatap = true;
+ *datap = newbuf;
+ *sizep = sizeof(uint32_t) + *sizep;
+ } else {
+ /*
+ * Compression failed, so we leave everything as it was.
+ * It is not critical for compression to succeed.
+ */
+ }
+
+ return (0);
+}
+
+static int
+compression_recv(struct hast_resource *res, struct nv *nv, void **datap,
+ size_t *sizep, bool *freedatap)
+{
+ unsigned char *newbuf;
+ const char *algo;
+ size_t origsize;
+
+ res = res; /* TODO */
+
+ /*
+ * TODO: For now we emulate compression.
+ */
+
+ algo = nv_get_string(nv, "compression");
+ if (algo == NULL)
+ return (0); /* No compression. */
+ if (strcmp(algo, "null") != 0) {
+ pjdlog_error("Unknown compression algorithm '%s'.", algo);
+ return (-1); /* Unknown compression algorithm. */
+ }
+
+ origsize = le32toh(*(uint32_t *)*datap);
+ newbuf = malloc(origsize);
+ if (newbuf == NULL)
+ return (-1);
+ bcopy((unsigned char *)*datap + sizeof(uint32_t), newbuf, origsize);
+ if (*freedatap)
+ free(*datap);
+ *freedatap = true;
+ *datap = newbuf;
+ *sizep = origsize;
+
+ return (0);
+}
+
+static int
+checksum_send(struct hast_resource *res, struct nv *nv, void **datap,
+ size_t *sizep, bool *freedatap __unused)
+{
+ unsigned char hash[SHA256_DIGEST_LENGTH];
+ SHA256_CTX ctx;
+
+ res = res; /* TODO */
+
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, *datap, *sizep);
+ SHA256_Final(hash, &ctx);
+
+ nv_add_string(nv, "sha256", "checksum");
+ nv_add_uint8_array(nv, hash, sizeof(hash), "hash");
+
+ return (0);
+}
+
+static int
+checksum_recv(struct hast_resource *res, struct nv *nv, void **datap,
+ size_t *sizep, bool *freedatap __unused)
+{
+ unsigned char chash[SHA256_DIGEST_LENGTH];
+ const unsigned char *rhash;
+ SHA256_CTX ctx;
+ const char *algo;
+ size_t size;
+
+ res = res; /* TODO */
+
+ algo = nv_get_string(nv, "checksum");
+ if (algo == NULL)
+ return (0); /* No checksum. */
+ if (strcmp(algo, "sha256") != 0) {
+ pjdlog_error("Unknown checksum algorithm '%s'.", algo);
+ return (-1); /* Unknown checksum algorithm. */
+ }
+ rhash = nv_get_uint8_array(nv, &size, "hash");
+ if (rhash == NULL) {
+ pjdlog_error("Checksum algorithm is present, but hash is missing.");
+ return (-1); /* Hash not found. */
+ }
+ if (size != sizeof(chash)) {
+ pjdlog_error("Invalid hash size (%zu) for %s, should be %zu.",
+ size, algo, sizeof(chash));
+ return (-1); /* Different hash size. */
+ }
+
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, *datap, *sizep);
+ SHA256_Final(chash, &ctx);
+
+ if (bcmp(rhash, chash, sizeof(chash)) != 0) {
+ pjdlog_error("Hash mismatch.");
+ return (-1); /* Hash mismatch. */
+ }
+
+ return (0);
+}
+
+/*
+ * Send the given nv structure via conn.
+ * We keep headers in nv structure and pass data in separate argument.
+ * There can be no data at all (data is NULL then).
+ */
+int
+hast_proto_send(struct hast_resource *res, struct proto_conn *conn,
+ struct nv *nv, const void *data, size_t size)
+{
+ struct hast_main_header hdr;
+ struct ebuf *eb;
+ bool freedata;
+ void *dptr, *hptr;
+ size_t hsize;
+ int ret;
+
+ dptr = (void *)(uintptr_t)data;
+ freedata = false;
+ ret = -1;
+
+ if (data != NULL) {
+if (false) {
+ unsigned int ii;
+
+ for (ii = 0; ii < sizeof(pipeline) / sizeof(pipeline[0]);
+ ii++) {
+ ret = pipeline[ii].hps_send(res, nv, &dptr, &size,
+ &freedata);
+ if (ret == -1)
+ goto end;
+ }
+ ret = -1;
+}
+ nv_add_uint32(nv, size, "size");
+ if (nv_error(nv) != 0) {
+ errno = nv_error(nv);
+ goto end;
+ }
+ }
+
+ eb = nv_hton(nv);
+ if (eb == NULL)
+ goto end;
+
+ hdr.version = HAST_PROTO_VERSION;
+ hdr.size = htole32((uint32_t)ebuf_size(eb));
+ if (ebuf_add_head(eb, &hdr, sizeof(hdr)) < 0)
+ goto end;
+
+ hptr = ebuf_data(eb, &hsize);
+ if (proto_send(conn, hptr, hsize) < 0)
+ goto end;
+ if (data != NULL && proto_send(conn, dptr, size) < 0)
+ goto end;
+
+ ret = 0;
+end:
+ if (freedata)
+ free(dptr);
+ return (ret);
+}
+
+int
+hast_proto_recv_hdr(struct proto_conn *conn, struct nv **nvp)
+{
+ struct hast_main_header hdr;
+ struct nv *nv;
+ struct ebuf *eb;
+ void *hptr;
+
+ eb = NULL;
+ nv = NULL;
+
+ if (proto_recv(conn, &hdr, sizeof(hdr)) < 0)
+ goto fail;
+
+ if (hdr.version != HAST_PROTO_VERSION) {
+ errno = ERPCMISMATCH;
+ goto fail;
+ }
+
+ hdr.size = le32toh(hdr.size);
+
+ eb = ebuf_alloc(hdr.size);
+ if (eb == NULL)
+ goto fail;
+ if (ebuf_add_tail(eb, NULL, hdr.size) < 0)
+ goto fail;
+ hptr = ebuf_data(eb, NULL);
+ assert(hptr != NULL);
+ if (proto_recv(conn, hptr, hdr.size) < 0)
+ goto fail;
+ nv = nv_ntoh(eb);
+ if (nv == NULL)
+ goto fail;
+
+ *nvp = nv;
+ return (0);
+fail:
+ if (nv != NULL)
+ nv_free(nv);
+ else if (eb != NULL)
+ ebuf_free(eb);
+ return (-1);
+}
+
+int
+hast_proto_recv_data(struct hast_resource *res, struct proto_conn *conn,
+ struct nv *nv, void *data, size_t size)
+{
+ unsigned int ii;
+ bool freedata;
+ size_t dsize;
+ void *dptr;
+ int ret;
+
+ assert(data != NULL);
+ assert(size > 0);
+
+ ret = -1;
+ freedata = false;
+ dptr = data;
+
+ dsize = nv_get_uint32(nv, "size");
+ if (dsize == 0)
+ (void)nv_set_error(nv, 0);
+ else {
+ if (proto_recv(conn, data, dsize) < 0)
+ goto end;
+if (false) {
+ for (ii = sizeof(pipeline) / sizeof(pipeline[0]); ii > 0;
+ ii--) {
+ assert(!"to be verified");
+ ret = pipeline[ii - 1].hps_recv(res, nv, &dptr,
+ &dsize, &freedata);
+ if (ret == -1)
+ goto end;
+ }
+ ret = -1;
+ if (dsize < size)
+ goto end;
+ /* TODO: 'size' doesn't seem right here. It is maximum data size. */
+ if (dptr != data)
+ bcopy(dptr, data, dsize);
+}
+ }
+
+ ret = 0;
+end:
+if (ret < 0) printf("%s:%u %s\n", __func__, __LINE__, strerror(errno));
+ if (freedata)
+ free(dptr);
+ return (ret);
+}
+
+int
+hast_proto_recv(struct hast_resource *res, struct proto_conn *conn,
+ struct nv **nvp, void *data, size_t size)
+{
+ struct nv *nv;
+ size_t dsize;
+ int ret;
+
+ ret = hast_proto_recv_hdr(conn, &nv);
+ if (ret < 0)
+ return (ret);
+ dsize = nv_get_uint32(nv, "size");
+ if (dsize == 0)
+ (void)nv_set_error(nv, 0);
+ else
+ ret = hast_proto_recv_data(res, conn, nv, data, size);
+ if (ret < 0)
+ nv_free(nv);
+ else
+ *nvp = nv;
+ return (ret);
+}
diff --git a/sbin/hastd/hast_proto.h b/sbin/hastd/hast_proto.h
new file mode 100644
index 0000000..3894e38
--- /dev/null
+++ b/sbin/hastd/hast_proto.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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 _HAST_PROTO_H_
+#define _HAST_PROTO_H_
+
+#include <stdlib.h> /* size_t */
+
+#include <nv.h>
+#include <proto.h>
+
+int hast_proto_send(struct hast_resource *res, struct proto_conn *conn,
+ struct nv *nv, const void *data, size_t size);
+int hast_proto_recv(struct hast_resource *res, struct proto_conn *conn,
+ struct nv **nvp, void *data, size_t size);
+int hast_proto_recv_hdr(struct proto_conn *conn, struct nv **nvp);
+int hast_proto_recv_data(struct hast_resource *res, struct proto_conn *conn,
+ struct nv *nv, void *data, size_t size);
+
+#endif /* !_HAST_PROTO_H_ */
diff --git a/sbin/hastd/hastd.8 b/sbin/hastd/hastd.8
new file mode 100644
index 0000000..276b3d3
--- /dev/null
+++ b/sbin/hastd/hastd.8
@@ -0,0 +1,232 @@
+.\" Copyright (c) 2010 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This software was developed by Pawel Jakub Dawidek under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 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 AUTHORS 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 AUTHORS 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$
+.\"
+.Dd February 1, 2010
+.Dt HASTD 8
+.Os
+.Sh NAME
+.Nm hastd
+.Nd "Highly Available Storage daemon"
+.Sh SYNOPSIS
+.Nm
+.Op Fl dFh
+.Op Fl c Ar config
+.Op Fl P Ar pidfile
+.Sh DESCRIPTION
+The
+.Nm
+daemon is responsible for managing highly available GEOM providers.
+.Pp
+.Nm
+allows to transparently store data on two physically separated machines
+connected over the TCP/IP network.
+Only one machine (cluster node) can actively use storage provided by
+.Nm .
+This machine is called primary.
+The
+.Nm
+daemon operates on block level, which makes it transparent for file
+systems and applications.
+.Pp
+There is one main
+.Nm
+daemon which starts new worker process as soon as a role for the given
+resource is changed to primary or as soon as a role for the given
+resource is changed to secondary and remote (primary) node will
+successfully connect to it.
+Every worker process gets a new process title (see
+.Xr setproctitle 3 ) ,
+which describes its role and resource it controls.
+The exact format is:
+.Bd -literal -offset indent
+hastd: <resource name> (<role>)
+.Ed
+.Pp
+When (and only when)
+.Nm
+operates in primary role for the given resource, corresponding
+.Pa /dev/hast/<name>
+disk-like device (GEOM provider) is created.
+File systems and applications can use this provider to send I/O
+requests to.
+Every write, delete and flush operation
+.Dv ( BIO_WRITE , BIO_DELETE , BIO_FLUSH )
+is send to local component and synchronously replicated
+to the remote (secondary) node if it is available.
+Read operations
+.Dv ( BIO_READ )
+are handled locally unless I/O error occurs or local version of the data
+is not up-to-date yet (synchronization is in progress).
+.Pp
+The
+.Nm
+daemon uses the GEOM Gate class to receive I/O requests from the
+in-kernel GEOM infrastructure.
+The
+.Nm geom_gate.ko
+module is loaded automatically if the kernel was not compiled with the
+following option:
+.Bd -ragged -offset indent
+.Cd "options GEOM_GATE"
+.Ed
+.Pp
+The connection between two
+.Nm
+daemons is always initiated from the one running as primary to the one
+running as secondary.
+When primary
+.Nm
+is unable to connect or connection fails, it will try to re-establish
+connection every few seconds.
+Once connection is established, primary
+.Nm
+will synchronize every extent that was modified during connection outage
+to the secondary
+.Nm .
+.Pp
+It is possible that in case of connection outage between the nodes
+.Nm
+primary role for the given resource will be configured on both nodes.
+This in turn leads to incompatible data modifications.
+Such condition is called split-brain and cannot be automatically
+resolved by the
+.Nm
+daemon as this will lead most likely to data corruption or lost of
+important changes.
+Even though it cannot be fixed by
+.Nm
+itself, it will be detected and further connection between independently
+modified nodes will not be possible.
+Once this situation is manually resolved by an administrator, resource
+on one of the nodes can be initialized (erasing local data), which makes
+connection to the remote node possible again.
+Connection of freshly initialized component will trigger full resource
+synchronization.
+.Pp
+The
+.Nm
+daemon itself never picks his role up automatically.
+The role has to be configured with the
+.Xr hastctl 8
+control utility by additional software like
+.Nm ucarp
+or
+.Nm heartbeat
+that can reliably manage role separation and switch secondary node to
+primary role in case of original primary failure.
+.Pp
+The
+.Nm
+daemon can be started with the following command line arguments:
+.Bl -tag -width ".Fl P Ar pidfile"
+.It Fl c Ar config
+Specify alternative location of the configuration file.
+The default location is
+.Pa /etc/hast.conf .
+.It Fl d
+Print or log debugging information.
+This option can be specified multiple times to raise the verbosity
+level.
+.It Fl F
+Start the
+.Nm
+daemon in the foreground.
+By default
+.Nm
+starts in the background.
+.It Fl h
+Print the
+.Nm
+usage message.
+.It Fl P Ar pidfile
+Specify alternative location of a file where main process PID will be
+stored.
+The default location is
+.Pa /var/run/hastd.pid .
+.El
+.Sh EXIT STATUS
+Exit status is 0 on success, or one of the values described in
+.Xr sysexits 3
+on failure.
+.Sh EXAMPLES
+Launch
+.Nm
+on both nodes.
+Set role for resource
+.Nm shared
+to primary on
+.Nm nodeA
+and to secondary on
+.Nm nodeB .
+Create file system on
+.Pa /dev/hast/shared
+provider and mount it.
+.Bd -literal -offset indent
+nodeB# hastd
+nodeB# hastctl role secondary shared
+
+nodeA# hastd
+nodeA# hastctl role primary shared
+nodeA# newfs -U /dev/hast/shared
+nodeA# mount -o noatime /dev/hast/shared /shared
+.Ed
+.Sh FILES
+.Bl -tag -width ".Pa /var/run/hastctl" -compact
+.It Pa /etc/hast.conf
+The configuration file for
+.Nm
+and
+.Xr hastctl 8 .
+.It Pa /var/run/hastctl
+Control socket used by the
+.Xr hastctl 8
+control utility to communicate with
+.Nm .
+.It Pa /var/run/hastd.pid
+The default location of the
+.Nm
+PID file.
+.El
+.Sh SEE ALSO
+.Xr sysexits 3 ,
+.Xr geom 4 ,
+.Xr hast.conf 5 ,
+.Xr ggatec 8 ,
+.Xr ggated 8 ,
+.Xr ggatel 8 ,
+.Xr hastctl 8 ,
+.Xr mount 8 ,
+.Xr newfs 8 ,
+.Xr g_bio 9 .
+.Sh AUTHORS
+The
+.Nm
+was developed by
+.An Pawel Jakub Dawidek Aq pjd@FreeBSD.org
+under sponsorship of the FreeBSD Foundation.
diff --git a/sbin/hastd/hastd.c b/sbin/hastd/hastd.c
new file mode 100644
index 0000000..19f0893
--- /dev/null
+++ b/sbin/hastd/hastd.c
@@ -0,0 +1,522 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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/linker.h>
+#include <sys/module.h>
+#include <sys/wait.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <libutil.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <activemap.h>
+#include <pjdlog.h>
+
+#include "control.h"
+#include "hast.h"
+#include "hast_proto.h"
+#include "hastd.h"
+#include "subr.h"
+
+/* Path to configuration file. */
+static const char *cfgpath = HAST_CONFIG;
+/* Hastd configuration. */
+static struct hastd_config *cfg;
+/* Was SIGCHLD signal received? */
+static bool sigchld_received = false;
+/* Was SIGHUP signal received? */
+static bool sighup_received = false;
+/* Was SIGINT or SIGTERM signal received? */
+bool sigexit_received = false;
+/* PID file handle. */
+struct pidfh *pfh;
+
+static void
+usage(void)
+{
+
+ errx(EX_USAGE, "[-dFh] [-c config] [-P pidfile]");
+}
+
+static void
+sighandler(int sig)
+{
+
+ switch (sig) {
+ case SIGCHLD:
+ sigchld_received = true;
+ break;
+ case SIGHUP:
+ sighup_received = true;
+ break;
+ default:
+ assert(!"invalid condition");
+ }
+}
+
+static void
+g_gate_load(void)
+{
+
+ if (modfind("g_gate") == -1) {
+ /* Not present in kernel, try loading it. */
+ if (kldload("geom_gate") == -1 || modfind("g_gate") == -1) {
+ if (errno != EEXIST) {
+ pjdlog_exit(EX_OSERR,
+ "Unable to load geom_gate module");
+ }
+ }
+ }
+}
+
+static void
+child_exit(void)
+{
+ struct hast_resource *res;
+ int status;
+ pid_t pid;
+
+ while ((pid = wait3(&status, WNOHANG, NULL)) > 0) {
+ /* Find resource related to the process that just exited. */
+ TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) {
+ if (pid == res->hr_workerpid)
+ break;
+ }
+ if (res == NULL) {
+ /*
+ * This can happen when new connection arrives and we
+ * cancel child responsible for the old one.
+ */
+ continue;
+ }
+ pjdlog_prefix_set("[%s] (%s) ", res->hr_name,
+ role2str(res->hr_role));
+ if (WEXITSTATUS(status) == 0) {
+ pjdlog_debug(1,
+ "Worker process exited gracefully (pid=%u).",
+ (unsigned int)pid);
+ } else {
+ pjdlog_error("Worker process failed (pid=%u, status=%d).",
+ (unsigned int)pid, WEXITSTATUS(status));
+ }
+ res->hr_workerpid = 0;
+ if (res->hr_role == HAST_ROLE_PRIMARY) {
+ sleep(1);
+ pjdlog_info("Restarting worker process.");
+ hastd_primary(res);
+ }
+ pjdlog_prefix_set("%s", "");
+ }
+}
+
+static void
+hastd_reload(void)
+{
+
+ /* TODO */
+ pjdlog_warning("Configuration reload is not implemented.");
+}
+
+static void
+listen_accept(void)
+{
+ struct hast_resource *res;
+ struct proto_conn *conn;
+ struct nv *nvin, *nvout, *nverr;
+ const char *resname;
+ const unsigned char *token;
+ char laddr[256], raddr[256];
+ size_t size;
+ pid_t pid;
+ int status;
+
+ proto_local_address(cfg->hc_listenconn, laddr, sizeof(laddr));
+ pjdlog_debug(1, "Accepting connection to %s.", laddr);
+
+ if (proto_accept(cfg->hc_listenconn, &conn) < 0) {
+ pjdlog_errno(LOG_ERR, "Unable to accept connection %s", laddr);
+ return;
+ }
+
+ proto_local_address(conn, laddr, sizeof(laddr));
+ proto_remote_address(conn, raddr, sizeof(raddr));
+ pjdlog_info("Connection from %s to %s.", laddr, raddr);
+
+ nvin = nvout = nverr = NULL;
+
+ /*
+ * Before receiving any data see if remote host have access to any
+ * resource.
+ */
+ TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) {
+ if (proto_address_match(conn, res->hr_remoteaddr))
+ break;
+ }
+ if (res == NULL) {
+ pjdlog_error("Client %s isn't known.", raddr);
+ goto close;
+ }
+ /* Ok, remote host can access at least one resource. */
+
+ if (hast_proto_recv_hdr(conn, &nvin) < 0) {
+ pjdlog_errno(LOG_ERR, "Unable to receive header from %s",
+ raddr);
+ goto close;
+ }
+
+ resname = nv_get_string(nvin, "resource");
+ if (resname == NULL) {
+ pjdlog_error("No 'resource' field in the header received from %s.",
+ raddr);
+ goto close;
+ }
+ pjdlog_debug(2, "%s: resource=%s", raddr, resname);
+ token = nv_get_uint8_array(nvin, &size, "token");
+ /*
+ * NULL token means that this is first conection.
+ */
+ if (token != NULL && size != sizeof(res->hr_token)) {
+ pjdlog_error("Received token of invalid size from %s (expected %zu, got %zu).",
+ raddr, sizeof(res->hr_token), size);
+ goto close;
+ }
+
+ /*
+ * From now on we want to send errors to the remote node.
+ */
+ nverr = nv_alloc();
+
+ /* Find resource related to this connection. */
+ TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) {
+ if (strcmp(resname, res->hr_name) == 0)
+ break;
+ }
+ /* Have we found the resource? */
+ if (res == NULL) {
+ pjdlog_error("No resource '%s' as requested by %s.",
+ resname, raddr);
+ nv_add_stringf(nverr, "errmsg", "Resource not configured.");
+ goto fail;
+ }
+
+ /* Now that we know resource name setup log prefix. */
+ pjdlog_prefix_set("[%s] (%s) ", res->hr_name, role2str(res->hr_role));
+
+ /* Does the remote host have access to this resource? */
+ if (!proto_address_match(conn, res->hr_remoteaddr)) {
+ pjdlog_error("Client %s has no access to the resource.", raddr);
+ nv_add_stringf(nverr, "errmsg", "No access to the resource.");
+ goto fail;
+ }
+ /* Is the resource marked as secondary? */
+ if (res->hr_role != HAST_ROLE_SECONDARY) {
+ pjdlog_error("We act as %s for the resource and not as %s as requested by %s.",
+ role2str(res->hr_role), role2str(HAST_ROLE_SECONDARY),
+ raddr);
+ nv_add_stringf(nverr, "errmsg",
+ "Remote node acts as %s for the resource and not as %s.",
+ role2str(res->hr_role), role2str(HAST_ROLE_SECONDARY));
+ goto fail;
+ }
+ /* Does token (if exists) match? */
+ if (token != NULL && memcmp(token, res->hr_token,
+ sizeof(res->hr_token)) != 0) {
+ pjdlog_error("Token received from %s doesn't match.", raddr);
+ nv_add_stringf(nverr, "errmsg", "Toke doesn't match.");
+ goto fail;
+ }
+ /*
+ * If there is no token, but we have half-open connection
+ * (only remotein) or full connection (worker process is running)
+ * we have to cancel those and accept the new connection.
+ */
+ if (token == NULL) {
+ assert(res->hr_remoteout == NULL);
+ pjdlog_debug(1, "Initial connection from %s.", raddr);
+ if (res->hr_workerpid != 0) {
+ assert(res->hr_remotein == NULL);
+ pjdlog_debug(1,
+ "Worker process exists (pid=%u), stopping it.",
+ (unsigned int)res->hr_workerpid);
+ /* Stop child process. */
+ if (kill(res->hr_workerpid, SIGINT) < 0) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to stop worker process (pid=%u)",
+ (unsigned int)res->hr_workerpid);
+ /*
+ * Other than logging the problem we
+ * ignore it - nothing smart to do.
+ */
+ }
+ /* Wait for it to exit. */
+ else if ((pid = waitpid(res->hr_workerpid,
+ &status, 0)) != res->hr_workerpid) {
+ pjdlog_errno(LOG_ERR,
+ "Waiting for worker process (pid=%u) failed",
+ (unsigned int)res->hr_workerpid);
+ /* See above. */
+ } else if (status != 0) {
+ pjdlog_error("Worker process (pid=%u) exited ungracefully: status=%d.",
+ (unsigned int)res->hr_workerpid, status);
+ /* See above. */
+ } else {
+ pjdlog_debug(1,
+ "Worker process (pid=%u) exited gracefully.",
+ (unsigned int)res->hr_workerpid);
+ }
+ res->hr_workerpid = 0;
+ } else if (res->hr_remotein != NULL) {
+ char oaddr[256];
+
+ proto_remote_address(conn, oaddr, sizeof(oaddr));
+ pjdlog_debug(1,
+ "Canceling half-open connection from %s on connection from %s.",
+ oaddr, raddr);
+ proto_close(res->hr_remotein);
+ res->hr_remotein = NULL;
+ }
+ }
+
+ /*
+ * Checks and cleanups are done.
+ */
+
+ if (token == NULL) {
+ arc4random_buf(res->hr_token, sizeof(res->hr_token));
+ nvout = nv_alloc();
+ nv_add_uint8_array(nvout, res->hr_token,
+ sizeof(res->hr_token), "token");
+ if (nv_error(nvout) != 0) {
+ pjdlog_common(LOG_ERR, 0, nv_error(nvout),
+ "Unable to prepare return header for %s", raddr);
+ nv_add_stringf(nverr, "errmsg",
+ "Remote node was unable to prepare return header: %s.",
+ strerror(nv_error(nvout)));
+ goto fail;
+ }
+ if (hast_proto_send(NULL, conn, nvout, NULL, 0) < 0) {
+ int error = errno;
+
+ pjdlog_errno(LOG_ERR, "Unable to send response to %s",
+ raddr);
+ nv_add_stringf(nverr, "errmsg",
+ "Remote node was unable to send response: %s.",
+ strerror(error));
+ goto fail;
+ }
+ res->hr_remotein = conn;
+ pjdlog_debug(1, "Incoming connection from %s configured.",
+ raddr);
+ } else {
+ res->hr_remoteout = conn;
+ pjdlog_debug(1, "Outgoing connection to %s configured.", raddr);
+ hastd_secondary(res, nvin);
+ }
+ nv_free(nvin);
+ nv_free(nvout);
+ nv_free(nverr);
+ pjdlog_prefix_set("%s", "");
+ return;
+fail:
+ if (nv_error(nverr) != 0) {
+ pjdlog_common(LOG_ERR, 0, nv_error(nverr),
+ "Unable to prepare error header for %s", raddr);
+ goto close;
+ }
+ if (hast_proto_send(NULL, conn, nverr, NULL, 0) < 0) {
+ pjdlog_errno(LOG_ERR, "Unable to send error to %s", raddr);
+ goto close;
+ }
+close:
+ if (nvin != NULL)
+ nv_free(nvin);
+ if (nvout != NULL)
+ nv_free(nvout);
+ if (nverr != NULL)
+ nv_free(nverr);
+ proto_close(conn);
+ pjdlog_prefix_set("%s", "");
+}
+
+static void
+main_loop(void)
+{
+ fd_set rfds, wfds;
+ int fd, maxfd, ret;
+
+ for (;;) {
+ if (sigchld_received) {
+ sigchld_received = false;
+ child_exit();
+ }
+ if (sighup_received) {
+ sighup_received = false;
+ hastd_reload();
+ }
+
+ maxfd = 0;
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+
+ /* Setup descriptors for select(2). */
+#define SETUP_FD(conn) do { \
+ fd = proto_descriptor(conn); \
+ if (fd >= 0) { \
+ maxfd = fd > maxfd ? fd : maxfd; \
+ FD_SET(fd, &rfds); \
+ FD_SET(fd, &wfds); \
+ } \
+} while (0)
+ SETUP_FD(cfg->hc_controlconn);
+ SETUP_FD(cfg->hc_listenconn);
+#undef SETUP_FD
+
+ ret = select(maxfd + 1, &rfds, &wfds, NULL, NULL);
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+ KEEP_ERRNO((void)pidfile_remove(pfh));
+ pjdlog_exit(EX_OSERR, "select() failed");
+ }
+
+#define ISSET_FD(conn) \
+ (FD_ISSET((fd = proto_descriptor(conn)), &rfds) || FD_ISSET(fd, &wfds))
+ if (ISSET_FD(cfg->hc_controlconn))
+ control_handle(cfg);
+ if (ISSET_FD(cfg->hc_listenconn))
+ listen_accept();
+#undef ISSET_FD
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ const char *pidfile;
+ pid_t otherpid;
+ bool foreground;
+ int debuglevel;
+
+ g_gate_load();
+
+ foreground = false;
+ debuglevel = 0;
+ pidfile = HASTD_PIDFILE;
+
+ for (;;) {
+ int ch;
+
+ ch = getopt(argc, argv, "c:dFhP:");
+ if (ch == -1)
+ break;
+ switch (ch) {
+ case 'c':
+ cfgpath = optarg;
+ break;
+ case 'd':
+ debuglevel++;
+ break;
+ case 'F':
+ foreground = true;
+ break;
+ case 'P':
+ pidfile = optarg;
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ pjdlog_debug_set(debuglevel);
+
+ pfh = pidfile_open(pidfile, 0600, &otherpid);
+ if (pfh == NULL) {
+ if (errno == EEXIST) {
+ pjdlog_exitx(EX_TEMPFAIL,
+ "Another hastd is already running, pid: %jd.",
+ (intmax_t)otherpid);
+ }
+ /* If we cannot create pidfile from other reasons, only warn. */
+ pjdlog_errno(LOG_WARNING, "Cannot open or create pidfile");
+ }
+
+ cfg = yy_config_parse(cfgpath);
+ assert(cfg != NULL);
+
+ signal(SIGHUP, sighandler);
+ signal(SIGCHLD, sighandler);
+
+ /* Listen on control address. */
+ if (proto_server(cfg->hc_controladdr, &cfg->hc_controlconn) < 0) {
+ KEEP_ERRNO((void)pidfile_remove(pfh));
+ pjdlog_exit(EX_OSERR, "Unable to listen on control address %s",
+ cfg->hc_controladdr);
+ }
+ /* Listen for remote connections. */
+ if (proto_server(cfg->hc_listenaddr, &cfg->hc_listenconn) < 0) {
+ KEEP_ERRNO((void)pidfile_remove(pfh));
+ pjdlog_exit(EX_OSERR, "Unable to listen on address %s",
+ cfg->hc_listenaddr);
+ }
+
+ if (!foreground) {
+ if (daemon(0, 0) < 0) {
+ KEEP_ERRNO((void)pidfile_remove(pfh));
+ pjdlog_exit(EX_OSERR, "Unable to daemonize");
+ }
+
+ /* Start logging to syslog. */
+ pjdlog_mode_set(PJDLOG_MODE_SYSLOG);
+
+ /* Write PID to a file. */
+ if (pidfile_write(pfh) < 0) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to write PID to a file");
+ }
+ }
+
+ main_loop();
+
+ exit(0);
+}
diff --git a/sbin/hastd/hastd.h b/sbin/hastd/hastd.h
new file mode 100644
index 0000000..199de8c
--- /dev/null
+++ b/sbin/hastd/hastd.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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 _HASTD_H_
+#define _HASTD_H_
+
+#include <sys/param.h>
+#include <libutil.h>
+
+#include <nv.h>
+
+#include "hast.h"
+
+extern bool sigexit_received;
+extern struct pidfh *pfh;
+
+void hastd_primary(struct hast_resource *res);
+void hastd_secondary(struct hast_resource *res, struct nv *nvin);
+
+#endif /* !_HASTD_H_ */
diff --git a/sbin/hastd/hooks.c b/sbin/hastd/hooks.c
new file mode 100644
index 0000000..1fdeb75
--- /dev/null
+++ b/sbin/hastd/hooks.c
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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/types.h>
+#include <sys/wait.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <libgen.h>
+#include <paths.h>
+
+#include <pjdlog.h>
+
+#include "hooks.h"
+
+static void
+descriptors(void)
+{
+ long maxfd;
+ int fd;
+
+ /*
+ * Close all descriptors.
+ */
+ maxfd = sysconf(_SC_OPEN_MAX);
+ if (maxfd < 0) {
+ pjdlog_errno(LOG_WARNING, "sysconf(_SC_OPEN_MAX) failed");
+ maxfd = 1024;
+ }
+ for (fd = 0; fd <= maxfd; fd++)
+ close(fd);
+ /*
+ * Redirect stdin, stdout and stderr to /dev/null.
+ */
+ fd = open(_PATH_DEVNULL, O_RDONLY);
+ if (fd < 0) {
+ pjdlog_errno(LOG_WARNING, "Unable to open %s for reading",
+ _PATH_DEVNULL);
+ } else if (fd != STDIN_FILENO) {
+ if (dup2(fd, STDIN_FILENO) < 0) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to duplicate descriptor for stdin");
+ }
+ close(fd);
+ }
+ fd = open(_PATH_DEVNULL, O_WRONLY);
+ if (fd < 0) {
+ pjdlog_errno(LOG_WARNING, "Unable to open %s for writing",
+ _PATH_DEVNULL);
+ } else {
+ if (fd != STDOUT_FILENO && dup2(fd, STDOUT_FILENO) < 0) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to duplicate descriptor for stdout");
+ }
+ if (fd != STDERR_FILENO && dup2(fd, STDERR_FILENO) < 0) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to duplicate descriptor for stderr");
+ }
+ if (fd != STDOUT_FILENO && fd != STDERR_FILENO)
+ close(fd);
+ }
+}
+
+int
+hook_exec(const char *path, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, path);
+ ret = hook_execv(path, ap);
+ va_end(ap);
+ return (ret);
+}
+
+int
+hook_execv(const char *path, va_list ap)
+{
+ char *args[64];
+ unsigned int ii;
+ pid_t pid, wpid;
+ int status;
+
+ if (path == NULL || path[0] == '\0')
+ return (0);
+
+ memset(args, 0, sizeof(args));
+ args[0] = basename(path);
+ for (ii = 1; ii < sizeof(args) / sizeof(args[0]); ii++) {
+ args[ii] = va_arg(ap, char *);
+ if (args[ii] == NULL)
+ break;
+ }
+ assert(ii < sizeof(args) / sizeof(args[0]));
+
+ pid = fork();
+ switch (pid) {
+ case -1: /* Error. */
+ pjdlog_errno(LOG_ERR, "Unable to fork %s", path);
+ return (-1);
+ case 0: /* Child. */
+ descriptors();
+ execv(path, args);
+ pjdlog_errno(LOG_ERR, "Unable to execute %s", path);
+ exit(EX_SOFTWARE);
+ default: /* Parent. */
+ break;
+ }
+
+ wpid = waitpid(pid, &status, 0);
+ assert(wpid == pid);
+
+ return (WEXITSTATUS(status));
+}
diff --git a/sbin/hastd/hooks.h b/sbin/hastd/hooks.h
new file mode 100644
index 0000000..799b781
--- /dev/null
+++ b/sbin/hastd/hooks.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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 _HOOKS_H_
+#define _HOOKS_H_
+
+#include <stdarg.h>
+
+int hook_exec(const char *path, ...);
+int hook_execv(const char *path, va_list ap);
+
+#endif /* !_HOOKS_H_ */
diff --git a/sbin/hastd/metadata.c b/sbin/hastd/metadata.c
new file mode 100644
index 0000000..9bca66b
--- /dev/null
+++ b/sbin/hastd/metadata.c
@@ -0,0 +1,222 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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 <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <ebuf.h>
+#include <nv.h>
+#include <pjdlog.h>
+#include <subr.h>
+
+#include "metadata.h"
+
+int
+metadata_read(struct hast_resource *res, bool openrw)
+{
+ unsigned char *buf;
+ struct ebuf *eb;
+ struct nv *nv;
+ ssize_t done;
+ const char *str;
+ int rerrno;
+ bool opened_here;
+
+ opened_here = false;
+ rerrno = 0;
+
+ /*
+ * Is this first metadata_read() call for this resource?
+ */
+ if (res->hr_localfd == -1) {
+ if (provinfo(res, openrw) < 0) {
+ rerrno = errno;
+ goto fail;
+ }
+ opened_here = true;
+ pjdlog_debug(1, "Obtained info about %s.", res->hr_localpath);
+ if (openrw) {
+ if (flock(res->hr_localfd, LOCK_EX | LOCK_NB) < 0) {
+ rerrno = errno;
+ if (errno == EOPNOTSUPP) {
+ pjdlog_warning("Unable to lock %s (operation not supported), but continuing.",
+ res->hr_localpath);
+ } else {
+ pjdlog_errno(LOG_ERR,
+ "Unable to lock %s",
+ res->hr_localpath);
+ goto fail;
+ }
+ }
+ pjdlog_debug(1, "Locked %s.", res->hr_localpath);
+ }
+ }
+
+ eb = ebuf_alloc(METADATA_SIZE);
+ if (eb == NULL) {
+ rerrno = errno;
+ pjdlog_errno(LOG_ERR,
+ "Unable to allocate memory to read metadata");
+ goto fail;
+ }
+ if (ebuf_add_tail(eb, NULL, METADATA_SIZE) < 0) {
+ rerrno = errno;
+ pjdlog_errno(LOG_ERR,
+ "Unable to allocate memory to read metadata");
+ goto fail;
+ }
+ buf = ebuf_data(eb, NULL);
+ assert(buf != NULL);
+ done = pread(res->hr_localfd, buf, METADATA_SIZE, 0);
+ if (done < 0 || done != METADATA_SIZE) {
+ rerrno = errno;
+ pjdlog_errno(LOG_ERR, "Unable to read metadata");
+ ebuf_free(eb);
+ goto fail;
+ }
+ nv = nv_ntoh(eb);
+ if (nv == NULL) {
+ rerrno = errno;
+ pjdlog_errno(LOG_ERR, "Metadata read from %s is invalid",
+ res->hr_localpath);
+ ebuf_free(eb);
+ goto fail;
+ }
+
+ str = nv_get_string(nv, "resource");
+ if (strcmp(str, res->hr_name) != 0) {
+ pjdlog_error("Provider %s is not part of resource %s.",
+ res->hr_localpath, res->hr_name);
+ nv_free(nv);
+ goto fail;
+ }
+
+ res->hr_datasize = nv_get_uint64(nv, "datasize");
+ res->hr_extentsize = (int)nv_get_uint32(nv, "extentsize");
+ res->hr_keepdirty = (int)nv_get_uint32(nv, "keepdirty");
+ res->hr_localoff = nv_get_uint64(nv, "offset");
+ res->hr_resuid = nv_get_uint64(nv, "resuid");
+ if (res->hr_role != HAST_ROLE_PRIMARY) {
+ /* Secondary or init role. */
+ res->hr_secondary_localcnt = nv_get_uint64(nv, "localcnt");
+ res->hr_secondary_remotecnt = nv_get_uint64(nv, "remotecnt");
+ }
+ if (res->hr_role != HAST_ROLE_SECONDARY) {
+ /* Primary or init role. */
+ res->hr_primary_localcnt = nv_get_uint64(nv, "localcnt");
+ res->hr_primary_remotecnt = nv_get_uint64(nv, "remotecnt");
+ }
+ str = nv_get_string(nv, "prevrole");
+ if (str != NULL) {
+ if (strcmp(str, "primary") == 0)
+ res->hr_previous_role = HAST_ROLE_PRIMARY;
+ else if (strcmp(str, "secondary") == 0)
+ res->hr_previous_role = HAST_ROLE_SECONDARY;
+ }
+
+ if (nv_error(nv) != 0) {
+ errno = rerrno = nv_error(nv);
+ pjdlog_errno(LOG_ERR, "Unable to read metadata from %s",
+ res->hr_localpath);
+ nv_free(nv);
+ goto fail;
+ }
+ return (0);
+fail:
+ if (opened_here) {
+ close(res->hr_localfd);
+ res->hr_localfd = -1;
+ }
+ errno = rerrno;
+ return (-1);
+}
+
+int
+metadata_write(struct hast_resource *res)
+{
+ struct ebuf *eb;
+ struct nv *nv;
+ unsigned char *buf, *ptr;
+ size_t size;
+ ssize_t done;
+
+ buf = calloc(1, METADATA_SIZE);
+ if (buf == NULL) {
+ pjdlog_error("Unable to allocate %zu bytes for metadata.",
+ (size_t)METADATA_SIZE);
+ return (-1);
+ }
+
+ nv = nv_alloc();
+ nv_add_string(nv, res->hr_name, "resource");
+ nv_add_uint64(nv, (uint64_t)res->hr_datasize, "datasize");
+ nv_add_uint32(nv, (uint32_t)res->hr_extentsize, "extentsize");
+ nv_add_uint32(nv, (uint32_t)res->hr_keepdirty, "keepdirty");
+ nv_add_uint64(nv, (uint64_t)res->hr_localoff, "offset");
+ nv_add_uint64(nv, res->hr_resuid, "resuid");
+ if (res->hr_role == HAST_ROLE_PRIMARY ||
+ res->hr_role == HAST_ROLE_INIT) {
+ nv_add_uint64(nv, res->hr_primary_localcnt, "localcnt");
+ nv_add_uint64(nv, res->hr_primary_remotecnt, "remotecnt");
+ } else /* if (res->hr_role == HAST_ROLE_SECONDARY) */ {
+ assert(res->hr_role == HAST_ROLE_SECONDARY);
+ nv_add_uint64(nv, res->hr_secondary_localcnt, "localcnt");
+ nv_add_uint64(nv, res->hr_secondary_remotecnt, "remotecnt");
+ }
+ nv_add_string(nv, role2str(res->hr_role), "prevrole");
+ if (nv_error(nv) != 0) {
+ pjdlog_error("Unable to create metadata.");
+ goto fail;
+ }
+ res->hr_previous_role = res->hr_role;
+ eb = nv_hton(nv);
+ assert(eb != NULL);
+ ptr = ebuf_data(eb, &size);
+ assert(ptr != NULL);
+ assert(size < METADATA_SIZE);
+ bcopy(ptr, buf, size);
+ done = pwrite(res->hr_localfd, buf, METADATA_SIZE, 0);
+ if (done < 0 || done != METADATA_SIZE) {
+ pjdlog_errno(LOG_ERR, "Unable to write metadata");
+ goto fail;
+ }
+
+ return (0);
+fail:
+ free(buf);
+ nv_free(nv);
+ return (-1);
+}
diff --git a/sys/ia64/include/sapicreg.h b/sbin/hastd/metadata.h
index 8f7dfbd..83d35f4 100644
--- a/sys/ia64/include/sapicreg.h
+++ b/sbin/hastd/metadata.h
@@ -1,7 +1,10 @@
/*-
- * Copyright (c) 2001 Doug Rabson
+ * Copyright (c) 2010 The FreeBSD Foundation
* All rights reserved.
*
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -11,10 +14,10 @@
* 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
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS 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)
@@ -26,23 +29,20 @@
* $FreeBSD$
*/
-#ifndef _MACHINE_SAPICREG_H_
-#define _MACHINE_SAPICREG_H_
+#ifndef _METADATA_H_
+#define _METADATA_H_
-/*
- * Offsets from the SAPIC base in memory. Most registers are accessed
- * by indexing using the SAPIC_IO_SELECT register.
- */
-#define SAPIC_IO_SELECT 0x00
-#define SAPIC_IO_WINDOW 0x10
-#define SAPIC_APIC_EOI 0x40
+#include <stdbool.h>
+
+#include <hast.h>
/*
- * Indexed registers.
+ * Maximum size of metadata.
+ * XXX: We should take sector size into account.
*/
-#define SAPIC_ID 0x00
-#define SAPIC_VERSION 0x01
-#define SAPIC_ARBITRATION_ID 0x02
-#define SAPIC_RTE_BASE 0x10
+#define METADATA_SIZE 4096
+
+int metadata_read(struct hast_resource *res, bool openrw);
+int metadata_write(struct hast_resource *res);
-#endif /* ! _MACHINE_SAPICREG_H_ */
+#endif /* !_METADATA_H_ */
diff --git a/sbin/hastd/nv.c b/sbin/hastd/nv.c
new file mode 100644
index 0000000..0b4e362
--- /dev/null
+++ b/sbin/hastd/nv.c
@@ -0,0 +1,882 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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/endian.h>
+
+#include <assert.h>
+#include <bitstring.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <ebuf.h>
+#include <nv.h>
+
+#define NV_MAGIC 0xaea1e
+struct nv {
+ int nv_magic;
+ int nv_error;
+ struct ebuf *nv_ebuf;
+};
+
+struct nvhdr {
+ uint8_t nvh_type;
+ uint8_t nvh_namesize;
+ uint32_t nvh_dsize;
+ char nvh_name[0];
+} __packed;
+#define NVH_DATA(nvh) ((unsigned char *)nvh + NVH_HSIZE(nvh))
+#define NVH_HSIZE(nvh) \
+ (sizeof(struct nvhdr) + roundup2((nvh)->nvh_namesize, 8))
+#define NVH_DSIZE(nvh) \
+ (((nvh)->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST ? \
+ (nvh)->nvh_dsize : \
+ le32toh((nvh)->nvh_dsize))
+#define NVH_SIZE(nvh) (NVH_HSIZE(nvh) + roundup2(NVH_DSIZE(nvh), 8))
+
+#define NV_CHECK(nv) do { \
+ assert((nv) != NULL); \
+ assert((nv)->nv_magic == NV_MAGIC); \
+} while (0)
+
+static void nv_add(struct nv *nv, const unsigned char *value, size_t vsize,
+ int type, const char *name);
+static void nv_addv(struct nv *nv, const unsigned char *value, size_t vsize,
+ int type, const char *namefmt, va_list nameap);
+static struct nvhdr *nv_find(struct nv *nv, int type, const char *namefmt,
+ va_list nameap);
+static void nv_swap(struct nvhdr *nvh, bool tohost);
+
+/*
+ * Allocate and initialize new nv structure.
+ * Return NULL in case of malloc(3) failure.
+ */
+struct nv *
+nv_alloc(void)
+{
+ struct nv *nv;
+
+ nv = malloc(sizeof(*nv));
+ if (nv == NULL)
+ return (NULL);
+ nv->nv_ebuf = ebuf_alloc(0);
+ if (nv->nv_ebuf == NULL) {
+ free(nv);
+ return (NULL);
+ }
+ nv->nv_error = 0;
+ nv->nv_magic = NV_MAGIC;
+ return (nv);
+}
+
+/*
+ * Free the given nv structure.
+ */
+void
+nv_free(struct nv *nv)
+{
+
+ if (nv == NULL)
+ return;
+
+ NV_CHECK(nv);
+
+ nv->nv_magic = 0;
+ ebuf_free(nv->nv_ebuf);
+ free(nv);
+}
+
+/*
+ * Return error for the given nv structure.
+ */
+int
+nv_error(const struct nv *nv)
+{
+
+ if (nv == NULL)
+ return (ENOMEM);
+
+ NV_CHECK(nv);
+
+ return (nv->nv_error);
+}
+
+/*
+ * Set error for the given nv structure and return previous error.
+ */
+int
+nv_set_error(struct nv *nv, int error)
+{
+ int preverr;
+
+ if (nv == NULL)
+ return (ENOMEM);
+
+ NV_CHECK(nv);
+
+ preverr = nv->nv_error;
+ nv->nv_error = error;
+ return (preverr);
+}
+
+/*
+ * Validate correctness of the entire nv structure and all its elements.
+ * If extrap is not NULL, store number of extra bytes at the end of the buffer.
+ */
+int
+nv_validate(struct nv *nv, size_t *extrap)
+{
+ struct nvhdr *nvh;
+ unsigned char *data, *ptr;
+ size_t dsize, size, vsize;
+ int error;
+
+ if (nv == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ NV_CHECK(nv);
+ assert(nv->nv_error == 0);
+
+ /* TODO: Check that names are unique? */
+
+ error = 0;
+ ptr = ebuf_data(nv->nv_ebuf, &size);
+ while (size > 0) {
+ /*
+ * Zeros at the end of the buffer are acceptable.
+ */
+ if (ptr[0] == '\0')
+ break;
+ /*
+ * Minimum size at this point is size of nvhdr structure, one
+ * character long name plus terminating '\0'.
+ */
+ if (size < sizeof(*nvh) + 2) {
+ error = EINVAL;
+ break;
+ }
+ nvh = (struct nvhdr *)ptr;
+ if (size < NVH_HSIZE(nvh)) {
+ error = EINVAL;
+ break;
+ }
+ if (nvh->nvh_name[nvh->nvh_namesize - 1] != '\0') {
+ error = EINVAL;
+ break;
+ }
+ if (strlen(nvh->nvh_name) !=
+ (size_t)(nvh->nvh_namesize - 1)) {
+ error = EINVAL;
+ break;
+ }
+ if ((nvh->nvh_type & NV_TYPE_MASK) < NV_TYPE_FIRST ||
+ (nvh->nvh_type & NV_TYPE_MASK) > NV_TYPE_LAST) {
+ error = EINVAL;
+ break;
+ }
+ dsize = NVH_DSIZE(nvh);
+ if (dsize == 0) {
+ error = EINVAL;
+ break;
+ }
+ if (size < NVH_SIZE(nvh)) {
+ error = EINVAL;
+ break;
+ }
+ vsize = 0;
+ switch (nvh->nvh_type & NV_TYPE_MASK) {
+ case NV_TYPE_INT8:
+ case NV_TYPE_UINT8:
+ if (vsize == 0)
+ vsize = 1;
+ /* FALLTHOUGH */
+ case NV_TYPE_INT16:
+ case NV_TYPE_UINT16:
+ if (vsize == 0)
+ vsize = 2;
+ /* FALLTHOUGH */
+ case NV_TYPE_INT32:
+ case NV_TYPE_UINT32:
+ if (vsize == 0)
+ vsize = 4;
+ /* FALLTHOUGH */
+ case NV_TYPE_INT64:
+ case NV_TYPE_UINT64:
+ if (vsize == 0)
+ vsize = 8;
+ if (dsize != vsize) {
+ error = EINVAL;
+ break;
+ }
+ break;
+ case NV_TYPE_INT8_ARRAY:
+ case NV_TYPE_UINT8_ARRAY:
+ break;
+ case NV_TYPE_INT16_ARRAY:
+ case NV_TYPE_UINT16_ARRAY:
+ if (vsize == 0)
+ vsize = 2;
+ /* FALLTHOUGH */
+ case NV_TYPE_INT32_ARRAY:
+ case NV_TYPE_UINT32_ARRAY:
+ if (vsize == 0)
+ vsize = 4;
+ /* FALLTHOUGH */
+ case NV_TYPE_INT64_ARRAY:
+ case NV_TYPE_UINT64_ARRAY:
+ if (vsize == 0)
+ vsize = 8;
+ if ((dsize % vsize) != 0) {
+ error = EINVAL;
+ break;
+ }
+ break;
+ case NV_TYPE_STRING:
+ data = NVH_DATA(nvh);
+ if (data[dsize - 1] != '\0') {
+ error = EINVAL;
+ break;
+ }
+ if (strlen((char *)data) != dsize - 1) {
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ assert(!"invalid condition");
+ }
+ if (error != 0)
+ break;
+ ptr += NVH_SIZE(nvh);
+ size -= NVH_SIZE(nvh);
+ }
+ if (error != 0) {
+ errno = error;
+ if (nv->nv_error == 0)
+ nv->nv_error = error;
+ return (-1);
+ }
+ if (extrap != NULL)
+ *extrap = size;
+ return (0);
+}
+
+/*
+ * Convert the given nv structure to network byte order and return ebuf
+ * structure.
+ */
+struct ebuf *
+nv_hton(struct nv *nv)
+{
+ struct nvhdr *nvh;
+ unsigned char *ptr;
+ size_t size;
+
+ NV_CHECK(nv);
+ assert(nv->nv_error == 0);
+
+ ptr = ebuf_data(nv->nv_ebuf, &size);
+ while (size > 0) {
+ /*
+ * Minimum size at this point is size of nvhdr structure,
+ * one character long name plus terminating '\0'.
+ */
+ assert(size >= sizeof(*nvh) + 2);
+ nvh = (struct nvhdr *)ptr;
+ assert(NVH_SIZE(nvh) <= size);
+ nv_swap(nvh, false);
+ ptr += NVH_SIZE(nvh);
+ size -= NVH_SIZE(nvh);
+ }
+
+ return (nv->nv_ebuf);
+}
+
+/*
+ * Create nv structure based on ebuf received from the network.
+ */
+struct nv *
+nv_ntoh(struct ebuf *eb)
+{
+ struct nv *nv;
+ size_t extra;
+ int rerrno;
+
+ assert(eb != NULL);
+
+ nv = malloc(sizeof(*nv));
+ if (nv == NULL)
+ return (NULL);
+ nv->nv_error = 0;
+ nv->nv_ebuf = eb;
+ nv->nv_magic = NV_MAGIC;
+
+ if (nv_validate(nv, &extra) < 0) {
+ rerrno = errno;
+ nv->nv_magic = 0;
+ free(nv);
+ errno = rerrno;
+ return (NULL);
+ }
+ /*
+ * Remove extra zeros at the end of the buffer.
+ */
+ ebuf_del_tail(eb, extra);
+
+ return (nv);
+}
+
+#define NV_DEFINE_ADD(type, TYPE) \
+void \
+nv_add_##type(struct nv *nv, type##_t value, const char *namefmt, ...) \
+{ \
+ va_list nameap; \
+ \
+ va_start(nameap, namefmt); \
+ nv_addv(nv, (unsigned char *)&value, sizeof(value), \
+ NV_TYPE_##TYPE, namefmt, nameap); \
+ va_end(nameap); \
+}
+
+NV_DEFINE_ADD(int8, INT8)
+NV_DEFINE_ADD(uint8, UINT8)
+NV_DEFINE_ADD(int16, INT16)
+NV_DEFINE_ADD(uint16, UINT16)
+NV_DEFINE_ADD(int32, INT32)
+NV_DEFINE_ADD(uint32, UINT32)
+NV_DEFINE_ADD(int64, INT64)
+NV_DEFINE_ADD(uint64, UINT64)
+
+#undef NV_DEFINE_ADD
+
+#define NV_DEFINE_ADD_ARRAY(type, TYPE) \
+void \
+nv_add_##type##_array(struct nv *nv, const type##_t *value, \
+ size_t nsize, const char *namefmt, ...) \
+{ \
+ va_list nameap; \
+ \
+ va_start(nameap, namefmt); \
+ nv_addv(nv, (const unsigned char *)value, \
+ sizeof(value[0]) * nsize, NV_TYPE_##TYPE##_ARRAY, namefmt, \
+ nameap); \
+ va_end(nameap); \
+}
+
+NV_DEFINE_ADD_ARRAY(int8, INT8)
+NV_DEFINE_ADD_ARRAY(uint8, UINT8)
+NV_DEFINE_ADD_ARRAY(int16, INT16)
+NV_DEFINE_ADD_ARRAY(uint16, UINT16)
+NV_DEFINE_ADD_ARRAY(int32, INT32)
+NV_DEFINE_ADD_ARRAY(uint32, UINT32)
+NV_DEFINE_ADD_ARRAY(int64, INT64)
+NV_DEFINE_ADD_ARRAY(uint64, UINT64)
+
+#undef NV_DEFINE_ADD_ARRAY
+
+void
+nv_add_string(struct nv *nv, const char *value, const char *namefmt, ...)
+{
+ va_list nameap;
+ size_t size;
+
+ size = strlen(value) + 1;
+
+ va_start(nameap, namefmt);
+ nv_addv(nv, (const unsigned char *)value, size, NV_TYPE_STRING,
+ namefmt, nameap);
+ va_end(nameap);
+}
+
+void
+nv_add_stringf(struct nv *nv, const char *name, const char *valuefmt, ...)
+{
+ va_list valueap;
+
+ va_start(valueap, valuefmt);
+ nv_add_stringv(nv, name, valuefmt, valueap);
+ va_end(valueap);
+}
+
+void
+nv_add_stringv(struct nv *nv, const char *name, const char *valuefmt,
+ va_list valueap)
+{
+ char *value;
+ ssize_t size;
+
+ size = vasprintf(&value, valuefmt, valueap);
+ if (size < 0) {
+ if (nv->nv_error == 0)
+ nv->nv_error = ENOMEM;
+ return;
+ }
+ size++;
+ nv_add(nv, (const unsigned char *)value, size, NV_TYPE_STRING, name);
+ free(value);
+}
+
+#define NV_DEFINE_GET(type, TYPE) \
+type##_t \
+nv_get_##type(struct nv *nv, const char *namefmt, ...) \
+{ \
+ struct nvhdr *nvh; \
+ va_list nameap; \
+ type##_t value; \
+ \
+ va_start(nameap, namefmt); \
+ nvh = nv_find(nv, NV_TYPE_##TYPE, namefmt, nameap); \
+ va_end(nameap); \
+ if (nvh == NULL) \
+ return (0); \
+ assert((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST); \
+ assert(sizeof(value) == nvh->nvh_dsize); \
+ bcopy(NVH_DATA(nvh), &value, sizeof(value)); \
+ \
+ return (value); \
+}
+
+NV_DEFINE_GET(int8, INT8)
+NV_DEFINE_GET(uint8, UINT8)
+NV_DEFINE_GET(int16, INT16)
+NV_DEFINE_GET(uint16, UINT16)
+NV_DEFINE_GET(int32, INT32)
+NV_DEFINE_GET(uint32, UINT32)
+NV_DEFINE_GET(int64, INT64)
+NV_DEFINE_GET(uint64, UINT64)
+
+#undef NV_DEFINE_GET
+
+#define NV_DEFINE_GET_ARRAY(type, TYPE) \
+const type##_t * \
+nv_get_##type##_array(struct nv *nv, size_t *sizep, \
+ const char *namefmt, ...) \
+{ \
+ struct nvhdr *nvh; \
+ va_list nameap; \
+ \
+ va_start(nameap, namefmt); \
+ nvh = nv_find(nv, NV_TYPE_##TYPE##_ARRAY, namefmt, nameap); \
+ va_end(nameap); \
+ if (nvh == NULL) \
+ return (NULL); \
+ assert((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST); \
+ assert((nvh->nvh_dsize % sizeof(type##_t)) == 0); \
+ if (sizep != NULL) \
+ *sizep = nvh->nvh_dsize / sizeof(type##_t); \
+ return ((type##_t *)(void *)NVH_DATA(nvh)); \
+}
+
+NV_DEFINE_GET_ARRAY(int8, INT8)
+NV_DEFINE_GET_ARRAY(uint8, UINT8)
+NV_DEFINE_GET_ARRAY(int16, INT16)
+NV_DEFINE_GET_ARRAY(uint16, UINT16)
+NV_DEFINE_GET_ARRAY(int32, INT32)
+NV_DEFINE_GET_ARRAY(uint32, UINT32)
+NV_DEFINE_GET_ARRAY(int64, INT64)
+NV_DEFINE_GET_ARRAY(uint64, UINT64)
+
+#undef NV_DEFINE_GET_ARRAY
+
+const char *
+nv_get_string(struct nv *nv, const char *namefmt, ...)
+{
+ struct nvhdr *nvh;
+ va_list nameap;
+ char *str;
+
+ va_start(nameap, namefmt);
+ nvh = nv_find(nv, NV_TYPE_STRING, namefmt, nameap);
+ va_end(nameap);
+ if (nvh == NULL)
+ return (NULL);
+ assert((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST);
+ assert(nvh->nvh_dsize >= 1);
+ str = NVH_DATA(nvh);
+ assert(str[nvh->nvh_dsize - 1] == '\0');
+ assert(strlen(str) == nvh->nvh_dsize - 1);
+ return (str);
+}
+
+/*
+ * Dump content of the nv structure.
+ */
+void
+nv_dump(struct nv *nv)
+{
+ struct nvhdr *nvh;
+ unsigned char *data, *ptr;
+ size_t dsize, size;
+ unsigned int ii;
+ bool swap;
+
+ if (nv_validate(nv, NULL) < 0) {
+ printf("error: %d\n", errno);
+ return;
+ }
+
+ NV_CHECK(nv);
+ assert(nv->nv_error == 0);
+
+ ptr = ebuf_data(nv->nv_ebuf, &size);
+ while (size > 0) {
+ assert(size >= sizeof(*nvh) + 2);
+ nvh = (struct nvhdr *)ptr;
+ assert(size >= NVH_SIZE(nvh));
+ swap = ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK);
+ dsize = NVH_DSIZE(nvh);
+ data = NVH_DATA(nvh);
+ printf(" %s", nvh->nvh_name);
+ switch (nvh->nvh_type & NV_TYPE_MASK) {
+ case NV_TYPE_INT8:
+ printf("(int8): %jd", (intmax_t)(*(int8_t *)data));
+ break;
+ case NV_TYPE_UINT8:
+ printf("(uint8): %ju", (uintmax_t)(*(uint8_t *)data));
+ break;
+ case NV_TYPE_INT16:
+ printf("(int16): %jd", swap ?
+ (intmax_t)le16toh(*(int16_t *)(void *)data) :
+ (intmax_t)*(int16_t *)(void *)data);
+ break;
+ case NV_TYPE_UINT16:
+ printf("(uint16): %ju", swap ?
+ (uintmax_t)le16toh(*(uint16_t *)(void *)data) :
+ (uintmax_t)*(uint16_t *)(void *)data);
+ break;
+ case NV_TYPE_INT32:
+ printf("(int32): %jd", swap ?
+ (intmax_t)le32toh(*(int32_t *)(void *)data) :
+ (intmax_t)*(int32_t *)(void *)data);
+ break;
+ case NV_TYPE_UINT32:
+ printf("(uint32): %ju", swap ?
+ (uintmax_t)le32toh(*(uint32_t *)(void *)data) :
+ (uintmax_t)*(uint32_t *)(void *)data);
+ break;
+ case NV_TYPE_INT64:
+ printf("(int64): %jd", swap ?
+ (intmax_t)le64toh(*(int64_t *)(void *)data) :
+ (intmax_t)*(int64_t *)(void *)data);
+ break;
+ case NV_TYPE_UINT64:
+ printf("(uint64): %ju", swap ?
+ (uintmax_t)le64toh(*(uint64_t *)(void *)data) :
+ (uintmax_t)*(uint64_t *)(void *)data);
+ break;
+ case NV_TYPE_INT8_ARRAY:
+ printf("(int8 array):");
+ for (ii = 0; ii < dsize; ii++)
+ printf(" %jd", (intmax_t)((int8_t *)data)[ii]);
+ break;
+ case NV_TYPE_UINT8_ARRAY:
+ printf("(uint8 array):");
+ for (ii = 0; ii < dsize; ii++)
+ printf(" %ju", (uintmax_t)((uint8_t *)data)[ii]);
+ break;
+ case NV_TYPE_INT16_ARRAY:
+ printf("(int16 array):");
+ for (ii = 0; ii < dsize / 2; ii++) {
+ printf(" %jd", swap ?
+ (intmax_t)le16toh(((int16_t *)(void *)data)[ii]) :
+ (intmax_t)((int16_t *)(void *)data)[ii]);
+ }
+ break;
+ case NV_TYPE_UINT16_ARRAY:
+ printf("(uint16 array):");
+ for (ii = 0; ii < dsize / 2; ii++) {
+ printf(" %ju", swap ?
+ (uintmax_t)le16toh(((uint16_t *)(void *)data)[ii]) :
+ (uintmax_t)((uint16_t *)(void *)data)[ii]);
+ }
+ break;
+ case NV_TYPE_INT32_ARRAY:
+ printf("(int32 array):");
+ for (ii = 0; ii < dsize / 4; ii++) {
+ printf(" %jd", swap ?
+ (intmax_t)le32toh(((int32_t *)(void *)data)[ii]) :
+ (intmax_t)((int32_t *)(void *)data)[ii]);
+ }
+ break;
+ case NV_TYPE_UINT32_ARRAY:
+ printf("(uint32 array):");
+ for (ii = 0; ii < dsize / 4; ii++) {
+ printf(" %ju", swap ?
+ (uintmax_t)le32toh(((uint32_t *)(void *)data)[ii]) :
+ (uintmax_t)((uint32_t *)(void *)data)[ii]);
+ }
+ break;
+ case NV_TYPE_INT64_ARRAY:
+ printf("(int64 array):");
+ for (ii = 0; ii < dsize / 8; ii++) {
+ printf(" %ju", swap ?
+ (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) :
+ (uintmax_t)((uint64_t *)(void *)data)[ii]);
+ }
+ break;
+ case NV_TYPE_UINT64_ARRAY:
+ printf("(uint64 array):");
+ for (ii = 0; ii < dsize / 8; ii++) {
+ printf(" %ju", swap ?
+ (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) :
+ (uintmax_t)((uint64_t *)(void *)data)[ii]);
+ }
+ break;
+ case NV_TYPE_STRING:
+ printf("(string): %s", (char *)data);
+ break;
+ default:
+ assert(!"invalid condition");
+ }
+ printf("\n");
+ ptr += NVH_SIZE(nvh);
+ size -= NVH_SIZE(nvh);
+ }
+}
+
+/*
+ * Local routines below.
+ */
+
+static void
+nv_add(struct nv *nv, const unsigned char *value, size_t vsize, int type,
+ const char *name)
+{
+ static unsigned char align[7];
+ struct nvhdr *nvh;
+ size_t namesize;
+
+ if (nv == NULL) {
+ errno = ENOMEM;
+ return;
+ }
+
+ NV_CHECK(nv);
+
+ namesize = strlen(name) + 1;
+
+ nvh = malloc(sizeof(*nvh) + roundup2(namesize, 8));
+ if (nvh == NULL) {
+ if (nv->nv_error == 0)
+ nv->nv_error = ENOMEM;
+ return;
+ }
+ nvh->nvh_type = NV_ORDER_HOST | type;
+ nvh->nvh_namesize = (uint8_t)namesize;
+ nvh->nvh_dsize = (uint32_t)vsize;
+ bcopy(name, nvh->nvh_name, namesize);
+
+ /* Add header first. */
+ if (ebuf_add_tail(nv->nv_ebuf, nvh, NVH_HSIZE(nvh)) < 0) {
+ assert(errno != 0);
+ if (nv->nv_error == 0)
+ nv->nv_error = errno;
+ return;
+ }
+ /* Add the actual data. */
+ if (ebuf_add_tail(nv->nv_ebuf, value, vsize) < 0) {
+ assert(errno != 0);
+ if (nv->nv_error == 0)
+ nv->nv_error = errno;
+ return;
+ }
+ /* Align the data (if needed). */
+ vsize = roundup2(vsize, 8) - vsize;
+ if (vsize == 0)
+ return;
+ assert(vsize > 0 && vsize <= sizeof(align));
+ if (ebuf_add_tail(nv->nv_ebuf, align, vsize) < 0) {
+ assert(errno != 0);
+ if (nv->nv_error == 0)
+ nv->nv_error = errno;
+ return;
+ }
+}
+
+static void
+nv_addv(struct nv *nv, const unsigned char *value, size_t vsize, int type,
+ const char *namefmt, va_list nameap)
+{
+ char name[255];
+ size_t namesize;
+
+ namesize = vsnprintf(name, sizeof(name), namefmt, nameap);
+ assert(namesize > 0 && namesize < sizeof(name));
+
+ nv_add(nv, value, vsize, type, name);
+}
+
+static struct nvhdr *
+nv_find(struct nv *nv, int type, const char *namefmt, va_list nameap)
+{
+ char name[255];
+ struct nvhdr *nvh;
+ unsigned char *ptr;
+ size_t size, namesize;
+
+ if (nv == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+
+ NV_CHECK(nv);
+
+ namesize = vsnprintf(name, sizeof(name), namefmt, nameap);
+ assert(namesize > 0 && namesize < sizeof(name));
+ namesize++;
+
+ ptr = ebuf_data(nv->nv_ebuf, &size);
+ while (size > 0) {
+ assert(size >= sizeof(*nvh) + 2);
+ nvh = (struct nvhdr *)ptr;
+ assert(size >= NVH_SIZE(nvh));
+ nv_swap(nvh, true);
+ if (strcmp(nvh->nvh_name, name) == 0) {
+ if ((nvh->nvh_type & NV_TYPE_MASK) != type) {
+ errno = EINVAL;
+ if (nv->nv_error == 0)
+ nv->nv_error = EINVAL;
+ return (NULL);
+ }
+ return (nvh);
+ }
+ ptr += NVH_SIZE(nvh);
+ size -= NVH_SIZE(nvh);
+ }
+ errno = ENOENT;
+ if (nv->nv_error == 0)
+ nv->nv_error = ENOENT;
+ return (NULL);
+}
+
+static void
+nv_swap(struct nvhdr *nvh, bool tohost)
+{
+ unsigned char *data, *end, *p;
+ size_t vsize;
+
+ data = NVH_DATA(nvh);
+ if (tohost) {
+ if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST)
+ return;
+ nvh->nvh_dsize = le32toh(nvh->nvh_dsize);
+ end = data + nvh->nvh_dsize;
+ nvh->nvh_type &= ~NV_ORDER_MASK;
+ nvh->nvh_type |= NV_ORDER_HOST;
+ } else {
+ if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK)
+ return;
+ end = data + nvh->nvh_dsize;
+ nvh->nvh_dsize = htole32(nvh->nvh_dsize);
+ nvh->nvh_type &= ~NV_ORDER_MASK;
+ nvh->nvh_type |= NV_ORDER_NETWORK;
+ }
+
+ vsize = 0;
+
+ switch (nvh->nvh_type & NV_TYPE_MASK) {
+ case NV_TYPE_INT8:
+ case NV_TYPE_UINT8:
+ case NV_TYPE_INT8_ARRAY:
+ case NV_TYPE_UINT8_ARRAY:
+ break;
+ case NV_TYPE_INT16:
+ case NV_TYPE_UINT16:
+ case NV_TYPE_INT16_ARRAY:
+ case NV_TYPE_UINT16_ARRAY:
+ if (vsize == 0)
+ vsize = 2;
+ /* FALLTHOUGH */
+ case NV_TYPE_INT32:
+ case NV_TYPE_UINT32:
+ case NV_TYPE_INT32_ARRAY:
+ case NV_TYPE_UINT32_ARRAY:
+ if (vsize == 0)
+ vsize = 4;
+ /* FALLTHOUGH */
+ case NV_TYPE_INT64:
+ case NV_TYPE_UINT64:
+ case NV_TYPE_INT64_ARRAY:
+ case NV_TYPE_UINT64_ARRAY:
+ if (vsize == 0)
+ vsize = 8;
+ for (p = data; p < end; p += vsize) {
+ if (tohost) {
+ switch (vsize) {
+ case 2:
+ *(uint16_t *)(void *)p =
+ le16toh(*(uint16_t *)(void *)p);
+ break;
+ case 4:
+ *(uint32_t *)(void *)p =
+ le32toh(*(uint32_t *)(void *)p);
+ break;
+ case 8:
+ *(uint64_t *)(void *)p =
+ le64toh(*(uint64_t *)(void *)p);
+ break;
+ default:
+ assert(!"invalid condition");
+ }
+ } else {
+ switch (vsize) {
+ case 2:
+ *(uint16_t *)(void *)p =
+ htole16(*(uint16_t *)(void *)p);
+ break;
+ case 4:
+ *(uint32_t *)(void *)p =
+ htole32(*(uint32_t *)(void *)p);
+ break;
+ case 8:
+ *(uint64_t *)(void *)p =
+ htole64(*(uint64_t *)(void *)p);
+ break;
+ default:
+ assert(!"invalid condition");
+ }
+ }
+ }
+ break;
+ case NV_TYPE_STRING:
+ break;
+ default:
+ assert(!"unrecognized type");
+ }
+}
diff --git a/sbin/hastd/nv.h b/sbin/hastd/nv.h
new file mode 100644
index 0000000..1677548
--- /dev/null
+++ b/sbin/hastd/nv.h
@@ -0,0 +1,158 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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 _NV_H_
+#define _NV_H_
+
+#include <sys/cdefs.h>
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <ebuf.h>
+
+#define NV_TYPE_INT8 1
+#define NV_TYPE_UINT8 2
+#define NV_TYPE_INT16 3
+#define NV_TYPE_UINT16 4
+#define NV_TYPE_INT32 5
+#define NV_TYPE_UINT32 6
+#define NV_TYPE_INT64 7
+#define NV_TYPE_UINT64 8
+#define NV_TYPE_INT8_ARRAY 9
+#define NV_TYPE_UINT8_ARRAY 10
+#define NV_TYPE_INT16_ARRAY 11
+#define NV_TYPE_UINT16_ARRAY 12
+#define NV_TYPE_INT32_ARRAY 13
+#define NV_TYPE_UINT32_ARRAY 14
+#define NV_TYPE_INT64_ARRAY 15
+#define NV_TYPE_UINT64_ARRAY 16
+#define NV_TYPE_STRING 17
+
+#define NV_TYPE_MASK 0x7f
+#define NV_TYPE_FIRST NV_TYPE_INT8
+#define NV_TYPE_LAST NV_TYPE_STRING
+
+#define NV_ORDER_NETWORK 0x00
+#define NV_ORDER_HOST 0x80
+
+#define NV_ORDER_MASK 0x80
+
+struct nv;
+
+struct nv *nv_alloc(void);
+void nv_free(struct nv *nv);
+int nv_error(const struct nv *nv);
+int nv_set_error(struct nv *nv, int error);
+int nv_validate(struct nv *nv, size_t *extrap);
+
+struct ebuf *nv_hton(struct nv *nv);
+struct nv *nv_ntoh(struct ebuf *eb);
+
+void nv_add_int8(struct nv *nv, int8_t value, const char *namefmt, ...)
+ __printflike(3, 4);
+void nv_add_uint8(struct nv *nv, uint8_t value, const char *namefmt, ...)
+ __printflike(3, 4);
+void nv_add_int16(struct nv *nv, int16_t value, const char *namefmt, ...)
+ __printflike(3, 4);
+void nv_add_uint16(struct nv *nv, uint16_t value, const char *namefmt, ...)
+ __printflike(3, 4);
+void nv_add_int32(struct nv *nv, int32_t value, const char *namefmt, ...)
+ __printflike(3, 4);
+void nv_add_uint32(struct nv *nv, uint32_t value, const char *namefmt, ...)
+ __printflike(3, 4);
+void nv_add_int64(struct nv *nv, int64_t value, const char *namefmt, ...)
+ __printflike(3, 4);
+void nv_add_uint64(struct nv *nv, uint64_t value, const char *namefmt, ...)
+ __printflike(3, 4);
+void nv_add_int8_array(struct nv *nv, const int8_t *value, size_t size,
+ const char *namefmt, ...) __printflike(4, 5);
+void nv_add_uint8_array(struct nv *nv, const uint8_t *value, size_t size,
+ const char *namefmt, ...) __printflike(4, 5);
+void nv_add_int16_array(struct nv *nv, const int16_t *value, size_t size,
+ const char *namefmt, ...) __printflike(4, 5);
+void nv_add_uint16_array(struct nv *nv, const uint16_t *value, size_t size,
+ const char *namefmt, ...) __printflike(4, 5);
+void nv_add_int32_array(struct nv *nv, const int32_t *value, size_t size,
+ const char *namefmt, ...) __printflike(4, 5);
+void nv_add_uint32_array(struct nv *nv, const uint32_t *value, size_t size,
+ const char *namefmt, ...) __printflike(4, 5);
+void nv_add_int64_array(struct nv *nv, const int64_t *value, size_t size,
+ const char *namefmt, ...) __printflike(4, 5);
+void nv_add_uint64_array(struct nv *nv, const uint64_t *value, size_t size,
+ const char *namefmt, ...) __printflike(4, 5);
+void nv_add_string(struct nv *nv, const char *value, const char *namefmt, ...)
+ __printflike(3, 4);
+void nv_add_stringf(struct nv *nv, const char *name, const char *valuefmt, ...)
+ __printflike(3, 4);
+void nv_add_stringv(struct nv *nv, const char *name, const char *valuefmt,
+ va_list valueap) __printflike(3, 0);
+
+int8_t nv_get_int8(struct nv *nv, const char *namefmt, ...)
+ __printflike(2, 3);
+uint8_t nv_get_uint8(struct nv *nv, const char *namefmt, ...)
+ __printflike(2, 3);
+int16_t nv_get_int16(struct nv *nv, const char *namefmt, ...)
+ __printflike(2, 3);
+uint16_t nv_get_uint16(struct nv *nv, const char *namefmt, ...)
+ __printflike(2, 3);
+int32_t nv_get_int32(struct nv *nv, const char *namefmt, ...)
+ __printflike(2, 3);
+uint32_t nv_get_uint32(struct nv *nv, const char *namefmt, ...)
+ __printflike(2, 3);
+int64_t nv_get_int64(struct nv *nv, const char *namefmt, ...)
+ __printflike(2, 3);
+uint64_t nv_get_uint64(struct nv *nv, const char *namefmt, ...)
+ __printflike(2, 3);
+const int8_t *nv_get_int8_array(struct nv *nv, size_t *sizep,
+ const char *namefmt, ...) __printflike(3, 4);
+const uint8_t *nv_get_uint8_array(struct nv *nv, size_t *sizep,
+ const char *namefmt, ...) __printflike(3, 4);
+const int16_t *nv_get_int16_array(struct nv *nv, size_t *sizep,
+ const char *namefmt, ...) __printflike(3, 4);
+const uint16_t *nv_get_uint16_array(struct nv *nv, size_t *sizep,
+ const char *namefmt, ...) __printflike(3, 4);
+const int32_t *nv_get_int32_array(struct nv *nv, size_t *sizep,
+ const char *namefmt, ...) __printflike(3, 4);
+const uint32_t *nv_get_uint32_array(struct nv *nv, size_t *sizep,
+ const char *namefmt, ...) __printflike(3, 4);
+const int64_t *nv_get_int64_array(struct nv *nv, size_t *sizep,
+ const char *namefmt, ...) __printflike(3, 4);
+const uint64_t *nv_get_uint64_array(struct nv *nv, size_t *sizep,
+ const char *namefmt, ...) __printflike(3, 4);
+const char *nv_get_string(struct nv *nv, const char *namefmt, ...)
+ __printflike(2, 3);
+
+void nv_dump(struct nv *nv);
+
+#endif /* !_NV_H_ */
diff --git a/sbin/hastd/parse.y b/sbin/hastd/parse.y
new file mode 100644
index 0000000..6755320
--- /dev/null
+++ b/sbin/hastd/parse.y
@@ -0,0 +1,507 @@
+%{
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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$
+ */
+
+#include <sys/param.h> /* MAXHOSTNAMELEN */
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "hast.h"
+
+extern int depth;
+extern int lineno;
+
+extern FILE *yyin;
+extern char *yytext;
+
+static struct hastd_config lconfig;
+static struct hast_resource *curres;
+static bool mynode;
+
+static char depth0_control[HAST_ADDRSIZE];
+static char depth0_listen[HAST_ADDRSIZE];
+static int depth0_replication;
+
+static char depth1_provname[PATH_MAX];
+static char depth1_localpath[PATH_MAX];
+
+static bool
+isitme(const char *name)
+{
+ char buf[MAXHOSTNAMELEN];
+ char *pos;
+ size_t bufsize;
+
+ /*
+ * First check if the give name matches our full hostname.
+ */
+ if (gethostname(buf, sizeof(buf)) < 0)
+ err(EX_OSERR, "gethostname() failed");
+ if (strcmp(buf, name) == 0)
+ return (true);
+
+ /*
+ * Now check if it matches first part of the host name.
+ */
+ pos = strchr(buf, '.');
+ if (pos != NULL && pos != buf && strncmp(buf, name, pos - buf) == 0)
+ return (true);
+
+ /*
+ * At the end check if name is equal to our host's UUID.
+ */
+ bufsize = sizeof(buf);
+ if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0)
+ err(EX_OSERR, "sysctlbyname(kern.hostuuid) failed");
+ if (strcasecmp(buf, name) == 0)
+ return (true);
+
+ /*
+ * Looks like this isn't about us.
+ */
+ return (false);
+}
+
+void
+yyerror(const char *str)
+{
+
+ fprintf(stderr, "error at line %d near '%s': %s\n",
+ lineno, yytext, str);
+}
+
+struct hastd_config *
+yy_config_parse(const char *config)
+{
+ int ret;
+
+ curres = NULL;
+ mynode = false;
+
+ depth0_replication = HAST_REPLICATION_MEMSYNC;
+ strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
+ strlcpy(depth0_listen, HASTD_LISTEN, sizeof(depth0_listen));
+
+ TAILQ_INIT(&lconfig.hc_resources);
+
+ yyin = fopen(config, "r");
+ if (yyin == NULL)
+ err(EX_OSFILE, "cannot open configuration file %s", config);
+ ret = yyparse();
+ fclose(yyin);
+ if (ret != 0) {
+ yy_config_free(&lconfig);
+ exit(EX_CONFIG);
+ }
+
+ /*
+ * Let's see if everything is set up.
+ */
+ if (lconfig.hc_controladdr[0] == '\0') {
+ strlcpy(lconfig.hc_controladdr, depth0_control,
+ sizeof(lconfig.hc_controladdr));
+ }
+ if (lconfig.hc_listenaddr[0] == '\0') {
+ strlcpy(lconfig.hc_listenaddr, depth0_listen,
+ sizeof(lconfig.hc_listenaddr));
+ }
+ TAILQ_FOREACH(curres, &lconfig.hc_resources, hr_next) {
+ assert(curres->hr_provname[0] != '\0');
+ assert(curres->hr_localpath[0] != '\0');
+ assert(curres->hr_remoteaddr[0] != '\0');
+
+ if (curres->hr_replication == -1) {
+ /*
+ * Replication is not set at resource-level.
+ * Use global or default setting.
+ */
+ curres->hr_replication = depth0_replication;
+ }
+ }
+
+ return (&lconfig);
+}
+
+void
+yy_config_free(struct hastd_config *config)
+{
+ struct hast_resource *res;
+
+ while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
+ TAILQ_REMOVE(&config->hc_resources, res, hr_next);
+ free(res);
+ }
+}
+%}
+
+%token CONTROL LISTEN PORT REPLICATION EXTENTSIZE RESOURCE NAME LOCAL REMOTE ON
+%token FULLSYNC MEMSYNC ASYNC
+%token NUM STR OB CB
+
+%type <num> replication_type
+
+%union
+{
+ int num;
+ char *str;
+}
+
+%token <num> NUM
+%token <str> STR
+
+%%
+
+statements:
+ |
+ statements statement
+ ;
+
+statement:
+ control_statement
+ |
+ listen_statement
+ |
+ replication_statement
+ |
+ node_statement
+ |
+ resource_statement
+ ;
+
+control_statement: CONTROL STR
+ {
+ switch (depth) {
+ case 0:
+ if (strlcpy(depth0_control, $2,
+ sizeof(depth0_control)) >=
+ sizeof(depth0_control)) {
+ errx(EX_CONFIG, "control argument too long");
+ }
+ break;
+ case 1:
+ if (mynode) {
+ if (strlcpy(lconfig.hc_controladdr, $2,
+ sizeof(lconfig.hc_controladdr)) >=
+ sizeof(lconfig.hc_controladdr)) {
+ errx(EX_CONFIG,
+ "control argument too long");
+ }
+ }
+ break;
+ default:
+ assert(!"control at wrong depth level");
+ }
+ }
+ ;
+
+listen_statement: LISTEN STR
+ {
+ switch (depth) {
+ case 0:
+ if (strlcpy(depth0_listen, $2,
+ sizeof(depth0_listen)) >=
+ sizeof(depth0_listen)) {
+ errx(EX_CONFIG, "listen argument too long");
+ }
+ break;
+ case 1:
+ if (mynode) {
+ if (strlcpy(lconfig.hc_listenaddr, $2,
+ sizeof(lconfig.hc_listenaddr)) >=
+ sizeof(lconfig.hc_listenaddr)) {
+ errx(EX_CONFIG,
+ "listen argument too long");
+ }
+ }
+ break;
+ default:
+ assert(!"listen at wrong depth level");
+ }
+ }
+ ;
+
+replication_statement: REPLICATION replication_type
+ {
+ switch (depth) {
+ case 0:
+ depth0_replication = $2;
+ break;
+ case 1:
+ if (curres != NULL)
+ curres->hr_replication = $2;
+ break;
+ default:
+ assert(!"replication at wrong depth level");
+ }
+ }
+ ;
+
+replication_type:
+ FULLSYNC { $$ = HAST_REPLICATION_FULLSYNC; }
+ |
+ MEMSYNC { $$ = HAST_REPLICATION_MEMSYNC; }
+ |
+ ASYNC { $$ = HAST_REPLICATION_ASYNC; }
+ ;
+
+node_statement: ON node_start OB node_entries CB
+ {
+ mynode = false;
+ }
+ ;
+
+node_start: STR
+ {
+ if (isitme($1))
+ mynode = true;
+ }
+ ;
+
+node_entries:
+ |
+ node_entries node_entry
+ ;
+
+node_entry:
+ control_statement
+ |
+ listen_statement
+ ;
+
+resource_statement: RESOURCE resource_start OB resource_entries CB
+ {
+ if (curres != NULL) {
+ /*
+ * Let's see there are some resource-level settings
+ * that we can use for node-level settings.
+ */
+ if (curres->hr_provname[0] == '\0' &&
+ depth1_provname[0] != '\0') {
+ /*
+ * Provider name is not set at node-level,
+ * but is set at resource-level, use it.
+ */
+ strlcpy(curres->hr_provname, depth1_provname,
+ sizeof(curres->hr_provname));
+ }
+ if (curres->hr_localpath[0] == '\0' &&
+ depth1_localpath[0] != '\0') {
+ /*
+ * Path to local provider is not set at
+ * node-level, but is set at resource-level,
+ * use it.
+ */
+ strlcpy(curres->hr_localpath, depth1_localpath,
+ sizeof(curres->hr_localpath));
+ }
+
+ /*
+ * If provider name is not given, use resource name
+ * as provider name.
+ */
+ if (curres->hr_provname[0] == '\0') {
+ strlcpy(curres->hr_provname, curres->hr_name,
+ sizeof(curres->hr_provname));
+ }
+
+ /*
+ * Remote address has to be configured at this point.
+ */
+ if (curres->hr_remoteaddr[0] == '\0') {
+ errx(EX_CONFIG,
+ "remote address not configured for resource %s",
+ curres->hr_name);
+ }
+ /*
+ * Path to local provider has to be configured at this
+ * point.
+ */
+ if (curres->hr_localpath[0] == '\0') {
+ errx(EX_CONFIG,
+ "path local component not configured for resource %s",
+ curres->hr_name);
+ }
+
+ /* Put it onto resource list. */
+ TAILQ_INSERT_TAIL(&lconfig.hc_resources, curres, hr_next);
+ curres = NULL;
+ }
+ }
+ ;
+
+resource_start: STR
+ {
+ /*
+ * Clear those, so we can tell if they were set at
+ * resource-level or not.
+ */
+ depth1_provname[0] = '\0';
+ depth1_localpath[0] = '\0';
+
+ curres = calloc(1, sizeof(*curres));
+ if (curres == NULL) {
+ errx(EX_TEMPFAIL,
+ "cannot allocate memory for resource");
+ }
+ if (strlcpy(curres->hr_name, $1,
+ sizeof(curres->hr_name)) >=
+ sizeof(curres->hr_name)) {
+ errx(EX_CONFIG,
+ "resource name (%s) too long", $1);
+ }
+ curres->hr_role = HAST_ROLE_INIT;
+ curres->hr_previous_role = HAST_ROLE_INIT;
+ curres->hr_replication = -1;
+ curres->hr_provname[0] = '\0';
+ curres->hr_localpath[0] = '\0';
+ curres->hr_localfd = -1;
+ curres->hr_remoteaddr[0] = '\0';
+ curres->hr_ggateunit = -1;
+ }
+ ;
+
+resource_entries:
+ |
+ resource_entries resource_entry
+ ;
+
+resource_entry:
+ replication_statement
+ |
+ name_statement
+ |
+ local_statement
+ |
+ resource_node_statement
+ ;
+
+name_statement: NAME STR
+ {
+ switch (depth) {
+ case 1:
+ if (strlcpy(depth1_provname, $2,
+ sizeof(depth1_provname)) >=
+ sizeof(depth1_provname)) {
+ errx(EX_CONFIG, "name argument too long");
+ }
+ break;
+ case 2:
+ if (mynode) {
+ assert(curres != NULL);
+ if (strlcpy(curres->hr_provname, $2,
+ sizeof(curres->hr_provname)) >=
+ sizeof(curres->hr_provname)) {
+ errx(EX_CONFIG,
+ "name argument too long");
+ }
+ }
+ break;
+ default:
+ assert(!"name at wrong depth level");
+ }
+ }
+ ;
+
+local_statement: LOCAL STR
+ {
+ switch (depth) {
+ case 1:
+ if (strlcpy(depth1_localpath, $2,
+ sizeof(depth1_localpath)) >=
+ sizeof(depth1_localpath)) {
+ errx(EX_CONFIG, "local argument too long");
+ }
+ break;
+ case 2:
+ if (mynode) {
+ assert(curres != NULL);
+ if (strlcpy(curres->hr_localpath, $2,
+ sizeof(curres->hr_localpath)) >=
+ sizeof(curres->hr_localpath)) {
+ errx(EX_CONFIG,
+ "local argument too long");
+ }
+ }
+ break;
+ default:
+ assert(!"local at wrong depth level");
+ }
+ }
+ ;
+
+resource_node_statement:ON resource_node_start OB resource_node_entries CB
+ {
+ mynode = false;
+ }
+ ;
+
+resource_node_start: STR
+ {
+ if (curres != NULL && isitme($1))
+ mynode = true;
+ }
+ ;
+
+resource_node_entries:
+ |
+ resource_node_entries resource_node_entry
+ ;
+
+resource_node_entry:
+ name_statement
+ |
+ local_statement
+ |
+ remote_statement
+ ;
+
+remote_statement: REMOTE STR
+ {
+ assert(depth == 2);
+ if (mynode) {
+ assert(curres != NULL);
+ if (strlcpy(curres->hr_remoteaddr, $2,
+ sizeof(curres->hr_remoteaddr)) >=
+ sizeof(curres->hr_remoteaddr)) {
+ errx(EX_CONFIG, "remote argument too long");
+ }
+ }
+ }
+ ;
diff --git a/sbin/hastd/pjdlog.c b/sbin/hastd/pjdlog.c
new file mode 100644
index 0000000..38c5539
--- /dev/null
+++ b/sbin/hastd/pjdlog.c
@@ -0,0 +1,367 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "pjdlog.h"
+
+static int pjdlog_mode = PJDLOG_MODE_STD;
+static int pjdlog_debug_level = 0;
+static char pjdlog_prefix[128];
+
+/*
+ * Configure where the logs should go.
+ * By default they are send to stdout/stderr, but after going into background
+ * (eg. by calling daemon(3)) application is responsible for changing mode to
+ * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
+ */
+void
+pjdlog_mode_set(int mode)
+{
+
+ assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
+
+ pjdlog_mode = mode;
+}
+
+/*
+ * Return current mode.
+ */
+int
+pjdlog_mode_get(void)
+{
+
+ return (pjdlog_mode);
+}
+
+/*
+ * Set debug level. All the logs above the level specified here will be
+ * ignored.
+ */
+void
+pjdlog_debug_set(int level)
+{
+
+ assert(level >= 0);
+
+ pjdlog_debug_level = level;
+}
+
+/*
+ * Return current debug level.
+ */
+int
+pjdlog_debug_get(void)
+{
+
+ return (pjdlog_debug_level);
+}
+
+/*
+ * Set prefix that will be used before each log.
+ * Setting prefix to NULL will remove it.
+ */
+void
+pjdlog_prefix_set(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ pjdlog_prefix_setv(fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Set prefix that will be used before each log.
+ * Setting prefix to NULL will remove it.
+ */
+void
+pjdlog_prefix_setv(const char *fmt, va_list ap)
+{
+
+ assert(fmt != NULL);
+
+ vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
+}
+
+/*
+ * Convert log level into string.
+ */
+static const char *
+pjdlog_level_string(int loglevel)
+{
+
+ switch (loglevel) {
+ case LOG_EMERG:
+ return ("EMERG");
+ case LOG_ALERT:
+ return ("ALERT");
+ case LOG_CRIT:
+ return ("CRIT");
+ case LOG_ERR:
+ return ("ERROR");
+ case LOG_WARNING:
+ return ("WARNING");
+ case LOG_NOTICE:
+ return ("NOTICE");
+ case LOG_INFO:
+ return ("INFO");
+ case LOG_DEBUG:
+ return ("DEBUG");
+ }
+ assert(!"Invalid log level.");
+ abort(); /* XXX: gcc */
+}
+
+/*
+ * Common log routine.
+ */
+void
+pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Common log routine, which can handle regular log level as well as debug
+ * level. We decide here where to send the logs (stdout/stderr or syslog).
+ */
+void
+pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
+ va_list ap)
+{
+
+ assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
+ loglevel == LOG_CRIT || loglevel == LOG_ERR ||
+ loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
+ loglevel == LOG_INFO || loglevel == LOG_DEBUG);
+ assert(loglevel != LOG_DEBUG || debuglevel > 0);
+ assert(error >= -1);
+
+ /* Ignore debug above configured level. */
+ if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
+ return;
+
+ switch (pjdlog_mode) {
+ case PJDLOG_MODE_STD:
+ {
+ FILE *out;
+
+ /*
+ * We send errors and warning to stderr and the rest to stdout.
+ */
+ switch (loglevel) {
+ case LOG_EMERG:
+ case LOG_ALERT:
+ case LOG_CRIT:
+ case LOG_ERR:
+ case LOG_WARNING:
+ out = stderr;
+ break;
+ case LOG_NOTICE:
+ case LOG_INFO:
+ case LOG_DEBUG:
+ out = stdout;
+ break;
+ default:
+ assert(!"Invalid loglevel.");
+ abort(); /* XXX: gcc */
+ }
+
+ fprintf(out, "[%s]", pjdlog_level_string(loglevel));
+ /* Attach debuglevel if this is debug log. */
+ if (loglevel == LOG_DEBUG)
+ fprintf(out, "[%d]", debuglevel);
+ fprintf(out, " ");
+ fprintf(out, "%s", pjdlog_prefix);
+ vfprintf(out, fmt, ap);
+ if (error != -1)
+ fprintf(out, ": %s.", strerror(error));
+ fprintf(out, "\n");
+ break;
+ }
+ case PJDLOG_MODE_SYSLOG:
+ {
+ char log[1024];
+ int len;
+
+ len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
+ if ((size_t)len < sizeof(log))
+ len = vsnprintf(log + len, sizeof(log) - len, fmt, ap);
+ if (error != -1 && (size_t)len < sizeof(log)) {
+ (void)snprintf(log + len, sizeof(log) - len, ": %s.",
+ strerror(error));
+ }
+ syslog(loglevel, "%s", log);
+ break;
+ }
+ default:
+ assert(!"Invalid mode.");
+ }
+}
+
+/*
+ * Regular logs.
+ */
+void
+pjdlogv(int loglevel, const char *fmt, va_list ap)
+{
+
+ /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
+ assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
+ loglevel == LOG_CRIT || loglevel == LOG_ERR ||
+ loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
+ loglevel == LOG_INFO);
+
+ pjdlogv_common(loglevel, 0, -1, fmt, ap);
+}
+
+/*
+ * Regular logs.
+ */
+void
+pjdlog(int loglevel, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ pjdlogv(loglevel, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Debug logs.
+ */
+void
+pjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
+{
+
+ pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
+}
+
+/*
+ * Debug logs.
+ */
+void
+pjdlog_debug(int debuglevel, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ pjdlogv_debug(debuglevel, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Error logs with errno logging.
+ */
+void
+pjdlogv_errno(int loglevel, const char *fmt, va_list ap)
+{
+
+ pjdlogv_common(loglevel, 0, errno, fmt, ap);
+}
+
+/*
+ * Error logs with errno logging.
+ */
+void
+pjdlog_errno(int loglevel, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ pjdlogv_errno(loglevel, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Log error, errno and exit.
+ */
+void
+pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
+{
+
+ pjdlogv_errno(LOG_ERR, fmt, ap);
+ exit(exitcode);
+}
+
+/*
+ * Log error, errno and exit.
+ */
+void
+pjdlog_exit(int exitcode, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ pjdlogv_exit(exitcode, fmt, ap);
+ /* NOTREACHED */
+ va_end(ap);
+}
+
+/*
+ * Log error and exit.
+ */
+void
+pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
+{
+
+ pjdlogv(LOG_ERR, fmt, ap);
+ exit(exitcode);
+}
+
+/*
+ * Log error and exit.
+ */
+void
+pjdlog_exitx(int exitcode, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ pjdlogv_exitx(exitcode, fmt, ap);
+ /* NOTREACHED */
+ va_end(ap);
+}
diff --git a/sbin/hastd/pjdlog.h b/sbin/hastd/pjdlog.h
new file mode 100644
index 0000000..2136b12
--- /dev/null
+++ b/sbin/hastd/pjdlog.h
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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 _PJDLOG_H_
+#define _PJDLOG_H_
+
+#include <sys/cdefs.h>
+
+#include <stdarg.h>
+#include <sysexits.h>
+#include <syslog.h>
+
+#define PJDLOG_MODE_STD 0
+#define PJDLOG_MODE_SYSLOG 1
+
+void pjdlog_mode_set(int mode);
+int pjdlog_mode_get(void);
+
+void pjdlog_debug_set(int level);
+int pjdlog_debug_get(void);
+
+void pjdlog_prefix_set(const char *fmt, ...) __printflike(1, 2);
+void pjdlog_prefix_setv(const char *fmt, va_list ap) __printflike(1, 0);
+
+void pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt,
+ ...) __printflike(4, 5);
+void pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
+ va_list ap) __printflike(4, 0);
+
+void pjdlog(int loglevel, const char *fmt, ...) __printflike(2, 3);
+void pjdlogv(int loglevel, const char *fmt, va_list ap) __printflike(2, 0);
+
+#define pjdlogv_emergency(fmt, ap) pjdlogv(LOG_EMERG, (fmt), (ap))
+#define pjdlog_emergency(...) pjdlog(LOG_EMERG, __VA_ARGS__)
+#define pjdlogv_alert(fmt, ap) pjdlogv(LOG_ALERT, (fmt), (ap))
+#define pjdlog_alert(...) pjdlog(LOG_ALERT, __VA_ARGS__)
+#define pjdlogv_critical(fmt, ap) pjdlogv(LOG_CRIT, (fmt), (ap))
+#define pjdlog_critical(...) pjdlog(LOG_CRIT, __VA_ARGS__)
+#define pjdlogv_error(fmt, ap) pjdlogv(LOG_ERR, (fmt), (ap))
+#define pjdlog_error(...) pjdlog(LOG_ERR, __VA_ARGS__)
+#define pjdlogv_warning(fmt, ap) pjdlogv(LOG_WARNING, (fmt), (ap))
+#define pjdlog_warning(...) pjdlog(LOG_WARNING, __VA_ARGS__)
+#define pjdlogv_notice(fmt, ap) pjdlogv(LOG_NOTICE, (fmt), (ap))
+#define pjdlog_notice(...) pjdlog(LOG_NOTICE, __VA_ARGS__)
+#define pjdlogv_info(fmt, ap) pjdlogv(LOG_INFO, (fmt), (ap))
+#define pjdlog_info(...) pjdlog(LOG_INFO, __VA_ARGS__)
+
+void pjdlog_debug(int debuglevel, const char *fmt, ...) __printflike(2, 3);
+void pjdlogv_debug(int debuglevel, const char *fmt, va_list ap) __printflike(2, 0);
+
+void pjdlog_errno(int loglevel, const char *fmt, ...) __printflike(2, 3);
+void pjdlogv_errno(int loglevel, const char *fmt, va_list ap) __printflike(2, 0);
+
+void pjdlog_exit(int exitcode, const char *fmt, ...) __printflike(2, 3) __dead2;
+void pjdlogv_exit(int exitcode, const char *fmt, va_list ap) __printflike(2, 0) __dead2;
+
+void pjdlog_exitx(int exitcode, const char *fmt, ...) __printflike(2, 3) __dead2;
+void pjdlogv_exitx(int exitcode, const char *fmt, va_list ap) __printflike(2, 0) __dead2;
+
+#endif /* !_PJDLOG_H_ */
diff --git a/sbin/hastd/primary.c b/sbin/hastd/primary.c
new file mode 100644
index 0000000..ed6e91c
--- /dev/null
+++ b/sbin/hastd/primary.c
@@ -0,0 +1,1769 @@
+/*-
+ * Copyright (c) 2009 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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/types.h>
+#include <sys/time.h>
+#include <sys/bio.h>
+#include <sys/disk.h>
+#include <sys/refcount.h>
+#include <sys/stat.h>
+
+#include <geom/gate/g_gate.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgeom.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <activemap.h>
+#include <nv.h>
+#include <rangelock.h>
+
+#include "control.h"
+#include "hast.h"
+#include "hast_proto.h"
+#include "hastd.h"
+#include "metadata.h"
+#include "proto.h"
+#include "pjdlog.h"
+#include "subr.h"
+#include "synch.h"
+
+struct hio {
+ /*
+ * Number of components we are still waiting for.
+ * When this field goes to 0, we can send the request back to the
+ * kernel. Each component has to decrease this counter by one
+ * even on failure.
+ */
+ unsigned int hio_countdown;
+ /*
+ * Each component has a place to store its own error.
+ * Once the request is handled by all components we can decide if the
+ * request overall is successful or not.
+ */
+ int *hio_errors;
+ /*
+ * Structure used to comunicate with GEOM Gate class.
+ */
+ struct g_gate_ctl_io hio_ggio;
+ TAILQ_ENTRY(hio) *hio_next;
+};
+#define hio_free_next hio_next[0]
+#define hio_done_next hio_next[0]
+
+/*
+ * Free list holds unused structures. When free list is empty, we have to wait
+ * until some in-progress requests are freed.
+ */
+static TAILQ_HEAD(, hio) hio_free_list;
+static pthread_mutex_t hio_free_list_lock;
+static pthread_cond_t hio_free_list_cond;
+/*
+ * There is one send list for every component. One requests is placed on all
+ * send lists - each component gets the same request, but each component is
+ * responsible for managing his own send list.
+ */
+static TAILQ_HEAD(, hio) *hio_send_list;
+static pthread_mutex_t *hio_send_list_lock;
+static pthread_cond_t *hio_send_list_cond;
+/*
+ * There is one recv list for every component, although local components don't
+ * use recv lists as local requests are done synchronously.
+ */
+static TAILQ_HEAD(, hio) *hio_recv_list;
+static pthread_mutex_t *hio_recv_list_lock;
+static pthread_cond_t *hio_recv_list_cond;
+/*
+ * Request is placed on done list by the slowest component (the one that
+ * decreased hio_countdown from 1 to 0).
+ */
+static TAILQ_HEAD(, hio) hio_done_list;
+static pthread_mutex_t hio_done_list_lock;
+static pthread_cond_t hio_done_list_cond;
+/*
+ * Structure below are for interaction with sync thread.
+ */
+static bool sync_inprogress;
+static pthread_mutex_t sync_lock;
+static pthread_cond_t sync_cond;
+/*
+ * The lock below allows to synchornize access to remote connections.
+ */
+static pthread_rwlock_t *hio_remote_lock;
+static pthread_mutex_t hio_guard_lock;
+static pthread_cond_t hio_guard_cond;
+
+/*
+ * Lock to synchronize metadata updates. Also synchronize access to
+ * hr_primary_localcnt and hr_primary_remotecnt fields.
+ */
+static pthread_mutex_t metadata_lock;
+
+/*
+ * Maximum number of outstanding I/O requests.
+ */
+#define HAST_HIO_MAX 256
+/*
+ * Number of components. At this point there are only two components: local
+ * and remote, but in the future it might be possible to use multiple local
+ * and remote components.
+ */
+#define HAST_NCOMPONENTS 2
+/*
+ * Number of seconds to sleep before next reconnect try.
+ */
+#define RECONNECT_SLEEP 5
+
+#define ISCONNECTED(res, no) \
+ ((res)->hr_remotein != NULL && (res)->hr_remoteout != NULL)
+
+#define QUEUE_INSERT1(hio, name, ncomp) do { \
+ bool _wakeup; \
+ \
+ mtx_lock(&hio_##name##_list_lock[(ncomp)]); \
+ _wakeup = TAILQ_EMPTY(&hio_##name##_list[(ncomp)]); \
+ TAILQ_INSERT_TAIL(&hio_##name##_list[(ncomp)], (hio), \
+ hio_next[(ncomp)]); \
+ mtx_unlock(&hio_##name##_list_lock[ncomp]); \
+ if (_wakeup) \
+ cv_signal(&hio_##name##_list_cond[(ncomp)]); \
+} while (0)
+#define QUEUE_INSERT2(hio, name) do { \
+ bool _wakeup; \
+ \
+ mtx_lock(&hio_##name##_list_lock); \
+ _wakeup = TAILQ_EMPTY(&hio_##name##_list); \
+ TAILQ_INSERT_TAIL(&hio_##name##_list, (hio), hio_##name##_next);\
+ mtx_unlock(&hio_##name##_list_lock); \
+ if (_wakeup) \
+ cv_signal(&hio_##name##_list_cond); \
+} while (0)
+#define QUEUE_TAKE1(hio, name, ncomp) do { \
+ mtx_lock(&hio_##name##_list_lock[(ncomp)]); \
+ while (((hio) = TAILQ_FIRST(&hio_##name##_list[(ncomp)])) == NULL) { \
+ cv_wait(&hio_##name##_list_cond[(ncomp)], \
+ &hio_##name##_list_lock[(ncomp)]); \
+ } \
+ TAILQ_REMOVE(&hio_##name##_list[(ncomp)], (hio), \
+ hio_next[(ncomp)]); \
+ mtx_unlock(&hio_##name##_list_lock[(ncomp)]); \
+} while (0)
+#define QUEUE_TAKE2(hio, name) do { \
+ mtx_lock(&hio_##name##_list_lock); \
+ while (((hio) = TAILQ_FIRST(&hio_##name##_list)) == NULL) { \
+ cv_wait(&hio_##name##_list_cond, \
+ &hio_##name##_list_lock); \
+ } \
+ TAILQ_REMOVE(&hio_##name##_list, (hio), hio_##name##_next); \
+ mtx_unlock(&hio_##name##_list_lock); \
+} while (0)
+
+#define SYNCREQ(hio) do { (hio)->hio_ggio.gctl_unit = -1; } while (0)
+#define ISSYNCREQ(hio) ((hio)->hio_ggio.gctl_unit == -1)
+#define SYNCREQDONE(hio) do { (hio)->hio_ggio.gctl_unit = -2; } while (0)
+#define ISSYNCREQDONE(hio) ((hio)->hio_ggio.gctl_unit == -2)
+
+static struct hast_resource *gres;
+
+static pthread_mutex_t range_lock;
+static struct rangelocks *range_regular;
+static bool range_regular_wait;
+static pthread_cond_t range_regular_cond;
+static struct rangelocks *range_sync;
+static bool range_sync_wait;
+static pthread_cond_t range_sync_cond;
+
+static void *ggate_recv_thread(void *arg);
+static void *local_send_thread(void *arg);
+static void *remote_send_thread(void *arg);
+static void *remote_recv_thread(void *arg);
+static void *ggate_send_thread(void *arg);
+static void *sync_thread(void *arg);
+static void *guard_thread(void *arg);
+
+static void sighandler(int sig);
+
+static void
+cleanup(struct hast_resource *res)
+{
+ int rerrno;
+
+ /* Remember errno. */
+ rerrno = errno;
+
+ /*
+ * Close descriptor to /dev/hast/<name>
+ * to work-around race in the kernel.
+ */
+ close(res->hr_localfd);
+
+ /* Destroy ggate provider if we created one. */
+ if (res->hr_ggateunit >= 0) {
+ struct g_gate_ctl_destroy ggiod;
+
+ ggiod.gctl_version = G_GATE_VERSION;
+ ggiod.gctl_unit = res->hr_ggateunit;
+ ggiod.gctl_force = 1;
+ if (ioctl(res->hr_ggatefd, G_GATE_CMD_DESTROY, &ggiod) < 0) {
+ pjdlog_warning("Unable to destroy hast/%s device",
+ res->hr_provname);
+ }
+ res->hr_ggateunit = -1;
+ }
+
+ /* Restore errno. */
+ errno = rerrno;
+}
+
+static void
+primary_exit(int exitcode, const char *fmt, ...)
+{
+ va_list ap;
+
+ assert(exitcode != EX_OK);
+ va_start(ap, fmt);
+ pjdlogv_errno(LOG_ERR, fmt, ap);
+ va_end(ap);
+ cleanup(gres);
+ exit(exitcode);
+}
+
+static void
+primary_exitx(int exitcode, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ pjdlogv(exitcode == EX_OK ? LOG_INFO : LOG_ERR, fmt, ap);
+ va_end(ap);
+ cleanup(gres);
+ exit(exitcode);
+}
+
+static int
+hast_activemap_flush(struct hast_resource *res)
+{
+ const unsigned char *buf;
+ size_t size;
+
+ buf = activemap_bitmap(res->hr_amp, &size);
+ assert(buf != NULL);
+ assert((size % res->hr_local_sectorsize) == 0);
+ if (pwrite(res->hr_localfd, buf, size, METADATA_SIZE) !=
+ (ssize_t)size) {
+ KEEP_ERRNO(pjdlog_errno(LOG_ERR,
+ "Unable to flush activemap to disk"));
+ return (-1);
+ }
+ return (0);
+}
+
+static void
+init_environment(struct hast_resource *res __unused)
+{
+ struct hio *hio;
+ unsigned int ii, ncomps;
+
+ /*
+ * In the future it might be per-resource value.
+ */
+ ncomps = HAST_NCOMPONENTS;
+
+ /*
+ * Allocate memory needed by lists.
+ */
+ hio_send_list = malloc(sizeof(hio_send_list[0]) * ncomps);
+ if (hio_send_list == NULL) {
+ primary_exitx(EX_TEMPFAIL,
+ "Unable to allocate %zu bytes of memory for send lists.",
+ sizeof(hio_send_list[0]) * ncomps);
+ }
+ hio_send_list_lock = malloc(sizeof(hio_send_list_lock[0]) * ncomps);
+ if (hio_send_list_lock == NULL) {
+ primary_exitx(EX_TEMPFAIL,
+ "Unable to allocate %zu bytes of memory for send list locks.",
+ sizeof(hio_send_list_lock[0]) * ncomps);
+ }
+ hio_send_list_cond = malloc(sizeof(hio_send_list_cond[0]) * ncomps);
+ if (hio_send_list_cond == NULL) {
+ primary_exitx(EX_TEMPFAIL,
+ "Unable to allocate %zu bytes of memory for send list condition variables.",
+ sizeof(hio_send_list_cond[0]) * ncomps);
+ }
+ hio_recv_list = malloc(sizeof(hio_recv_list[0]) * ncomps);
+ if (hio_recv_list == NULL) {
+ primary_exitx(EX_TEMPFAIL,
+ "Unable to allocate %zu bytes of memory for recv lists.",
+ sizeof(hio_recv_list[0]) * ncomps);
+ }
+ hio_recv_list_lock = malloc(sizeof(hio_recv_list_lock[0]) * ncomps);
+ if (hio_recv_list_lock == NULL) {
+ primary_exitx(EX_TEMPFAIL,
+ "Unable to allocate %zu bytes of memory for recv list locks.",
+ sizeof(hio_recv_list_lock[0]) * ncomps);
+ }
+ hio_recv_list_cond = malloc(sizeof(hio_recv_list_cond[0]) * ncomps);
+ if (hio_recv_list_cond == NULL) {
+ primary_exitx(EX_TEMPFAIL,
+ "Unable to allocate %zu bytes of memory for recv list condition variables.",
+ sizeof(hio_recv_list_cond[0]) * ncomps);
+ }
+ hio_remote_lock = malloc(sizeof(hio_remote_lock[0]) * ncomps);
+ if (hio_remote_lock == NULL) {
+ primary_exitx(EX_TEMPFAIL,
+ "Unable to allocate %zu bytes of memory for remote connections locks.",
+ sizeof(hio_remote_lock[0]) * ncomps);
+ }
+
+ /*
+ * Initialize lists, their locks and theirs condition variables.
+ */
+ TAILQ_INIT(&hio_free_list);
+ mtx_init(&hio_free_list_lock);
+ cv_init(&hio_free_list_cond);
+ for (ii = 0; ii < HAST_NCOMPONENTS; ii++) {
+ TAILQ_INIT(&hio_send_list[ii]);
+ mtx_init(&hio_send_list_lock[ii]);
+ cv_init(&hio_send_list_cond[ii]);
+ TAILQ_INIT(&hio_recv_list[ii]);
+ mtx_init(&hio_recv_list_lock[ii]);
+ cv_init(&hio_recv_list_cond[ii]);
+ rw_init(&hio_remote_lock[ii]);
+ }
+ TAILQ_INIT(&hio_done_list);
+ mtx_init(&hio_done_list_lock);
+ cv_init(&hio_done_list_cond);
+ mtx_init(&hio_guard_lock);
+ cv_init(&hio_guard_cond);
+ mtx_init(&metadata_lock);
+
+ /*
+ * Allocate requests pool and initialize requests.
+ */
+ for (ii = 0; ii < HAST_HIO_MAX; ii++) {
+ hio = malloc(sizeof(*hio));
+ if (hio == NULL) {
+ primary_exitx(EX_TEMPFAIL,
+ "Unable to allocate %zu bytes of memory for hio request.",
+ sizeof(*hio));
+ }
+ hio->hio_countdown = 0;
+ hio->hio_errors = malloc(sizeof(hio->hio_errors[0]) * ncomps);
+ if (hio->hio_errors == NULL) {
+ primary_exitx(EX_TEMPFAIL,
+ "Unable allocate %zu bytes of memory for hio errors.",
+ sizeof(hio->hio_errors[0]) * ncomps);
+ }
+ hio->hio_next = malloc(sizeof(hio->hio_next[0]) * ncomps);
+ if (hio->hio_next == NULL) {
+ primary_exitx(EX_TEMPFAIL,
+ "Unable allocate %zu bytes of memory for hio_next field.",
+ sizeof(hio->hio_next[0]) * ncomps);
+ }
+ hio->hio_ggio.gctl_version = G_GATE_VERSION;
+ hio->hio_ggio.gctl_data = malloc(MAXPHYS);
+ if (hio->hio_ggio.gctl_data == NULL) {
+ primary_exitx(EX_TEMPFAIL,
+ "Unable to allocate %zu bytes of memory for gctl_data.",
+ MAXPHYS);
+ }
+ hio->hio_ggio.gctl_length = MAXPHYS;
+ hio->hio_ggio.gctl_error = 0;
+ TAILQ_INSERT_HEAD(&hio_free_list, hio, hio_free_next);
+ }
+
+ /*
+ * Turn on signals handling.
+ */
+ signal(SIGINT, sighandler);
+ signal(SIGTERM, sighandler);
+}
+
+static void
+init_local(struct hast_resource *res)
+{
+ unsigned char *buf;
+ size_t mapsize;
+
+ if (metadata_read(res, true) < 0)
+ exit(EX_NOINPUT);
+ mtx_init(&res->hr_amp_lock);
+ if (activemap_init(&res->hr_amp, res->hr_datasize, res->hr_extentsize,
+ res->hr_local_sectorsize, res->hr_keepdirty) < 0) {
+ primary_exit(EX_TEMPFAIL, "Unable to create activemap");
+ }
+ mtx_init(&range_lock);
+ cv_init(&range_regular_cond);
+ if (rangelock_init(&range_regular) < 0)
+ primary_exit(EX_TEMPFAIL, "Unable to create regular range lock");
+ cv_init(&range_sync_cond);
+ if (rangelock_init(&range_sync) < 0)
+ primary_exit(EX_TEMPFAIL, "Unable to create sync range lock");
+ mapsize = activemap_ondisk_size(res->hr_amp);
+ buf = calloc(1, mapsize);
+ if (buf == NULL) {
+ primary_exitx(EX_TEMPFAIL,
+ "Unable to allocate buffer for activemap.");
+ }
+ if (pread(res->hr_localfd, buf, mapsize, METADATA_SIZE) !=
+ (ssize_t)mapsize) {
+ primary_exit(EX_NOINPUT, "Unable to read activemap");
+ }
+ activemap_copyin(res->hr_amp, buf, mapsize);
+ if (res->hr_resuid != 0)
+ return;
+ /*
+ * We're using provider for the first time, so we have to generate
+ * resource unique identifier and initialize local and remote counts.
+ */
+ arc4random_buf(&res->hr_resuid, sizeof(res->hr_resuid));
+ res->hr_primary_localcnt = 1;
+ res->hr_primary_remotecnt = 0;
+ if (metadata_write(res) < 0)
+ exit(EX_NOINPUT);
+}
+
+static void
+init_remote(struct hast_resource *res)
+{
+ struct nv *nvout, *nvin;
+ const unsigned char *token;
+ unsigned char *map;
+ const char *errmsg;
+ int32_t extentsize;
+ int64_t datasize;
+ uint32_t mapsize;
+ size_t size;
+
+ /* Prepare outgoing connection with remote node. */
+ if (proto_client(res->hr_remoteaddr, &res->hr_remoteout) < 0) {
+ primary_exit(EX_OSERR, "Unable to create connection to %s",
+ res->hr_remoteaddr);
+ }
+ /* Try to connect, but accept failure. */
+ if (proto_connect(res->hr_remoteout) < 0) {
+ pjdlog_errno(LOG_WARNING, "Unable to connect to %s",
+ res->hr_remoteaddr);
+ goto close;
+ }
+ /*
+ * First handshake step.
+ * Setup outgoing connection with remote node.
+ */
+ nvout = nv_alloc();
+ nv_add_string(nvout, res->hr_name, "resource");
+ if (nv_error(nvout) != 0) {
+ pjdlog_common(LOG_WARNING, 0, nv_error(nvout),
+ "Unable to allocate header for connection with %s",
+ res->hr_remoteaddr);
+ nv_free(nvout);
+ goto close;
+ }
+ if (hast_proto_send(res, res->hr_remoteout, nvout, NULL, 0) < 0) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to send handshake header to %s",
+ res->hr_remoteaddr);
+ nv_free(nvout);
+ goto close;
+ }
+ nv_free(nvout);
+ if (hast_proto_recv_hdr(res->hr_remoteout, &nvin) < 0) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to receive handshake header from %s",
+ res->hr_remoteaddr);
+ goto close;
+ }
+ errmsg = nv_get_string(nvin, "errmsg");
+ if (errmsg != NULL) {
+ pjdlog_warning("%s", errmsg);
+ nv_free(nvin);
+ goto close;
+ }
+ token = nv_get_uint8_array(nvin, &size, "token");
+ if (token == NULL) {
+ pjdlog_warning("Handshake header from %s has no 'token' field.",
+ res->hr_remoteaddr);
+ nv_free(nvin);
+ goto close;
+ }
+ if (size != sizeof(res->hr_token)) {
+ pjdlog_warning("Handshake header from %s contains 'token' of wrong size (got %zu, expected %zu).",
+ res->hr_remoteaddr, size, sizeof(res->hr_token));
+ nv_free(nvin);
+ goto close;
+ }
+ bcopy(token, res->hr_token, sizeof(res->hr_token));
+ nv_free(nvin);
+
+ /*
+ * Second handshake step.
+ * Setup incoming connection with remote node.
+ */
+ if (proto_client(res->hr_remoteaddr, &res->hr_remotein) < 0) {
+ pjdlog_errno(LOG_WARNING, "Unable to create connection to %s",
+ res->hr_remoteaddr);
+ }
+ /* Try to connect, but accept failure. */
+ if (proto_connect(res->hr_remotein) < 0) {
+ pjdlog_errno(LOG_WARNING, "Unable to connect to %s",
+ res->hr_remoteaddr);
+ goto close;
+ }
+ nvout = nv_alloc();
+ nv_add_string(nvout, res->hr_name, "resource");
+ nv_add_uint8_array(nvout, res->hr_token, sizeof(res->hr_token),
+ "token");
+ nv_add_uint64(nvout, res->hr_resuid, "resuid");
+ nv_add_uint64(nvout, res->hr_primary_localcnt, "localcnt");
+ nv_add_uint64(nvout, res->hr_primary_remotecnt, "remotecnt");
+ if (nv_error(nvout) != 0) {
+ pjdlog_common(LOG_WARNING, 0, nv_error(nvout),
+ "Unable to allocate header for connection with %s",
+ res->hr_remoteaddr);
+ nv_free(nvout);
+ goto close;
+ }
+ if (hast_proto_send(res, res->hr_remotein, nvout, NULL, 0) < 0) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to send handshake header to %s",
+ res->hr_remoteaddr);
+ nv_free(nvout);
+ goto close;
+ }
+ nv_free(nvout);
+ if (hast_proto_recv_hdr(res->hr_remoteout, &nvin) < 0) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to receive handshake header from %s",
+ res->hr_remoteaddr);
+ goto close;
+ }
+ errmsg = nv_get_string(nvin, "errmsg");
+ if (errmsg != NULL) {
+ pjdlog_warning("%s", errmsg);
+ nv_free(nvin);
+ goto close;
+ }
+ datasize = nv_get_int64(nvin, "datasize");
+ if (datasize != res->hr_datasize) {
+ pjdlog_warning("Data size differs between nodes (local=%jd, remote=%jd).",
+ (intmax_t)res->hr_datasize, (intmax_t)datasize);
+ nv_free(nvin);
+ goto close;
+ }
+ extentsize = nv_get_int32(nvin, "extentsize");
+ if (extentsize != res->hr_extentsize) {
+ pjdlog_warning("Extent size differs between nodes (local=%zd, remote=%zd).",
+ (ssize_t)res->hr_extentsize, (ssize_t)extentsize);
+ nv_free(nvin);
+ goto close;
+ }
+ res->hr_secondary_localcnt = nv_get_uint64(nvin, "localcnt");
+ res->hr_secondary_remotecnt = nv_get_uint64(nvin, "remotecnt");
+ res->hr_syncsrc = nv_get_uint8(nvin, "syncsrc");
+ map = NULL;
+ mapsize = nv_get_uint32(nvin, "mapsize");
+ if (mapsize > 0) {
+ map = malloc(mapsize);
+ if (map == NULL) {
+ pjdlog_error("Unable to allocate memory for remote activemap (mapsize=%ju).",
+ (uintmax_t)mapsize);
+ nv_free(nvin);
+ goto close;
+ }
+ /*
+ * Remote node have some dirty extents on its own, lets
+ * download its activemap.
+ */
+ if (hast_proto_recv_data(res, res->hr_remoteout, nvin, map,
+ mapsize) < 0) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to receive remote activemap");
+ nv_free(nvin);
+ free(map);
+ goto close;
+ }
+ /*
+ * Merge local and remote bitmaps.
+ */
+ activemap_merge(res->hr_amp, map, mapsize);
+ free(map);
+ /*
+ * Now that we merged bitmaps from both nodes, flush it to the
+ * disk before we start to synchronize.
+ */
+ (void)hast_activemap_flush(res);
+ }
+ pjdlog_info("Connected to %s.", res->hr_remoteaddr);
+ mtx_lock(&sync_lock);
+ sync_inprogress = true;
+ mtx_unlock(&sync_lock);
+ cv_signal(&sync_cond);
+ return;
+close:
+ proto_close(res->hr_remoteout);
+ res->hr_remoteout = NULL;
+ if (res->hr_remotein != NULL) {
+ proto_close(res->hr_remotein);
+ res->hr_remotein = NULL;
+ }
+}
+
+static void
+init_ggate(struct hast_resource *res)
+{
+ struct g_gate_ctl_create ggiocreate;
+ struct g_gate_ctl_cancel ggiocancel;
+
+ /*
+ * We communicate with ggate via /dev/ggctl. Open it.
+ */
+ res->hr_ggatefd = open("/dev/" G_GATE_CTL_NAME, O_RDWR);
+ if (res->hr_ggatefd < 0)
+ primary_exit(EX_OSFILE, "Unable to open /dev/" G_GATE_CTL_NAME);
+ /*
+ * Create provider before trying to connect, as connection failure
+ * is not critical, but may take some time.
+ */
+ ggiocreate.gctl_version = G_GATE_VERSION;
+ ggiocreate.gctl_mediasize = res->hr_datasize;
+ ggiocreate.gctl_sectorsize = res->hr_local_sectorsize;
+ ggiocreate.gctl_flags = 0;
+ ggiocreate.gctl_maxcount = 128;
+ ggiocreate.gctl_timeout = 0;
+ ggiocreate.gctl_unit = G_GATE_NAME_GIVEN;
+ snprintf(ggiocreate.gctl_name, sizeof(ggiocreate.gctl_name), "hast/%s",
+ res->hr_provname);
+ bzero(ggiocreate.gctl_info, sizeof(ggiocreate.gctl_info));
+ if (ioctl(res->hr_ggatefd, G_GATE_CMD_CREATE, &ggiocreate) == 0) {
+ pjdlog_info("Device hast/%s created.", res->hr_provname);
+ res->hr_ggateunit = ggiocreate.gctl_unit;
+ return;
+ }
+ if (errno != EEXIST) {
+ primary_exit(EX_OSERR, "Unable to create hast/%s device",
+ res->hr_provname);
+ }
+ pjdlog_debug(1,
+ "Device hast/%s already exists, we will try to take it over.",
+ res->hr_provname);
+ /*
+ * If we received EEXIST, we assume that the process who created the
+ * provider died and didn't clean up. In that case we will start from
+ * where he left of.
+ */
+ ggiocancel.gctl_version = G_GATE_VERSION;
+ ggiocancel.gctl_unit = G_GATE_NAME_GIVEN;
+ snprintf(ggiocancel.gctl_name, sizeof(ggiocancel.gctl_name), "hast/%s",
+ res->hr_provname);
+ if (ioctl(res->hr_ggatefd, G_GATE_CMD_CANCEL, &ggiocancel) == 0) {
+ pjdlog_info("Device hast/%s recovered.", res->hr_provname);
+ res->hr_ggateunit = ggiocancel.gctl_unit;
+ return;
+ }
+ primary_exit(EX_OSERR, "Unable to take over hast/%s device",
+ res->hr_provname);
+}
+
+void
+hastd_primary(struct hast_resource *res)
+{
+ pthread_t td;
+ pid_t pid;
+ int error;
+
+ gres = res;
+
+ /*
+ * Create communication channel between parent and child.
+ */
+ if (proto_client("socketpair://", &res->hr_ctrl) < 0) {
+ KEEP_ERRNO((void)pidfile_remove(pfh));
+ primary_exit(EX_OSERR,
+ "Unable to create control sockets between parent and child");
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ KEEP_ERRNO((void)pidfile_remove(pfh));
+ primary_exit(EX_OSERR, "Unable to fork");
+ }
+
+ if (pid > 0) {
+ /* This is parent. */
+ res->hr_workerpid = pid;
+ return;
+ }
+ (void)pidfile_close(pfh);
+
+ setproctitle("%s (primary)", res->hr_name);
+
+ init_local(res);
+ init_remote(res);
+ init_ggate(res);
+ init_environment(res);
+ error = pthread_create(&td, NULL, ggate_recv_thread, res);
+ assert(error == 0);
+ error = pthread_create(&td, NULL, local_send_thread, res);
+ assert(error == 0);
+ error = pthread_create(&td, NULL, remote_send_thread, res);
+ assert(error == 0);
+ error = pthread_create(&td, NULL, remote_recv_thread, res);
+ assert(error == 0);
+ error = pthread_create(&td, NULL, ggate_send_thread, res);
+ assert(error == 0);
+ error = pthread_create(&td, NULL, sync_thread, res);
+ assert(error == 0);
+ error = pthread_create(&td, NULL, ctrl_thread, res);
+ assert(error == 0);
+ (void)guard_thread(res);
+}
+
+static void
+reqlog(int loglevel, int debuglevel, struct g_gate_ctl_io *ggio, const char *fmt, ...)
+{
+ char msg[1024];
+ va_list ap;
+ int len;
+
+ va_start(ap, fmt);
+ len = vsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+ if ((size_t)len < sizeof(msg)) {
+ switch (ggio->gctl_cmd) {
+ case BIO_READ:
+ (void)snprintf(msg + len, sizeof(msg) - len,
+ "READ(%ju, %ju).", (uintmax_t)ggio->gctl_offset,
+ (uintmax_t)ggio->gctl_length);
+ break;
+ case BIO_DELETE:
+ (void)snprintf(msg + len, sizeof(msg) - len,
+ "DELETE(%ju, %ju).", (uintmax_t)ggio->gctl_offset,
+ (uintmax_t)ggio->gctl_length);
+ break;
+ case BIO_FLUSH:
+ (void)snprintf(msg + len, sizeof(msg) - len, "FLUSH.");
+ break;
+ case BIO_WRITE:
+ (void)snprintf(msg + len, sizeof(msg) - len,
+ "WRITE(%ju, %ju).", (uintmax_t)ggio->gctl_offset,
+ (uintmax_t)ggio->gctl_length);
+ break;
+ default:
+ (void)snprintf(msg + len, sizeof(msg) - len,
+ "UNKNOWN(%u).", (unsigned int)ggio->gctl_cmd);
+ break;
+ }
+ }
+ pjdlog_common(loglevel, debuglevel, -1, "%s", msg);
+}
+
+static void
+remote_close(struct hast_resource *res, int ncomp)
+{
+
+ rw_wlock(&hio_remote_lock[ncomp]);
+ /*
+ * A race is possible between dropping rlock and acquiring wlock -
+ * another thread can close connection in-between.
+ */
+ if (!ISCONNECTED(res, ncomp)) {
+ assert(res->hr_remotein == NULL);
+ assert(res->hr_remoteout == NULL);
+ rw_unlock(&hio_remote_lock[ncomp]);
+ return;
+ }
+
+ assert(res->hr_remotein != NULL);
+ assert(res->hr_remoteout != NULL);
+
+ pjdlog_debug(2, "Closing old incoming connection to %s.",
+ res->hr_remoteaddr);
+ proto_close(res->hr_remotein);
+ res->hr_remotein = NULL;
+ pjdlog_debug(2, "Closing old outgoing connection to %s.",
+ res->hr_remoteaddr);
+ proto_close(res->hr_remoteout);
+ res->hr_remoteout = NULL;
+
+ rw_unlock(&hio_remote_lock[ncomp]);
+
+ /*
+ * Stop synchronization if in-progress.
+ */
+ mtx_lock(&sync_lock);
+ if (sync_inprogress)
+ sync_inprogress = false;
+ mtx_unlock(&sync_lock);
+
+ /*
+ * Wake up guard thread, so it can immediately start reconnect.
+ */
+ mtx_lock(&hio_guard_lock);
+ cv_signal(&hio_guard_cond);
+ mtx_unlock(&hio_guard_lock);
+}
+
+/*
+ * Thread receives ggate I/O requests from the kernel and passes them to
+ * appropriate threads:
+ * WRITE - always goes to both local_send and remote_send threads
+ * READ (when the block is up-to-date on local component) -
+ * only local_send thread
+ * READ (when the block isn't up-to-date on local component) -
+ * only remote_send thread
+ * DELETE - always goes to both local_send and remote_send threads
+ * FLUSH - always goes to both local_send and remote_send threads
+ */
+static void *
+ggate_recv_thread(void *arg)
+{
+ struct hast_resource *res = arg;
+ struct g_gate_ctl_io *ggio;
+ struct hio *hio;
+ unsigned int ii, ncomp, ncomps;
+ int error;
+
+ ncomps = HAST_NCOMPONENTS;
+
+ for (;;) {
+ pjdlog_debug(2, "ggate_recv: Taking free request.");
+ QUEUE_TAKE2(hio, free);
+ pjdlog_debug(2, "ggate_recv: (%p) Got free request.", hio);
+ ggio = &hio->hio_ggio;
+ ggio->gctl_unit = res->hr_ggateunit;
+ ggio->gctl_length = MAXPHYS;
+ ggio->gctl_error = 0;
+ pjdlog_debug(2,
+ "ggate_recv: (%p) Waiting for request from the kernel.",
+ hio);
+ if (ioctl(res->hr_ggatefd, G_GATE_CMD_START, ggio) < 0) {
+ if (sigexit_received)
+ pthread_exit(NULL);
+ primary_exit(EX_OSERR, "G_GATE_CMD_START failed");
+ }
+ error = ggio->gctl_error;
+ switch (error) {
+ case 0:
+ break;
+ case ECANCELED:
+ /* Exit gracefully. */
+ if (!sigexit_received) {
+ pjdlog_debug(2,
+ "ggate_recv: (%p) Received cancel from the kernel.",
+ hio);
+ pjdlog_info("Received cancel from the kernel, exiting.");
+ }
+ pthread_exit(NULL);
+ case ENOMEM:
+ /*
+ * Buffer too small? Impossible, we allocate MAXPHYS
+ * bytes - request can't be bigger than that.
+ */
+ /* FALLTHROUGH */
+ case ENXIO:
+ default:
+ primary_exitx(EX_OSERR, "G_GATE_CMD_START failed: %s.",
+ strerror(error));
+ }
+ for (ii = 0; ii < ncomps; ii++)
+ hio->hio_errors[ii] = EINVAL;
+ reqlog(LOG_DEBUG, 2, ggio,
+ "ggate_recv: (%p) Request received from the kernel: ",
+ hio);
+ /*
+ * Inform all components about new write request.
+ * For read request prefer local component unless the given
+ * range is out-of-date, then use remote component.
+ */
+ switch (ggio->gctl_cmd) {
+ case BIO_READ:
+ pjdlog_debug(2,
+ "ggate_recv: (%p) Moving request to the send queue.",
+ hio);
+ refcount_init(&hio->hio_countdown, 1);
+ mtx_lock(&metadata_lock);
+ if (res->hr_syncsrc == HAST_SYNCSRC_UNDEF ||
+ res->hr_syncsrc == HAST_SYNCSRC_PRIMARY) {
+ /*
+ * This range is up-to-date on local component,
+ * so handle request locally.
+ */
+ /* Local component is 0 for now. */
+ ncomp = 0;
+ } else /* if (res->hr_syncsrc ==
+ HAST_SYNCSRC_SECONDARY) */ {
+ assert(res->hr_syncsrc ==
+ HAST_SYNCSRC_SECONDARY);
+ /*
+ * This range is out-of-date on local component,
+ * so send request to the remote node.
+ */
+ /* Remote component is 1 for now. */
+ ncomp = 1;
+ }
+ mtx_unlock(&metadata_lock);
+ QUEUE_INSERT1(hio, send, ncomp);
+ break;
+ case BIO_WRITE:
+ for (;;) {
+ mtx_lock(&range_lock);
+ if (rangelock_islocked(range_sync,
+ ggio->gctl_offset, ggio->gctl_length)) {
+ pjdlog_debug(2,
+ "regular: Range offset=%jd length=%zu locked.",
+ (intmax_t)ggio->gctl_offset,
+ (size_t)ggio->gctl_length);
+ range_regular_wait = true;
+ cv_wait(&range_regular_cond, &range_lock);
+ range_regular_wait = false;
+ mtx_unlock(&range_lock);
+ continue;
+ }
+ if (rangelock_add(range_regular,
+ ggio->gctl_offset, ggio->gctl_length) < 0) {
+ mtx_unlock(&range_lock);
+ pjdlog_debug(2,
+ "regular: Range offset=%jd length=%zu is already locked, waiting.",
+ (intmax_t)ggio->gctl_offset,
+ (size_t)ggio->gctl_length);
+ sleep(1);
+ continue;
+ }
+ mtx_unlock(&range_lock);
+ break;
+ }
+ mtx_lock(&res->hr_amp_lock);
+ if (activemap_write_start(res->hr_amp,
+ ggio->gctl_offset, ggio->gctl_length)) {
+ (void)hast_activemap_flush(res);
+ }
+ mtx_unlock(&res->hr_amp_lock);
+ /* FALLTHROUGH */
+ case BIO_DELETE:
+ case BIO_FLUSH:
+ pjdlog_debug(2,
+ "ggate_recv: (%p) Moving request to the send queues.",
+ hio);
+ refcount_init(&hio->hio_countdown, ncomps);
+ for (ii = 0; ii < ncomps; ii++)
+ QUEUE_INSERT1(hio, send, ii);
+ break;
+ }
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+/*
+ * Thread reads from or writes to local component.
+ * If local read fails, it redirects it to remote_send thread.
+ */
+static void *
+local_send_thread(void *arg)
+{
+ struct hast_resource *res = arg;
+ struct g_gate_ctl_io *ggio;
+ struct hio *hio;
+ unsigned int ncomp, rncomp;
+ ssize_t ret;
+
+ /* Local component is 0 for now. */
+ ncomp = 0;
+ /* Remote component is 1 for now. */
+ rncomp = 1;
+
+ for (;;) {
+ pjdlog_debug(2, "local_send: Taking request.");
+ QUEUE_TAKE1(hio, send, ncomp);
+ pjdlog_debug(2, "local_send: (%p) Got request.", hio);
+ ggio = &hio->hio_ggio;
+ switch (ggio->gctl_cmd) {
+ case BIO_READ:
+ ret = pread(res->hr_localfd, ggio->gctl_data,
+ ggio->gctl_length,
+ ggio->gctl_offset + res->hr_localoff);
+ if (ret == ggio->gctl_length)
+ hio->hio_errors[ncomp] = 0;
+ else {
+ /*
+ * If READ failed, try to read from remote node.
+ */
+ QUEUE_INSERT1(hio, send, rncomp);
+ continue;
+ }
+ break;
+ case BIO_WRITE:
+ ret = pwrite(res->hr_localfd, ggio->gctl_data,
+ ggio->gctl_length,
+ ggio->gctl_offset + res->hr_localoff);
+ if (ret < 0)
+ hio->hio_errors[ncomp] = errno;
+ else if (ret != ggio->gctl_length)
+ hio->hio_errors[ncomp] = EIO;
+ else
+ hio->hio_errors[ncomp] = 0;
+ break;
+ case BIO_DELETE:
+ ret = g_delete(res->hr_localfd,
+ ggio->gctl_offset + res->hr_localoff,
+ ggio->gctl_length);
+ if (ret < 0)
+ hio->hio_errors[ncomp] = errno;
+ else
+ hio->hio_errors[ncomp] = 0;
+ break;
+ case BIO_FLUSH:
+ ret = g_flush(res->hr_localfd);
+ if (ret < 0)
+ hio->hio_errors[ncomp] = errno;
+ else
+ hio->hio_errors[ncomp] = 0;
+ break;
+ }
+ if (refcount_release(&hio->hio_countdown)) {
+ if (ISSYNCREQ(hio)) {
+ mtx_lock(&sync_lock);
+ SYNCREQDONE(hio);
+ mtx_unlock(&sync_lock);
+ cv_signal(&sync_cond);
+ } else {
+ pjdlog_debug(2,
+ "local_send: (%p) Moving request to the done queue.",
+ hio);
+ QUEUE_INSERT2(hio, done);
+ }
+ }
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+/*
+ * Thread sends request to secondary node.
+ */
+static void *
+remote_send_thread(void *arg)
+{
+ struct hast_resource *res = arg;
+ struct g_gate_ctl_io *ggio;
+ struct hio *hio;
+ struct nv *nv;
+ unsigned int ncomp;
+ bool wakeup;
+ uint64_t offset, length;
+ uint8_t cmd;
+ void *data;
+
+ /* Remote component is 1 for now. */
+ ncomp = 1;
+
+ for (;;) {
+ pjdlog_debug(2, "remote_send: Taking request.");
+ QUEUE_TAKE1(hio, send, ncomp);
+ pjdlog_debug(2, "remote_send: (%p) Got request.", hio);
+ ggio = &hio->hio_ggio;
+ switch (ggio->gctl_cmd) {
+ case BIO_READ:
+ cmd = HIO_READ;
+ data = NULL;
+ offset = ggio->gctl_offset;
+ length = ggio->gctl_length;
+ break;
+ case BIO_WRITE:
+ cmd = HIO_WRITE;
+ data = ggio->gctl_data;
+ offset = ggio->gctl_offset;
+ length = ggio->gctl_length;
+ break;
+ case BIO_DELETE:
+ cmd = HIO_DELETE;
+ data = NULL;
+ offset = ggio->gctl_offset;
+ length = ggio->gctl_length;
+ break;
+ case BIO_FLUSH:
+ cmd = HIO_FLUSH;
+ data = NULL;
+ offset = 0;
+ length = 0;
+ break;
+ default:
+ assert(!"invalid condition");
+ abort();
+ }
+ nv = nv_alloc();
+ nv_add_uint8(nv, cmd, "cmd");
+ nv_add_uint64(nv, (uint64_t)ggio->gctl_seq, "seq");
+ nv_add_uint64(nv, offset, "offset");
+ nv_add_uint64(nv, length, "length");
+ if (nv_error(nv) != 0) {
+ hio->hio_errors[ncomp] = nv_error(nv);
+ pjdlog_debug(2,
+ "remote_send: (%p) Unable to prepare header to send.",
+ hio);
+ reqlog(LOG_ERR, 0, ggio,
+ "Unable to prepare header to send (%s): ",
+ strerror(nv_error(nv)));
+ /* Move failed request immediately to the done queue. */
+ goto done_queue;
+ }
+ pjdlog_debug(2,
+ "remote_send: (%p) Moving request to the recv queue.",
+ hio);
+ /*
+ * Protect connection from disappearing.
+ */
+ rw_rlock(&hio_remote_lock[ncomp]);
+ if (!ISCONNECTED(res, ncomp)) {
+ rw_unlock(&hio_remote_lock[ncomp]);
+ hio->hio_errors[ncomp] = ENOTCONN;
+ goto done_queue;
+ }
+ /*
+ * Move the request to recv queue before sending it, because
+ * in different order we can get reply before we move request
+ * to recv queue.
+ */
+ mtx_lock(&hio_recv_list_lock[ncomp]);
+ wakeup = TAILQ_EMPTY(&hio_recv_list[ncomp]);
+ TAILQ_INSERT_TAIL(&hio_recv_list[ncomp], hio, hio_next[ncomp]);
+ mtx_unlock(&hio_recv_list_lock[ncomp]);
+ if (hast_proto_send(res, res->hr_remoteout, nv, data,
+ data != NULL ? length : 0) < 0) {
+ hio->hio_errors[ncomp] = errno;
+ rw_unlock(&hio_remote_lock[ncomp]);
+ remote_close(res, ncomp);
+ pjdlog_debug(2,
+ "remote_send: (%p) Unable to send request.", hio);
+ reqlog(LOG_ERR, 0, ggio,
+ "Unable to send request (%s): ",
+ strerror(hio->hio_errors[ncomp]));
+ /*
+ * Take request back from the receive queue and move
+ * it immediately to the done queue.
+ */
+ mtx_lock(&hio_recv_list_lock[ncomp]);
+ TAILQ_REMOVE(&hio_recv_list[ncomp], hio, hio_next[ncomp]);
+ mtx_unlock(&hio_recv_list_lock[ncomp]);
+ goto done_queue;
+ }
+ rw_unlock(&hio_remote_lock[ncomp]);
+ nv_free(nv);
+ if (wakeup)
+ cv_signal(&hio_recv_list_cond[ncomp]);
+ continue;
+done_queue:
+ nv_free(nv);
+ if (ISSYNCREQ(hio)) {
+ if (!refcount_release(&hio->hio_countdown))
+ continue;
+ mtx_lock(&sync_lock);
+ SYNCREQDONE(hio);
+ mtx_unlock(&sync_lock);
+ cv_signal(&sync_cond);
+ continue;
+ }
+ if (ggio->gctl_cmd == BIO_WRITE) {
+ mtx_lock(&res->hr_amp_lock);
+ if (activemap_need_sync(res->hr_amp, ggio->gctl_offset,
+ ggio->gctl_length)) {
+ (void)hast_activemap_flush(res);
+ }
+ mtx_unlock(&res->hr_amp_lock);
+ }
+ if (!refcount_release(&hio->hio_countdown))
+ continue;
+ pjdlog_debug(2,
+ "remote_send: (%p) Moving request to the done queue.",
+ hio);
+ QUEUE_INSERT2(hio, done);
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+/*
+ * Thread receives answer from secondary node and passes it to ggate_send
+ * thread.
+ */
+static void *
+remote_recv_thread(void *arg)
+{
+ struct hast_resource *res = arg;
+ struct g_gate_ctl_io *ggio;
+ struct hio *hio;
+ struct nv *nv;
+ unsigned int ncomp;
+ uint64_t seq;
+ int error;
+
+ /* Remote component is 1 for now. */
+ ncomp = 1;
+
+ for (;;) {
+ /* Wait until there is anything to receive. */
+ mtx_lock(&hio_recv_list_lock[ncomp]);
+ while (TAILQ_EMPTY(&hio_recv_list[ncomp])) {
+ pjdlog_debug(2, "remote_recv: No requests, waiting.");
+ cv_wait(&hio_recv_list_cond[ncomp],
+ &hio_recv_list_lock[ncomp]);
+ }
+ mtx_unlock(&hio_recv_list_lock[ncomp]);
+ rw_rlock(&hio_remote_lock[ncomp]);
+ if (!ISCONNECTED(res, ncomp)) {
+ rw_unlock(&hio_remote_lock[ncomp]);
+ /*
+ * Connection is dead, so move all pending requests to
+ * the done queue (one-by-one).
+ */
+ mtx_lock(&hio_recv_list_lock[ncomp]);
+ hio = TAILQ_FIRST(&hio_recv_list[ncomp]);
+ assert(hio != NULL);
+ TAILQ_REMOVE(&hio_recv_list[ncomp], hio,
+ hio_next[ncomp]);
+ mtx_unlock(&hio_recv_list_lock[ncomp]);
+ goto done_queue;
+ }
+ if (hast_proto_recv_hdr(res->hr_remotein, &nv) < 0) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to receive reply header");
+ rw_unlock(&hio_remote_lock[ncomp]);
+ remote_close(res, ncomp);
+ continue;
+ }
+ rw_unlock(&hio_remote_lock[ncomp]);
+ seq = nv_get_uint64(nv, "seq");
+ if (seq == 0) {
+ pjdlog_error("Header contains no 'seq' field.");
+ nv_free(nv);
+ continue;
+ }
+ mtx_lock(&hio_recv_list_lock[ncomp]);
+ TAILQ_FOREACH(hio, &hio_recv_list[ncomp], hio_next[ncomp]) {
+ if (hio->hio_ggio.gctl_seq == seq) {
+ TAILQ_REMOVE(&hio_recv_list[ncomp], hio,
+ hio_next[ncomp]);
+ break;
+ }
+ }
+ mtx_unlock(&hio_recv_list_lock[ncomp]);
+ if (hio == NULL) {
+ pjdlog_error("Found no request matching received 'seq' field (%ju).",
+ (uintmax_t)seq);
+ nv_free(nv);
+ continue;
+ }
+ error = nv_get_int16(nv, "error");
+ if (error != 0) {
+ /* Request failed on remote side. */
+ hio->hio_errors[ncomp] = 0;
+ nv_free(nv);
+ goto done_queue;
+ }
+ ggio = &hio->hio_ggio;
+ switch (ggio->gctl_cmd) {
+ case BIO_READ:
+ rw_rlock(&hio_remote_lock[ncomp]);
+ if (!ISCONNECTED(res, ncomp)) {
+ rw_unlock(&hio_remote_lock[ncomp]);
+ nv_free(nv);
+ goto done_queue;
+ }
+ if (hast_proto_recv_data(res, res->hr_remotein, nv,
+ ggio->gctl_data, ggio->gctl_length) < 0) {
+ hio->hio_errors[ncomp] = errno;
+ pjdlog_errno(LOG_ERR,
+ "Unable to receive reply data");
+ rw_unlock(&hio_remote_lock[ncomp]);
+ nv_free(nv);
+ remote_close(res, ncomp);
+ goto done_queue;
+ }
+ rw_unlock(&hio_remote_lock[ncomp]);
+ break;
+ case BIO_WRITE:
+ case BIO_DELETE:
+ case BIO_FLUSH:
+ break;
+ default:
+ assert(!"invalid condition");
+ abort();
+ }
+ hio->hio_errors[ncomp] = 0;
+ nv_free(nv);
+done_queue:
+ if (refcount_release(&hio->hio_countdown)) {
+ if (ISSYNCREQ(hio)) {
+ mtx_lock(&sync_lock);
+ SYNCREQDONE(hio);
+ mtx_unlock(&sync_lock);
+ cv_signal(&sync_cond);
+ } else {
+ pjdlog_debug(2,
+ "remote_recv: (%p) Moving request to the done queue.",
+ hio);
+ QUEUE_INSERT2(hio, done);
+ }
+ }
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+/*
+ * Thread sends answer to the kernel.
+ */
+static void *
+ggate_send_thread(void *arg)
+{
+ struct hast_resource *res = arg;
+ struct g_gate_ctl_io *ggio;
+ struct hio *hio;
+ unsigned int ii, ncomp, ncomps;
+
+ ncomps = HAST_NCOMPONENTS;
+
+ for (;;) {
+ pjdlog_debug(2, "ggate_send: Taking request.");
+ QUEUE_TAKE2(hio, done);
+ pjdlog_debug(2, "ggate_send: (%p) Got request.", hio);
+ ggio = &hio->hio_ggio;
+ for (ii = 0; ii < ncomps; ii++) {
+ if (hio->hio_errors[ii] == 0) {
+ /*
+ * One successful request is enough to declare
+ * success.
+ */
+ ggio->gctl_error = 0;
+ break;
+ }
+ }
+ if (ii == ncomps) {
+ /*
+ * None of the requests were successful.
+ * Use first error.
+ */
+ ggio->gctl_error = hio->hio_errors[0];
+ }
+ if (ggio->gctl_error == 0 && ggio->gctl_cmd == BIO_WRITE) {
+ mtx_lock(&res->hr_amp_lock);
+ activemap_write_complete(res->hr_amp,
+ ggio->gctl_offset, ggio->gctl_length);
+ mtx_unlock(&res->hr_amp_lock);
+ }
+ if (ggio->gctl_cmd == BIO_WRITE) {
+ /*
+ * Unlock range we locked.
+ */
+ mtx_lock(&range_lock);
+ rangelock_del(range_regular, ggio->gctl_offset,
+ ggio->gctl_length);
+ if (range_sync_wait)
+ cv_signal(&range_sync_cond);
+ mtx_unlock(&range_lock);
+ /*
+ * Bump local count if this is first write after
+ * connection failure with remote node.
+ */
+ ncomp = 1;
+ rw_rlock(&hio_remote_lock[ncomp]);
+ if (!ISCONNECTED(res, ncomp)) {
+ mtx_lock(&metadata_lock);
+ if (res->hr_primary_localcnt ==
+ res->hr_secondary_remotecnt) {
+ res->hr_primary_localcnt++;
+ pjdlog_debug(1,
+ "Increasing localcnt to %ju.",
+ (uintmax_t)res->hr_primary_localcnt);
+ (void)metadata_write(res);
+ }
+ mtx_unlock(&metadata_lock);
+ }
+ rw_unlock(&hio_remote_lock[ncomp]);
+ }
+ if (ioctl(res->hr_ggatefd, G_GATE_CMD_DONE, ggio) < 0)
+ primary_exit(EX_OSERR, "G_GATE_CMD_DONE failed");
+ pjdlog_debug(2,
+ "ggate_send: (%p) Moving request to the free queue.", hio);
+ QUEUE_INSERT2(hio, free);
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+/*
+ * Thread synchronize local and remote components.
+ */
+static void *
+sync_thread(void *arg __unused)
+{
+ struct hast_resource *res = arg;
+ struct hio *hio;
+ struct g_gate_ctl_io *ggio;
+ unsigned int ii, ncomp, ncomps;
+ off_t offset, length, synced;
+ bool dorewind;
+ int syncext;
+
+ ncomps = HAST_NCOMPONENTS;
+ dorewind = true;
+ synced = 0;
+
+ for (;;) {
+ mtx_lock(&sync_lock);
+ while (!sync_inprogress) {
+ dorewind = true;
+ synced = 0;
+ cv_wait(&sync_cond, &sync_lock);
+ }
+ mtx_unlock(&sync_lock);
+ /*
+ * Obtain offset at which we should synchronize.
+ * Rewind synchronization if needed.
+ */
+ mtx_lock(&res->hr_amp_lock);
+ if (dorewind)
+ activemap_sync_rewind(res->hr_amp);
+ offset = activemap_sync_offset(res->hr_amp, &length, &syncext);
+ if (syncext != -1) {
+ /*
+ * We synchronized entire syncext extent, we can mark
+ * it as clean now.
+ */
+ if (activemap_extent_complete(res->hr_amp, syncext))
+ (void)hast_activemap_flush(res);
+ }
+ mtx_unlock(&res->hr_amp_lock);
+ if (dorewind) {
+ dorewind = false;
+ if (offset < 0)
+ pjdlog_info("Nodes are in sync.");
+ else {
+ pjdlog_info("Synchronization started. %ju bytes to go.",
+ (uintmax_t)(res->hr_extentsize *
+ activemap_ndirty(res->hr_amp)));
+ }
+ }
+ if (offset < 0) {
+ mtx_lock(&sync_lock);
+ sync_inprogress = false;
+ mtx_unlock(&sync_lock);
+ pjdlog_debug(1, "Nothing to synchronize.");
+ /*
+ * Synchronization complete, make both localcnt and
+ * remotecnt equal.
+ */
+ ncomp = 1;
+ rw_rlock(&hio_remote_lock[ncomp]);
+ if (ISCONNECTED(res, ncomp)) {
+ if (synced > 0) {
+ pjdlog_info("Synchronization complete. "
+ "%jd bytes synchronized.",
+ (intmax_t)synced);
+ }
+ mtx_lock(&metadata_lock);
+ res->hr_syncsrc = HAST_SYNCSRC_UNDEF;
+ res->hr_primary_localcnt =
+ res->hr_secondary_localcnt;
+ res->hr_primary_remotecnt =
+ res->hr_secondary_remotecnt;
+ pjdlog_debug(1,
+ "Setting localcnt to %ju and remotecnt to %ju.",
+ (uintmax_t)res->hr_primary_localcnt,
+ (uintmax_t)res->hr_secondary_localcnt);
+ (void)metadata_write(res);
+ mtx_unlock(&metadata_lock);
+ } else if (synced > 0) {
+ pjdlog_info("Synchronization interrupted. "
+ "%jd bytes synchronized so far.",
+ (intmax_t)synced);
+ }
+ rw_unlock(&hio_remote_lock[ncomp]);
+ continue;
+ }
+ pjdlog_debug(2, "sync: Taking free request.");
+ QUEUE_TAKE2(hio, free);
+ pjdlog_debug(2, "sync: (%p) Got free request.", hio);
+ /*
+ * Lock the range we are going to synchronize. We don't want
+ * race where someone writes between our read and write.
+ */
+ for (;;) {
+ mtx_lock(&range_lock);
+ if (rangelock_islocked(range_regular, offset, length)) {
+ pjdlog_debug(2,
+ "sync: Range offset=%jd length=%jd locked.",
+ (intmax_t)offset, (intmax_t)length);
+ range_sync_wait = true;
+ cv_wait(&range_sync_cond, &range_lock);
+ range_sync_wait = false;
+ mtx_unlock(&range_lock);
+ continue;
+ }
+ if (rangelock_add(range_sync, offset, length) < 0) {
+ mtx_unlock(&range_lock);
+ pjdlog_debug(2,
+ "sync: Range offset=%jd length=%jd is already locked, waiting.",
+ (intmax_t)offset, (intmax_t)length);
+ sleep(1);
+ continue;
+ }
+ mtx_unlock(&range_lock);
+ break;
+ }
+ /*
+ * First read the data from synchronization source.
+ */
+ SYNCREQ(hio);
+ ggio = &hio->hio_ggio;
+ ggio->gctl_cmd = BIO_READ;
+ ggio->gctl_offset = offset;
+ ggio->gctl_length = length;
+ ggio->gctl_error = 0;
+ for (ii = 0; ii < ncomps; ii++)
+ hio->hio_errors[ii] = EINVAL;
+ reqlog(LOG_DEBUG, 2, ggio, "sync: (%p) Sending sync request: ",
+ hio);
+ pjdlog_debug(2, "sync: (%p) Moving request to the send queue.",
+ hio);
+ mtx_lock(&metadata_lock);
+ if (res->hr_syncsrc == HAST_SYNCSRC_PRIMARY) {
+ /*
+ * This range is up-to-date on local component,
+ * so handle request locally.
+ */
+ /* Local component is 0 for now. */
+ ncomp = 0;
+ } else /* if (res->hr_syncsrc == HAST_SYNCSRC_SECONDARY) */ {
+ assert(res->hr_syncsrc == HAST_SYNCSRC_SECONDARY);
+ /*
+ * This range is out-of-date on local component,
+ * so send request to the remote node.
+ */
+ /* Remote component is 1 for now. */
+ ncomp = 1;
+ }
+ mtx_unlock(&metadata_lock);
+ refcount_init(&hio->hio_countdown, 1);
+ QUEUE_INSERT1(hio, send, ncomp);
+
+ /*
+ * Let's wait for READ to finish.
+ */
+ mtx_lock(&sync_lock);
+ while (!ISSYNCREQDONE(hio))
+ cv_wait(&sync_cond, &sync_lock);
+ mtx_unlock(&sync_lock);
+
+ if (hio->hio_errors[ncomp] != 0) {
+ pjdlog_error("Unable to read synchronization data: %s.",
+ strerror(hio->hio_errors[ncomp]));
+ goto free_queue;
+ }
+
+ /*
+ * We read the data from synchronization source, now write it
+ * to synchronization target.
+ */
+ SYNCREQ(hio);
+ ggio->gctl_cmd = BIO_WRITE;
+ for (ii = 0; ii < ncomps; ii++)
+ hio->hio_errors[ii] = EINVAL;
+ reqlog(LOG_DEBUG, 2, ggio, "sync: (%p) Sending sync request: ",
+ hio);
+ pjdlog_debug(2, "sync: (%p) Moving request to the send queue.",
+ hio);
+ mtx_lock(&metadata_lock);
+ if (res->hr_syncsrc == HAST_SYNCSRC_PRIMARY) {
+ /*
+ * This range is up-to-date on local component,
+ * so we update remote component.
+ */
+ /* Remote component is 1 for now. */
+ ncomp = 1;
+ } else /* if (res->hr_syncsrc == HAST_SYNCSRC_SECONDARY) */ {
+ assert(res->hr_syncsrc == HAST_SYNCSRC_SECONDARY);
+ /*
+ * This range is out-of-date on local component,
+ * so we update it.
+ */
+ /* Local component is 0 for now. */
+ ncomp = 0;
+ }
+ mtx_unlock(&metadata_lock);
+
+ pjdlog_debug(2, "sync: (%p) Moving request to the send queues.",
+ hio);
+ refcount_init(&hio->hio_countdown, 1);
+ QUEUE_INSERT1(hio, send, ncomp);
+
+ /*
+ * Let's wait for WRITE to finish.
+ */
+ mtx_lock(&sync_lock);
+ while (!ISSYNCREQDONE(hio))
+ cv_wait(&sync_cond, &sync_lock);
+ mtx_unlock(&sync_lock);
+
+ if (hio->hio_errors[ncomp] != 0) {
+ pjdlog_error("Unable to write synchronization data: %s.",
+ strerror(hio->hio_errors[ncomp]));
+ goto free_queue;
+ }
+free_queue:
+ mtx_lock(&range_lock);
+ rangelock_del(range_sync, offset, length);
+ if (range_regular_wait)
+ cv_signal(&range_regular_cond);
+ mtx_unlock(&range_lock);
+
+ synced += length;
+
+ pjdlog_debug(2, "sync: (%p) Moving request to the free queue.",
+ hio);
+ QUEUE_INSERT2(hio, free);
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+static void
+sighandler(int sig)
+{
+ bool unlock;
+
+ switch (sig) {
+ case SIGINT:
+ case SIGTERM:
+ sigexit_received = true;
+ break;
+ default:
+ assert(!"invalid condition");
+ }
+ /*
+ * XXX: Racy, but if we cannot obtain hio_guard_lock here, we don't
+ * want to risk deadlock.
+ */
+ unlock = mtx_trylock(&hio_guard_lock);
+ cv_signal(&hio_guard_cond);
+ if (unlock)
+ mtx_unlock(&hio_guard_lock);
+}
+
+/*
+ * Thread guards remote connections and reconnects when needed, handles
+ * signals, etc.
+ */
+static void *
+guard_thread(void *arg)
+{
+ struct hast_resource *res = arg;
+ unsigned int ii, ncomps;
+ int timeout;
+
+ ncomps = HAST_NCOMPONENTS;
+ /* The is only one remote component for now. */
+#define ISREMOTE(no) ((no) == 1)
+
+ for (;;) {
+ if (sigexit_received) {
+ primary_exitx(EX_OK,
+ "Termination signal received, exiting.");
+ }
+ /*
+ * If all the connection will be fine, we will sleep until
+ * someone wakes us up.
+ * If any of the connections will be broken and we won't be
+ * able to connect, we will sleep only for RECONNECT_SLEEP
+ * seconds so we can retry soon.
+ */
+ timeout = 0;
+ pjdlog_debug(2, "remote_guard: Checking connections.");
+ mtx_lock(&hio_guard_lock);
+ for (ii = 0; ii < ncomps; ii++) {
+ if (!ISREMOTE(ii))
+ continue;
+ rw_rlock(&hio_remote_lock[ii]);
+ if (ISCONNECTED(res, ii)) {
+ assert(res->hr_remotein != NULL);
+ assert(res->hr_remoteout != NULL);
+ rw_unlock(&hio_remote_lock[ii]);
+ pjdlog_debug(2,
+ "remote_guard: Connection to %s is ok.",
+ res->hr_remoteaddr);
+ } else {
+ assert(res->hr_remotein == NULL);
+ assert(res->hr_remoteout == NULL);
+ /*
+ * Upgrade the lock. It doesn't have to be
+ * atomic as no other thread can change
+ * connection status from disconnected to
+ * connected.
+ */
+ rw_unlock(&hio_remote_lock[ii]);
+ rw_wlock(&hio_remote_lock[ii]);
+ assert(res->hr_remotein == NULL);
+ assert(res->hr_remoteout == NULL);
+ pjdlog_debug(2,
+ "remote_guard: Reconnecting to %s.",
+ res->hr_remoteaddr);
+ init_remote(res);
+ if (ISCONNECTED(res, ii)) {
+ pjdlog_info("Successfully reconnected to %s.",
+ res->hr_remoteaddr);
+ } else {
+ /* Both connections should be NULL. */
+ assert(res->hr_remotein == NULL);
+ assert(res->hr_remoteout == NULL);
+ pjdlog_debug(2,
+ "remote_guard: Reconnect to %s failed.",
+ res->hr_remoteaddr);
+ timeout = RECONNECT_SLEEP;
+ }
+ rw_unlock(&hio_remote_lock[ii]);
+ }
+ }
+ (void)cv_timedwait(&hio_guard_cond, &hio_guard_lock, timeout);
+ mtx_unlock(&hio_guard_lock);
+ }
+#undef ISREMOTE
+ /* NOTREACHED */
+ return (NULL);
+}
diff --git a/sbin/hastd/proto.c b/sbin/hastd/proto.c
new file mode 100644
index 0000000..103f20c
--- /dev/null
+++ b/sbin/hastd/proto.c
@@ -0,0 +1,261 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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/queue.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include "proto.h"
+#include "proto_impl.h"
+
+#define PROTO_CONN_MAGIC 0x907041c
+struct proto_conn {
+ int pc_magic;
+ struct hast_proto *pc_proto;
+ void *pc_ctx;
+ int pc_side;
+#define PROTO_SIDE_CLIENT 0
+#define PROTO_SIDE_SERVER_LISTEN 1
+#define PROTO_SIDE_SERVER_WORK 2
+};
+
+static LIST_HEAD(, hast_proto) protos = LIST_HEAD_INITIALIZER(protos);
+
+void
+proto_register(struct hast_proto *proto)
+{
+
+ LIST_INSERT_HEAD(&protos, proto, hp_next);
+}
+
+static int
+proto_common_setup(const char *addr, struct proto_conn **connp, int side)
+{
+ struct hast_proto *proto;
+ struct proto_conn *conn;
+ void *ctx;
+ int ret;
+
+ assert(side == PROTO_SIDE_CLIENT || side == PROTO_SIDE_SERVER_LISTEN);
+
+ conn = malloc(sizeof(*conn));
+ if (conn == NULL)
+ return (-1);
+
+ LIST_FOREACH(proto, &protos, hp_next) {
+ if (side == PROTO_SIDE_CLIENT)
+ ret = proto->hp_client(addr, &ctx);
+ else /* if (side == PROTO_SIDE_SERVER_LISTEN) */
+ ret = proto->hp_server(addr, &ctx);
+ /*
+ * ret == 0 - success
+ * ret == -1 - addr is not for this protocol
+ * ret > 0 - right protocol, but an error occured
+ */
+ if (ret >= 0)
+ break;
+ }
+ if (proto == NULL) {
+ /* Unrecognized address. */
+ free(conn);
+ errno = EINVAL;
+ return (-1);
+ }
+ if (ret > 0) {
+ /* An error occured. */
+ free(conn);
+ errno = ret;
+ return (-1);
+ }
+ conn->pc_proto = proto;
+ conn->pc_ctx = ctx;
+ conn->pc_side = side;
+ conn->pc_magic = PROTO_CONN_MAGIC;
+ *connp = conn;
+ return (0);
+}
+
+int
+proto_client(const char *addr, struct proto_conn **connp)
+{
+
+ return (proto_common_setup(addr, connp, PROTO_SIDE_CLIENT));
+}
+
+int
+proto_connect(struct proto_conn *conn)
+{
+ int ret;
+
+ assert(conn != NULL);
+ assert(conn->pc_magic == PROTO_CONN_MAGIC);
+ assert(conn->pc_side == PROTO_SIDE_CLIENT);
+ assert(conn->pc_proto != NULL);
+
+ ret = conn->pc_proto->hp_connect(conn->pc_ctx);
+ if (ret != 0) {
+ errno = ret;
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+proto_server(const char *addr, struct proto_conn **connp)
+{
+
+ return (proto_common_setup(addr, connp, PROTO_SIDE_SERVER_LISTEN));
+}
+
+int
+proto_accept(struct proto_conn *conn, struct proto_conn **newconnp)
+{
+ struct proto_conn *newconn;
+ int ret;
+
+ assert(conn != NULL);
+ assert(conn->pc_magic == PROTO_CONN_MAGIC);
+ assert(conn->pc_side == PROTO_SIDE_SERVER_LISTEN);
+ assert(conn->pc_proto != NULL);
+
+ newconn = malloc(sizeof(*newconn));
+ if (newconn == NULL)
+ return (-1);
+
+ ret = conn->pc_proto->hp_accept(conn->pc_ctx, &newconn->pc_ctx);
+ if (ret != 0) {
+ free(newconn);
+ errno = ret;
+ return (-1);
+ }
+
+ newconn->pc_proto = conn->pc_proto;
+ newconn->pc_side = PROTO_SIDE_SERVER_WORK;
+ newconn->pc_magic = PROTO_CONN_MAGIC;
+ *newconnp = newconn;
+
+ return (0);
+}
+
+int
+proto_send(struct proto_conn *conn, const void *data, size_t size)
+{
+ int ret;
+
+ assert(conn != NULL);
+ assert(conn->pc_magic == PROTO_CONN_MAGIC);
+ assert(conn->pc_proto != NULL);
+
+ ret = conn->pc_proto->hp_send(conn->pc_ctx, data, size);
+ if (ret != 0) {
+ errno = ret;
+ return (-1);
+ }
+ return (0);
+}
+
+int
+proto_recv(struct proto_conn *conn, void *data, size_t size)
+{
+ int ret;
+
+ assert(conn != NULL);
+ assert(conn->pc_magic == PROTO_CONN_MAGIC);
+ assert(conn->pc_proto != NULL);
+
+ ret = conn->pc_proto->hp_recv(conn->pc_ctx, data, size);
+ if (ret != 0) {
+ errno = ret;
+ return (-1);
+ }
+ return (0);
+}
+
+int
+proto_descriptor(const struct proto_conn *conn)
+{
+
+ assert(conn != NULL);
+ assert(conn->pc_magic == PROTO_CONN_MAGIC);
+ assert(conn->pc_proto != NULL);
+
+ return (conn->pc_proto->hp_descriptor(conn->pc_ctx));
+}
+
+bool
+proto_address_match(const struct proto_conn *conn, const char *addr)
+{
+
+ assert(conn != NULL);
+ assert(conn->pc_magic == PROTO_CONN_MAGIC);
+ assert(conn->pc_proto != NULL);
+
+ return (conn->pc_proto->hp_address_match(conn->pc_ctx, addr));
+}
+
+void
+proto_local_address(const struct proto_conn *conn, char *addr, size_t size)
+{
+
+ assert(conn != NULL);
+ assert(conn->pc_magic == PROTO_CONN_MAGIC);
+ assert(conn->pc_proto != NULL);
+
+ conn->pc_proto->hp_local_address(conn->pc_ctx, addr, size);
+}
+
+void
+proto_remote_address(const struct proto_conn *conn, char *addr, size_t size)
+{
+
+ assert(conn != NULL);
+ assert(conn->pc_magic == PROTO_CONN_MAGIC);
+ assert(conn->pc_proto != NULL);
+
+ conn->pc_proto->hp_remote_address(conn->pc_ctx, addr, size);
+}
+
+void
+proto_close(struct proto_conn *conn)
+{
+
+ assert(conn != NULL);
+ assert(conn->pc_magic == PROTO_CONN_MAGIC);
+ assert(conn->pc_proto != NULL);
+
+ conn->pc_proto->hp_close(conn->pc_ctx);
+ conn->pc_magic = 0;
+ free(conn);
+}
diff --git a/sbin/hastd/proto.h b/sbin/hastd/proto.h
new file mode 100644
index 0000000..cb196d8
--- /dev/null
+++ b/sbin/hastd/proto.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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 _PROTO_H_
+#define _PROTO_H_
+
+#include <stdbool.h> /* bool */
+#include <stdlib.h> /* size_t */
+
+struct proto_conn;
+
+int proto_client(const char *addr, struct proto_conn **connp);
+int proto_connect(struct proto_conn *conn);
+int proto_server(const char *addr, struct proto_conn **connp);
+int proto_accept(struct proto_conn *conn, struct proto_conn **newconnp);
+int proto_send(struct proto_conn *conn, const void *data, size_t size);
+int proto_recv(struct proto_conn *conn, void *data, size_t size);
+int proto_descriptor(const struct proto_conn *conn);
+bool proto_address_match(const struct proto_conn *conn, const char *addr);
+void proto_local_address(const struct proto_conn *conn, char *addr,
+ size_t size);
+void proto_remote_address(const struct proto_conn *conn, char *addr,
+ size_t size);
+void proto_close(struct proto_conn *conn);
+
+#endif /* !_PROTO_H_ */
diff --git a/sbin/hastd/proto_common.c b/sbin/hastd/proto_common.c
new file mode 100644
index 0000000..22102d8
--- /dev/null
+++ b/sbin/hastd/proto_common.c
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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/types.h>
+#include <sys/socket.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include "proto_impl.h"
+
+/* Maximum size of packet we want to use when sending data. */
+#ifndef MAX_SEND_SIZE
+//#define MAX_SEND_SIZE 32768
+#define MAX_SEND_SIZE 131072
+#endif
+
+int
+proto_common_send(int fd, const unsigned char *data, size_t size)
+{
+ ssize_t done;
+ size_t sendsize;
+
+ do {
+ sendsize = size < MAX_SEND_SIZE ? size : MAX_SEND_SIZE;
+ done = send(fd, data, sendsize, MSG_NOSIGNAL);
+ if (done == 0)
+ return (ENOTCONN);
+ else if (done < 0) {
+ if (errno == EAGAIN)
+ continue;
+ return (errno);
+ }
+ data += done;
+ size -= done;
+ } while (size > 0);
+
+ return (0);
+}
+
+int
+proto_common_recv(int fd, unsigned char *data, size_t size)
+{
+ ssize_t done;
+
+ do {
+ done = recv(fd, data, size, MSG_WAITALL);
+ } while (done == -1 && errno == EAGAIN);
+ if (done == 0)
+ return (ENOTCONN);
+ else if (done < 0)
+ return (errno);
+ return (0);
+}
diff --git a/sbin/hastd/proto_impl.h b/sbin/hastd/proto_impl.h
new file mode 100644
index 0000000..ea6548d
--- /dev/null
+++ b/sbin/hastd/proto_impl.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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 _PROTO_IMPL_H_
+#define _PROTO_IMPL_H_
+
+#include <sys/queue.h>
+
+#include <stdbool.h> /* bool */
+#include <stdlib.h> /* size_t */
+
+#define __constructor __attribute__((constructor))
+
+typedef int hp_client_t(const char *, void **);
+typedef int hp_connect_t(void *);
+typedef int hp_server_t(const char *, void **);
+typedef int hp_accept_t(void *, void **);
+typedef int hp_send_t(void *, const unsigned char *, size_t);
+typedef int hp_recv_t(void *, unsigned char *, size_t);
+typedef int hp_descriptor_t(const void *);
+typedef bool hp_address_match_t(const void *, const char *);
+typedef void hp_local_address_t(const void *, char *, size_t);
+typedef void hp_remote_address_t(const void *, char *, size_t);
+typedef void hp_close_t(void *);
+
+struct hast_proto {
+ const char *hp_name;
+ hp_client_t *hp_client;
+ hp_connect_t *hp_connect;
+ hp_server_t *hp_server;
+ hp_accept_t *hp_accept;
+ hp_send_t *hp_send;
+ hp_recv_t *hp_recv;
+ hp_descriptor_t *hp_descriptor;
+ hp_address_match_t *hp_address_match;
+ hp_local_address_t *hp_local_address;
+ hp_remote_address_t *hp_remote_address;
+ hp_close_t *hp_close;
+ LIST_ENTRY(hast_proto) hp_next;
+};
+
+void proto_register(struct hast_proto *proto);
+
+int proto_common_send(int fd, const unsigned char *data, size_t size);
+int proto_common_recv(int fd, unsigned char *data, size_t size);
+
+#endif /* !_PROTO_IMPL_H_ */
diff --git a/sbin/hastd/proto_socketpair.c b/sbin/hastd/proto_socketpair.c
new file mode 100644
index 0000000..08d0c66
--- /dev/null
+++ b/sbin/hastd/proto_socketpair.c
@@ -0,0 +1,275 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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/types.h>
+#include <sys/socket.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "hast.h"
+#include "proto_impl.h"
+
+#define SP_CTX_MAGIC 0x50c3741
+struct sp_ctx {
+ int sp_magic;
+ int sp_fd[2];
+ int sp_side;
+#define SP_SIDE_UNDEF 0
+#define SP_SIDE_CLIENT 1
+#define SP_SIDE_SERVER 2
+};
+
+static void sp_close(void *ctx);
+
+static int
+sp_client(const char *addr, void **ctxp)
+{
+ struct sp_ctx *spctx;
+ int ret;
+
+ if (strcmp(addr, "socketpair://") != 0)
+ return (-1);
+
+ spctx = malloc(sizeof(*spctx));
+ if (spctx == NULL)
+ return (errno);
+
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) < 0) {
+ ret = errno;
+ free(spctx);
+ return (ret);
+ }
+
+ spctx->sp_side = SP_SIDE_UNDEF;
+ spctx->sp_magic = SP_CTX_MAGIC;
+ *ctxp = spctx;
+
+ return (0);
+}
+
+static int
+sp_connect(void *ctx __unused)
+{
+
+ assert(!"proto_connect() not supported on socketpairs");
+ abort();
+}
+
+static int
+sp_server(const char *addr, void **ctxp __unused)
+{
+
+ if (strcmp(addr, "socketpair://") != 0)
+ return (-1);
+
+ assert(!"proto_server() not supported on socketpairs");
+ abort();
+}
+
+static int
+sp_accept(void *ctx __unused, void **newctxp __unused)
+{
+
+ assert(!"proto_server() not supported on socketpairs");
+ abort();
+}
+
+static int
+sp_send(void *ctx, const unsigned char *data, size_t size)
+{
+ struct sp_ctx *spctx = ctx;
+ int fd;
+
+ assert(spctx != NULL);
+ assert(spctx->sp_magic == SP_CTX_MAGIC);
+
+ switch (spctx->sp_side) {
+ case SP_SIDE_UNDEF:
+ /*
+ * If the first operation done by the caller is proto_send(),
+ * we assume this the client.
+ */
+ /* FALLTHROUGH */
+ spctx->sp_side = SP_SIDE_CLIENT;
+ /* Close other end. */
+ close(spctx->sp_fd[1]);
+ case SP_SIDE_CLIENT:
+ assert(spctx->sp_fd[0] >= 0);
+ fd = spctx->sp_fd[0];
+ break;
+ case SP_SIDE_SERVER:
+ assert(spctx->sp_fd[1] >= 0);
+ fd = spctx->sp_fd[1];
+ break;
+ default:
+ abort();
+ }
+
+ return (proto_common_send(fd, data, size));
+}
+
+static int
+sp_recv(void *ctx, unsigned char *data, size_t size)
+{
+ struct sp_ctx *spctx = ctx;
+ int fd;
+
+ assert(spctx != NULL);
+ assert(spctx->sp_magic == SP_CTX_MAGIC);
+
+ switch (spctx->sp_side) {
+ case SP_SIDE_UNDEF:
+ /*
+ * If the first operation done by the caller is proto_recv(),
+ * we assume this the server.
+ */
+ /* FALLTHROUGH */
+ spctx->sp_side = SP_SIDE_SERVER;
+ /* Close other end. */
+ close(spctx->sp_fd[0]);
+ case SP_SIDE_SERVER:
+ assert(spctx->sp_fd[1] >= 0);
+ fd = spctx->sp_fd[1];
+ break;
+ case SP_SIDE_CLIENT:
+ assert(spctx->sp_fd[0] >= 0);
+ fd = spctx->sp_fd[0];
+ break;
+ default:
+ abort();
+ }
+
+ return (proto_common_recv(fd, data, size));
+}
+
+static int
+sp_descriptor(const void *ctx)
+{
+ const struct sp_ctx *spctx = ctx;
+
+ assert(spctx != NULL);
+ assert(spctx->sp_magic == SP_CTX_MAGIC);
+ assert(spctx->sp_side == SP_SIDE_CLIENT ||
+ spctx->sp_side == SP_SIDE_SERVER);
+
+ switch (spctx->sp_side) {
+ case SP_SIDE_CLIENT:
+ assert(spctx->sp_fd[0] >= 0);
+ return (spctx->sp_fd[0]);
+ case SP_SIDE_SERVER:
+ assert(spctx->sp_fd[1] >= 0);
+ return (spctx->sp_fd[1]);
+ }
+
+ abort();
+}
+
+static bool
+sp_address_match(const void *ctx __unused, const char *addr __unused)
+{
+
+ assert(!"proto_address_match() not supported on socketpairs");
+ abort();
+}
+
+static void
+sp_local_address(const void *ctx __unused, char *addr __unused,
+ size_t size __unused)
+{
+
+ assert(!"proto_local_address() not supported on socketpairs");
+ abort();
+}
+
+static void
+sp_remote_address(const void *ctx __unused, char *addr __unused,
+ size_t size __unused)
+{
+
+ assert(!"proto_remote_address() not supported on socketpairs");
+ abort();
+}
+
+static void
+sp_close(void *ctx)
+{
+ struct sp_ctx *spctx = ctx;
+
+ assert(spctx != NULL);
+ assert(spctx->sp_magic == SP_CTX_MAGIC);
+
+ switch (spctx->sp_side) {
+ case SP_SIDE_UNDEF:
+ close(spctx->sp_fd[0]);
+ close(spctx->sp_fd[1]);
+ break;
+ case SP_SIDE_CLIENT:
+ close(spctx->sp_fd[0]);
+ break;
+ case SP_SIDE_SERVER:
+ close(spctx->sp_fd[1]);
+ break;
+ default:
+ abort();
+ }
+
+ spctx->sp_magic = 0;
+ free(spctx);
+}
+
+static struct hast_proto sp_proto = {
+ .hp_name = "socketpair",
+ .hp_client = sp_client,
+ .hp_connect = sp_connect,
+ .hp_server = sp_server,
+ .hp_accept = sp_accept,
+ .hp_send = sp_send,
+ .hp_recv = sp_recv,
+ .hp_descriptor = sp_descriptor,
+ .hp_address_match = sp_address_match,
+ .hp_local_address = sp_local_address,
+ .hp_remote_address = sp_remote_address,
+ .hp_close = sp_close
+};
+
+static __constructor void
+sp_ctor(void)
+{
+
+ proto_register(&sp_proto);
+}
diff --git a/sbin/hastd/proto_tcp4.c b/sbin/hastd/proto_tcp4.c
new file mode 100644
index 0000000..2fba996
--- /dev/null
+++ b/sbin/hastd/proto_tcp4.c
@@ -0,0 +1,447 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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> /* MAXHOSTNAMELEN */
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "hast.h"
+#include "pjdlog.h"
+#include "proto_impl.h"
+
+#define TCP4_CTX_MAGIC 0x7c441c
+struct tcp4_ctx {
+ int tc_magic;
+ struct sockaddr_in tc_sin;
+ int tc_fd;
+ int tc_side;
+#define TCP4_SIDE_CLIENT 0
+#define TCP4_SIDE_SERVER_LISTEN 1
+#define TCP4_SIDE_SERVER_WORK 2
+};
+
+static void tcp4_close(void *ctx);
+
+static in_addr_t
+str2ip(const char *str)
+{
+ struct hostent *hp;
+ in_addr_t ip;
+
+ ip = inet_addr(str);
+ if (ip != INADDR_NONE) {
+ /* It is a valid IP address. */
+ return (ip);
+ }
+ /* Check if it is a valid host name. */
+ hp = gethostbyname(str);
+ if (hp == NULL)
+ return (INADDR_NONE);
+ return (((struct in_addr *)(void *)hp->h_addr)->s_addr);
+}
+
+/*
+ * Function converts the given string to unsigned number.
+ */
+static int
+numfromstr(const char *str, intmax_t minnum, intmax_t maxnum, intmax_t *nump)
+{
+ intmax_t digit, num;
+
+ if (str[0] == '\0')
+ goto invalid; /* Empty string. */
+ num = 0;
+ for (; *str != '\0'; str++) {
+ if (*str < '0' || *str > '9')
+ goto invalid; /* Non-digit character. */
+ digit = *str - '0';
+ if (num > num * 10 + digit)
+ goto invalid; /* Overflow. */
+ num = num * 10 + digit;
+ if (num > maxnum)
+ goto invalid; /* Too big. */
+ }
+ if (num < minnum)
+ goto invalid; /* Too small. */
+ *nump = num;
+ return (0);
+invalid:
+ errno = EINVAL;
+ return (-1);
+}
+
+static int
+tcp4_addr(const char *addr, struct sockaddr_in *sinp)
+{
+ char iporhost[MAXHOSTNAMELEN];
+ const char *pp;
+ size_t size;
+ in_addr_t ip;
+
+ if (addr == NULL)
+ return (-1);
+
+ if (strncasecmp(addr, "tcp4://", 7) == 0)
+ addr += 7;
+ else if (strncasecmp(addr, "tcp://", 6) == 0)
+ addr += 6;
+ else if (addr[0] != '/' && /* If this is not path... */
+ strstr(addr, "://") == NULL)/* ...and has no prefix... */
+ ; /* ...tcp4 is the default. */
+ else
+ return (-1);
+
+ sinp->sin_family = AF_INET;
+ sinp->sin_len = sizeof(*sinp);
+ /* Extract optional port. */
+ pp = strrchr(addr, ':');
+ if (pp == NULL) {
+ /* Port not given, use the default. */
+ sinp->sin_port = htons(HASTD_PORT);
+ } else {
+ intmax_t port;
+
+ if (numfromstr(pp + 1, 1, 65535, &port) < 0)
+ return (errno);
+ sinp->sin_port = htons(port);
+ }
+ /* Extract host name or IP address. */
+ if (pp == NULL) {
+ size = sizeof(iporhost);
+ if (strlcpy(iporhost, addr, size) >= size)
+ return (ENAMETOOLONG);
+ } else {
+ size = (size_t)(pp - addr + 1);
+ if (size > sizeof(iporhost))
+ return (ENAMETOOLONG);
+ strlcpy(iporhost, addr, size);
+ }
+ /* Convert string (IP address or host name) to in_addr_t. */
+ ip = str2ip(iporhost);
+ if (ip == INADDR_NONE)
+ return (EINVAL);
+ sinp->sin_addr.s_addr = ip;
+
+ return (0);
+}
+
+static int
+tcp4_common_setup(const char *addr, void **ctxp, int side)
+{
+ struct tcp4_ctx *tctx;
+ int ret, val;
+
+ tctx = malloc(sizeof(*tctx));
+ if (tctx == NULL)
+ return (errno);
+
+ /* Parse given address. */
+ if ((ret = tcp4_addr(addr, &tctx->tc_sin)) != 0) {
+ free(tctx);
+ return (ret);
+ }
+
+ tctx->tc_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (tctx->tc_fd == -1) {
+ ret = errno;
+ free(tctx);
+ return (ret);
+ }
+
+ /* Socket settings. */
+ val = 1;
+ if (setsockopt(tctx->tc_fd, IPPROTO_TCP, TCP_NODELAY, &val,
+ sizeof(val)) == -1) {
+ pjdlog_warning("Unable to set TCP_NOELAY on %s", addr);
+ }
+ val = 131072;
+ if (setsockopt(tctx->tc_fd, SOL_SOCKET, SO_SNDBUF, &val,
+ sizeof(val)) == -1) {
+ pjdlog_warning("Unable to set send buffer size on %s", addr);
+ }
+ val = 131072;
+ if (setsockopt(tctx->tc_fd, SOL_SOCKET, SO_RCVBUF, &val,
+ sizeof(val)) == -1) {
+ pjdlog_warning("Unable to set receive buffer size on %s", addr);
+ }
+
+ tctx->tc_side = side;
+ tctx->tc_magic = TCP4_CTX_MAGIC;
+ *ctxp = tctx;
+
+ return (0);
+}
+
+static int
+tcp4_client(const char *addr, void **ctxp)
+{
+
+ return (tcp4_common_setup(addr, ctxp, TCP4_SIDE_CLIENT));
+}
+
+static int
+tcp4_connect(void *ctx)
+{
+ struct tcp4_ctx *tctx = ctx;
+
+ assert(tctx != NULL);
+ assert(tctx->tc_magic == TCP4_CTX_MAGIC);
+ assert(tctx->tc_side == TCP4_SIDE_CLIENT);
+ assert(tctx->tc_fd >= 0);
+
+ if (connect(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sin,
+ sizeof(tctx->tc_sin)) < 0) {
+ return (errno);
+ }
+
+ return (0);
+}
+
+static int
+tcp4_server(const char *addr, void **ctxp)
+{
+ struct tcp4_ctx *tctx;
+ int ret, val;
+
+ ret = tcp4_common_setup(addr, ctxp, TCP4_SIDE_SERVER_LISTEN);
+ if (ret != 0)
+ return (ret);
+
+ tctx = *ctxp;
+
+ val = 1;
+ /* Ignore failure. */
+ (void)setsockopt(tctx->tc_fd, SOL_SOCKET, SO_REUSEADDR, &val,
+ sizeof(val));
+
+ if (bind(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sin,
+ sizeof(tctx->tc_sin)) < 0) {
+ ret = errno;
+ tcp4_close(tctx);
+ return (ret);
+ }
+ if (listen(tctx->tc_fd, 8) < 0) {
+ ret = errno;
+ tcp4_close(tctx);
+ return (ret);
+ }
+
+ return (0);
+}
+
+static int
+tcp4_accept(void *ctx, void **newctxp)
+{
+ struct tcp4_ctx *tctx = ctx;
+ struct tcp4_ctx *newtctx;
+ socklen_t fromlen;
+ int ret;
+
+ assert(tctx != NULL);
+ assert(tctx->tc_magic == TCP4_CTX_MAGIC);
+ assert(tctx->tc_side == TCP4_SIDE_SERVER_LISTEN);
+ assert(tctx->tc_fd >= 0);
+
+ newtctx = malloc(sizeof(*newtctx));
+ if (newtctx == NULL)
+ return (errno);
+
+ fromlen = sizeof(tctx->tc_sin);
+ newtctx->tc_fd = accept(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sin,
+ &fromlen);
+ if (newtctx->tc_fd < 0) {
+ ret = errno;
+ free(newtctx);
+ return (ret);
+ }
+
+ newtctx->tc_side = TCP4_SIDE_SERVER_WORK;
+ newtctx->tc_magic = TCP4_CTX_MAGIC;
+ *newctxp = newtctx;
+
+ return (0);
+}
+
+static int
+tcp4_send(void *ctx, const unsigned char *data, size_t size)
+{
+ struct tcp4_ctx *tctx = ctx;
+
+ assert(tctx != NULL);
+ assert(tctx->tc_magic == TCP4_CTX_MAGIC);
+ assert(tctx->tc_fd >= 0);
+
+ return (proto_common_send(tctx->tc_fd, data, size));
+}
+
+static int
+tcp4_recv(void *ctx, unsigned char *data, size_t size)
+{
+ struct tcp4_ctx *tctx = ctx;
+
+ assert(tctx != NULL);
+ assert(tctx->tc_magic == TCP4_CTX_MAGIC);
+ assert(tctx->tc_fd >= 0);
+
+ return (proto_common_recv(tctx->tc_fd, data, size));
+}
+
+static int
+tcp4_descriptor(const void *ctx)
+{
+ const struct tcp4_ctx *tctx = ctx;
+
+ assert(tctx != NULL);
+ assert(tctx->tc_magic == TCP4_CTX_MAGIC);
+
+ return (tctx->tc_fd);
+}
+
+static void
+sin2str(struct sockaddr_in *sinp, char *addr, size_t size)
+{
+ in_addr_t ip;
+ unsigned int port;
+
+ assert(addr != NULL);
+ assert(sinp->sin_family == AF_INET);
+
+ ip = ntohl(sinp->sin_addr.s_addr);
+ port = ntohs(sinp->sin_port);
+ snprintf(addr, size, "tcp4://%u.%u.%u.%u:%u", ((ip >> 24) & 0xff),
+ ((ip >> 16) & 0xff), ((ip >> 8) & 0xff), (ip & 0xff), port);
+}
+
+static bool
+tcp4_address_match(const void *ctx, const char *addr)
+{
+ const struct tcp4_ctx *tctx = ctx;
+ struct sockaddr_in sin;
+ socklen_t sinlen;
+ in_addr_t ip1, ip2;
+
+ assert(tctx != NULL);
+ assert(tctx->tc_magic == TCP4_CTX_MAGIC);
+
+ if (tcp4_addr(addr, &sin) != 0)
+ return (false);
+ ip1 = sin.sin_addr.s_addr;
+
+ sinlen = sizeof(sin);
+ if (getpeername(tctx->tc_fd, (struct sockaddr *)&sin, &sinlen) < 0)
+ return (false);
+ ip2 = sin.sin_addr.s_addr;
+
+ return (ip1 == ip2);
+}
+
+static void
+tcp4_local_address(const void *ctx, char *addr, size_t size)
+{
+ const struct tcp4_ctx *tctx = ctx;
+ struct sockaddr_in sin;
+ socklen_t sinlen;
+
+ assert(tctx != NULL);
+ assert(tctx->tc_magic == TCP4_CTX_MAGIC);
+
+ sinlen = sizeof(sin);
+ if (getsockname(tctx->tc_fd, (struct sockaddr *)&sin, &sinlen) < 0) {
+ strlcpy(addr, "N/A", size);
+ return;
+ }
+ sin2str(&sin, addr, size);
+}
+
+static void
+tcp4_remote_address(const void *ctx, char *addr, size_t size)
+{
+ const struct tcp4_ctx *tctx = ctx;
+ struct sockaddr_in sin;
+ socklen_t sinlen;
+
+ assert(tctx != NULL);
+ assert(tctx->tc_magic == TCP4_CTX_MAGIC);
+
+ sinlen = sizeof(sin);
+ if (getpeername(tctx->tc_fd, (struct sockaddr *)&sin, &sinlen) < 0) {
+ strlcpy(addr, "N/A", size);
+ return;
+ }
+ sin2str(&sin, addr, size);
+}
+
+static void
+tcp4_close(void *ctx)
+{
+ struct tcp4_ctx *tctx = ctx;
+
+ assert(tctx != NULL);
+ assert(tctx->tc_magic == TCP4_CTX_MAGIC);
+
+ if (tctx->tc_fd >= 0)
+ close(tctx->tc_fd);
+ tctx->tc_magic = 0;
+ free(tctx);
+}
+
+static struct hast_proto tcp4_proto = {
+ .hp_name = "tcp4",
+ .hp_client = tcp4_client,
+ .hp_connect = tcp4_connect,
+ .hp_server = tcp4_server,
+ .hp_accept = tcp4_accept,
+ .hp_send = tcp4_send,
+ .hp_recv = tcp4_recv,
+ .hp_descriptor = tcp4_descriptor,
+ .hp_address_match = tcp4_address_match,
+ .hp_local_address = tcp4_local_address,
+ .hp_remote_address = tcp4_remote_address,
+ .hp_close = tcp4_close
+};
+
+static __constructor void
+tcp4_ctor(void)
+{
+
+ proto_register(&tcp4_proto);
+}
diff --git a/sbin/hastd/proto_uds.c b/sbin/hastd/proto_uds.c
new file mode 100644
index 0000000..0fac82f
--- /dev/null
+++ b/sbin/hastd/proto_uds.c
@@ -0,0 +1,330 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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$");
+
+/* UDS - UNIX Domain Socket */
+
+#include <sys/un.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "hast.h"
+#include "proto_impl.h"
+
+#define UDS_CTX_MAGIC 0xd541c
+struct uds_ctx {
+ int uc_magic;
+ struct sockaddr_un uc_sun;
+ int uc_fd;
+ int uc_side;
+#define UDS_SIDE_CLIENT 0
+#define UDS_SIDE_SERVER_LISTEN 1
+#define UDS_SIDE_SERVER_WORK 2
+};
+
+static void uds_close(void *ctx);
+
+static int
+uds_addr(const char *addr, struct sockaddr_un *sunp)
+{
+
+ if (addr == NULL)
+ return (-1);
+
+ if (strncasecmp(addr, "uds://", 6) == 0)
+ addr += 6;
+ else if (strncasecmp(addr, "unix://", 7) == 0)
+ addr += 7;
+ else if (addr[0] == '/' && /* If it starts from /... */
+ strstr(addr, "://") == NULL)/* ...and there is no prefix... */
+ ; /* ...we assume its us. */
+ else
+ return (-1);
+
+ sunp->sun_family = AF_UNIX;
+ if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >=
+ sizeof(sunp->sun_path)) {
+ return (ENAMETOOLONG);
+ }
+ sunp->sun_len = SUN_LEN(sunp);
+
+ return (0);
+}
+
+static int
+uds_common_setup(const char *addr, void **ctxp, int side)
+{
+ struct uds_ctx *uctx;
+ int ret;
+
+ uctx = malloc(sizeof(*uctx));
+ if (uctx == NULL)
+ return (errno);
+
+ /* Parse given address. */
+ if ((ret = uds_addr(addr, &uctx->uc_sun)) != 0) {
+ free(uctx);
+ return (ret);
+ }
+
+ uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (uctx->uc_fd == -1) {
+ ret = errno;
+ free(uctx);
+ return (ret);
+ }
+
+ uctx->uc_side = side;
+ uctx->uc_magic = UDS_CTX_MAGIC;
+ *ctxp = uctx;
+
+ return (0);
+}
+
+static int
+uds_client(const char *addr, void **ctxp)
+{
+
+ return (uds_common_setup(addr, ctxp, UDS_SIDE_CLIENT));
+}
+
+static int
+uds_connect(void *ctx)
+{
+ struct uds_ctx *uctx = ctx;
+
+ assert(uctx != NULL);
+ assert(uctx->uc_magic == UDS_CTX_MAGIC);
+ assert(uctx->uc_side == UDS_SIDE_CLIENT);
+ assert(uctx->uc_fd >= 0);
+
+ if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
+ sizeof(uctx->uc_sun)) < 0) {
+ return (errno);
+ }
+
+ return (0);
+}
+
+static int
+uds_server(const char *addr, void **ctxp)
+{
+ struct uds_ctx *uctx;
+ int ret;
+
+ ret = uds_common_setup(addr, ctxp, UDS_SIDE_SERVER_LISTEN);
+ if (ret != 0)
+ return (ret);
+
+ uctx = *ctxp;
+
+ unlink(uctx->uc_sun.sun_path);
+ if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
+ sizeof(uctx->uc_sun)) < 0) {
+ ret = errno;
+ uds_close(uctx);
+ return (ret);
+ }
+ if (listen(uctx->uc_fd, 8) < 0) {
+ ret = errno;
+ uds_close(uctx);
+ return (ret);
+ }
+
+ return (0);
+}
+
+static int
+uds_accept(void *ctx, void **newctxp)
+{
+ struct uds_ctx *uctx = ctx;
+ struct uds_ctx *newuctx;
+ socklen_t fromlen;
+ int ret;
+
+ assert(uctx != NULL);
+ assert(uctx->uc_magic == UDS_CTX_MAGIC);
+ assert(uctx->uc_side == UDS_SIDE_SERVER_LISTEN);
+ assert(uctx->uc_fd >= 0);
+
+ newuctx = malloc(sizeof(*newuctx));
+ if (newuctx == NULL)
+ return (errno);
+
+ fromlen = sizeof(uctx->uc_sun);
+ newuctx->uc_fd = accept(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
+ &fromlen);
+ if (newuctx->uc_fd < 0) {
+ ret = errno;
+ free(newuctx);
+ return (ret);
+ }
+
+ newuctx->uc_side = UDS_SIDE_SERVER_WORK;
+ newuctx->uc_magic = UDS_CTX_MAGIC;
+ *newctxp = newuctx;
+
+ return (0);
+}
+
+static int
+uds_send(void *ctx, const unsigned char *data, size_t size)
+{
+ struct uds_ctx *uctx = ctx;
+
+ assert(uctx != NULL);
+ assert(uctx->uc_magic == UDS_CTX_MAGIC);
+ assert(uctx->uc_fd >= 0);
+
+ return (proto_common_send(uctx->uc_fd, data, size));
+}
+
+static int
+uds_recv(void *ctx, unsigned char *data, size_t size)
+{
+ struct uds_ctx *uctx = ctx;
+
+ assert(uctx != NULL);
+ assert(uctx->uc_magic == UDS_CTX_MAGIC);
+ assert(uctx->uc_fd >= 0);
+
+ return (proto_common_recv(uctx->uc_fd, data, size));
+}
+
+static int
+uds_descriptor(const void *ctx)
+{
+ const struct uds_ctx *uctx = ctx;
+
+ assert(uctx != NULL);
+ assert(uctx->uc_magic == UDS_CTX_MAGIC);
+
+ return (uctx->uc_fd);
+}
+
+static bool
+uds_address_match(const void *ctx __unused, const char *addr __unused)
+{
+
+ assert(!"proto_address_match() not supported on UNIX domain sockets");
+ abort();
+}
+
+static void
+uds_local_address(const void *ctx, char *addr, size_t size)
+{
+ const struct uds_ctx *uctx = ctx;
+ struct sockaddr_un sun;
+ socklen_t sunlen;
+
+ assert(uctx != NULL);
+ assert(uctx->uc_magic == UDS_CTX_MAGIC);
+ assert(addr != NULL);
+
+ sunlen = sizeof(sun);
+ if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) {
+ strlcpy(addr, "N/A", size);
+ return;
+ }
+ assert(sun.sun_family == AF_UNIX);
+ if (sun.sun_path[0] == '\0') {
+ strlcpy(addr, "N/A", size);
+ return;
+ }
+ snprintf(addr, size, "uds://%s", sun.sun_path);
+}
+
+static void
+uds_remote_address(const void *ctx, char *addr, size_t size)
+{
+ const struct uds_ctx *uctx = ctx;
+ struct sockaddr_un sun;
+ socklen_t sunlen;
+
+ assert(uctx != NULL);
+ assert(uctx->uc_magic == UDS_CTX_MAGIC);
+ assert(addr != NULL);
+
+ sunlen = sizeof(sun);
+ if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) {
+ strlcpy(addr, "N/A", size);
+ return;
+ }
+ assert(sun.sun_family == AF_UNIX);
+ if (sun.sun_path[0] == '\0') {
+ strlcpy(addr, "N/A", size);
+ return;
+ }
+ snprintf(addr, size, "uds://%s", sun.sun_path);
+}
+
+static void
+uds_close(void *ctx)
+{
+ struct uds_ctx *uctx = ctx;
+
+ assert(uctx != NULL);
+ assert(uctx->uc_magic == UDS_CTX_MAGIC);
+
+ if (uctx->uc_fd >= 0)
+ close(uctx->uc_fd);
+ unlink(uctx->uc_sun.sun_path);
+ uctx->uc_magic = 0;
+ free(uctx);
+}
+
+static struct hast_proto uds_proto = {
+ .hp_name = "uds",
+ .hp_client = uds_client,
+ .hp_connect = uds_connect,
+ .hp_server = uds_server,
+ .hp_accept = uds_accept,
+ .hp_send = uds_send,
+ .hp_recv = uds_recv,
+ .hp_descriptor = uds_descriptor,
+ .hp_address_match = uds_address_match,
+ .hp_local_address = uds_local_address,
+ .hp_remote_address = uds_remote_address,
+ .hp_close = uds_close
+};
+
+static __constructor void
+uds_ctor(void)
+{
+
+ proto_register(&uds_proto);
+}
diff --git a/sbin/hastd/rangelock.c b/sbin/hastd/rangelock.c
new file mode 100644
index 0000000..02247d6
--- /dev/null
+++ b/sbin/hastd/rangelock.c
@@ -0,0 +1,137 @@
+/*-
+ * Copyright (c) 2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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/queue.h>
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "rangelock.h"
+
+#define RANGELOCKS_MAGIC 0x94310c
+struct rangelocks {
+ int rls_magic; /* Magic value. */
+ TAILQ_HEAD(, rlock) rls_locks; /* List of locked ranges. */
+};
+
+struct rlock {
+ off_t rl_start;
+ off_t rl_end;
+ TAILQ_ENTRY(rlock) rl_next;
+};
+
+int
+rangelock_init(struct rangelocks **rlsp)
+{
+ struct rangelocks *rls;
+
+ assert(rlsp != NULL);
+
+ rls = malloc(sizeof(*rls));
+ if (rls == NULL)
+ return (-1);
+
+ TAILQ_INIT(&rls->rls_locks);
+
+ rls->rls_magic = RANGELOCKS_MAGIC;
+ *rlsp = rls;
+
+ return (0);
+}
+
+void
+rangelock_free(struct rangelocks *rls)
+{
+ struct rlock *rl;
+
+ assert(rls->rls_magic == RANGELOCKS_MAGIC);
+
+ rls->rls_magic = 0;
+
+ while ((rl = TAILQ_FIRST(&rls->rls_locks)) != NULL) {
+ TAILQ_REMOVE(&rls->rls_locks, rl, rl_next);
+ free(rl);
+ }
+ free(rls);
+}
+
+int
+rangelock_add(struct rangelocks *rls, off_t offset, off_t length)
+{
+ struct rlock *rl;
+
+ assert(rls->rls_magic == RANGELOCKS_MAGIC);
+
+ rl = malloc(sizeof(*rl));
+ if (rl == NULL)
+ return (-1);
+ rl->rl_start = offset;
+ rl->rl_end = offset + length;
+ TAILQ_INSERT_TAIL(&rls->rls_locks, rl, rl_next);
+ return (0);
+}
+
+void
+rangelock_del(struct rangelocks *rls, off_t offset, off_t length)
+{
+ struct rlock *rl;
+
+ assert(rls->rls_magic == RANGELOCKS_MAGIC);
+
+ TAILQ_FOREACH(rl, &rls->rls_locks, rl_next) {
+ if (rl->rl_start == offset && rl->rl_end == offset + length)
+ break;
+ }
+ assert(rl != NULL);
+ TAILQ_REMOVE(&rls->rls_locks, rl, rl_next);
+ free(rl);
+}
+
+bool
+rangelock_islocked(struct rangelocks *rls, off_t offset, off_t length)
+{
+ struct rlock *rl;
+
+ assert(rls->rls_magic == RANGELOCKS_MAGIC);
+
+ TAILQ_FOREACH(rl, &rls->rls_locks, rl_next) {
+ if (rl->rl_start >= offset && rl->rl_start < offset + length)
+ break;
+ else if (rl->rl_end > offset && rl->rl_end <= offset + length)
+ break;
+ else if (rl->rl_start < offset && rl->rl_end > offset + length)
+ break;
+ }
+ return (rl != NULL);
+}
diff --git a/sbin/hastd/rangelock.h b/sbin/hastd/rangelock.h
new file mode 100644
index 0000000..2ad9895
--- /dev/null
+++ b/sbin/hastd/rangelock.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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 _RANGELOCK_H_
+#define _RANGELOCK_H_
+
+#include <stdbool.h>
+#include <unistd.h>
+
+struct rangelocks;
+
+int rangelock_init(struct rangelocks **rlsp);
+void rangelock_free(struct rangelocks *rls);
+int rangelock_add(struct rangelocks *rls, off_t offset, off_t length);
+void rangelock_del(struct rangelocks *rls, off_t offset, off_t length);
+bool rangelock_islocked(struct rangelocks *rls, off_t offset, off_t length);
+
+#endif /* !_RANGELOCK_H_ */
diff --git a/sbin/hastd/secondary.c b/sbin/hastd/secondary.c
new file mode 100644
index 0000000..6af95b5
--- /dev/null
+++ b/sbin/hastd/secondary.c
@@ -0,0 +1,697 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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/time.h>
+#include <sys/bio.h>
+#include <sys/disk.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgeom.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <activemap.h>
+#include <nv.h>
+#include <pjdlog.h>
+
+#include "control.h"
+#include "hast.h"
+#include "hast_proto.h"
+#include "hastd.h"
+#include "metadata.h"
+#include "proto.h"
+#include "subr.h"
+#include "synch.h"
+
+struct hio {
+ uint64_t hio_seq;
+ int hio_error;
+ struct nv *hio_nv;
+ void *hio_data;
+ uint8_t hio_cmd;
+ uint64_t hio_offset;
+ uint64_t hio_length;
+ TAILQ_ENTRY(hio) hio_next;
+};
+
+/*
+ * Free list holds unused structures. When free list is empty, we have to wait
+ * until some in-progress requests are freed.
+ */
+static TAILQ_HEAD(, hio) hio_free_list;
+static pthread_mutex_t hio_free_list_lock;
+static pthread_cond_t hio_free_list_cond;
+/*
+ * Disk thread (the one that do I/O requests) takes requests from this list.
+ */
+static TAILQ_HEAD(, hio) hio_disk_list;
+static pthread_mutex_t hio_disk_list_lock;
+static pthread_cond_t hio_disk_list_cond;
+/*
+ * There is one recv list for every component, although local components don't
+ * use recv lists as local requests are done synchronously.
+ */
+static TAILQ_HEAD(, hio) hio_send_list;
+static pthread_mutex_t hio_send_list_lock;
+static pthread_cond_t hio_send_list_cond;
+
+/*
+ * Maximum number of outstanding I/O requests.
+ */
+#define HAST_HIO_MAX 256
+
+static void *recv_thread(void *arg);
+static void *disk_thread(void *arg);
+static void *send_thread(void *arg);
+
+static void
+init_environment(void)
+{
+ struct hio *hio;
+ unsigned int ii;
+
+ /*
+ * Initialize lists, their locks and theirs condition variables.
+ */
+ TAILQ_INIT(&hio_free_list);
+ mtx_init(&hio_free_list_lock);
+ cv_init(&hio_free_list_cond);
+ TAILQ_INIT(&hio_disk_list);
+ mtx_init(&hio_disk_list_lock);
+ cv_init(&hio_disk_list_cond);
+ TAILQ_INIT(&hio_send_list);
+ mtx_init(&hio_send_list_lock);
+ cv_init(&hio_send_list_cond);
+
+ /*
+ * Allocate requests pool and initialize requests.
+ */
+ for (ii = 0; ii < HAST_HIO_MAX; ii++) {
+ hio = malloc(sizeof(*hio));
+ if (hio == NULL) {
+ errx(EX_TEMPFAIL, "cannot allocate %zu bytes of memory "
+ "for hio request", sizeof(*hio));
+ }
+ hio->hio_error = 0;
+ hio->hio_data = malloc(MAXPHYS);
+ if (hio->hio_data == NULL) {
+ errx(EX_TEMPFAIL, "cannot allocate %zu bytes of memory "
+ "for gctl_data", (size_t)MAXPHYS);
+ }
+ TAILQ_INSERT_HEAD(&hio_free_list, hio, hio_next);
+ }
+}
+
+static void
+init_local(struct hast_resource *res)
+{
+
+ if (metadata_read(res, true) < 0)
+ exit(EX_NOINPUT);
+}
+
+static void
+init_remote(struct hast_resource *res, struct nv *nvin)
+{
+ uint64_t resuid;
+ struct nv *nvout;
+ unsigned char *map;
+ size_t mapsize;
+
+ map = NULL;
+ mapsize = 0;
+ nvout = nv_alloc();
+ nv_add_int64(nvout, (int64_t)res->hr_datasize, "datasize");
+ nv_add_int32(nvout, (int32_t)res->hr_extentsize, "extentsize");
+ resuid = nv_get_uint64(nvin, "resuid");
+ res->hr_primary_localcnt = nv_get_uint64(nvin, "localcnt");
+ res->hr_primary_remotecnt = nv_get_uint64(nvin, "remotecnt");
+ nv_add_uint64(nvout, res->hr_secondary_localcnt, "localcnt");
+ nv_add_uint64(nvout, res->hr_secondary_remotecnt, "remotecnt");
+ mapsize = activemap_calc_ondisk_size(res->hr_local_mediasize -
+ METADATA_SIZE, res->hr_extentsize, res->hr_local_sectorsize);
+ map = malloc(mapsize);
+ if (map == NULL) {
+ pjdlog_exitx(EX_TEMPFAIL,
+ "Unable to allocate memory (%zu bytes) for activemap.",
+ mapsize);
+ }
+ nv_add_uint32(nvout, (uint32_t)mapsize, "mapsize");
+ /*
+ * When we work as primary and secondary is missing we will increase
+ * localcnt in our metadata. When secondary is connected and synced
+ * we make localcnt be equal to remotecnt, which means nodes are more
+ * or less in sync.
+ * Split-brain condition is when both nodes are not able to communicate
+ * and are both configured as primary nodes. In turn, they can both
+ * make incompatible changes to the data and we have to detect that.
+ * Under split-brain condition we will increase our localcnt on first
+ * write and remote node will increase its localcnt on first write.
+ * When we connect we can see that primary's localcnt is greater than
+ * our remotecnt (primary was modified while we weren't watching) and
+ * our localcnt is greater than primary's remotecnt (we were modified
+ * while primary wasn't watching).
+ * There are many possible combinations which are all gathered below.
+ * Don't pay too much attention to exact numbers, the more important
+ * is to compare them. We compare secondary's local with primary's
+ * remote and secondary's remote with primary's local.
+ * Note that every case where primary's localcnt is smaller than
+ * secondary's remotecnt and where secondary's localcnt is smaller than
+ * primary's remotecnt should be impossible in practise. We will perform
+ * full synchronization then. Those cases are marked with an asterisk.
+ * Regular synchronization means that only extents marked as dirty are
+ * synchronized (regular synchronization).
+ *
+ * SECONDARY METADATA PRIMARY METADATA
+ * local=3 remote=3 local=2 remote=2* ?! Full sync from secondary.
+ * local=3 remote=3 local=2 remote=3* ?! Full sync from primary.
+ * local=3 remote=3 local=2 remote=4* ?! Full sync from primary.
+ * local=3 remote=3 local=3 remote=2 Primary is out-of-date,
+ * regular sync from secondary.
+ * local=3 remote=3 local=3 remote=3 Regular sync just in case.
+ * local=3 remote=3 local=3 remote=4* ?! Full sync from primary.
+ * local=3 remote=3 local=4 remote=2 Split-brain condition.
+ * local=3 remote=3 local=4 remote=3 Secondary out-of-date,
+ * regular sync from primary.
+ * local=3 remote=3 local=4 remote=4* ?! Full sync from primary.
+ */
+ if (res->hr_resuid == 0) {
+ /*
+ * Provider is used for the first time. Initialize everything.
+ */
+ assert(res->hr_secondary_localcnt == 0);
+ res->hr_resuid = resuid;
+ if (metadata_write(res) < 0)
+ exit(EX_NOINPUT);
+ memset(map, 0xff, mapsize);
+ nv_add_uint8(nvout, HAST_SYNCSRC_PRIMARY, "syncsrc");
+ } else if (
+ /* Is primary is out-of-date? */
+ (res->hr_secondary_localcnt > res->hr_primary_remotecnt &&
+ res->hr_secondary_remotecnt == res->hr_primary_localcnt) ||
+ /* Node are more or less in sync? */
+ (res->hr_secondary_localcnt == res->hr_primary_remotecnt &&
+ res->hr_secondary_remotecnt == res->hr_primary_localcnt) ||
+ /* Is secondary is out-of-date? */
+ (res->hr_secondary_localcnt == res->hr_primary_remotecnt &&
+ res->hr_secondary_remotecnt < res->hr_primary_localcnt)) {
+ /*
+ * Nodes are more or less in sync or one of the nodes is
+ * out-of-date.
+ * It doesn't matter at this point which one, we just have to
+ * send out local bitmap to the remote node.
+ */
+ if (pread(res->hr_localfd, map, mapsize, METADATA_SIZE) !=
+ (ssize_t)mapsize) {
+ pjdlog_exit(LOG_ERR, "Unable to read activemap");
+ }
+ if (res->hr_secondary_localcnt > res->hr_primary_remotecnt &&
+ res->hr_secondary_remotecnt == res->hr_primary_localcnt) {
+ /* Primary is out-of-date, sync from secondary. */
+ nv_add_uint8(nvout, HAST_SYNCSRC_SECONDARY, "syncsrc");
+ } else {
+ /*
+ * Secondary is out-of-date or counts match.
+ * Sync from primary.
+ */
+ nv_add_uint8(nvout, HAST_SYNCSRC_PRIMARY, "syncsrc");
+ }
+ } else if (res->hr_secondary_localcnt > res->hr_primary_remotecnt &&
+ res->hr_primary_localcnt > res->hr_secondary_remotecnt) {
+ /*
+ * Not good, we have split-brain condition.
+ */
+ pjdlog_error("Split-brain detected, exiting.");
+ nv_add_string(nvout, "Split-brain condition!", "errmsg");
+ free(map);
+ map = NULL;
+ mapsize = 0;
+ } else /* if (res->hr_secondary_localcnt < res->hr_primary_remotecnt ||
+ res->hr_primary_localcnt < res->hr_secondary_remotecnt) */ {
+ /*
+ * This should never happen in practise, but we will perform
+ * full synchronization.
+ */
+ assert(res->hr_secondary_localcnt < res->hr_primary_remotecnt ||
+ res->hr_primary_localcnt < res->hr_secondary_remotecnt);
+ mapsize = activemap_calc_ondisk_size(res->hr_local_mediasize -
+ METADATA_SIZE, res->hr_extentsize,
+ res->hr_local_sectorsize);
+ memset(map, 0xff, mapsize);
+ if (res->hr_secondary_localcnt > res->hr_primary_remotecnt) {
+ /* In this one of five cases sync from secondary. */
+ nv_add_uint8(nvout, HAST_SYNCSRC_SECONDARY, "syncsrc");
+ } else {
+ /* For the rest four cases sync from primary. */
+ nv_add_uint8(nvout, HAST_SYNCSRC_PRIMARY, "syncsrc");
+ }
+ pjdlog_warning("This should never happen, asking for full synchronization (primary(local=%ju, remote=%ju), secondary(local=%ju, remote=%ju)).",
+ (uintmax_t)res->hr_primary_localcnt,
+ (uintmax_t)res->hr_primary_remotecnt,
+ (uintmax_t)res->hr_secondary_localcnt,
+ (uintmax_t)res->hr_secondary_remotecnt);
+ }
+ if (hast_proto_send(res, res->hr_remotein, nvout, map, mapsize) < 0) {
+ pjdlog_errno(LOG_WARNING, "Unable to send activemap to %s",
+ res->hr_remoteaddr);
+ nv_free(nvout);
+ exit(EX_TEMPFAIL);
+ }
+ if (res->hr_secondary_localcnt > res->hr_primary_remotecnt &&
+ res->hr_primary_localcnt > res->hr_secondary_remotecnt) {
+ /* Exit on split-brain. */
+ exit(EX_CONFIG);
+ }
+}
+
+void
+hastd_secondary(struct hast_resource *res, struct nv *nvin)
+{
+ pthread_t td;
+ pid_t pid;
+ int error;
+
+ /*
+ * Create communication channel between parent and child.
+ */
+ if (proto_client("socketpair://", &res->hr_ctrl) < 0) {
+ KEEP_ERRNO((void)pidfile_remove(pfh));
+ pjdlog_exit(EX_OSERR,
+ "Unable to create control sockets between parent and child");
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ KEEP_ERRNO((void)pidfile_remove(pfh));
+ pjdlog_exit(EX_OSERR, "Unable to fork");
+ }
+
+ if (pid > 0) {
+ /* This is parent. */
+ proto_close(res->hr_remotein);
+ res->hr_remotein = NULL;
+ proto_close(res->hr_remoteout);
+ res->hr_remoteout = NULL;
+ res->hr_workerpid = pid;
+ return;
+ }
+ (void)pidfile_close(pfh);
+
+ setproctitle("%s (secondary)", res->hr_name);
+
+ init_local(res);
+ init_remote(res, nvin);
+ init_environment();
+
+ error = pthread_create(&td, NULL, recv_thread, res);
+ assert(error == 0);
+ error = pthread_create(&td, NULL, disk_thread, res);
+ assert(error == 0);
+ error = pthread_create(&td, NULL, send_thread, res);
+ assert(error == 0);
+ (void)ctrl_thread(res);
+}
+
+static void
+reqlog(int loglevel, int debuglevel, int error, struct hio *hio, const char *fmt, ...)
+{
+ char msg[1024];
+ va_list ap;
+ int len;
+
+ va_start(ap, fmt);
+ len = vsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+ if ((size_t)len < sizeof(msg)) {
+ switch (hio->hio_cmd) {
+ case HIO_READ:
+ (void)snprintf(msg + len, sizeof(msg) - len,
+ "READ(%ju, %ju).", (uintmax_t)hio->hio_offset,
+ (uintmax_t)hio->hio_length);
+ break;
+ case HIO_DELETE:
+ (void)snprintf(msg + len, sizeof(msg) - len,
+ "DELETE(%ju, %ju).", (uintmax_t)hio->hio_offset,
+ (uintmax_t)hio->hio_length);
+ break;
+ case HIO_FLUSH:
+ (void)snprintf(msg + len, sizeof(msg) - len, "FLUSH.");
+ break;
+ case HIO_WRITE:
+ (void)snprintf(msg + len, sizeof(msg) - len,
+ "WRITE(%ju, %ju).", (uintmax_t)hio->hio_offset,
+ (uintmax_t)hio->hio_length);
+ break;
+ default:
+ (void)snprintf(msg + len, sizeof(msg) - len,
+ "UNKNOWN(%u).", (unsigned int)hio->hio_cmd);
+ break;
+ }
+ }
+ pjdlog_common(loglevel, debuglevel, error, "%s", msg);
+}
+
+static int
+requnpack(struct hast_resource *res, struct hio *hio)
+{
+
+ hio->hio_cmd = nv_get_uint8(hio->hio_nv, "cmd");
+ if (hio->hio_cmd == 0) {
+ pjdlog_error("Header contains no 'cmd' field.");
+ hio->hio_error = EINVAL;
+ goto end;
+ }
+ switch (hio->hio_cmd) {
+ case HIO_READ:
+ case HIO_WRITE:
+ case HIO_DELETE:
+ hio->hio_offset = nv_get_uint64(hio->hio_nv, "offset");
+ if (nv_error(hio->hio_nv) != 0) {
+ pjdlog_error("Header is missing 'offset' field.");
+ hio->hio_error = EINVAL;
+ goto end;
+ }
+ hio->hio_length = nv_get_uint64(hio->hio_nv, "length");
+ if (nv_error(hio->hio_nv) != 0) {
+ pjdlog_error("Header is missing 'length' field.");
+ hio->hio_error = EINVAL;
+ goto end;
+ }
+ if (hio->hio_length == 0) {
+ pjdlog_error("Data length is zero.");
+ hio->hio_error = EINVAL;
+ goto end;
+ }
+ if (hio->hio_length > MAXPHYS) {
+ pjdlog_error("Data length is too large (%ju > %ju).",
+ (uintmax_t)hio->hio_length, (uintmax_t)MAXPHYS);
+ hio->hio_error = EINVAL;
+ goto end;
+ }
+ if ((hio->hio_offset % res->hr_local_sectorsize) != 0) {
+ pjdlog_error("Offset %ju is not multiple of sector size.",
+ (uintmax_t)hio->hio_offset);
+ hio->hio_error = EINVAL;
+ goto end;
+ }
+ if ((hio->hio_length % res->hr_local_sectorsize) != 0) {
+ pjdlog_error("Length %ju is not multiple of sector size.",
+ (uintmax_t)hio->hio_length);
+ hio->hio_error = EINVAL;
+ goto end;
+ }
+ if (hio->hio_offset + hio->hio_length >
+ (uint64_t)res->hr_datasize) {
+ pjdlog_error("Data offset is too large (%ju > %ju).",
+ (uintmax_t)(hio->hio_offset + hio->hio_length),
+ (uintmax_t)res->hr_datasize);
+ hio->hio_error = EINVAL;
+ goto end;
+ }
+ break;
+ default:
+ pjdlog_error("Header contains invalid 'cmd' (%hhu).",
+ hio->hio_cmd);
+ hio->hio_error = EINVAL;
+ goto end;
+ }
+ hio->hio_error = 0;
+end:
+ return (hio->hio_error);
+}
+
+/*
+ * Thread receives requests from the primary node.
+ */
+static void *
+recv_thread(void *arg)
+{
+ struct hast_resource *res = arg;
+ struct hio *hio;
+ bool wakeup;
+
+ for (;;) {
+ pjdlog_debug(2, "recv: Taking free request.");
+ mtx_lock(&hio_free_list_lock);
+ while ((hio = TAILQ_FIRST(&hio_free_list)) == NULL) {
+ pjdlog_debug(2, "recv: No free requests, waiting.");
+ cv_wait(&hio_free_list_cond, &hio_free_list_lock);
+ }
+ TAILQ_REMOVE(&hio_free_list, hio, hio_next);
+ mtx_unlock(&hio_free_list_lock);
+ pjdlog_debug(2, "recv: (%p) Got request.", hio);
+ if (hast_proto_recv_hdr(res->hr_remotein, &hio->hio_nv) < 0) {
+ pjdlog_exit(EX_TEMPFAIL,
+ "Unable to receive request header");
+ }
+ if (requnpack(res, hio) != 0)
+ goto send_queue;
+ reqlog(LOG_DEBUG, 2, -1, hio,
+ "recv: (%p) Got request header: ", hio);
+ if (hio->hio_cmd == HIO_WRITE) {
+ if (hast_proto_recv_data(res, res->hr_remotein,
+ hio->hio_nv, hio->hio_data, MAXPHYS) < 0) {
+ pjdlog_exit(EX_TEMPFAIL,
+ "Unable to receive reply data");
+ }
+ }
+ pjdlog_debug(2, "recv: (%p) Moving request to the disk queue.",
+ hio);
+ mtx_lock(&hio_disk_list_lock);
+ wakeup = TAILQ_EMPTY(&hio_disk_list);
+ TAILQ_INSERT_TAIL(&hio_disk_list, hio, hio_next);
+ mtx_unlock(&hio_disk_list_lock);
+ if (wakeup)
+ cv_signal(&hio_disk_list_cond);
+ continue;
+send_queue:
+ pjdlog_debug(2, "recv: (%p) Moving request to the send queue.",
+ hio);
+ mtx_lock(&hio_send_list_lock);
+ wakeup = TAILQ_EMPTY(&hio_send_list);
+ TAILQ_INSERT_TAIL(&hio_send_list, hio, hio_next);
+ mtx_unlock(&hio_send_list_lock);
+ if (wakeup)
+ cv_signal(&hio_send_list_cond);
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+/*
+ * Thread reads from or writes to local component and also handles DELETE and
+ * FLUSH requests.
+ */
+static void *
+disk_thread(void *arg)
+{
+ struct hast_resource *res = arg;
+ struct hio *hio;
+ ssize_t ret;
+ bool clear_activemap, wakeup;
+
+ clear_activemap = true;
+
+ for (;;) {
+ pjdlog_debug(2, "disk: Taking request.");
+ mtx_lock(&hio_disk_list_lock);
+ while ((hio = TAILQ_FIRST(&hio_disk_list)) == NULL) {
+ pjdlog_debug(2, "disk: No requests, waiting.");
+ cv_wait(&hio_disk_list_cond, &hio_disk_list_lock);
+ }
+ TAILQ_REMOVE(&hio_disk_list, hio, hio_next);
+ mtx_unlock(&hio_disk_list_lock);
+ while (clear_activemap) {
+ unsigned char *map;
+ size_t mapsize;
+
+ /*
+ * When first request is received, it means that primary
+ * already received our activemap, merged it and stored
+ * locally. We can now safely clear our activemap.
+ */
+ mapsize =
+ activemap_calc_ondisk_size(res->hr_local_mediasize -
+ METADATA_SIZE, res->hr_extentsize,
+ res->hr_local_sectorsize);
+ map = calloc(1, mapsize);
+ if (map == NULL) {
+ pjdlog_warning("Unable to allocate memory to clear local activemap.");
+ break;
+ }
+ if (pwrite(res->hr_localfd, map, mapsize,
+ METADATA_SIZE) != (ssize_t)mapsize) {
+ pjdlog_errno(LOG_WARNING,
+ "Unable to store cleared activemap");
+ free(map);
+ break;
+ }
+ free(map);
+ clear_activemap = false;
+ pjdlog_debug(1, "Local activemap cleared.");
+ }
+ reqlog(LOG_DEBUG, 2, -1, hio, "disk: (%p) Got request: ", hio);
+ /* Handle the actual request. */
+ switch (hio->hio_cmd) {
+ case HIO_READ:
+ ret = pread(res->hr_localfd, hio->hio_data,
+ hio->hio_length,
+ hio->hio_offset + res->hr_localoff);
+ if (ret < 0)
+ hio->hio_error = errno;
+ else if (ret != (int64_t)hio->hio_length)
+ hio->hio_error = EIO;
+ else
+ hio->hio_error = 0;
+ break;
+ case HIO_WRITE:
+ ret = pwrite(res->hr_localfd, hio->hio_data,
+ hio->hio_length,
+ hio->hio_offset + res->hr_localoff);
+ if (ret < 0)
+ hio->hio_error = errno;
+ else if (ret != (int64_t)hio->hio_length)
+ hio->hio_error = EIO;
+ else
+ hio->hio_error = 0;
+ break;
+ case HIO_DELETE:
+ ret = g_delete(res->hr_localfd,
+ hio->hio_offset + res->hr_localoff,
+ hio->hio_length);
+ if (ret < 0)
+ hio->hio_error = errno;
+ else
+ hio->hio_error = 0;
+ break;
+ case HIO_FLUSH:
+ ret = g_flush(res->hr_localfd);
+ if (ret < 0)
+ hio->hio_error = errno;
+ else
+ hio->hio_error = 0;
+ break;
+ }
+ if (hio->hio_error != 0) {
+ reqlog(LOG_ERR, 0, hio->hio_error, hio,
+ "Request failed: ");
+ }
+ pjdlog_debug(2, "disk: (%p) Moving request to the send queue.",
+ hio);
+ mtx_lock(&hio_send_list_lock);
+ wakeup = TAILQ_EMPTY(&hio_send_list);
+ TAILQ_INSERT_TAIL(&hio_send_list, hio, hio_next);
+ mtx_unlock(&hio_send_list_lock);
+ if (wakeup)
+ cv_signal(&hio_send_list_cond);
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+/*
+ * Thread sends requests back to primary node.
+ */
+static void *
+send_thread(void *arg)
+{
+ struct hast_resource *res = arg;
+ struct nv *nvout;
+ struct hio *hio;
+ void *data;
+ size_t length;
+ bool wakeup;
+
+ for (;;) {
+ pjdlog_debug(2, "send: Taking request.");
+ mtx_lock(&hio_send_list_lock);
+ while ((hio = TAILQ_FIRST(&hio_send_list)) == NULL) {
+ pjdlog_debug(2, "send: No requests, waiting.");
+ cv_wait(&hio_send_list_cond, &hio_send_list_lock);
+ }
+ TAILQ_REMOVE(&hio_send_list, hio, hio_next);
+ mtx_unlock(&hio_send_list_lock);
+ reqlog(LOG_DEBUG, 2, -1, hio, "send: (%p) Got request: ", hio);
+ nvout = nv_alloc();
+ /* Copy sequence number. */
+ nv_add_uint64(nvout, nv_get_uint64(hio->hio_nv, "seq"), "seq");
+ switch (hio->hio_cmd) {
+ case HIO_READ:
+ if (hio->hio_error == 0) {
+ data = hio->hio_data;
+ length = hio->hio_length;
+ break;
+ }
+ /*
+ * We send no data in case of an error.
+ */
+ /* FALLTHROUGH */
+ case HIO_DELETE:
+ case HIO_FLUSH:
+ case HIO_WRITE:
+ data = NULL;
+ length = 0;
+ break;
+ default:
+ abort();
+ break;
+ }
+ if (hio->hio_error != 0)
+ nv_add_int16(nvout, hio->hio_error, "error");
+ if (hast_proto_send(res, res->hr_remoteout, nvout, data,
+ length) < 0) {
+ pjdlog_exit(EX_TEMPFAIL, "Unable to send reply.");
+ }
+ nv_free(nvout);
+ pjdlog_debug(2, "disk: (%p) Moving request to the free queue.",
+ hio);
+ nv_free(hio->hio_nv);
+ hio->hio_error = 0;
+ mtx_lock(&hio_free_list_lock);
+ wakeup = TAILQ_EMPTY(&hio_free_list);
+ TAILQ_INSERT_TAIL(&hio_free_list, hio, hio_next);
+ mtx_unlock(&hio_free_list_lock);
+ if (wakeup)
+ cv_signal(&hio_free_list_cond);
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
diff --git a/sbin/hastd/subr.c b/sbin/hastd/subr.c
new file mode 100644
index 0000000..16ea93f
--- /dev/null
+++ b/sbin/hastd/subr.c
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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/types.h>
+#include <sys/disk.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <pjdlog.h>
+
+#include "hast.h"
+#include "subr.h"
+
+int
+provinfo(struct hast_resource *res, bool dowrite)
+{
+ struct stat sb;
+
+ assert(res->hr_localpath != NULL && res->hr_localpath[0] != '\0');
+
+ if (res->hr_localfd == -1) {
+ res->hr_localfd = open(res->hr_localpath,
+ dowrite ? O_RDWR : O_RDONLY);
+ if (res->hr_localfd < 0) {
+ KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to open %s",
+ res->hr_localpath));
+ return (-1);
+ }
+ }
+ if (fstat(res->hr_localfd, &sb) < 0) {
+ KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to stat %s",
+ res->hr_localpath));
+ return (-1);
+ }
+ if (S_ISCHR(sb.st_mode)) {
+ /*
+ * If this is character device, it is most likely GEOM provider.
+ */
+ if (ioctl(res->hr_localfd, DIOCGMEDIASIZE,
+ &res->hr_local_mediasize) < 0) {
+ KEEP_ERRNO(pjdlog_errno(LOG_ERR,
+ "Unable obtain provider %s mediasize",
+ res->hr_localpath));
+ return (-1);
+ }
+ if (ioctl(res->hr_localfd, DIOCGSECTORSIZE,
+ &res->hr_local_sectorsize) < 0) {
+ KEEP_ERRNO(pjdlog_errno(LOG_ERR,
+ "Unable obtain provider %s sectorsize",
+ res->hr_localpath));
+ return (-1);
+ }
+ } else if (S_ISREG(sb.st_mode)) {
+ /*
+ * We also support regular files for which we hardcode
+ * sector size of 512 bytes.
+ */
+ res->hr_local_mediasize = sb.st_size;
+ res->hr_local_sectorsize = 512;
+ } else {
+ /*
+ * We support no other file types.
+ */
+ pjdlog_error("%s is neither GEOM provider nor regular file.",
+ res->hr_localpath);
+ errno = EFTYPE;
+ return (-1);
+ }
+ return (0);
+}
+
+const char *
+role2str(int role)
+{
+
+ switch (role) {
+ case HAST_ROLE_INIT:
+ return ("init");
+ case HAST_ROLE_PRIMARY:
+ return ("primary");
+ case HAST_ROLE_SECONDARY:
+ return ("secondary");
+ }
+ return ("unknown");
+}
diff --git a/sbin/hastd/subr.h b/sbin/hastd/subr.h
new file mode 100644
index 0000000..c486f5c
--- /dev/null
+++ b/sbin/hastd/subr.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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 _SUBR_H_
+#define _SUBR_H_
+
+#include <sys/types.h>
+#include <stdbool.h>
+
+#include "hast.h"
+
+#define KEEP_ERRNO(work) do { \
+ int _rerrno; \
+ \
+ _rerrno = errno; \
+ work; \
+ errno = _rerrno; \
+} while (0)
+
+int provinfo(struct hast_resource *res, bool dowrite);
+const char *role2str(int role);
+
+#endif /* !_SUBR_H_ */
diff --git a/sbin/hastd/synch.h b/sbin/hastd/synch.h
new file mode 100644
index 0000000..7269aea
--- /dev/null
+++ b/sbin/hastd/synch.h
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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 _SYNCH_H_
+#define _SYNCH_H_
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <time.h>
+
+static __inline void
+mtx_init(pthread_mutex_t *lock)
+{
+ int error;
+
+ error = pthread_mutex_init(lock, NULL);
+ assert(error == 0);
+}
+static __inline void
+mtx_lock(pthread_mutex_t *lock)
+{
+ int error;
+
+ error = pthread_mutex_lock(lock);
+ assert(error == 0);
+}
+static __inline bool
+mtx_trylock(pthread_mutex_t *lock)
+{
+ int error;
+
+ error = pthread_mutex_trylock(lock);
+ assert(error == 0 || error == EBUSY);
+ return (error == 0);
+}
+static __inline void
+mtx_unlock(pthread_mutex_t *lock)
+{
+ int error;
+
+ error = pthread_mutex_unlock(lock);
+ assert(error == 0);
+}
+
+static __inline void
+rw_init(pthread_rwlock_t *lock)
+{
+ int error;
+
+ error = pthread_rwlock_init(lock, NULL);
+ assert(error == 0);
+}
+static __inline void
+rw_rlock(pthread_rwlock_t *lock)
+{
+ int error;
+
+ error = pthread_rwlock_rdlock(lock);
+ assert(error == 0);
+}
+static __inline void
+rw_wlock(pthread_rwlock_t *lock)
+{
+ int error;
+
+ error = pthread_rwlock_wrlock(lock);
+ assert(error == 0);
+}
+static __inline void
+rw_unlock(pthread_rwlock_t *lock)
+{
+ int error;
+
+ error = pthread_rwlock_unlock(lock);
+ assert(error == 0);
+}
+
+static __inline void
+cv_init(pthread_cond_t *cv)
+{
+ pthread_condattr_t attr;
+ int error;
+
+ error = pthread_condattr_init(&attr);
+ assert(error == 0);
+ error = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+ assert(error == 0);
+ error = pthread_cond_init(cv, &attr);
+ assert(error == 0);
+}
+static __inline void
+cv_wait(pthread_cond_t *cv, pthread_mutex_t *lock)
+{
+ int error;
+
+ error = pthread_cond_wait(cv, lock);
+ assert(error == 0);
+}
+static __inline bool
+cv_timedwait(pthread_cond_t *cv, pthread_mutex_t *lock, int timeout)
+{
+ struct timespec ts;
+ int error;
+
+ if (timeout == 0) {
+ cv_wait(cv, lock);
+ return (false);
+ }
+
+ error = clock_gettime(CLOCK_MONOTONIC, &ts);
+ assert(error == 0);
+ ts.tv_sec += timeout;
+ error = pthread_cond_timedwait(cv, lock, &ts);
+ assert(error == 0 || error == ETIMEDOUT);
+ return (error == ETIMEDOUT);
+}
+static __inline void
+cv_signal(pthread_cond_t *cv)
+{
+ int error;
+
+ error = pthread_cond_signal(cv);
+ assert(error == 0);
+}
+static __inline void
+cv_broadcast(pthread_cond_t *cv)
+{
+ int error;
+
+ error = pthread_cond_broadcast(cv);
+ assert(error == 0);
+}
+#endif /* !_SYNCH_H_ */
diff --git a/sbin/hastd/token.l b/sbin/hastd/token.l
new file mode 100644
index 0000000..7b80384
--- /dev/null
+++ b/sbin/hastd/token.l
@@ -0,0 +1,66 @@
+%{
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 AUTHORS 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 AUTHORS 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$
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "hast.h"
+
+#include "y.tab.h"
+
+int depth;
+int lineno;
+
+#define DP do { } while (0)
+%}
+
+%%
+control { DP; return CONTROL; }
+listen { DP; return LISTEN; }
+port { DP; return PORT; }
+replication { DP; return REPLICATION; }
+resource { DP; return RESOURCE; }
+name { DP; return NAME; }
+local { DP; return LOCAL; }
+remote { DP; return REMOTE; }
+on { DP; return ON; }
+fullsync { DP; return FULLSYNC; }
+memsync { DP; return MEMSYNC; }
+async { DP; return ASYNC; }
+[0-9]+ { DP; yylval.num = atoi(yytext); return NUM; }
+[a-zA-Z0-9\.\-_/\:]+ { DP; yylval.str = strdup(yytext); return STR; }
+\{ { DP; depth++; return OB; }
+\} { DP; depth--; return CB; }
+#.*$ /* ignore comments */;
+\n { lineno++; }
+[ \t]+ /* ignore whitespace */;
+%%
diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile
index 8fd21ae..77491f2 100644
--- a/sbin/ifconfig/Makefile
+++ b/sbin/ifconfig/Makefile
@@ -28,7 +28,7 @@ SRCS+= ifgre.c # GRE keys etc
SRCS+= ifgif.c # GIF reversed header workaround
SRCS+= ifieee80211.c regdomain.c # SIOC[GS]IEEE80211 support
-DPADD+= ${LIBBSDXML} ${LIBSBUF} ${LIBJAIL}
+DPADD+= ${LIBBSDXML} ${LIBJAIL} ${LIBSBUF}
LDADD+= -lbsdxml -ljail -lsbuf
SRCS+= ifcarp.c # SIOC[GS]VH support
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index 539cbdf..eafd5d8 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -28,7 +28,7 @@
.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94
.\" $FreeBSD$
.\"
-.Dd January 26, 2010
+.Dd February 20, 2010
.Dt IFCONFIG 8
.Os
.Sh NAME
@@ -408,20 +408,20 @@ they support in their capabilities.
is a synonym for enabling all available WOL mechanisms.
To disable WOL use
.Fl wol .
-.It Cm vlanmtu , vlanhwtag, vlanhwfilter
+.It Cm vlanmtu , vlanhwtag, vlanhwfilter, vlanhwtso
If the driver offers user-configurable VLAN support, enable
-reception of extended frames, tag processing in hardware, or
-frame filtering in hardware,
+reception of extended frames, tag processing in hardware,
+frame filtering in hardware, or TSO on VLAN,
respectively.
Note that this must be issued on a physical interface associated with
.Xr vlan 4 ,
not on a
.Xr vlan 4
interface itself.
-.It Fl vlanmtu , vlanhwtag, vlanhwfilter
+.It Fl vlanmtu , vlanhwtag, vlanhwfilter, vlanhwtso
If the driver offers user-configurable VLAN support, disable
-reception of extended frames, tag processing in hardware, or
-frame filtering in hardware,
+reception of extended frames, tag processing in hardware,
+frame filtering in hardware, or TSO on VLAN,
respectively.
.It Cm vnet Ar jail
Move the interface to the
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 5dc0871..aebcdc0 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -881,7 +881,7 @@ unsetifdescr(const char *val, int value, int s, const struct afswtch *afp)
#define IFCAPBITS \
"\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \
"\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO\14WOL_UCAST\15WOL_MCAST\16WOL_MAGIC" \
-"\21VLAN_HWFILTER"
+"\21VLAN_HWFILTER\23VLAN_HWTSO"
/*
* Print the status of the interface. If an address family was
diff --git a/sbin/ifconfig/ifvlan.c b/sbin/ifconfig/ifvlan.c
index c59cac1..3000585 100644
--- a/sbin/ifconfig/ifvlan.c
+++ b/sbin/ifconfig/ifvlan.c
@@ -181,6 +181,8 @@ static struct cmd vlan_cmds[] = {
DEF_CMD("-vlanhwtag", -IFCAP_VLAN_HWTAGGING, setifcap),
DEF_CMD("vlanhwfilter", IFCAP_VLAN_HWFILTER, setifcap),
DEF_CMD("-vlanhwfilter", -IFCAP_VLAN_HWFILTER, setifcap),
+ DEF_CMD("-vlanhwtso", -IFCAP_VLAN_HWTSO, setifcap),
+ DEF_CMD("vlanhwtso", IFCAP_VLAN_HWTSO, setifcap),
};
static struct afswtch af_vlan = {
.af_name = "af_vlan",
diff --git a/sbin/ipf/ipftest/Makefile b/sbin/ipf/ipftest/Makefile
index 8903f25..d089b2b 100644
--- a/sbin/ipf/ipftest/Makefile
+++ b/sbin/ipf/ipftest/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-WARNS=0
-
PROG= ipftest
SRCS= ${GENHDRS} ipftest.c fil.c ip_frag.c ip_state.c ip_nat.c \
ip_proxy.c ip_auth.c ip_htable.c ip_lookup.c \
@@ -10,6 +8,7 @@ SRCS= ${GENHDRS} ipftest.c fil.c ip_frag.c ip_state.c ip_nat.c \
ipf_l.c ipnat_y.c ipnat_l.c md5.c radix.c bpf_filter.c
MAN= ipftest.1
+WARNS?= 0
CFLAGS+= -DIPFILTER_LOG -DIPFILTER_COMPILED -DIPFILTER_LOOKUP \
-DIPFILTER_SCAN -DIPFILTER_SYNC -DIPFILTER_CKSUM -I.
diff --git a/sbin/ipfw/altq.c b/sbin/ipfw/altq.c
index b00a1e0..8cf19e5 100644
--- a/sbin/ipfw/altq.c
+++ b/sbin/ipfw/altq.c
@@ -39,6 +39,7 @@
#include <net/if.h> /* IFNAMSIZ */
#include <net/pfvar.h>
+#include <netinet/in.h> /* in_addr */
#include <netinet/ip_fw.h>
/*
diff --git a/sbin/ipfw/dummynet.c b/sbin/ipfw/dummynet.c
index 490aa53..68b2220 100644
--- a/sbin/ipfw/dummynet.c
+++ b/sbin/ipfw/dummynet.c
@@ -1,10 +1,5 @@
/*
- * Copyright (c) 2002-2003 Luigi Rizzo
- * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
- * Copyright (c) 1994 Ugen J.S.Antsilevich
- *
- * Idea and grammar partially left from:
- * Copyright (c) 1993 Daniel Boulet
+ * Copyright (c) 2002-2003,2010 Luigi Rizzo
*
* Redistribution and use in source forms, with and without modification,
* are permitted provided that this entire comment appears intact.
@@ -24,7 +19,6 @@
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/queue.h>
/* XXX there are several sysctl leftover here */
#include <sys/sysctl.h>
@@ -46,6 +40,7 @@
#include <netinet/ip_dummynet.h>
#include <arpa/inet.h> /* inet_ntoa */
+
static struct _s_x dummynet_params[] = {
{ "plr", TOK_PLR },
{ "noerror", TOK_NOERROR },
@@ -56,27 +51,59 @@ static struct _s_x dummynet_params[] = {
{ "src-port", TOK_SRCPORT },
{ "proto", TOK_PROTO },
{ "weight", TOK_WEIGHT },
+ { "lmax", TOK_LMAX },
+ { "maxlen", TOK_LMAX },
{ "all", TOK_ALL },
- { "mask", TOK_MASK },
+ { "mask", TOK_MASK }, /* alias for both */
+ { "sched_mask", TOK_SCHED_MASK },
+ { "flow_mask", TOK_FLOW_MASK },
{ "droptail", TOK_DROPTAIL },
{ "red", TOK_RED },
{ "gred", TOK_GRED },
{ "bw", TOK_BW },
{ "bandwidth", TOK_BW },
{ "delay", TOK_DELAY },
+ { "link", TOK_LINK },
{ "pipe", TOK_PIPE },
{ "queue", TOK_QUEUE },
+ { "flowset", TOK_FLOWSET },
+ { "sched", TOK_SCHED },
+ { "pri", TOK_PRI },
+ { "priority", TOK_PRI },
+ { "type", TOK_TYPE },
{ "flow-id", TOK_FLOWID},
{ "dst-ipv6", TOK_DSTIP6},
{ "dst-ip6", TOK_DSTIP6},
{ "src-ipv6", TOK_SRCIP6},
{ "src-ip6", TOK_SRCIP6},
- { "profile", TOK_PIPE_PROFILE},
+ { "profile", TOK_PROFILE},
{ "burst", TOK_BURST},
{ "dummynet-params", TOK_NULL },
{ NULL, 0 } /* terminator */
};
+#define O_NEXT(p, len) ((void *)((char *)p + len))
+
+static void
+oid_fill(struct dn_id *oid, int len, int type, uintptr_t id)
+{
+ oid->len = len;
+ oid->type = type;
+ oid->subtype = 0;
+ oid->id = id;
+}
+
+/* make room in the buffer and move the pointer forward */
+static void *
+o_next(struct dn_id **o, int len, int type)
+{
+ struct dn_id *ret = *o;
+ oid_fill(ret, len, type, 0);
+ *o = O_NEXT(*o, len);
+ return ret;
+}
+
+#if 0
static int
sort_q(void *arg, const void *pa, const void *pb)
{
@@ -108,117 +135,81 @@ sort_q(void *arg, const void *pa, const void *pb)
res = 1;
return (int)(rev ? res : -res);
}
+#endif
+/* print a mask and header for the subsequent list of flows */
static void
-list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
+print_mask(struct ipfw_flow_id *id)
+{
+ if (!IS_IP6_FLOW_ID(id)) {
+ printf(" "
+ "mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
+ id->proto,
+ id->src_ip, id->src_port,
+ id->dst_ip, id->dst_port);
+
+ printf("BKT Prot ___Source IP/port____ "
+ "____Dest. IP/port____ "
+ "Tot_pkt/bytes Pkt/Byte Drp\n");
+ } else {
+ char buf[255];
+ printf("\n mask: proto: 0x%02x, flow_id: 0x%08x, ",
+ id->proto, id->flow_id6);
+ inet_ntop(AF_INET6, &(id->src_ip6), buf, sizeof(buf));
+ printf("%s/0x%04x -> ", buf, id->src_port);
+ inet_ntop(AF_INET6, &(id->dst_ip6), buf, sizeof(buf));
+ printf("%s/0x%04x\n", buf, id->dst_port);
+
+ printf("BKT ___Prot___ _flow-id_ "
+ "______________Source IPv6/port_______________ "
+ "_______________Dest. IPv6/port_______________ "
+ "Tot_pkt/bytes Pkt/Byte Drp\n");
+ }
+}
+
+static void
+list_flow(struct dn_flow *ni)
{
- int l;
- int index_printed, indexes = 0;
char buff[255];
struct protoent *pe;
+ struct in_addr ina;
+ struct ipfw_flow_id *id = &ni->fid;
- if (fs->rq_elements == 0)
- return;
-
- if (co.do_sort != 0)
- qsort_r(q, fs->rq_elements, sizeof *q, NULL, sort_q);
-
- /* Print IPv4 flows */
- index_printed = 0;
- for (l = 0; l < fs->rq_elements; l++) {
- struct in_addr ina;
-
+ pe = getprotobynumber(id->proto);
/* XXX: Should check for IPv4 flows */
- if (IS_IP6_FLOW_ID(&(q[l].id)))
- continue;
-
- if (!index_printed) {
- index_printed = 1;
- if (indexes > 0) /* currently a no-op */
- printf("\n");
- indexes++;
- printf(" "
- "mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
- fs->flow_mask.proto,
- fs->flow_mask.src_ip, fs->flow_mask.src_port,
- fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
-
- printf("BKT Prot ___Source IP/port____ "
- "____Dest. IP/port____ "
- "Tot_pkt/bytes Pkt/Byte Drp\n");
- }
-
- printf("%3d ", q[l].hash_slot);
- pe = getprotobynumber(q[l].id.proto);
+ printf("%3u ", (ni->oid.id) & 0xff);
+ if (!IS_IP6_FLOW_ID(id)) {
if (pe)
printf("%-4s ", pe->p_name);
else
- printf("%4u ", q[l].id.proto);
- ina.s_addr = htonl(q[l].id.src_ip);
+ printf("%4u ", id->proto);
+ ina.s_addr = htonl(id->src_ip);
printf("%15s/%-5d ",
- inet_ntoa(ina), q[l].id.src_port);
- ina.s_addr = htonl(q[l].id.dst_ip);
+ inet_ntoa(ina), id->src_port);
+ ina.s_addr = htonl(id->dst_ip);
printf("%15s/%-5d ",
- inet_ntoa(ina), q[l].id.dst_port);
- printf("%4llu %8llu %2u %4u %3u\n",
- align_uint64(&q[l].tot_pkts),
- align_uint64(&q[l].tot_bytes),
- q[l].len, q[l].len_bytes, q[l].drops);
- if (co.verbose)
- printf(" S %20llu F %20llu\n",
- align_uint64(&q[l].S), align_uint64(&q[l].F));
- }
-
- /* Print IPv6 flows */
- index_printed = 0;
- for (l = 0; l < fs->rq_elements; l++) {
- if (!IS_IP6_FLOW_ID(&(q[l].id)))
- continue;
-
- if (!index_printed) {
- index_printed = 1;
- if (indexes > 0)
- printf("\n");
- indexes++;
- printf("\n mask: proto: 0x%02x, flow_id: 0x%08x, ",
- fs->flow_mask.proto, fs->flow_mask.flow_id6);
- inet_ntop(AF_INET6, &(fs->flow_mask.src_ip6),
- buff, sizeof(buff));
- printf("%s/0x%04x -> ", buff, fs->flow_mask.src_port);
- inet_ntop( AF_INET6, &(fs->flow_mask.dst_ip6),
- buff, sizeof(buff) );
- printf("%s/0x%04x\n", buff, fs->flow_mask.dst_port);
-
- printf("BKT ___Prot___ _flow-id_ "
- "______________Source IPv6/port_______________ "
- "_______________Dest. IPv6/port_______________ "
- "Tot_pkt/bytes Pkt/Byte Drp\n");
- }
- printf("%3d ", q[l].hash_slot);
- pe = getprotobynumber(q[l].id.proto);
+ inet_ntoa(ina), id->dst_port);
+ } else {
+ /* Print IPv6 flows */
if (pe != NULL)
printf("%9s ", pe->p_name);
else
- printf("%9u ", q[l].id.proto);
- printf("%7d %39s/%-5d ", q[l].id.flow_id6,
- inet_ntop(AF_INET6, &(q[l].id.src_ip6), buff, sizeof(buff)),
- q[l].id.src_port);
+ printf("%9u ", id->proto);
+ printf("%7d %39s/%-5d ", id->flow_id6,
+ inet_ntop(AF_INET6, &(id->src_ip6), buff, sizeof(buff)),
+ id->src_port);
printf(" %39s/%-5d ",
- inet_ntop(AF_INET6, &(q[l].id.dst_ip6), buff, sizeof(buff)),
- q[l].id.dst_port);
- printf(" %4llu %8llu %2u %4u %3u\n",
- align_uint64(&q[l].tot_pkts),
- align_uint64(&q[l].tot_bytes),
- q[l].len, q[l].len_bytes, q[l].drops);
- if (co.verbose)
- printf(" S %20llu F %20llu\n",
- align_uint64(&q[l].S),
- align_uint64(&q[l].F));
+ inet_ntop(AF_INET6, &(id->dst_ip6), buff, sizeof(buff)),
+ id->dst_port);
}
+ printf("%4llu %8llu %2u %4u %3u\n",
+ align_uint64(&ni->tot_pkts),
+ align_uint64(&ni->tot_bytes),
+ ni->length, ni->len_bytes, ni->drops);
}
static void
-print_flowset_parms(struct dn_flow_set *fs, char *prefix)
+print_flowset_parms(struct dn_fs *fs, char *prefix)
{
int l;
char qs[30];
@@ -226,7 +217,7 @@ print_flowset_parms(struct dn_flow_set *fs, char *prefix)
char red[90]; /* Display RED parameters */
l = fs->qsize;
- if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
+ if (fs->flags & DN_QSIZE_BYTES) {
if (l >= 8192)
sprintf(qs, "%d KB", l / 1024);
else
@@ -237,23 +228,34 @@ print_flowset_parms(struct dn_flow_set *fs, char *prefix)
sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
else
plr[0] = '\0';
- if (fs->flags_fs & DN_IS_RED) /* RED parameters */
+
+ if (fs->flags & DN_IS_RED) /* RED parameters */
sprintf(red,
"\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
- (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
+ (fs->flags & DN_IS_GENTLE_RED) ? 'G' : ' ',
1.0 * fs->w_q / (double)(1 << SCALE_RED),
- SCALE_VAL(fs->min_th),
- SCALE_VAL(fs->max_th),
+ fs->min_th,
+ fs->max_th,
1.0 * fs->max_p / (double)(1 << SCALE_RED));
else
sprintf(red, "droptail");
- printf("%s %s%s %d queues (%d buckets) %s\n",
- prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
+ if (prefix[0]) {
+ printf("%s %s%s %d queues (%d buckets) %s\n",
+ prefix, qs, plr, fs->oid.id, fs->buckets, red);
+ prefix[0] = '\0';
+ } else {
+ printf("q%05d %s%s %d flows (%d buckets) sched %d "
+ "weight %d lmax %d pri %d %s\n",
+ fs->fs_nr, qs, plr, fs->oid.id, fs->buckets,
+ fs->sched_nr, fs->par[0], fs->par[1], fs->par[2], red);
+ if (fs->flags & DN_HAVE_MASK)
+ print_mask(&fs->flow_mask);
+ }
}
static void
-print_extra_delay_parms(struct dn_pipe *p)
+print_extra_delay_parms(struct dn_profile *p)
{
double loss;
if (p->samples_no <= 0)
@@ -265,105 +267,126 @@ print_extra_delay_parms(struct dn_pipe *p)
p->name, loss, p->samples_no);
}
-void
-ipfw_list_pipes(void *data, uint nbytes, int ac, char *av[])
+static void
+flush_buf(char *buf)
{
- int rulenum;
- void *next = data;
- struct dn_pipe *p = (struct dn_pipe *) data;
- struct dn_flow_set *fs;
- struct dn_flow_queue *q;
- int l;
-
- if (ac > 0)
- rulenum = strtoul(*av++, NULL, 10);
- else
- rulenum = 0;
- for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) {
- double b = p->bandwidth;
- char buf[30];
- char prefix[80];
- char burst[5 + 7];
-
- if (SLIST_NEXT(p, next) != (struct dn_pipe *)DN_IS_PIPE)
- break; /* done with pipes, now queues */
-
- /*
- * compute length, as pipe have variable size
- */
- l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
- next = (char *)p + l;
- nbytes -= l;
-
- if ((rulenum != 0 && rulenum != p->pipe_nr) || co.do_pipe == 2)
- continue;
-
- /*
- * Print rate (or clocking interface)
- */
- if (p->if_name[0] != '\0')
- sprintf(buf, "%s", p->if_name);
- else if (b == 0)
- sprintf(buf, "unlimited");
- else if (b >= 1000000)
- sprintf(buf, "%7.3f Mbit/s", b/1000000);
- else if (b >= 1000)
- sprintf(buf, "%7.3f Kbit/s", b/1000);
- else
- sprintf(buf, "%7.3f bit/s ", b);
-
- sprintf(prefix, "%05d: %s %4d ms ",
- p->pipe_nr, buf, p->delay);
-
- print_flowset_parms(&(p->fs), prefix);
-
- if (humanize_number(burst, sizeof(burst), p->burst,
- "Byte", HN_AUTOSCALE, 0) < 0 || co.verbose)
- printf("\t burst: %ju Byte\n", p->burst);
- else
- printf("\t burst: %s\n", burst);
-
- print_extra_delay_parms(p);
-
- q = (struct dn_flow_queue *)(p+1);
- list_queues(&(p->fs), q);
- }
- for (fs = next; nbytes >= sizeof *fs; fs = next) {
- char prefix[80];
-
- if (SLIST_NEXT(fs, next) != (struct dn_flow_set *)DN_IS_QUEUE)
- break;
- l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
- next = (char *)fs + l;
- nbytes -= l;
-
- if (rulenum != 0 && ((rulenum != fs->fs_nr && co.do_pipe == 2) ||
- (rulenum != fs->parent_nr && co.do_pipe == 1))) {
- continue;
- }
-
- q = (struct dn_flow_queue *)(fs+1);
- sprintf(prefix, "q%05d: weight %d pipe %d ",
- fs->fs_nr, fs->weight, fs->parent_nr);
- print_flowset_parms(fs, prefix);
- list_queues(fs, q);
+ if (buf[0])
+ printf("%s\n", buf);
+ buf[0] = '\0';
+}
+
+/*
+ * generic list routine. We expect objects in a specific order, i.e.
+ * PIPES AND SCHEDULERS:
+ * link; scheduler; internal flowset if any; instances
+ * we can tell a pipe from the number.
+ *
+ * FLOWSETS:
+ * flowset; queues;
+ * link i (int queue); scheduler i; si(i) { flowsets() : queues }
+ */
+static void
+list_pipes(struct dn_id *oid, struct dn_id *end)
+{
+ char buf[160]; /* pending buffer */
+ buf[0] = '\0';
+
+ for (; oid != end; oid = O_NEXT(oid, oid->len)) {
+ if (oid->len < sizeof(*oid))
+ errx(1, "invalid oid len %d\n", oid->len);
+
+ switch (oid->type) {
+ default:
+ flush_buf(buf);
+ printf("unrecognized object %d size %d\n", oid->type, oid->len);
+ break;
+ case DN_TEXT: /* list of attached flowsets */
+ {
+ int i, l;
+ struct {
+ struct dn_id id;
+ uint32_t p[0];
+ } *d = (void *)oid;
+ l = (oid->len - sizeof(*oid))/sizeof(d->p[0]);
+ if (l == 0)
+ break;
+ printf(" Children flowsets: ");
+ for (i = 0; i < l; i++)
+ printf("%u ", d->p[i]);
+ printf("\n");
+ break;
+ }
+ case DN_CMD_GET:
+ if (co.verbose)
+ printf("answer for cmd %d, len %d\n", oid->type, oid->id);
+ break;
+ case DN_SCH: {
+ struct dn_sch *s = (struct dn_sch *)oid;
+ flush_buf(buf);
+ printf(" sched %d type %s flags 0x%x %d buckets %d active\n",
+ s->sched_nr,
+ s->name, s->flags, s->buckets, s->oid.id);
+ if (s->flags & DN_HAVE_MASK)
+ print_mask(&s->sched_mask);
+ }
+ break;
+
+ case DN_FLOW:
+ list_flow((struct dn_flow *)oid);
+ break;
+
+ case DN_LINK: {
+ struct dn_link *p = (struct dn_link *)oid;
+ double b = p->bandwidth;
+ char bwbuf[30];
+ char burst[5 + 7];
+
+ /* This starts a new object so flush buffer */
+ flush_buf(buf);
+ /* data rate */
+ if (b == 0)
+ sprintf(bwbuf, "unlimited ");
+ else if (b >= 1000000)
+ sprintf(bwbuf, "%7.3f Mbit/s", b/1000000);
+ else if (b >= 1000)
+ sprintf(bwbuf, "%7.3f Kbit/s", b/1000);
+ else
+ sprintf(bwbuf, "%7.3f bit/s ", b);
+
+ if (humanize_number(burst, sizeof(burst), p->burst,
+ "", HN_AUTOSCALE, 0) < 0 || co.verbose)
+ sprintf(burst, "%d", (int)p->burst);
+ sprintf(buf, "%05d: %s %4d ms burst %s",
+ p->link_nr % DN_MAX_ID, bwbuf, p->delay, burst);
+ }
+ break;
+
+ case DN_FS:
+ print_flowset_parms((struct dn_fs *)oid, buf);
+ break;
+ case DN_PROFILE:
+ flush_buf(buf);
+ print_extra_delay_parms((struct dn_profile *)oid);
}
+ flush_buf(buf); // XXX does it really go here ?
+ }
}
/*
- * Delete pipe or queue i
+ * Delete pipe, queue or scheduler i
*/
int
-ipfw_delete_pipe(int pipe_or_queue, int i)
+ipfw_delete_pipe(int do_pipe, int i)
{
- struct dn_pipe p;
-
- memset(&p, 0, sizeof p);
- if (pipe_or_queue == 1)
- p.pipe_nr = i; /* pipe */
- else
- p.fs.fs_nr = i; /* queue */
- i = do_cmd(IP_DUMMYNET_DEL, &p, sizeof p);
+ struct {
+ struct dn_id oid;
+ uintptr_t a[1]; /* add more if we want a list */
+ } cmd;
+ oid_fill((void *)&cmd, sizeof(cmd), DN_CMD_DELETE, DN_API_VERSION);
+ cmd.oid.subtype = (do_pipe == 1) ? DN_LINK :
+ ( (do_pipe == 2) ? DN_FS : DN_SCH);
+ cmd.a[0] = i;
+ i = do_cmd(IP_DUMMYNET3, &cmd, cmd.oid.len);
if (i) {
i = 1;
warn("rule %u: setsockopt(IP_DUMMYNET_DEL)", i);
@@ -400,7 +423,7 @@ ipfw_delete_pipe(int pipe_or_queue, int i)
* The empirical curve may have both vertical and horizontal lines.
* Vertical lines represent constant delay for a range of
* probabilities; horizontal lines correspond to a discontinuty
- * in the delay distribution: the pipe will use the largest delay
+ * in the delay distribution: the link will use the largest delay
* for a given probability.
*
* To pass the curve to dummynet, we must store the parameters
@@ -490,9 +513,12 @@ static void
read_bandwidth(char *arg, int *bandwidth, char *if_name, int namelen)
{
if (*bandwidth != -1)
- warn("duplicate token, override bandwidth value!");
+ warnx("duplicate token, override bandwidth value!");
if (arg[0] >= 'a' && arg[0] <= 'z') {
+ if (!if_name) {
+ errx(1, "no if support");
+ }
if (namelen >= IFNAMSIZ)
warn("interface name truncated");
namelen--;
@@ -521,7 +547,8 @@ read_bandwidth(char *arg, int *bandwidth, char *if_name, int namelen)
errx(EX_DATAERR, "bandwidth too large");
*bandwidth = bw;
- if_name[0] = '\0';
+ if (if_name)
+ if_name[0] = '\0';
}
}
@@ -551,7 +578,8 @@ compare_points(const void *vp1, const void *vp2)
#define ED_EFMT(s) EX_DATAERR,"error in %s at line %d: "#s,filename,lineno
static void
-load_extra_delays(const char *filename, struct dn_pipe *p)
+load_extra_delays(const char *filename, struct dn_profile *p,
+ struct dn_link *link)
{
char line[ED_MAX_LINE_LEN];
FILE *f;
@@ -566,6 +594,9 @@ load_extra_delays(const char *filename, struct dn_pipe *p)
struct point points[ED_MAX_SAMPLES_NO];
int points_no = 0;
+ /* XXX link never NULL? */
+ p->link_nr = link->link_nr;
+
profile_name[0] = '\0';
f = fopen(filename, "r");
if (f == NULL)
@@ -606,7 +637,8 @@ load_extra_delays(const char *filename, struct dn_pipe *p)
ED_MAX_SAMPLES_NO);
do_points = 0;
} else if (!strcasecmp(name, ED_TOK_BW)) {
- read_bandwidth(arg, &p->bandwidth, p->if_name, sizeof(p->if_name));
+ char buf[IFNAMSIZ];
+ read_bandwidth(arg, &link->bandwidth, buf, sizeof(buf));
} else if (!strcasecmp(name, ED_TOK_LOSS)) {
if (loss != -1.0)
errx(ED_EFMT("duplicated token: %s"), name);
@@ -676,17 +708,17 @@ load_extra_delays(const char *filename, struct dn_pipe *p)
double y2 = points[i+1].prob * samples;
double x2 = points[i+1].delay;
- int index = y1;
+ int ix = y1;
int stop = y2;
if (x1 == x2) {
- for (; index<stop; ++index)
- p->samples[index] = x1;
+ for (; ix<stop; ++ix)
+ p->samples[ix] = x1;
} else {
double m = (y2-y1)/(x2-x1);
double c = y1 - m*x1;
- for (; index<stop ; ++index)
- p->samples[index] = (index - c)/m;
+ for (; ix<stop ; ++ix)
+ p->samples[ix] = (ix - c)/m;
}
}
p->samples_no = samples;
@@ -694,27 +726,120 @@ load_extra_delays(const char *filename, struct dn_pipe *p)
strncpy(p->name, profile_name, sizeof(p->name));
}
+/*
+ * configuration of pipes, schedulers, flowsets.
+ * When we configure a new scheduler, an empty pipe is created, so:
+ *
+ * do_pipe = 1 -> "pipe N config ..." only for backward compatibility
+ * sched N+Delta type fifo sched_mask ...
+ * pipe N+Delta <parameters>
+ * flowset N+Delta pipe N+Delta (no parameters)
+ * sched N type wf2q+ sched_mask ...
+ * pipe N <parameters>
+ *
+ * do_pipe = 2 -> flowset N config
+ * flowset N parameters
+ *
+ * do_pipe = 3 -> sched N config
+ * sched N parameters (default no pipe)
+ * optional Pipe N config ...
+ * pipe ==>
+ */
void
ipfw_config_pipe(int ac, char **av)
{
- int samples[ED_MAX_SAMPLES_NO];
- struct dn_pipe p;
- int i;
+ int i, j;
char *end;
void *par = NULL;
-
- memset(&p, 0, sizeof p);
- p.bandwidth = -1;
+ struct dn_id *buf, *base;
+ struct dn_sch *sch = NULL;
+ struct dn_link *p = NULL;
+ struct dn_fs *fs = NULL;
+ struct dn_profile *pf = NULL;
+ struct ipfw_flow_id *mask = NULL;
+ int lmax;
+ uint32_t _foo = 0, *flags = &_foo , *buckets = &_foo;
+
+ /*
+ * allocate space for 1 header,
+ * 1 scheduler, 1 link, 1 flowset, 1 profile
+ */
+ lmax = sizeof(struct dn_id); /* command header */
+ lmax += sizeof(struct dn_sch) + sizeof(struct dn_link) +
+ sizeof(struct dn_fs) + sizeof(struct dn_profile);
av++; ac--;
/* Pipe number */
if (ac && isdigit(**av)) {
i = atoi(*av); av++; ac--;
- if (co.do_pipe == 1)
- p.pipe_nr = i;
- else
- p.fs.fs_nr = i;
+ } else
+ i = -1;
+ if (i <= 0)
+ errx(EX_USAGE, "need a pipe/flowset/sched number");
+ base = buf = safe_calloc(1, lmax);
+ /* all commands start with a 'CONFIGURE' and a version */
+ o_next(&buf, sizeof(struct dn_id), DN_CMD_CONFIG);
+ base->id = DN_API_VERSION;
+
+ switch (co.do_pipe) {
+ case 1: /* "pipe N config ..." */
+ /* Allocate space for the WF2Q+ scheduler, its link
+ * and the FIFO flowset. Set the number, but leave
+ * the scheduler subtype and other parameters to 0
+ * so the kernel will use appropriate defaults.
+ * XXX todo: add a flag to record if a parameter
+ * is actually configured.
+ * If we do a 'pipe config' mask -> sched_mask.
+ * The FIFO scheduler and link are derived from the
+ * WF2Q+ one in the kernel.
+ */
+ sch = o_next(&buf, sizeof(*sch), DN_SCH);
+ p = o_next(&buf, sizeof(*p), DN_LINK);
+ fs = o_next(&buf, sizeof(*fs), DN_FS);
+
+ sch->sched_nr = i;
+ sch->oid.subtype = 0; /* defaults to WF2Q+ */
+ mask = &sch->sched_mask;
+ flags = &sch->flags;
+ buckets = &sch->buckets;
+ *flags |= DN_PIPE_CMD;
+
+ p->link_nr = i;
+
+ /* This flowset is only for the FIFO scheduler */
+ fs->fs_nr = i + 2*DN_MAX_ID;
+ fs->sched_nr = i + DN_MAX_ID;
+ break;
+
+ case 2: /* "queue N config ... " */
+ fs = o_next(&buf, sizeof(*fs), DN_FS);
+ fs->fs_nr = i;
+ mask = &fs->flow_mask;
+ flags = &fs->flags;
+ buckets = &fs->buckets;
+ break;
+
+ case 3: /* "sched N config ..." */
+ sch = o_next(&buf, sizeof(*sch), DN_SCH);
+ fs = o_next(&buf, sizeof(*fs), DN_FS);
+ sch->sched_nr = i;
+ mask = &sch->sched_mask;
+ flags = &sch->flags;
+ buckets = &sch->buckets;
+ /* fs is used only with !MULTIQUEUE schedulers */
+ fs->fs_nr = i + DN_MAX_ID;
+ fs->sched_nr = i;
+ break;
}
+ /* set to -1 those fields for which we want to reuse existing
+ * values from the kernel.
+ * Also, *_nr and subtype = 0 mean reuse the value from the kernel.
+ * XXX todo: support reuse of the mask.
+ */
+ if (p)
+ p->bandwidth = -1;
+ for (j = 0; j < sizeof(fs->par)/sizeof(fs->par[0]); j++)
+ fs->par[j] = -1;
while (ac > 0) {
double d;
int tok = match_token(dummynet_params, *av);
@@ -722,41 +847,48 @@ ipfw_config_pipe(int ac, char **av)
switch(tok) {
case TOK_NOERROR:
- p.fs.flags_fs |= DN_NOERROR;
+ NEED(fs, "noerror is only for pipes");
+ fs->flags |= DN_NOERROR;
break;
case TOK_PLR:
+ NEED(fs, "plr is only for pipes");
NEED1("plr needs argument 0..1\n");
d = strtod(av[0], NULL);
if (d > 1)
d = 1;
else if (d < 0)
d = 0;
- p.fs.plr = (int)(d*0x7fffffff);
+ fs->plr = (int)(d*0x7fffffff);
ac--; av++;
break;
case TOK_QUEUE:
+ NEED(fs, "queue is only for pipes or flowsets");
NEED1("queue needs queue size\n");
end = NULL;
- p.fs.qsize = strtoul(av[0], &end, 0);
+ fs->qsize = strtoul(av[0], &end, 0);
if (*end == 'K' || *end == 'k') {
- p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
- p.fs.qsize *= 1024;
+ fs->flags |= DN_QSIZE_BYTES;
+ fs->qsize *= 1024;
} else if (*end == 'B' ||
_substrcmp2(end, "by", "bytes") == 0) {
- p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
+ fs->flags |= DN_QSIZE_BYTES;
}
ac--; av++;
break;
case TOK_BUCKETS:
+ NEED(fs, "buckets is only for pipes or flowsets");
NEED1("buckets needs argument\n");
- p.fs.rq_size = strtoul(av[0], NULL, 0);
+ *buckets = strtoul(av[0], NULL, 0);
ac--; av++;
break;
+ case TOK_FLOW_MASK:
+ case TOK_SCHED_MASK:
case TOK_MASK:
+ NEED(mask, "tok_mask");
NEED1("mask needs mask specifier\n");
/*
* per-flow queue, mask is dst_ip, dst_port,
@@ -764,7 +896,7 @@ ipfw_config_pipe(int ac, char **av)
*/
par = NULL;
- bzero(&p.fs.flow_mask, sizeof(p.fs.flow_mask));
+ bzero(mask, sizeof(*mask));
end = NULL;
while (ac >= 1) {
@@ -781,43 +913,48 @@ ipfw_config_pipe(int ac, char **av)
/*
* special case, all bits significant
*/
- p.fs.flow_mask.dst_ip = ~0;
- p.fs.flow_mask.src_ip = ~0;
- p.fs.flow_mask.dst_port = ~0;
- p.fs.flow_mask.src_port = ~0;
- p.fs.flow_mask.proto = ~0;
- n2mask(&(p.fs.flow_mask.dst_ip6), 128);
- n2mask(&(p.fs.flow_mask.src_ip6), 128);
- p.fs.flow_mask.flow_id6 = ~0;
- p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
+ mask->dst_ip = ~0;
+ mask->src_ip = ~0;
+ mask->dst_port = ~0;
+ mask->src_port = ~0;
+ mask->proto = ~0;
+ n2mask(&mask->dst_ip6, 128);
+ n2mask(&mask->src_ip6, 128);
+ mask->flow_id6 = ~0;
+ *flags |= DN_HAVE_MASK;
goto end_mask;
case TOK_DSTIP:
- p32 = &p.fs.flow_mask.dst_ip;
+ mask->addr_type = 4;
+ p32 = &mask->dst_ip;
break;
case TOK_SRCIP:
- p32 = &p.fs.flow_mask.src_ip;
+ mask->addr_type = 4;
+ p32 = &mask->src_ip;
break;
case TOK_DSTIP6:
- pa6 = &(p.fs.flow_mask.dst_ip6);
+ mask->addr_type = 6;
+ pa6 = &mask->dst_ip6;
break;
case TOK_SRCIP6:
- pa6 = &(p.fs.flow_mask.src_ip6);
+ mask->addr_type = 6;
+ pa6 = &mask->src_ip6;
break;
case TOK_FLOWID:
- p20 = &p.fs.flow_mask.flow_id6;
+ mask->addr_type = 6;
+ p20 = &mask->flow_id6;
break;
case TOK_DSTPORT:
- p16 = &p.fs.flow_mask.dst_port;
+ p16 = &mask->dst_port;
break;
case TOK_SRCPORT:
- p16 = &p.fs.flow_mask.src_port;
+ p16 = &mask->src_port;
break;
case TOK_PROTO:
@@ -857,10 +994,10 @@ ipfw_config_pipe(int ac, char **av)
if (a > 0xFF)
errx(EX_DATAERR,
"proto mask must be 8 bit");
- p.fs.flow_mask.proto = (uint8_t)a;
+ fs->flow_mask.proto = (uint8_t)a;
}
if (a != 0)
- p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
+ *flags |= DN_HAVE_MASK;
ac--; av++;
} /* end while, config masks */
end_mask:
@@ -869,9 +1006,9 @@ end_mask:
case TOK_RED:
case TOK_GRED:
NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
- p.fs.flags_fs |= DN_IS_RED;
+ fs->flags |= DN_IS_RED;
if (tok == TOK_GRED)
- p.fs.flags_fs |= DN_IS_GENTLE_RED;
+ fs->flags |= DN_IS_GENTLE_RED;
/*
* the format for parameters is w_q/min_th/max_th/max_p
*/
@@ -879,82 +1016,108 @@ end_mask:
double w_q = strtod(end, NULL);
if (w_q > 1 || w_q <= 0)
errx(EX_DATAERR, "0 < w_q <= 1");
- p.fs.w_q = (int) (w_q * (1 << SCALE_RED));
+ fs->w_q = (int) (w_q * (1 << SCALE_RED));
}
if ((end = strsep(&av[0], "/"))) {
- p.fs.min_th = strtoul(end, &end, 0);
+ fs->min_th = strtoul(end, &end, 0);
if (*end == 'K' || *end == 'k')
- p.fs.min_th *= 1024;
+ fs->min_th *= 1024;
}
if ((end = strsep(&av[0], "/"))) {
- p.fs.max_th = strtoul(end, &end, 0);
+ fs->max_th = strtoul(end, &end, 0);
if (*end == 'K' || *end == 'k')
- p.fs.max_th *= 1024;
+ fs->max_th *= 1024;
}
if ((end = strsep(&av[0], "/"))) {
double max_p = strtod(end, NULL);
if (max_p > 1 || max_p <= 0)
errx(EX_DATAERR, "0 < max_p <= 1");
- p.fs.max_p = (int)(max_p * (1 << SCALE_RED));
+ fs->max_p = (int)(max_p * (1 << SCALE_RED));
}
ac--; av++;
break;
case TOK_DROPTAIL:
- p.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
+ NEED(fs, "droptail is only for flowsets");
+ fs->flags &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
break;
case TOK_BW:
+ NEED(p, "bw is only for links");
NEED1("bw needs bandwidth or interface\n");
- if (co.do_pipe != 1)
- errx(EX_DATAERR, "bandwidth only valid for pipes");
- read_bandwidth(av[0], &p.bandwidth, p.if_name, sizeof(p.if_name));
+ read_bandwidth(av[0], &p->bandwidth, NULL, 0);
ac--; av++;
break;
case TOK_DELAY:
- if (co.do_pipe != 1)
- errx(EX_DATAERR, "delay only valid for pipes");
+ NEED(p, "delay is only for links");
NEED1("delay needs argument 0..10000ms\n");
- p.delay = strtoul(av[0], NULL, 0);
+ p->delay = strtoul(av[0], NULL, 0);
+ ac--; av++;
+ break;
+
+ case TOK_TYPE: {
+ int l;
+ NEED(sch, "type is only for schedulers");
+ NEED1("type needs a string");
+ l = strlen(av[0]);
+ if (l == 0 || l > 15)
+ errx(1, "type %s too long\n", av[0]);
+ strcpy(sch->name, av[0]);
+ sch->oid.subtype = 0; /* use string */
ac--; av++;
break;
+ }
case TOK_WEIGHT:
- if (co.do_pipe == 1)
- errx(EX_DATAERR,"weight only valid for queues");
- NEED1("weight needs argument 0..100\n");
- p.fs.weight = strtoul(av[0], &end, 0);
+ NEED(fs, "weight is only for flowsets");
+ NEED1("weight needs argument\n");
+ fs->par[0] = strtol(av[0], &end, 0);
+ ac--; av++;
+ break;
+
+ case TOK_LMAX:
+ NEED(fs, "lmax is only for flowsets");
+ NEED1("lmax needs argument\n");
+ fs->par[1] = strtol(av[0], &end, 0);
ac--; av++;
break;
+ case TOK_PRI:
+ NEED(fs, "priority is only for flowsets");
+ NEED1("priority needs argument\n");
+ fs->par[2] = strtol(av[0], &end, 0);
+ ac--; av++;
+ break;
+
+ case TOK_SCHED:
case TOK_PIPE:
- if (co.do_pipe == 1)
- errx(EX_DATAERR,"pipe only valid for queues");
- NEED1("pipe needs pipe_number\n");
- p.fs.parent_nr = strtoul(av[0], &end, 0);
+ NEED(fs, "pipe/sched");
+ NEED1("pipe/link/sched needs number\n");
+ fs->sched_nr = strtoul(av[0], &end, 0);
ac--; av++;
break;
- case TOK_PIPE_PROFILE:
- if (co.do_pipe != 1)
- errx(EX_DATAERR, "extra delay only valid for pipes");
+ case TOK_PROFILE:
+ NEED((!pf), "profile already set");
+ NEED(p, "profile");
+ {
NEED1("extra delay needs the file name\n");
- p.samples = &samples[0];
- load_extra_delays(av[0], &p);
+ pf = o_next(&buf, sizeof(*pf), DN_PROFILE);
+ load_extra_delays(av[0], pf, p); //XXX can't fail?
--ac; ++av;
+ }
break;
case TOK_BURST:
- if (co.do_pipe != 1)
- errx(EX_DATAERR, "burst only valid for pipes");
+ NEED(p, "burst");
NEED1("burst needs argument\n");
errno = 0;
- if (expand_number(av[0], (int64_t *)&p.burst) < 0)
+ if (expand_number(av[0], (int64_t *)&p->burst) < 0)
if (errno != ERANGE)
errx(EX_DATAERR,
"burst: invalid argument");
- if (errno || p.burst > (1ULL << 48) - 1)
+ if (errno || p->burst > (1ULL << 48) - 1)
errx(EX_DATAERR,
"burst: out of range (0..2^48-1)");
ac--; av++;
@@ -964,26 +1127,17 @@ end_mask:
errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]);
}
}
- if (co.do_pipe == 1) {
- if (p.pipe_nr == 0)
- errx(EX_DATAERR, "pipe_nr must be > 0");
- if (p.delay > 10000)
- errx(EX_DATAERR, "delay must be < 10000");
- } else { /* co.do_pipe == 2, queue */
- if (p.fs.parent_nr == 0)
- errx(EX_DATAERR, "pipe must be > 0");
- if (p.fs.weight >100)
- errx(EX_DATAERR, "weight must be <= 100");
- }
- /* check for bandwidth value */
- if (p.bandwidth == -1) {
- p.bandwidth = 0;
- if (p.samples_no > 0)
- errx(EX_DATAERR, "profile requires a bandwidth limit");
+ /* check validity of parameters */
+ if (p) {
+ if (p->delay > 10000)
+ errx(EX_DATAERR, "delay must be < 10000");
+ if (p->bandwidth == -1)
+ p->bandwidth = 0;
}
-
- if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) {
+ if (fs) {
+ /* XXX accept a 0 scheduler to keep the default */
+ if (fs->flags & DN_QSIZE_BYTES) {
size_t len;
long limit;
@@ -991,9 +1145,9 @@ end_mask:
if (sysctlbyname("net.inet.ip.dummynet.pipe_byte_limit",
&limit, &len, NULL, 0) == -1)
limit = 1024*1024;
- if (p.fs.qsize > limit)
+ if (fs->qsize > limit)
errx(EX_DATAERR, "queue size must be < %ldB", limit);
- } else {
+ } else {
size_t len;
long limit;
@@ -1001,27 +1155,25 @@ end_mask:
if (sysctlbyname("net.inet.ip.dummynet.pipe_slot_limit",
&limit, &len, NULL, 0) == -1)
limit = 100;
- if (p.fs.qsize > limit)
+ if (fs->qsize > limit)
errx(EX_DATAERR, "2 <= queue size <= %ld", limit);
- }
- if (p.fs.flags_fs & DN_IS_RED) {
+ }
+
+ if (fs->flags & DN_IS_RED) {
size_t len;
int lookup_depth, avg_pkt_size;
- double s, idle, weight, w_q;
- struct clockinfo ck;
- int t;
+ double w_q;
- if (p.fs.min_th >= p.fs.max_th)
+ if (fs->min_th >= fs->max_th)
errx(EX_DATAERR, "min_th %d must be < than max_th %d",
- p.fs.min_th, p.fs.max_th);
- if (p.fs.max_th == 0)
+ fs->min_th, fs->max_th);
+ if (fs->max_th == 0)
errx(EX_DATAERR, "max_th must be > 0");
len = sizeof(int);
if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
&lookup_depth, &len, NULL, 0) == -1)
- errx(1, "sysctlbyname(\"%s\")",
- "net.inet.ip.dummynet.red_lookup_depth");
+ lookup_depth = 256;
if (lookup_depth == 0)
errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
" must be greater than zero");
@@ -1029,18 +1181,13 @@ end_mask:
len = sizeof(int);
if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
&avg_pkt_size, &len, NULL, 0) == -1)
+ avg_pkt_size = 512;
- errx(1, "sysctlbyname(\"%s\")",
- "net.inet.ip.dummynet.red_avg_pkt_size");
if (avg_pkt_size == 0)
errx(EX_DATAERR,
"net.inet.ip.dummynet.red_avg_pkt_size must"
" be greater than zero");
- len = sizeof(struct clockinfo);
- if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1)
- errx(1, "sysctlbyname(\"%s\")", "kern.clockrate");
-
/*
* Ticks needed for sending a medium-sized packet.
* Unfortunately, when we are configuring a WF2Q+ queue, we
@@ -1050,38 +1197,77 @@ end_mask:
* correct. But on the other hand, why do we want RED with
* WF2Q+ ?
*/
+#if 0
if (p.bandwidth==0) /* this is a WF2Q+ queue */
s = 0;
else
s = (double)ck.hz * avg_pkt_size * 8 / p.bandwidth;
-
+#endif
/*
* max idle time (in ticks) before avg queue size becomes 0.
* NOTA: (3/w_q) is approx the value x so that
* (1-w_q)^x < 10^-3.
*/
- w_q = ((double)p.fs.w_q) / (1 << SCALE_RED);
+ w_q = ((double)fs->w_q) / (1 << SCALE_RED);
+#if 0 // go in kernel
idle = s * 3. / w_q;
- p.fs.lookup_step = (int)idle / lookup_depth;
- if (!p.fs.lookup_step)
- p.fs.lookup_step = 1;
+ fs->lookup_step = (int)idle / lookup_depth;
+ if (!fs->lookup_step)
+ fs->lookup_step = 1;
weight = 1 - w_q;
- for (t = p.fs.lookup_step; t > 1; --t)
+ for (t = fs->lookup_step; t > 1; --t)
weight *= 1 - w_q;
- p.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
+ fs->lookup_weight = (int)(weight * (1 << SCALE_RED));
+#endif
+ }
}
- if (p.samples_no <= 0) {
- i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, sizeof p);
- } else {
- struct dn_pipe_max pm;
- int len = sizeof(pm);
-
- memcpy(&pm.pipe, &p, sizeof(pm.pipe));
- memcpy(&pm.samples, samples, sizeof(pm.samples));
- i = do_cmd(IP_DUMMYNET_CONFIGURE, &pm, len);
- }
+ i = do_cmd(IP_DUMMYNET3, base, (char *)buf - (char *)base);
if (i)
err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
}
+
+void
+dummynet_flush(void)
+{
+ struct dn_id oid;
+ oid_fill(&oid, sizeof(oid), DN_CMD_FLUSH, DN_API_VERSION);
+ do_cmd(IP_DUMMYNET3, &oid, oid.len);
+}
+
+/* main entry point for dummynet list functions. co.do_pipe indicates
+ * which function we want to support.
+ * XXX todo- accept filtering arguments.
+ */
+void
+dummynet_list(int ac, char *av[], int show_counters)
+{
+ struct dn_id oid, *x;
+ int ret, l = sizeof(oid);
+
+ oid_fill(&oid, l, DN_CMD_GET, DN_API_VERSION);
+ switch (co.do_pipe) {
+ case 1:
+ oid.subtype = DN_LINK; /* list pipe */
+ break;
+ case 2:
+ oid.subtype = DN_FS; /* list queue */
+ break;
+ case 3:
+ oid.subtype = DN_SCH; /* list sched */
+ break;
+ }
+ ret = do_cmd(-IP_DUMMYNET3, &oid, (uintptr_t)&l);
+ // printf("%s returns %d need %d\n", __FUNCTION__, ret, oid.id);
+ if (ret != 0 || oid.id <= sizeof(oid))
+ return;
+ l = oid.id;
+ x = safe_calloc(1, l);
+ *x = oid;
+ ret = do_cmd(-IP_DUMMYNET3, x, (uintptr_t)&l);
+ // printf("%s returns %d need %d\n", __FUNCTION__, ret, oid.id);
+ // XXX filter on ac, av
+ list_pipes(x, O_NEXT(x, l));
+ free(x);
+}
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
index fc83ecc..d605d5e 100644
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -6,8 +6,10 @@
.Os
.Sh NAME
.Nm ipfw
-.Nd IP firewall and traffic shaper control program
+.Nd User interface for firewall, traffic shaper, packet scheduler,
+in-kernel NAT.
.Sh SYNOPSIS
+.Ss FIREWALL CONFIGURATION
.Nm
.Op Fl cq
.Cm add
@@ -26,12 +28,6 @@
.Op Cm set Ar N
.Brq Cm delete | zero | resetlog
.Op Ar number ...
-.Nm
-.Cm enable
-.Brq Cm firewall | altq | one_pass | debug | verbose | dyn_keepalive
-.Nm
-.Cm disable
-.Brq Cm firewall | altq | one_pass | debug | verbose | dyn_keepalive
.Pp
.Nm
.Cm set Oo Cm disable Ar number ... Oc Op Cm enable Ar number ...
@@ -43,8 +39,17 @@
.Cm set swap Ar number number
.Nm
.Cm set show
+.Ss SYSCTL SHORTCUTS
.Pp
.Nm
+.Cm enable
+.Brq Cm firewall | altq | one_pass | debug | verbose | dyn_keepalive
+.Nm
+.Cm disable
+.Brq Cm firewall | altq | one_pass | debug | verbose | dyn_keepalive
+.Pp
+.Ss LOOKUP TABLES
+.Nm
.Cm table Ar number Cm add Ar addr Ns Oo / Ns Ar masklen Oc Op Ar value
.Nm
.Cm table Ar number Cm delete Ar addr Ns Op / Ns Ar masklen
@@ -57,17 +62,19 @@
.Brq Ar number | all
.Cm list
.Pp
+.Ss DUMMYNET CONFIGURATION (TRAFFIC SHAPER AND PACKET SCHEDULER)
.Nm
-.Brq Cm pipe | queue
+.Brq Cm pipe | queue | sched
.Ar number
.Cm config
.Ar config-options
.Nm
.Op Fl s Op Ar field
-.Brq Cm pipe | queue
+.Brq Cm pipe | queue | sched
.Brq Cm delete | list | show
.Op Ar number ...
.Pp
+.Ss IN-KERNEL NAT
.Nm
.Op Fl q
.Cm nat
@@ -89,28 +96,27 @@ The
.Nm
utility is the user interface for controlling the
.Xr ipfw 4
-firewall and the
+firewall, the
.Xr dummynet 4
-traffic shaper in
-.Fx .
+traffic shaper/packet scheduler, and the
+in-kernel NAT services.
.Pp
-An
-.Nm
-configuration, or
+A firewall configuration, or
.Em ruleset ,
is made of a list of
.Em rules
numbered from 1 to 65535.
-Packets are passed to
-.Nm
+Packets are passed to the firewall
from a number of different places in the protocol stack
(depending on the source and destination of the packet,
-it is possible that
-.Nm
-is invoked multiple times on the same packet).
+it is possible for the firewall to be
+invoked multiple times on the same packet).
The packet passed to the firewall is compared
-against each of the rules in the firewall
-.Em ruleset .
+against each of the rules in the
+.Em ruleset ,
+in rule-number order
+(multiple rules with the same number are permitted, in which case
+they are processed in order of insertion).
When a match is found, the action corresponding to the
matching rule is performed.
.Pp
@@ -118,9 +124,7 @@ Depending on the action and certain system settings, packets
can be reinjected into the firewall at some rule after the
matching one for further processing.
.Pp
-An
-.Nm
-ruleset always includes a
+A ruleset always includes a
.Em default
rule (numbered 65535) which cannot be modified or deleted,
and matches all packets.
@@ -137,14 +141,14 @@ If the ruleset includes one or more rules with the
or
.Cm limit
option,
-.Nm
-will have a
+the firewall will have a
.Em stateful
-behaviour, i.e., upon a match it will create dynamic rules matching
-the exact parameters (source and destination addresses and ports)
-of the matching packet.
-.Pp
-These dynamic rules, which have a limited lifetime, are checked
+behaviour, i.e., upon a match it will create
+.Em dynamic rules ,
+i.e. rules that match packets with the same 5-tuple
+(protocol, source and destination addresses and ports)
+as the packet which caused their creation.
+Dynamic rules, which have a limited lifetime, are checked
at the first occurrence of a
.Cm check-state ,
.Cm keep-state
@@ -283,6 +287,7 @@ When listing, show last match timestamp as seconds from the epoch.
This form can be more convenient for postprocessing by scripts.
.El
.Pp
+.Ss LIST OF RULES AND PREPROCESSING
To ease configuration, rules can be put into a file which is
processed using
.Nm
@@ -322,14 +327,16 @@ This allows for flexible configuration files (like conditionalizing
them on the local hostname) and the use of macros to centralize
frequently required arguments like IP addresses.
.Pp
+.Ss TRAFFIC SHAPER CONFIGURATION
The
.Nm
-.Cm pipe
+.Cm pipe , queue
and
-.Cm queue
-commands are used to configure the traffic shaper, as shown in the
+.Cm sched
+commands are used to configure the traffic shaper and packet scheduler.
+See the
.Sx TRAFFIC SHAPER (DUMMYNET) CONFIGURATION
-Section below.
+Section below for details.
.Pp
If the world and the kernel get out of sync the
.Nm
@@ -362,7 +369,7 @@ have this picture in mind in order to design a correct ruleset.
| to devices |
.Ed
.Pp
-As can be noted from the above picture, the number of
+The number of
times the same packet goes through the firewall can
vary between 0 and 4 depending on packet source and
destination, and system configuration.
@@ -421,9 +428,9 @@ Keywords are case-sensitive, whereas arguments may
or may not be case-sensitive depending on their nature
(e.g.\& uid's are, hostnames are not).
.Pp
-In
-.Nm ipfw2
-you can introduce spaces after commas ',' to make
+Some arguments (e.g. port or address lists) are comma-separated
+lists of values.
+In this case, spaces after commas ',' are allowed to make
the line more readable.
You can also put the entire
command (including flags) into a single argument.
@@ -434,9 +441,7 @@ ipfw -q add deny src-ip 10.0.0.0/24, 127.0.0.1/8
ipfw "-q add deny src-ip 10.0.0.0/24, 127.0.0.1/8"
.Ed
.Sh RULE FORMAT
-The format of
-.Nm
-rules is the following:
+The format of firewall rules is the following:
.Bd -ragged -offset indent
.Bk -words
.Op Ar rule_number
@@ -496,7 +501,7 @@ in future forwarding decisions.
.El
.Pp
Note that some of the above information, e.g.\& source MAC or IP addresses and
-TCP/UDP ports, could easily be spoofed, so filtering on those fields
+TCP/UDP ports, can be easily spoofed, so filtering on those fields
alone might not guarantee the desired results.
.Bl -tag -width indent
.It Ar rule_number
@@ -1643,15 +1648,17 @@ because it engages only on packets with source addresses of directly
connected networks instead of all source addresses.
.El
.Sh LOOKUP TABLES
-Lookup tables are useful to handle large sparse address sets,
-typically from a hundred to several thousands of entries.
+Lookup tables are useful to handle large sparse sets of
+addresses or other search keys (e.g. ports, jail IDs).
+In the rest of this section we will use the term ``address''
+to mean any unsigned value of up to 32-bit.
There may be up to 128 different lookup tables, numbered 0 to 127.
.Pp
Each entry is represented by an
.Ar addr Ns Op / Ns Ar masklen
and will match all addresses with base
.Ar addr
-(specified as an IP address or a hostname)
+(specified as an IP address, a hostname or an unsigned integer)
and mask width of
.Ar masklen
bits.
@@ -1669,9 +1676,9 @@ is not specified, it defaults to 0.
.Pp
An entry can be added to a table
.Pq Cm add ,
-removed from a table
-.Pq Cm delete ,
-a table can be examined
+or removed from a table
+.Pq Cm delete .
+A table can be examined
.Pq Cm list
or flushed
.Pq Cm flush .
@@ -1680,7 +1687,7 @@ Internally, each table is stored in a Radix tree, the same way as
the routing table (see
.Xr route 4 ) .
.Pp
-Lookup tables currently support IPv4 addresses only.
+Lookup tables currently support only ports, jail IDs and IPv4 addresses.
.Pp
The
.Cm tablearg
@@ -1838,7 +1845,7 @@ for more examples on how to use dynamic rules.
.Nm
is also the user interface for the
.Nm dummynet
-traffic shaper and network emulator, a subsystem that
+traffic shaper, packet scheduler and network emulator, a subsystem that
can artificially queue, delay or drop packets
emulator the behaviour of certain network links
or queueing systems.
@@ -1858,17 +1865,17 @@ Packets are queued in front of the pipe as they come out from the classifier,
and then transferred to the pipe according to the pipe's parameters.
.It Em queue
A queue
-is an abstraction used to implement the WF2Q+
-(Worst-case Fair Weighted Fair Queueing) policy, which is
-an efficient variant of the WFQ policy.
+is an abstraction used to implement packet scheduling
+using one of several packet scheduling algorithms.
.Pp
The queue associates a
.Em weight
-and a reference pipe to each flow (a flow is a set of packets
+and a reference scheduler to each flow (a flow is a set of packets
with the same addresses and ports after masking).
-All backlogged flows (i.e., those
-with packets queued) linked to the same pipe share the pipe's
-bandwidth proportionally to their weights.
+A scheduler in turn is connected to a pipe, and arbitrates
+the pipe's bandwidth among backlogged flows according to
+weights and to the features of the scheduling algorithm in use.
+.Pp
Note that weights are not priorities; a flow with a lower weight
is still guaranteed to get its fraction of the bandwidth even if a
flow with a higher weight is permanently backlogged.
@@ -1911,16 +1918,19 @@ mode can be enabled by setting the
.Xr sysctl 8
variable to a non-zero value.
.Pp
-.Ss PIPE AND QUEUE CONFIGURATION
+.Ss PIPE, QUEUE AND SCHEDULER CONFIGURATION
The
-.Em pipe
-and
+.Em pipe ,
.Em queue
+and
+.Em scheduler
configuration commands are the following:
.Bd -ragged -offset indent
.Cm pipe Ar number Cm config Ar pipe-configuration
.Pp
.Cm queue Ar number Cm config Ar queue-configuration
+.Pp
+.Cm sched Ar number Cm config Ar sched-configuration
.Ed
.Pp
The following parameters can be configured for a pipe:
@@ -2073,6 +2083,14 @@ Specifies the weight to be used for flows matching this queue.
The weight must be in the range 1..100, and defaults to 1.
.El
.Pp
+The following parameters can be configured for a scheduler:
+.Pp
+.Bl -tag -width indent -compact
+.It Cm type Ar {fifo | wf2qp | rr | qfq}
+.El
+.Pp
+plus all the parameters allowed for a pipe.
+.Pp
Finally, the following parameters can be configured for both
pipes and queues:
.Pp
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index d4740c9..9adce1b 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -57,7 +57,7 @@ struct cmdline_opts co; /* global options */
int resvd_set_number = RESVD_SET;
#define GET_UINT_ARG(arg, min, max, tok, s_x) do { \
- if (!ac) \
+ if (!av[0]) \
errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \
if (_substrcmp(*av, "tablearg") == 0) { \
arg = IP_FW_TABLEARG; \
@@ -65,23 +65,23 @@ int resvd_set_number = RESVD_SET;
} \
\
{ \
- long val; \
+ long _xval; \
char *end; \
\
- val = strtol(*av, &end, 10); \
+ _xval = strtol(*av, &end, 10); \
\
- if (!isdigit(**av) || *end != '\0' || (val == 0 && errno == EINVAL)) \
+ if (!isdigit(**av) || *end != '\0' || (_xval == 0 && errno == EINVAL)) \
errx(EX_DATAERR, "%s: invalid argument: %s", \
match_value(s_x, tok), *av); \
\
- if (errno == ERANGE || val < min || val > max) \
+ if (errno == ERANGE || _xval < min || _xval > max) \
errx(EX_DATAERR, "%s: argument is out of range (%u..%u): %s", \
match_value(s_x, tok), min, max, *av); \
\
- if (val == IP_FW_TABLEARG) \
+ if (_xval == IP_FW_TABLEARG) \
errx(EX_DATAERR, "%s: illegal argument value: %s", \
match_value(s_x, tok), *av); \
- arg = val; \
+ arg = _xval; \
} \
} while (0)
@@ -353,6 +353,7 @@ safe_realloc(void *ptr, size_t size)
/*
* conditionally runs the command.
+ * Selected options or negative -> getsockopt
*/
int
do_cmd(int optname, void *optval, uintptr_t optlen)
@@ -372,11 +373,15 @@ do_cmd(int optname, void *optval, uintptr_t optlen)
optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST ||
optname == IP_FW_TABLE_GETSIZE ||
optname == IP_FW_NAT_GET_CONFIG ||
- optname == IP_FW_NAT_GET_LOG)
+ optname < 0 ||
+ optname == IP_FW_NAT_GET_LOG) {
+ if (optname < 0)
+ optname = -optname;
i = getsockopt(s, IPPROTO_IP, optname, optval,
(socklen_t *)optlen);
- else
+ } else {
i = setsockopt(s, IPPROTO_IP, optname, optval, optlen);
+ }
return i;
}
@@ -749,7 +754,7 @@ static void
print_ip(ipfw_insn_ip *cmd, char const *s)
{
struct hostent *he = NULL;
- int len = F_LEN((ipfw_insn *)cmd);
+ uint32_t len = F_LEN((ipfw_insn *)cmd);
uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) {
@@ -1126,9 +1131,11 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
else
printf(" log");
}
+#ifndef NO_ALTQ
if (altqptr) {
print_altq_cmd(altqptr);
}
+#endif
if (tagptr) {
if (tagptr->len & F_NOT)
PRINT_UINT_ARG(" untag ", tagptr->arg1);
@@ -1606,17 +1613,16 @@ show_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth)
* ipfw set move rule X to Y
*/
void
-ipfw_sets_handler(int ac, char *av[])
+ipfw_sets_handler(char *av[])
{
uint32_t set_disable, masks[2];
int i, nbytes;
uint16_t rulenum;
uint8_t cmd, new_set;
- ac--;
av++;
- if (!ac)
+ if (av[0] == NULL)
errx(EX_USAGE, "set needs command");
if (_substrcmp(*av, "show") == 0) {
void *data;
@@ -1642,8 +1648,8 @@ ipfw_sets_handler(int ac, char *av[])
}
printf("\n");
} else if (_substrcmp(*av, "swap") == 0) {
- ac--; av++;
- if (ac != 2)
+ av++;
+ if ( av[0] == NULL || av[1] == NULL )
errx(EX_USAGE, "set swap needs 2 set numbers\n");
rulenum = atoi(av[0]);
new_set = atoi(av[1]);
@@ -1654,13 +1660,14 @@ ipfw_sets_handler(int ac, char *av[])
masks[0] = (4 << 24) | (new_set << 16) | (rulenum);
i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t));
} else if (_substrcmp(*av, "move") == 0) {
- ac--; av++;
- if (ac && _substrcmp(*av, "rule") == 0) {
+ av++;
+ if (!av[0] && _substrcmp(*av, "rule") == 0) {
cmd = 2;
- ac--; av++;
+ av++;
} else
cmd = 3;
- if (ac != 3 || _substrcmp(av[1], "to") != 0)
+ if (av[0] == NULL || av[1] == NULL || av[2] == NULL ||
+ av[3] != NULL || _substrcmp(av[1], "to") != 0)
errx(EX_USAGE, "syntax: set move [rule] X to Y\n");
rulenum = atoi(av[0]);
new_set = atoi(av[2]);
@@ -1675,10 +1682,10 @@ ipfw_sets_handler(int ac, char *av[])
_substrcmp(*av, "enable") == 0 ) {
int which = _substrcmp(*av, "enable") == 0 ? 1 : 0;
- ac--; av++;
+ av++;
masks[0] = masks[1] = 0;
- while (ac) {
+ while (!av[0]) {
if (isdigit(**av)) {
i = atoi(*av);
if (i < 0 || i > RESVD_SET)
@@ -1692,7 +1699,7 @@ ipfw_sets_handler(int ac, char *av[])
else
errx(EX_DATAERR,
"invalid set command %s\n", *av);
- av++; ac--;
+ av++;
}
if ( (masks[0] & masks[1]) != 0 )
errx(EX_DATAERR,
@@ -1706,12 +1713,11 @@ ipfw_sets_handler(int ac, char *av[])
}
void
-ipfw_sysctl_handler(int ac, char *av[], int which)
+ipfw_sysctl_handler(char *av[], int which)
{
- ac--;
av++;
- if (ac == 0) {
+ if (av[0] == NULL) {
warnx("missing keyword to enable/disable\n");
} else if (_substrcmp(*av, "firewall") == 0) {
sysctlbyname("net.inet.ip.fw.enable", NULL, 0,
@@ -1728,8 +1734,10 @@ ipfw_sysctl_handler(int ac, char *av[], int which)
} else if (_substrcmp(*av, "dyn_keepalive") == 0) {
sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0,
&which, sizeof(which));
+#ifndef NO_ALTQ
} else if (_substrcmp(*av, "altq") == 0) {
altq_set_enabled(which);
+#endif
} else {
warnx("unrecognize enable/disable keyword: %s\n", *av);
}
@@ -1762,6 +1770,10 @@ ipfw_list(int ac, char *av[], int show_counters)
fprintf(stderr, "Testing only, list disabled\n");
return;
}
+ if (co.do_pipe) {
+ dummynet_list(ac, av, show_counters);
+ return;
+ }
ac--;
av++;
@@ -1778,11 +1790,6 @@ ipfw_list(int ac, char *av[], int show_counters)
co.do_pipe ? "DUMMYNET" : "FW");
}
- if (co.do_pipe) {
- ipfw_list_pipes(data, nbytes, ac, av);
- goto done;
- }
-
/*
* Count static rules. They have variable size so we
* need to scan the list to count them.
@@ -2130,7 +2137,7 @@ fill_ip(ipfw_insn_ip *cmd, char *av)
return;
}
/* A single IP can be stored in an optimized format */
- if (d[1] == ~0 && av == NULL && len == 0) {
+ if (d[1] == (uint32_t)~0 && av == NULL && len == 0) {
cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);
return;
}
@@ -2199,29 +2206,28 @@ fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode,
void
-ipfw_delete(int ac, char *av[])
+ipfw_delete(char *av[])
{
uint32_t rulenum;
int i;
int exitval = EX_OK;
int do_set = 0;
-
- av++; ac--;
+ av++;
NEED1("missing rule specification");
- if (ac > 0 && _substrcmp(*av, "set") == 0) {
+ if ( *av && _substrcmp(*av, "set") == 0) {
/* Do not allow using the following syntax:
* ipfw set N delete set M
*/
if (co.use_set)
errx(EX_DATAERR, "invalid syntax");
do_set = 1; /* delete set */
- ac--; av++;
+ av++;
}
/* Rule number */
- while (ac && isdigit(**av)) {
- i = atoi(*av); av++; ac--;
+ while (*av && isdigit(**av)) {
+ i = atoi(*av); av++;
if (co.do_nat) {
exitval = do_cmd(IP_FW_NAT_DEL, &i, sizeof i);
if (exitval) {
@@ -2275,7 +2281,8 @@ fill_iface(ipfw_insn_if *cmd, char *arg)
static void
get_mac_addr_mask(const char *p, uint8_t *addr, uint8_t *mask)
{
- int i, l;
+ int i;
+ size_t l;
char *ap, *ptr, *optr;
struct ether_addr *mac;
const char *macset = "0123456789abcdefABCDEF:";
@@ -2297,11 +2304,11 @@ get_mac_addr_mask(const char *p, uint8_t *addr, uint8_t *mask)
if (ptr != NULL) { /* we have mask? */
if (p[ptr - optr - 1] == '/') { /* mask len */
- l = strtol(ptr, &ap, 10);
- if (*ap != 0 || l > ETHER_ADDR_LEN * 8 || l < 0)
+ long ml = strtol(ptr, &ap, 10);
+ if (*ap != 0 || ml > ETHER_ADDR_LEN * 8 || ml < 0)
errx(EX_DATAERR, "Incorrect mask length");
- for (i = 0; l > 0 && i < ETHER_ADDR_LEN; l -= 8, i++)
- mask[i] = (l >= 8) ? 0xff: (~0) << (8 - l);
+ for (i = 0; ml > 0 && i < ETHER_ADDR_LEN; ml -= 8, i++)
+ mask[i] = (ml >= 8) ? 0xff: (~0) << (8 - ml);
} else { /* mask */
l = strlen(ptr);
if (strspn(ptr, macset) != l ||
@@ -2336,7 +2343,7 @@ next_cmd(ipfw_insn *cmd)
* Takes arguments and copies them into a comment
*/
static void
-fill_comment(ipfw_insn *cmd, int ac, char **av)
+fill_comment(ipfw_insn *cmd, char **av)
{
int i, l;
char *p = (char *)(cmd + 1);
@@ -2345,7 +2352,7 @@ fill_comment(ipfw_insn *cmd, int ac, char **av)
cmd->len = (cmd->len & (F_NOT | F_OR));
/* Compute length of comment string. */
- for (i = 0, l = 0; i < ac; i++)
+ for (i = 0, l = 0; av[i] != NULL; i++)
l += strlen(av[i]) + 1;
if (l == 0)
return;
@@ -2354,7 +2361,7 @@ fill_comment(ipfw_insn *cmd, int ac, char **av)
"comment too long (max 80 chars)");
l = 1 + (l+3)/4;
cmd->len = (cmd->len & (F_NOT | F_OR)) | l;
- for (i = 0; i < ac; i++) {
+ for (i = 0; av[i] != NULL; i++) {
strcpy(p, av[i]);
p += strlen(av[i]);
*p++ = ' ';
@@ -2379,11 +2386,11 @@ fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg)
* two microinstructions, and returns the pointer to the last one.
*/
static ipfw_insn *
-add_mac(ipfw_insn *cmd, int ac, char *av[])
+add_mac(ipfw_insn *cmd, char *av[])
{
ipfw_insn_mac *mac;
- if (ac < 2)
+ if ( ( av[0] == NULL ) || ( av[1] == NULL ) )
errx(EX_DATAERR, "MAC dst src");
cmd->opcode = O_MACADDR2;
@@ -2397,9 +2404,9 @@ add_mac(ipfw_insn *cmd, int ac, char *av[])
}
static ipfw_insn *
-add_mactype(ipfw_insn *cmd, int ac, char *av)
+add_mactype(ipfw_insn *cmd, char *av)
{
- if (ac < 1)
+ if (!av)
errx(EX_DATAERR, "missing MAC type");
if (strcmp(av, "any") != 0) { /* we have a non-null type */
fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE);
@@ -2507,6 +2514,7 @@ add_dstip(ipfw_insn *cmd, char *av)
static ipfw_insn *
add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode)
{
+ /* XXX "any" is trapped before. Perhaps "to" */
if (_substrcmp(av, "any") == 0) {
return NULL;
} else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) {
@@ -2530,11 +2538,11 @@ add_src(ipfw_insn *cmd, char *av, u_char proto)
*ch = '\0';
if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 ||
- inet_pton(AF_INET6, host, &a))
+ inet_pton(AF_INET6, host, &a) == 1)
ret = add_srcip6(cmd, av);
/* XXX: should check for IPv4, not !IPv6 */
if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
- !inet_pton(AF_INET6, host, &a)))
+ inet_pton(AF_INET6, host, &a) != 1))
ret = add_srcip(cmd, av);
if (ret == NULL && strcmp(av, "any") != 0)
ret = cmd;
@@ -2556,11 +2564,11 @@ add_dst(ipfw_insn *cmd, char *av, u_char proto)
*ch = '\0';
if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 ||
- inet_pton(AF_INET6, host, &a))
+ inet_pton(AF_INET6, host, &a) == 1)
ret = add_dstip6(cmd, av);
/* XXX: should check for IPv4, not !IPv6 */
if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
- !inet_pton(AF_INET6, host, &a)))
+ inet_pton(AF_INET6, host, &a) != 1))
ret = add_dstip(cmd, av);
if (ret == NULL && strcmp(av, "any") != 0)
ret = cmd;
@@ -2582,7 +2590,7 @@ add_dst(ipfw_insn *cmd, char *av, u_char proto)
*
*/
void
-ipfw_add(int ac, char *av[])
+ipfw_add(char *av[])
{
/*
* rules are added into the 'rulebuf' and then copied in
@@ -2621,37 +2629,36 @@ ipfw_add(int ac, char *av[])
cmd = (ipfw_insn *)cmdbuf;
action = (ipfw_insn *)actbuf;
- av++; ac--;
+ av++;
/* [rule N] -- Rule number optional */
- if (ac && isdigit(**av)) {
+ if (av[0] && isdigit(**av)) {
rule->rulenum = atoi(*av);
av++;
- ac--;
}
/* [set N] -- set number (0..RESVD_SET), optional */
- if (ac > 1 && _substrcmp(*av, "set") == 0) {
+ if (av[0] && !av[1] && _substrcmp(*av, "set") == 0) {
int set = strtoul(av[1], NULL, 10);
if (set < 0 || set > RESVD_SET)
errx(EX_DATAERR, "illegal set %s", av[1]);
rule->set = set;
- av += 2; ac -= 2;
+ av += 2;
}
/* [prob D] -- match probability, optional */
- if (ac > 1 && _substrcmp(*av, "prob") == 0) {
+ if (av[0] && av[1] && _substrcmp(*av, "prob") == 0) {
match_prob = strtod(av[1], NULL);
if (match_prob <= 0 || match_prob > 1)
errx(EX_DATAERR, "illegal match prob. %s", av[1]);
- av += 2; ac -= 2;
+ av += 2;
}
/* action -- mandatory */
NEED1("missing action");
i = match_token(rule_actions, *av);
- ac--; av++;
+ av++;
action->len = 1; /* default */
switch(i) {
case TOK_CHECKSTATE:
@@ -2687,14 +2694,14 @@ ipfw_add(int ac, char *av[])
action->opcode = O_REJECT;
NEED1("missing reject code");
fill_reject_code(&action->arg1, *av);
- ac--; av++;
+ av++;
break;
case TOK_UNREACH6:
action->opcode = O_UNREACH6;
NEED1("missing unreach code");
fill_unreach6_code(&action->arg1, *av);
- ac--; av++;
+ av++;
break;
case TOK_COUNT:
@@ -2727,7 +2734,7 @@ ipfw_add(int ac, char *av[])
case TOK_TEE:
action->opcode = O_TEE;
chkarg:
- if (!ac)
+ if (!av[0])
errx(EX_USAGE, "missing argument for %s", *(av - 1));
if (isdigit(**av)) {
action->arg1 = strtoul(*av, NULL, 10);
@@ -2746,7 +2753,7 @@ chkarg:
errx(EX_DATAERR, "illegal divert/tee port");
} else
errx(EX_DATAERR, "illegal argument for %s", *(av - 1));
- ac--; av++;
+ av++;
break;
case TOK_FORWARD: {
@@ -2784,13 +2791,13 @@ chkarg:
p->sa.sin_addr.s_addr = INADDR_ANY;
else
lookup_host(*av, &(p->sa.sin_addr));
- ac--; av++;
+ av++;
break;
}
case TOK_COMMENT:
/* pretend it is a 'count' rule followed by the comment */
action->opcode = O_COUNT;
- ac++; av--; /* go back... */
+ av--; /* go back... */
break;
case TOK_SETFIB:
@@ -2805,7 +2812,7 @@ chkarg:
errx(EX_DATAERR, "fibs not suported.\n");
if (action->arg1 >= numfibs) /* Temporary */
errx(EX_DATAERR, "fib too large.\n");
- ac--; av++;
+ av++;
break;
}
@@ -2825,8 +2832,8 @@ chkarg:
* If they exist, it go first in the cmdbuf, but then it is
* skipped in the copy section to the end of the buffer.
*/
- while (ac != 0 && (i = match_token(rule_action_params, *av)) != -1) {
- ac--; av++;
+ while (av[0] != NULL && (i = match_token(rule_action_params, *av)) != -1) {
+ av++;
switch (i) {
case TOK_LOG:
{
@@ -2839,15 +2846,15 @@ chkarg:
have_log = (ipfw_insn *)c;
cmd->len = F_INSN_SIZE(ipfw_insn_log);
cmd->opcode = O_LOG;
- if (ac && _substrcmp(*av, "logamount") == 0) {
- ac--; av++;
+ if (av[0] && _substrcmp(*av, "logamount") == 0) {
+ av++;
NEED1("logamount requires argument");
l = atoi(*av);
if (l < 0)
errx(EX_DATAERR,
"logamount must be positive");
c->max_log = l;
- ac--; av++;
+ av++;
} else {
len = sizeof(c->max_log);
if (sysctlbyname("net.inet.ip.fw.verbose_limit",
@@ -2858,6 +2865,7 @@ chkarg:
}
break;
+#ifndef NO_ALTQ
case TOK_ALTQ:
{
ipfw_insn_altq *a = (ipfw_insn_altq *)cmd;
@@ -2870,9 +2878,10 @@ chkarg:
cmd->len = F_INSN_SIZE(ipfw_insn_altq);
cmd->opcode = O_ALTQ;
a->qid = altq_name_to_qid(*av);
- ac--; av++;
+ av++;
}
break;
+#endif
case TOK_TAG:
case TOK_UNTAG: {
@@ -2885,7 +2894,7 @@ chkarg:
rule_action_params);
have_tag = cmd;
fill_cmd(cmd, O_TAG, (i == TOK_TAG) ? 0: F_NOT, tag);
- ac--; av++;
+ av++;
break;
}
@@ -2899,13 +2908,13 @@ chkarg:
goto done;
#define OR_START(target) \
- if (ac && (*av[0] == '(' || *av[0] == '{')) { \
+ if (av[0] && (*av[0] == '(' || *av[0] == '{')) { \
if (open_par) \
errx(EX_USAGE, "nested \"(\" not allowed\n"); \
prev = NULL; \
open_par = 1; \
if ( (av[0])[1] == '\0') { \
- ac--; av++; \
+ av++; \
} else \
(*av)++; \
} \
@@ -2914,30 +2923,30 @@ chkarg:
#define CLOSE_PAR \
if (open_par) { \
- if (ac && ( \
+ if (av[0] && ( \
strcmp(*av, ")") == 0 || \
strcmp(*av, "}") == 0)) { \
prev = NULL; \
open_par = 0; \
- ac--; av++; \
+ av++; \
} else \
errx(EX_USAGE, "missing \")\"\n"); \
}
#define NOT_BLOCK \
- if (ac && _substrcmp(*av, "not") == 0) { \
+ if (av[0] && _substrcmp(*av, "not") == 0) { \
if (cmd->len & F_NOT) \
errx(EX_USAGE, "double \"not\" not allowed\n"); \
cmd->len |= F_NOT; \
- ac--; av++; \
+ av++; \
}
#define OR_BLOCK(target) \
- if (ac && _substrcmp(*av, "or") == 0) { \
+ if (av[0] && _substrcmp(*av, "or") == 0) { \
if (prev == NULL || open_par == 0) \
errx(EX_DATAERR, "invalid OR block"); \
prev->len |= F_OR; \
- ac--; av++; \
+ av++; \
goto target; \
} \
CLOSE_PAR;
@@ -2954,15 +2963,15 @@ chkarg:
NEED1("missing protocol");
if (_substrcmp(*av, "MAC") == 0 ||
_substrcmp(*av, "mac") == 0) {
- ac--; av++; /* the "MAC" keyword */
- add_mac(cmd, ac, av); /* exits in case of errors */
+ av++; /* the "MAC" keyword */
+ add_mac(cmd, av); /* exits in case of errors */
cmd = next_cmd(cmd);
- ac -= 2; av += 2; /* dst-mac and src-mac */
+ av += 2; /* dst-mac and src-mac */
NOT_BLOCK;
NEED1("missing mac type");
- if (add_mactype(cmd, ac, av[0]))
+ if (add_mactype(cmd, av[0]))
cmd = next_cmd(cmd);
- ac--; av++; /* any or mac-type */
+ av++; /* any or mac-type */
goto read_options;
}
#endif
@@ -2974,7 +2983,7 @@ chkarg:
NOT_BLOCK;
NEED1("missing protocol");
if (add_proto_compat(cmd, *av, &proto)) {
- av++; ac--;
+ av++;
if (F_LEN(cmd) != 0) {
prev = cmd;
cmd = next_cmd(cmd);
@@ -2988,9 +2997,9 @@ chkarg:
/*
* "from", mandatory
*/
- if (!ac || _substrcmp(*av, "from") != 0)
+ if ((av[0] == NULL) || _substrcmp(*av, "from") != 0)
errx(EX_USAGE, "missing ``from''");
- ac--; av++;
+ av++;
/*
* source IP, mandatory
@@ -2999,7 +3008,7 @@ chkarg:
NOT_BLOCK; /* optional "not" */
NEED1("missing source address");
if (add_src(cmd, *av, proto)) {
- ac--; av++;
+ av++;
if (F_LEN(cmd) != 0) { /* ! any */
prev = cmd;
cmd = next_cmd(cmd);
@@ -3012,10 +3021,10 @@ chkarg:
* source ports, optional
*/
NOT_BLOCK; /* optional "not" */
- if (ac) {
+ if ( av[0] != NULL ) {
if (_substrcmp(*av, "any") == 0 ||
add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
- ac--; av++;
+ av++;
if (F_LEN(cmd) != 0)
cmd = next_cmd(cmd);
}
@@ -3024,9 +3033,9 @@ chkarg:
/*
* "to", mandatory
*/
- if (!ac || _substrcmp(*av, "to") != 0)
+ if ( (av[0] == NULL) || _substrcmp(*av, "to") != 0 )
errx(EX_USAGE, "missing ``to''");
- av++; ac--;
+ av++;
/*
* destination, mandatory
@@ -3035,7 +3044,7 @@ chkarg:
NOT_BLOCK; /* optional "not" */
NEED1("missing dst address");
if (add_dst(cmd, *av, proto)) {
- ac--; av++;
+ av++;
if (F_LEN(cmd) != 0) { /* ! any */
prev = cmd;
cmd = next_cmd(cmd);
@@ -3048,17 +3057,17 @@ chkarg:
* dest. ports, optional
*/
NOT_BLOCK; /* optional "not" */
- if (ac) {
+ if (av[0]) {
if (_substrcmp(*av, "any") == 0 ||
add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
- ac--; av++;
+ av++;
if (F_LEN(cmd) != 0)
cmd = next_cmd(cmd);
}
}
read_options:
- if (ac && first_cmd == cmd) {
+ if (av[0] && first_cmd == cmd) {
/*
* nothing specified so far, store in the rule to ease
* printout later.
@@ -3066,7 +3075,7 @@ read_options:
rule->_pad = 1;
}
prev = NULL;
- while (ac) {
+ while ( av[0] != NULL ) {
char *s;
ipfw_insn_u32 *cmd32; /* alias for cmd */
@@ -3080,7 +3089,7 @@ read_options:
s++;
}
i = match_token(rule_options, s);
- ac--; av++;
+ av++;
switch(i) {
case TOK_NOT:
if (cmd->len & F_NOT)
@@ -3142,7 +3151,7 @@ read_options:
NEED1("recv, xmit, via require interface name"
" or address");
fill_iface((ipfw_insn_if *)cmd, av[0]);
- ac--; av++;
+ av++;
if (F_LEN(cmd) == 0) /* not a valid address */
break;
if (i == TOK_XMIT)
@@ -3156,13 +3165,13 @@ read_options:
case TOK_ICMPTYPES:
NEED1("icmptypes requires list of types");
fill_icmptypes((ipfw_insn_u32 *)cmd, *av);
- av++; ac--;
+ av++;
break;
case TOK_ICMP6TYPES:
NEED1("icmptypes requires list of types");
fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av);
- av++; ac--;
+ av++;
break;
case TOK_IPTTL:
@@ -3172,7 +3181,7 @@ read_options:
errx(EX_DATAERR, "invalid ipttl %s", *av);
} else
fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0));
- ac--; av++;
+ av++;
break;
case TOK_IPID:
@@ -3182,7 +3191,7 @@ read_options:
errx(EX_DATAERR, "invalid ipid %s", *av);
} else
fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0));
- ac--; av++;
+ av++;
break;
case TOK_IPLEN:
@@ -3192,32 +3201,32 @@ read_options:
errx(EX_DATAERR, "invalid ip len %s", *av);
} else
fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0));
- ac--; av++;
+ av++;
break;
case TOK_IPVER:
NEED1("ipver requires version");
fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0));
- ac--; av++;
+ av++;
break;
case TOK_IPPRECEDENCE:
NEED1("ipprecedence requires value");
fill_cmd(cmd, O_IPPRECEDENCE, 0,
(strtoul(*av, NULL, 0) & 7) << 5);
- ac--; av++;
+ av++;
break;
case TOK_IPOPTS:
NEED1("missing argument for ipoptions");
fill_flags(cmd, O_IPOPT, f_ipopts, *av);
- ac--; av++;
+ av++;
break;
case TOK_IPTOS:
NEED1("missing argument for iptos");
fill_flags(cmd, O_IPTOS, f_iptos, *av);
- ac--; av++;
+ av++;
break;
case TOK_UID:
@@ -3234,7 +3243,7 @@ read_options:
errx(EX_DATAERR, "uid \"%s\" nonexistent", *av);
cmd32->d[0] = pwd->pw_uid;
cmd->len |= F_INSN_SIZE(ipfw_insn_u32);
- ac--; av++;
+ av++;
}
break;
@@ -3252,7 +3261,7 @@ read_options:
errx(EX_DATAERR, "gid \"%s\" nonexistent", *av);
cmd32->d[0] = grp->gr_gid;
cmd->len |= F_INSN_SIZE(ipfw_insn_u32);
- ac--; av++;
+ av++;
}
break;
@@ -3268,7 +3277,7 @@ read_options:
errx(EX_DATAERR, "jail requires prison ID");
cmd32->d[0] = (uint32_t)jid;
cmd->len |= F_INSN_SIZE(ipfw_insn_u32);
- ac--; av++;
+ av++;
}
break;
@@ -3289,13 +3298,13 @@ read_options:
} else
fill_cmd(cmd, O_TCPDATALEN, 0,
strtoul(*av, NULL, 0));
- ac--; av++;
+ av++;
break;
case TOK_TCPOPTS:
NEED1("missing argument for tcpoptions");
fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av);
- ac--; av++;
+ av++;
break;
case TOK_TCPSEQ:
@@ -3304,21 +3313,21 @@ read_options:
cmd->len = F_INSN_SIZE(ipfw_insn_u32);
cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK;
cmd32->d[0] = htonl(strtoul(*av, NULL, 0));
- ac--; av++;
+ av++;
break;
case TOK_TCPWIN:
NEED1("tcpwin requires length");
fill_cmd(cmd, O_TCPWIN, 0,
htons(strtoul(*av, NULL, 0)));
- ac--; av++;
+ av++;
break;
case TOK_TCPFLAGS:
NEED1("missing argument for tcpflags");
cmd->opcode = O_TCPFLAGS;
fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av);
- ac--; av++;
+ av++;
break;
case TOK_KEEPSTATE:
@@ -3348,11 +3357,11 @@ read_options:
cmd->opcode = O_LIMIT;
c->limit_mask = c->conn_limit = 0;
- while (ac > 0) {
+ while ( av[0] != NULL ) {
if ((val = match_token(limit_masks, *av)) <= 0)
break;
c->limit_mask |= val;
- ac--; av++;
+ av++;
}
if (c->limit_mask == 0)
@@ -3361,14 +3370,14 @@ read_options:
GET_UINT_ARG(c->conn_limit, IPFW_ARG_MIN, IPFW_ARG_MAX,
TOK_LIMIT, rule_options);
- ac--; av++;
+ av++;
break;
}
case TOK_PROTO:
NEED1("missing protocol");
if (add_proto(cmd, *av, &proto)) {
- ac--; av++;
+ av++;
} else
errx(EX_DATAERR, "invalid protocol ``%s''",
*av);
@@ -3377,28 +3386,28 @@ read_options:
case TOK_SRCIP:
NEED1("missing source IP");
if (add_srcip(cmd, *av)) {
- ac--; av++;
+ av++;
}
break;
case TOK_DSTIP:
NEED1("missing destination IP");
if (add_dstip(cmd, *av)) {
- ac--; av++;
+ av++;
}
break;
case TOK_SRCIP6:
NEED1("missing source IP6");
if (add_srcip6(cmd, *av)) {
- ac--; av++;
+ av++;
}
break;
case TOK_DSTIP6:
NEED1("missing destination IP6");
if (add_dstip6(cmd, *av)) {
- ac--; av++;
+ av++;
}
break;
@@ -3406,7 +3415,7 @@ read_options:
NEED1("missing source port");
if (_substrcmp(*av, "any") == 0 ||
add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
- ac--; av++;
+ av++;
} else
errx(EX_DATAERR, "invalid source port %s", *av);
break;
@@ -3415,23 +3424,22 @@ read_options:
NEED1("missing destination port");
if (_substrcmp(*av, "any") == 0 ||
add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
- ac--; av++;
+ av++;
} else
errx(EX_DATAERR, "invalid destination port %s",
*av);
break;
case TOK_MAC:
- if (add_mac(cmd, ac, av)) {
- ac -= 2; av += 2;
- }
+ if (add_mac(cmd, av))
+ av += 2;
break;
case TOK_MACTYPE:
NEED1("missing mac type");
- if (!add_mactype(cmd, ac, *av))
+ if (!add_mactype(cmd, *av))
errx(EX_DATAERR, "invalid mac type %s", *av);
- ac--; av++;
+ av++;
break;
case TOK_VERREVPATH:
@@ -3460,7 +3468,7 @@ read_options:
case TOK_EXT6HDR:
fill_ext6hdr( cmd, *av );
- ac--; av++;
+ av++;
break;
case TOK_FLOWID:
@@ -3468,17 +3476,16 @@ read_options:
errx( EX_USAGE, "flow-id filter is active "
"only for ipv6 protocol\n");
fill_flow6( (ipfw_insn_u32 *) cmd, *av );
- ac--; av++;
+ av++;
break;
case TOK_COMMENT:
- fill_comment(cmd, ac, av);
- av += ac;
- ac = 0;
+ fill_comment(cmd, av);
+ av[0]=NULL;
break;
case TOK_TAGGED:
- if (ac > 0 && strpbrk(*av, "-,")) {
+ if (av[0] && strpbrk(*av, "-,")) {
if (!add_ports(cmd, *av, 0, O_TAGGED))
errx(EX_DATAERR, "tagged: invalid tag"
" list: %s", *av);
@@ -3490,13 +3497,13 @@ read_options:
TOK_TAGGED, rule_options);
fill_cmd(cmd, O_TAGGED, 0, tag);
}
- ac--; av++;
+ av++;
break;
case TOK_FIB:
NEED1("fib requires fib number");
fill_cmd(cmd, O_FIB, 0, strtoul(*av, NULL, 0));
- ac--; av++;
+ av++;
break;
case TOK_LOOKUP: {
@@ -3504,7 +3511,7 @@ read_options:
char *p;
int j;
- if (ac < 2)
+ if (av[0] && av[1])
errx(EX_USAGE, "format: lookup argument tablenum");
cmd->opcode = O_IP_DST_LOOKUP;
cmd->len |= F_INSN_SIZE(ipfw_insn) + 2;
@@ -3516,11 +3523,11 @@ read_options:
if (lookup_key[j] <= 0)
errx(EX_USAGE, "format: cannot lookup on %s", *av);
c->d[1] = j; // i converted to option
- ac--; av++;
+ av++;
cmd->arg1 = strtoul(*av, &p, 0);
if (p && *p)
errx(EX_USAGE, "format: lookup argument tablenum");
- ac--; av++;
+ av++;
}
break;
@@ -3698,6 +3705,10 @@ ipfw_flush(int force)
if (c == 'N') /* user said no */
return;
}
+ if (co.do_pipe) {
+ dummynet_flush();
+ return;
+ }
/* `ipfw set N flush` - is the same that `ipfw delete set N` */
if (co.use_set) {
uint32_t arg = ((co.use_set - 1) & 0xffff) | (1 << 24);
@@ -3811,14 +3822,14 @@ ipfw_table_handler(int ac, char *av[])
}
}
} else if (_substrcmp(*av, "flush") == 0) {
- a = is_all ? tables_max : (ent.tbl + 1);
+ a = is_all ? tables_max : (uint32_t)(ent.tbl + 1);
do {
if (do_cmd(IP_FW_TABLE_FLUSH, &ent.tbl,
sizeof(ent.tbl)) < 0)
err(EX_OSERR, "setsockopt(IP_FW_TABLE_FLUSH)");
} while (++ent.tbl < a);
} else if (_substrcmp(*av, "list") == 0) {
- a = is_all ? tables_max : (ent.tbl + 1);
+ a = is_all ? tables_max : (uint32_t)(ent.tbl + 1);
do {
table_list(ent, is_all);
} while (++ent.tbl < a);
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
index b393a7d..1dbb42b 100644
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -35,7 +35,7 @@ struct cmdline_opts {
int do_resolv; /* try to resolve all ip to names */
int do_time; /* Show time stamps */
int do_quiet; /* Be quiet in add and flush */
- int do_pipe; /* this cmd refers to a pipe */
+ int do_pipe; /* this cmd refers to a pipe/queue/sched */
int do_nat; /* this cmd refers to a nat config */
int do_dynamic; /* display dynamic rules */
int do_expired; /* display expired dynamic rules */
@@ -82,7 +82,10 @@ enum tokens {
TOK_ACCEPT,
TOK_COUNT,
TOK_PIPE,
+ TOK_LINK,
TOK_QUEUE,
+ TOK_FLOWSET,
+ TOK_SCHED,
TOK_DIVERT,
TOK_TEE,
TOK_NETGRAPH,
@@ -151,15 +154,23 @@ enum tokens {
TOK_SRCPORT,
TOK_ALL,
TOK_MASK,
+ TOK_FLOW_MASK,
+ TOK_SCHED_MASK,
TOK_BW,
TOK_DELAY,
- TOK_PIPE_PROFILE,
+ TOK_PROFILE,
TOK_BURST,
TOK_RED,
TOK_GRED,
TOK_DROPTAIL,
TOK_PROTO,
+ /* dummynet tokens */
TOK_WEIGHT,
+ TOK_LMAX,
+ TOK_PRI,
+ TOK_TYPE,
+ TOK_SLOTSIZE,
+
TOK_IP,
TOK_IF,
TOK_ALOG,
@@ -192,7 +203,8 @@ enum tokens {
* the following macro returns an error message if we run out of
* arguments.
*/
-#define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);}
+#define NEED(_p, msg) {if (!_p) errx(EX_USAGE, msg);}
+#define NEED1(msg) {if (!(*av)) errx(EX_USAGE, msg);}
unsigned long long align_uint64(const uint64_t *pll);
@@ -236,14 +248,14 @@ struct _ipfw_insn_icmp6;
extern int resvd_set_number;
/* first-level command handlers */
-void ipfw_add(int ac, char *av[]);
+void ipfw_add(char *av[]);
void ipfw_show_nat(int ac, char **av);
void ipfw_config_pipe(int ac, char **av);
void ipfw_config_nat(int ac, char **av);
-void ipfw_sets_handler(int ac, char *av[]);
+void ipfw_sets_handler(char *av[]);
void ipfw_table_handler(int ac, char *av[]);
-void ipfw_sysctl_handler(int ac, char *av[], int which);
-void ipfw_delete(int ac, char *av[]);
+void ipfw_sysctl_handler(char *av[], int which);
+void ipfw_delete(char *av[]);
void ipfw_flush(int force);
void ipfw_zero(int ac, char *av[], int optname);
void ipfw_list(int ac, char *av[], int show_counters);
@@ -255,7 +267,8 @@ u_int32_t altq_name_to_qid(const char *name);
void print_altq_cmd(struct _ipfw_insn_altq *altqptr);
/* dummynet.c */
-void ipfw_list_pipes(void *data, uint nbytes, int ac, char *av[]);
+void dummynet_list(int ac, char *av[], int show_counters);
+void dummynet_flush(void);
int ipfw_delete_pipe(int pipe_or_queue, int n);
/* ipv6.c */
diff --git a/sbin/ipfw/main.c b/sbin/ipfw/main.c
index 3916057..3f48178 100644
--- a/sbin/ipfw/main.c
+++ b/sbin/ipfw/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002-2003 Luigi Rizzo
+ * Copyright (c) 2002-2003,2010 Luigi Rizzo
* Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
* Copyright (c) 1994 Ugen J.S.Antsilevich
*
@@ -80,31 +80,27 @@ help(void)
}
/*
- * Free a the (locally allocated) copy of command line arguments.
- */
-static void
-free_args(int ac, char **av)
-{
- int i;
-
- for (i=0; i < ac; i++)
- free(av[i]);
- free(av);
-}
-
-/*
* Called with the arguments, including program name because getopt
* wants it to be present.
* Returns 0 if successful, 1 if empty command, errx() in case of errors.
+ * First thing we do is process parameters creating an argv[] array
+ * which includes the program name and a NULL entry at the end.
+ * If we are called with a single string, we split it on whitespace.
+ * Also, arguments with a trailing ',' are joined to the next one.
+ * The pointers (av[]) and data are in a a single chunk of memory.
+ * av[0] points to the original program name, all other entries
+ * point into the allocated chunk.
*/
static int
ipfw_main(int oldac, char **oldav)
{
- int ch, ac, save_ac;
+ int ch, ac;
const char *errstr;
char **av, **save_av;
int do_acct = 0; /* Show packet/byte count */
int try_next = 0; /* set if pipe cmd not found */
+ int av_size; /* compute the av size */
+ char *av_p; /* used to build the av list */
#define WHITESP " \t\f\v\n\r"
if (oldac < 2)
@@ -112,10 +108,9 @@ ipfw_main(int oldac, char **oldav)
if (oldac == 2) {
/*
- * If we are called with a single string, try to split it into
- * arguments for subsequent parsing.
- * But first, remove spaces after a ',', by copying the string
- * in-place.
+ * If we are called with one argument, try to split it into
+ * words for subsequent parsing. Spaces after a ',' are
+ * removed by copying the string in-place.
*/
char *arg = oldav[1]; /* The string is the first arg. */
int l = strlen(arg);
@@ -150,31 +145,59 @@ ipfw_main(int oldac, char **oldav)
ac++;
/*
- * Allocate the argument list, including one entry for
- * the program name because getopt expects it.
+ * Allocate the argument list structure as a single block
+ * of memory, containing pointers and the argument
+ * strings. We include one entry for the program name
+ * because getopt expects it, and a NULL at the end
+ * to simplify further parsing.
*/
- av = safe_calloc(ac + 1, sizeof(char *));
+ ac++; /* add 1 for the program name */
+ av_size = (ac+1) * sizeof(char *) + l + 1;
+ av = safe_calloc(av_size, 1);
/*
- * Second, copy arguments from arg[] to av[]. For each one,
+ * Init the argument pointer to the end of the array
+ * and copy arguments from arg[] to av[]. For each one,
* j is the initial character, i is the one past the end.
*/
- for (ac = 1, i = j = 0; i < l; i++)
+ av_p = (char *)&av[ac+1];
+ for (ac = 1, i = j = 0; i < l; i++) {
if (index(WHITESP, arg[i]) != NULL || i == l-1) {
if (i == l-1)
i++;
- av[ac] = safe_calloc(i-j+1, 1);
- bcopy(arg+j, av[ac], i-j);
+ bcopy(arg+j, av_p, i-j);
+ av[ac] = av_p;
+ av_p += i-j; /* the lenght of the string */
+ *av_p++ = '\0';
ac++;
j = i + 1;
}
+ }
} else {
/*
* If an argument ends with ',' join with the next one.
*/
- int first, i, l;
+ int first, i, l=0;
+
+ /*
+ * Allocate the argument list structure as a single block
+ * of memory, containing both pointers and the argument
+ * strings. We include some space for the program name
+ * because getopt expects it.
+ * We add an extra pointer to the end of the array,
+ * to make simpler further parsing.
+ */
+ for (i=0; i<oldac; i++)
+ l += strlen(oldav[i]);
+
+ av_size = (oldac+1) * sizeof(char *) + l + oldac;
+ av = safe_calloc(av_size, 1);
- av = safe_calloc(oldac, sizeof(char *));
+ /*
+ * Init the argument pointer to the end of the array
+ * and copy arguments from arg[] to av[]
+ */
+ av_p = (char *)&av[oldac+1];
for (first = i = ac = 1, l = 0; i < oldac; i++) {
char *arg = oldav[i];
int k = strlen(arg);
@@ -182,11 +205,12 @@ ipfw_main(int oldac, char **oldav)
l += k;
if (arg[k-1] != ',' || i == oldac-1) {
/* Time to copy. */
- av[ac] = safe_calloc(l+1, 1);
+ av[ac] = av_p;
for (l=0; first <= i; first++) {
- strcat(av[ac]+l, oldav[first]);
- l += strlen(oldav[first]);
+ strcat(av_p, oldav[first]);
+ av_p += strlen(oldav[first]);
}
+ *av_p++ = '\0';
ac++;
l = 0;
first = i+1;
@@ -194,13 +218,47 @@ ipfw_main(int oldac, char **oldav)
}
}
- av[0] = strdup(oldav[0]); /* copy progname from the caller */
+ /*
+ * set the progname pointer to the original string
+ * and terminate the array with null
+ */
+ av[0] = oldav[0];
+ av[ac] = NULL;
+
/* Set the force flag for non-interactive processes */
if (!co.do_force)
co.do_force = !isatty(STDIN_FILENO);
+#ifdef EMULATE_SYSCTL /* sysctl emulation */
+ if ( ac >= 2 && !strcmp(av[1], "sysctl")) {
+ char *s;
+ int i;
+
+ if (ac != 3) {
+ printf( "sysctl emulation usage:\n"
+ " ipfw sysctl name[=value]\n"
+ " ipfw sysctl -a\n");
+ return 0;
+ }
+ s = index(av[2], '=');
+ if (s == NULL) {
+ s = !strcmp(av[2], "-a") ? NULL : av[2];
+ sysctlbyname(s, NULL, NULL, NULL, 0);
+ } else { /* ipfw sysctl x.y.z=value */
+ /* assume an INT value, will extend later */
+ if (s[1] == '\0') {
+ printf("ipfw sysctl: missing value\n\n");
+ return 0;
+ }
+ *s = '\0';
+ i = strtol(s+1, NULL, 0);
+ sysctlbyname(av[2], NULL, NULL, &i, sizeof(int));
+ }
+ return 0;
+ }
+#endif
+
/* Save arguments for final freeing of memory. */
- save_ac = ac;
save_av = av;
optind = optreset = 1; /* restart getopt() */
@@ -232,7 +290,7 @@ ipfw_main(int oldac, char **oldav)
break;
case 'h': /* help */
- free_args(save_ac, save_av);
+ free(save_av);
help();
break; /* NOTREACHED */
@@ -273,7 +331,7 @@ ipfw_main(int oldac, char **oldav)
break;
default:
- free_args(save_ac, save_av);
+ free(save_av);
return 1;
}
@@ -304,6 +362,10 @@ ipfw_main(int oldac, char **oldav)
co.do_pipe = 1;
else if (_substrcmp(*av, "queue") == 0)
co.do_pipe = 2;
+ else if (_substrcmp(*av, "flowset") == 0)
+ co.do_pipe = 2;
+ else if (_substrcmp(*av, "sched") == 0)
+ co.do_pipe = 3;
else if (!strncmp(*av, "set", strlen(*av))) {
if (ac > 1 && isdigit(av[1][0])) {
co.use_set = strtonum(av[1], 0, resvd_set_number,
@@ -335,7 +397,7 @@ ipfw_main(int oldac, char **oldav)
if (co.use_set == 0) {
if (_substrcmp(*av, "add") == 0)
- ipfw_add(ac, av);
+ ipfw_add(av);
else if (co.do_nat && _substrcmp(*av, "show") == 0)
ipfw_show_nat(ac, av);
else if (co.do_pipe && _substrcmp(*av, "config") == 0)
@@ -343,20 +405,20 @@ ipfw_main(int oldac, char **oldav)
else if (co.do_nat && _substrcmp(*av, "config") == 0)
ipfw_config_nat(ac, av);
else if (_substrcmp(*av, "set") == 0)
- ipfw_sets_handler(ac, av);
+ ipfw_sets_handler(av);
else if (_substrcmp(*av, "table") == 0)
ipfw_table_handler(ac, av);
else if (_substrcmp(*av, "enable") == 0)
- ipfw_sysctl_handler(ac, av, 1);
+ ipfw_sysctl_handler(av, 1);
else if (_substrcmp(*av, "disable") == 0)
- ipfw_sysctl_handler(ac, av, 0);
+ ipfw_sysctl_handler(av, 0);
else
try_next = 1;
}
if (co.use_set || try_next) {
if (_substrcmp(*av, "delete") == 0)
- ipfw_delete(ac, av);
+ ipfw_delete(av);
else if (_substrcmp(*av, "flush") == 0)
ipfw_flush(co.do_force);
else if (_substrcmp(*av, "zero") == 0)
@@ -373,7 +435,7 @@ ipfw_main(int oldac, char **oldav)
}
/* Free memory allocated in the argument parsing. */
- free_args(save_ac, save_av);
+ free(save_av);
return 0;
}
diff --git a/sbin/mount_hpfs/Makefile b/sbin/mount_hpfs/Makefile
index 0843774..9e65b8e 100644
--- a/sbin/mount_hpfs/Makefile
+++ b/sbin/mount_hpfs/Makefile
@@ -7,8 +7,7 @@ SRCS= mount_hpfs.c getmntopts.c
MAN= mount_hpfs.8
MOUNT= ${.CURDIR}/../mount
-CFLAGS+=-I${MOUNT} -DHPFS
-WARNS?= 0
+CFLAGS+= -I${MOUNT} -DHPFS
.PATH: ${MOUNT}
diff --git a/sbin/mount_hpfs/mount_hpfs.c b/sbin/mount_hpfs/mount_hpfs.c
index a9a87e2..0106377 100644
--- a/sbin/mount_hpfs/mount_hpfs.c
+++ b/sbin/mount_hpfs/mount_hpfs.c
@@ -60,9 +60,7 @@ static void usage(void) __dead2;
static void load_u2wtable(struct hpfs_args *, char *);
int
-main(argc, argv)
- int argc;
- char **argv;
+main(int argc, char *argv[])
{
struct hpfs_args args;
struct stat sb;
@@ -150,8 +148,7 @@ main(argc, argv)
}
gid_t
-a_gid(s)
- char *s;
+a_gid(char *s)
{
struct group *gr;
char *gname;
@@ -170,8 +167,7 @@ a_gid(s)
}
uid_t
-a_uid(s)
- char *s;
+a_uid(char *s)
{
struct passwd *pw;
char *uname;
@@ -190,8 +186,7 @@ a_uid(s)
}
mode_t
-a_mask(s)
- char *s;
+a_mask(char *s)
{
int done, rv=0;
char *ep;
@@ -207,16 +202,14 @@ a_mask(s)
}
void
-usage()
+usage(void)
{
fprintf(stderr, "usage: mount_hpfs [-u user] [-g group] [-m mask] bdev dir\n");
exit(EX_USAGE);
}
void
-load_u2wtable (pargs, name)
- struct hpfs_args *pargs;
- char *name;
+load_u2wtable (struct hpfs_args *pargs, char *name)
{
FILE *f;
int i, code;
diff --git a/sbin/mount_ntfs/Makefile b/sbin/mount_ntfs/Makefile
index 5938b0d..416f1ac 100644
--- a/sbin/mount_ntfs/Makefile
+++ b/sbin/mount_ntfs/Makefile
@@ -9,8 +9,7 @@ DPADD= ${LIBKICONV}
LDADD= -lkiconv
MOUNT= ${.CURDIR}/../mount
-CFLAGS+=-I${MOUNT}
-WARNS?= 0
+CFLAGS+= -I${MOUNT}
# Needs to be dynamically linked for optional dlopen() access to
# userland libiconv
diff --git a/sbin/mount_ntfs/mount_ntfs.c b/sbin/mount_ntfs/mount_ntfs.c
index 4bd118f..80fcab0 100644
--- a/sbin/mount_ntfs/mount_ntfs.c
+++ b/sbin/mount_ntfs/mount_ntfs.c
@@ -69,9 +69,7 @@ static void usage(void) __dead2;
static int set_charset(struct ntfs_args *);
int
-main(argc, argv)
- int argc;
- char **argv;
+main(int argc, char *argv[])
{
struct ntfs_args args;
struct stat sb;
@@ -193,8 +191,7 @@ main(argc, argv)
}
gid_t
-a_gid(s)
- char *s;
+a_gid(char *s)
{
struct group *gr;
char *gname;
@@ -213,8 +210,7 @@ a_gid(s)
}
uid_t
-a_uid(s)
- char *s;
+a_uid(char *s)
{
struct passwd *pw;
char *uname;
@@ -233,8 +229,7 @@ a_uid(s)
}
mode_t
-a_mask(s)
- char *s;
+a_mask(char *s)
{
int done, rv=0;
char *ep;
@@ -250,7 +245,7 @@ a_mask(s)
}
void
-usage()
+usage(void)
{
#ifdef TRANSITION_PERIOD_HACK
fprintf(stderr, "%s\n%s\n",
diff --git a/sbin/restore/restore.h b/sbin/restore/restore.h
index 8c6a87b..5d02bdf 100644
--- a/sbin/restore/restore.h
+++ b/sbin/restore/restore.h
@@ -41,7 +41,7 @@
extern int bflag; /* set input block size */
extern int dflag; /* print out debugging info */
extern int Dflag; /* degraded mode - try hard to get stuff back */
-extern int hflag; /* restore heirarchies */
+extern int hflag; /* restore hierarchies */
extern int mflag; /* restore by name instead of inode number */
extern int Nflag; /* do not write the disk */
extern int uflag; /* unlink symlink targets */
diff --git a/sbin/route/Makefile b/sbin/route/Makefile
index ef56dfd..0f4cd67 100644
--- a/sbin/route/Makefile
+++ b/sbin/route/Makefile
@@ -6,7 +6,7 @@
PROG= route
MAN= route.8
SRCS= route.c keywords.h
-WARNS?= 0
+WARNS?= 3
CLEANFILES+=keywords.h _keywords.tmp
CFLAGS+= -DNS
diff --git a/sbin/route/route.c b/sbin/route/route.c
index 4380f42..f0bb07b 100644
--- a/sbin/route/route.c
+++ b/sbin/route/route.c
@@ -70,7 +70,7 @@ __FBSDID("$FreeBSD$");
#include <ifaddrs.h>
struct keytab {
- char *kt_cp;
+ const char *kt_cp;
int kt_i;
} keywords[] = {
#include "keywords.h"
@@ -100,39 +100,39 @@ struct rt_metrics rt_metrics;
u_long rtm_inits;
uid_t uid;
-int atalk_aton(const char *, struct at_addr *);
-char *atalk_ntoa(struct at_addr);
-void bprintf(FILE *, int, u_char *);
-void flushroutes(int argc, char *argv[]);
-int getaddr(int, char *, struct hostent **);
-int keyword(char *);
-void inet_makenetandmask(u_long, struct sockaddr_in *, u_long);
+static int atalk_aton(const char *, struct at_addr *);
+static char *atalk_ntoa(struct at_addr);
+static void bprintf(FILE *, int, u_char *);
+static void flushroutes(int argc, char *argv[]);
+static int getaddr(int, char *, struct hostent **);
+static int keyword(const char *);
+static void inet_makenetandmask(u_long, struct sockaddr_in *, u_long);
#ifdef INET6
-static int inet6_makenetandmask(struct sockaddr_in6 *, char *);
+static int inet6_makenetandmask(struct sockaddr_in6 *, const char *);
#endif
-void interfaces(void);
-void mask_addr(void);
-void monitor(void);
-const char *netname(struct sockaddr *);
-void newroute(int, char **);
-void pmsg_addrs(char *, int);
-void pmsg_common(struct rt_msghdr *);
-int prefixlen(char *);
-void print_getmsg(struct rt_msghdr *, int);
-void print_rtmsg(struct rt_msghdr *, int);
-const char *routename(struct sockaddr *);
-int rtmsg(int, int);
-void set_metric(char *, int);
-void sockaddr(char *, struct sockaddr *);
-void sodump(sup, char *);
-extern char *iso_ntoa();
-
-void usage(const char *) __dead2;
+static void interfaces(void);
+static void mask_addr(void);
+static void monitor(void);
+static const char *netname(struct sockaddr *);
+static void newroute(int, char **);
+static void pmsg_addrs(char *, int);
+static void pmsg_common(struct rt_msghdr *);
+static int prefixlen(const char *);
+static void print_getmsg(struct rt_msghdr *, int);
+static void print_rtmsg(struct rt_msghdr *, int);
+static const char *routename(struct sockaddr *);
+static int rtmsg(int, int);
+static void set_metric(char *, int);
+static void sockaddr(char *, struct sockaddr *);
+static void sodump(sup, const char *);
+extern char *iso_ntoa(void);
+
+static void usage(const char *) __dead2;
void
usage(const char *cp)
{
- if (cp)
+ if (cp != NULL)
warnx("bad keyword: %s", cp);
(void) fprintf(stderr,
"usage: route [-dnqtv] command [[modifiers] args]\n");
@@ -146,7 +146,7 @@ main(int argc, char **argv)
int ch;
if (argc < 2)
- usage((char *)NULL);
+ usage(NULL);
while ((ch = getopt(argc, argv, "nqdtv")) != -1)
switch(ch) {
@@ -167,7 +167,7 @@ main(int argc, char **argv)
break;
case '?':
default:
- usage((char *)NULL);
+ usage(NULL);
}
argc -= optind;
argv += optind;
@@ -180,7 +180,7 @@ main(int argc, char **argv)
s = socket(PF_ROUTE, SOCK_RAW, 0);
if (s < 0)
err(EX_OSERR, "socket");
- if (*argv)
+ if (*argv != NULL)
switch (keyword(*argv)) {
case K_GET:
case K_SHOW:
@@ -211,7 +211,7 @@ main(int argc, char **argv)
* Purge all entries in the routing tables not
* associated with network interfaces.
*/
-void
+static void
flushroutes(int argc, char *argv[])
{
size_t needed;
@@ -219,7 +219,7 @@ flushroutes(int argc, char *argv[])
char *buf, *next, *lim;
struct rt_msghdr *rtm;
- if (uid && !debugonly) {
+ if (uid != 0 && !debugonly) {
errx(EX_NOPERM, "must be root to alter routing table");
}
shutdown(s, SHUT_RD); /* Don't want to read back our messages */
@@ -259,7 +259,7 @@ retry:
errx(EX_OSERR, "malloc failed");
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
if (errno == ENOMEM && count++ < 10) {
- warnx("Routing table grew, retrying");
+ warnx("Routing table grew, retrying");
sleep(1);
free(buf);
goto retry;
@@ -276,7 +276,7 @@ retry:
print_rtmsg(rtm, rtm->rtm_msglen);
if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
continue;
- if (af) {
+ if (af != 0) {
struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
if (sa->sa_family != af)
@@ -315,7 +315,7 @@ retry:
const char *
routename(struct sockaddr *sa)
{
- char *cp;
+ const char *cp;
static char line[MAXHOSTNAMELEN + 1];
struct hostent *hp;
static char domain[MAXHOSTNAMELEN + 1];
@@ -339,20 +339,22 @@ routename(struct sockaddr *sa)
{ struct in_addr in;
in = ((struct sockaddr_in *)sa)->sin_addr;
- cp = 0;
+ cp = NULL;
if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
cp = "default";
- if (cp == 0 && !nflag) {
+ if (cp == NULL && !nflag) {
hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
AF_INET);
- if (hp) {
- if ((cp = strchr(hp->h_name, '.')) &&
- !strcmp(cp + 1, domain))
- *cp = 0;
+ if (hp != NULL) {
+ char *cptr;
+ cptr = strchr(hp->h_name, '.');
+ if (cptr != NULL &&
+ strcmp(cptr + 1, domain) == 0)
+ *cptr = '\0';
cp = hp->h_name;
}
}
- if (cp) {
+ if (cp != NULL) {
strncpy(line, cp, sizeof(line) - 1);
line[sizeof(line) - 1] = '\0';
} else
@@ -400,16 +402,17 @@ routename(struct sockaddr *sa)
return (link_ntoa((struct sockaddr_dl *)sa));
default:
- { u_short *s = (u_short *)sa;
- u_short *slim = s + ((sa->sa_len + 1) >> 1);
- char *cp = line + sprintf(line, "(%d)", sa->sa_family);
+ {
+ u_short *sp = (u_short *)sa;
+ u_short *splim = sp + ((sa->sa_len + 1) >> 1);
+ char *cps = line + sprintf(line, "(%d)", sa->sa_family);
char *cpe = line + sizeof(line);
- while (++s < slim && cp < cpe) /* start with sa->sa_data */
- if ((n = snprintf(cp, cpe - cp, " %x", *s)) > 0)
- cp += n;
+ while (++sp < splim && cps < cpe) /* start with sa->sa_data */
+ if ((n = snprintf(cps, cpe - cps, " %x", *sp)) > 0)
+ cps += n;
else
- *cp = '\0';
+ *cps = '\0';
break;
}
}
@@ -423,9 +426,9 @@ routename(struct sockaddr *sa)
const char *
netname(struct sockaddr *sa)
{
- char *cp = 0;
+ const char *cp = NULL;
static char line[MAXHOSTNAMELEN + 1];
- struct netent *np = 0;
+ struct netent *np = NULL;
u_long net, mask;
u_long i;
int n, subnetshift;
@@ -462,11 +465,11 @@ netname(struct sockaddr *sa)
while ((mask & 1) == 0)
mask >>= 1, net >>= 1;
np = getnetbyaddr(net, AF_INET);
- if (np)
+ if (np != NULL)
cp = np->n_name;
}
#define C(x) (unsigned)((x) & 0xff)
- if (cp)
+ if (cp != NULL)
strncpy(line, cp, sizeof(line));
else if ((in.s_addr & 0xffffff) == 0)
(void) sprintf(line, "%u", C(in.s_addr >> 24));
@@ -525,23 +528,24 @@ netname(struct sockaddr *sa)
default:
- { u_short *s = (u_short *)sa->sa_data;
- u_short *slim = s + ((sa->sa_len + 1)>>1);
- char *cp = line + sprintf(line, "af %d:", sa->sa_family);
+ {
+ u_short *sp = (u_short *)sa->sa_data;
+ u_short *splim = sp + ((sa->sa_len + 1)>>1);
+ char *cps = line + sprintf(line, "af %d:", sa->sa_family);
char *cpe = line + sizeof(line);
- while (s < slim && cp < cpe)
- if ((n = snprintf(cp, cpe - cp, " %x", *s++)) > 0)
- cp += n;
+ while (sp < splim && cps < cpe)
+ if ((n = snprintf(cps, cpe - cps, " %x", *sp++)) > 0)
+ cps += n;
else
- *cp = '\0';
+ *cps = '\0';
break;
}
}
return (line);
}
-void
+static void
set_metric(char *value, int key)
{
int flag = 0;
@@ -567,15 +571,16 @@ set_metric(char *value, int key)
*valp = atoi(value);
}
-void
+static void
newroute(int argc, char **argv)
{
- char *cmd, *dest = "", *gateway = "", *errmsg;
+ char *cmd;
+ const char *dest = "", *gateway = "", *errmsg;
int ishost = 0, proxy = 0, ret, attempts, oerrno, flags = RTF_STATIC;
int key;
struct hostent *hp = 0;
- if (uid) {
+ if (uid != 0) {
errx(EX_NOPERM, "must be root to alter routing table");
}
cmd = argv[0];
@@ -652,33 +657,33 @@ newroute(int argc, char **argv)
break;
case K_IFA:
if (!--argc)
- usage((char *)NULL);
+ usage(NULL);
(void) getaddr(RTA_IFA, *++argv, 0);
break;
case K_IFP:
if (!--argc)
- usage((char *)NULL);
+ usage(NULL);
(void) getaddr(RTA_IFP, *++argv, 0);
break;
case K_GENMASK:
if (!--argc)
- usage((char *)NULL);
+ usage(NULL);
(void) getaddr(RTA_GENMASK, *++argv, 0);
break;
case K_GATEWAY:
if (!--argc)
- usage((char *)NULL);
+ usage(NULL);
(void) getaddr(RTA_GATEWAY, *++argv, 0);
break;
case K_DST:
if (!--argc)
- usage((char *)NULL);
+ usage(NULL);
ishost = getaddr(RTA_DST, *++argv, &hp);
dest = *argv;
break;
case K_NETMASK:
if (!--argc)
- usage((char *)NULL);
+ usage(NULL);
(void) getaddr(RTA_NETMASK, *++argv, 0);
/* FALLTHROUGH */
case K_NET:
@@ -686,7 +691,7 @@ newroute(int argc, char **argv)
break;
case K_PREFIXLEN:
if (!--argc)
- usage((char *)NULL);
+ usage(NULL);
if (prefixlen(*++argv) == -1) {
forcenet = 0;
ishost = 1;
@@ -705,7 +710,7 @@ newroute(int argc, char **argv)
case K_RTTVAR:
case K_WEIGHT:
if (!--argc)
- usage((char *)NULL);
+ usage(NULL);
set_metric(*++argv, key);
break;
default:
@@ -729,9 +734,9 @@ newroute(int argc, char **argv)
#ifdef INET6
if (af == AF_INET6) {
rtm_addrs &= ~RTA_NETMASK;
- memset((void *)&so_mask, 0, sizeof(so_mask));
+ memset((void *)&so_mask, 0, sizeof(so_mask));
}
-#endif
+#endif
}
if (forcenet)
ishost = 0;
@@ -750,10 +755,12 @@ newroute(int argc, char **argv)
break;
if (errno != ENETUNREACH && errno != ESRCH)
break;
- if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
+ if (af == AF_INET && *gateway != '\0' &&
+ hp != NULL && hp->h_addr_list[1] != NULL) {
hp->h_addr_list++;
memmove(&so_gate.sin.sin_addr, hp->h_addr_list[0],
- MIN(hp->h_length, sizeof(so_gate.sin.sin_addr)));
+ MIN((size_t)hp->h_length,
+ sizeof(so_gate.sin.sin_addr)));
} else
break;
}
@@ -798,14 +805,14 @@ newroute(int argc, char **argv)
exit(ret != 0);
}
-void
+static void
inet_makenetandmask(u_long net, struct sockaddr_in *sin, u_long bits)
{
u_long addr, mask = 0;
char *cp;
rtm_addrs |= RTA_NETMASK;
- /*
+ /*
* XXX: This approach unable to handle 0.0.0.1/32 correctly
* as inet_network() converts 0.0.0.1 and 1 equally.
*/
@@ -818,7 +825,7 @@ inet_makenetandmask(u_long net, struct sockaddr_in *sin, u_long bits)
else
addr = net;
/*
- * If no /xx was specified we must cacluate the
+ * If no /xx was specified we must calculate the
* CIDR address.
*/
if ((bits == 0) && (addr != 0)) {
@@ -851,11 +858,11 @@ inet_makenetandmask(u_long net, struct sockaddr_in *sin, u_long bits)
* XXX the function may need more improvement...
*/
static int
-inet6_makenetandmask(struct sockaddr_in6 *sin6, char *plen)
+inet6_makenetandmask(struct sockaddr_in6 *sin6, const char *plen)
{
struct in6_addr in6;
- if (!plen) {
+ if (plen == NULL) {
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
sin6->sin6_scope_id == 0) {
plen = "0";
@@ -868,11 +875,11 @@ inet6_makenetandmask(struct sockaddr_in6 *sin6, char *plen)
}
}
- if (!plen || strcmp(plen, "128") == 0)
- return 1;
+ if (plen == NULL || strcmp(plen, "128") == 0)
+ return (1);
rtm_addrs |= RTA_NETMASK;
- (void)prefixlen(plen);
- return 0;
+ prefixlen(plen);
+ return (0);
}
#endif
@@ -880,8 +887,8 @@ inet6_makenetandmask(struct sockaddr_in6 *sin6, char *plen)
* Interpret an argument as a network address of some kind,
* returning 1 if a host address, 0 if a network address.
*/
-int
-getaddr(int which, char *s, struct hostent **hpp)
+static int
+getaddr(int which, char *str, struct hostent **hpp)
{
sup su;
struct hostent *hp;
@@ -909,17 +916,17 @@ getaddr(int which, char *s, struct hostent **hpp)
if (getifaddrs(&ifap))
err(1, "getifaddrs");
- for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr->sa_family != AF_LINK)
continue;
- if (strcmp(s, ifa->ifa_name))
+ if (strcmp(str, ifa->ifa_name) != 0)
continue;
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
}
/* If we found it, then use it */
- if (sdl) {
+ if (sdl != NULL) {
/*
* Copy is safe since we have a
* sockaddr_storage member in sockunion{}.
@@ -929,7 +936,7 @@ getaddr(int which, char *s, struct hostent **hpp)
memcpy(&su->sdl, sdl, sdl->sdl_len);
}
freeifaddrs(ifap);
- if (sdl)
+ if (sdl != NULL)
return(1);
}
break;
@@ -952,9 +959,9 @@ getaddr(int which, char *s, struct hostent **hpp)
}
su->sa.sa_len = aflen;
su->sa.sa_family = afamily; /* cases that don't want it have left already */
- if (strcmp(s, "default") == 0) {
+ if (strcmp(str, "default") == 0) {
/*
- * Default is net 0.0.0.0/0
+ * Default is net 0.0.0.0/0
*/
switch (which) {
case RTA_DST:
@@ -962,7 +969,7 @@ getaddr(int which, char *s, struct hostent **hpp)
#if 0
bzero(su, sizeof(*su)); /* for readability */
#endif
- (void) getaddr(RTA_NETMASK, s, 0);
+ getaddr(RTA_NETMASK, str, 0);
break;
#if 0
case RTA_NETMASK:
@@ -980,15 +987,15 @@ getaddr(int which, char *s, struct hostent **hpp)
int ecode;
q = NULL;
- if (which == RTA_DST && (q = strchr(s, '/')) != NULL)
+ if (which == RTA_DST && (q = strchr(str, '/')) != NULL)
*q = '\0';
memset(&hints, 0, sizeof(hints));
hints.ai_family = afamily; /*AF_INET6*/
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
- ecode = getaddrinfo(s, NULL, &hints, &res);
+ ecode = getaddrinfo(str, NULL, &hints, &res);
if (ecode != 0 || res->ai_family != AF_INET6 ||
res->ai_addrlen != sizeof(su->sin6)) {
- (void) fprintf(stderr, "%s: %s\n", s,
+ (void) fprintf(stderr, "%s: %s\n", str,
gai_strerror(ecode));
exit(1);
}
@@ -1012,19 +1019,19 @@ getaddr(int which, char *s, struct hostent **hpp)
#endif /* INET6 */
case AF_APPLETALK:
- if (!atalk_aton(s, &su->sat.sat_addr))
- errx(EX_NOHOST, "bad address: %s", s);
+ if (!atalk_aton(str, &su->sat.sat_addr))
+ errx(EX_NOHOST, "bad address: %s", str);
rtm_addrs |= RTA_NETMASK;
return(forcehost || su->sat.sat_addr.s_node != 0);
case AF_LINK:
- link_addr(s, &su->sdl);
+ link_addr(str, &su->sdl);
return (1);
case PF_ROUTE:
su->sa.sa_len = sizeof(*su);
- sockaddr(s, &su->sa);
+ sockaddr(str, &su->sa);
return (1);
case AF_INET:
@@ -1036,10 +1043,10 @@ getaddr(int which, char *s, struct hostent **hpp)
hpp = &hp;
*hpp = NULL;
- q = strchr(s,'/');
- if (q && which == RTA_DST) {
+ q = strchr(str,'/');
+ if (q != NULL && which == RTA_DST) {
*q = '\0';
- if ((val = inet_network(s)) != INADDR_NONE) {
+ if ((val = inet_network(str)) != INADDR_NONE) {
inet_makenetandmask(
val, &su->sin, strtoul(q+1, 0, 0));
return (0);
@@ -1047,7 +1054,7 @@ getaddr(int which, char *s, struct hostent **hpp)
*q = '/';
}
if ((which != RTA_DST || forcenet == 0) &&
- inet_aton(s, &su->sin.sin_addr)) {
+ inet_aton(str, &su->sin.sin_addr)) {
val = su->sin.sin_addr.s_addr;
if (which != RTA_DST || forcehost ||
inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
@@ -1058,27 +1065,27 @@ getaddr(int which, char *s, struct hostent **hpp)
}
}
if (which == RTA_DST && forcehost == 0 &&
- ((val = inet_network(s)) != INADDR_NONE ||
- ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0))) {
+ ((val = inet_network(str)) != INADDR_NONE ||
+ ((np = getnetbyname(str)) != NULL && (val = np->n_net) != 0))) {
netdone:
inet_makenetandmask(val, &su->sin, 0);
return (0);
}
- hp = gethostbyname(s);
- if (hp) {
+ hp = gethostbyname(str);
+ if (hp != NULL) {
*hpp = hp;
su->sin.sin_family = hp->h_addrtype;
memmove((char *)&su->sin.sin_addr, hp->h_addr,
- MIN(hp->h_length, sizeof(su->sin.sin_addr)));
+ MIN((size_t)hp->h_length, sizeof(su->sin.sin_addr)));
return (1);
}
- errx(EX_NOHOST, "bad address: %s", s);
+ errx(EX_NOHOST, "bad address: %s", str);
}
-int
-prefixlen(char *s)
+static int
+prefixlen(const char *str)
{
- int len = atoi(s), q, r;
+ int len = atoi(str), q, r;
int max;
char *p;
@@ -1095,13 +1102,12 @@ prefixlen(char *s)
p = (char *)&so_mask.sin.sin_addr;
break;
default:
- (void) fprintf(stderr, "prefixlen not supported in this af\n");
+ fprintf(stderr, "prefixlen not supported in this af\n");
exit(1);
- /*NOTREACHED*/
}
if (len < 0 || max < len) {
- (void) fprintf(stderr, "%s: bad value\n", s);
+ fprintf(stderr, "%s: bad value\n", str);
exit(1);
}
@@ -1115,12 +1121,12 @@ prefixlen(char *s)
if (r > 0)
*((u_char *)p + q) = (0xff00 >> r) & 0xff;
if (len == max)
- return -1;
+ return (-1);
else
- return len;
+ return (len);
}
-void
+static void
interfaces(void)
{
size_t needed;
@@ -1155,7 +1161,7 @@ retry2:
}
}
-void
+static void
monitor(void)
{
int n;
@@ -1166,7 +1172,7 @@ monitor(void)
interfaces();
exit(0);
}
- for(;;) {
+ for (;;) {
time_t now;
n = read(s, msg, 2048);
now = time(NULL);
@@ -1180,7 +1186,7 @@ struct {
char m_space[512];
} m_rtmsg;
-int
+static int
rtmsg(int cmd, int flags)
{
static int seq;
@@ -1250,7 +1256,7 @@ rtmsg(int cmd, int flags)
return (0);
}
-void
+static void
mask_addr(void)
{
int olen = so_mask.sa.sa_len;
@@ -1281,7 +1287,7 @@ mask_addr(void)
*--cp1 &= *--cp2;
}
-char *msgtypes[] = {
+const char *msgtypes[] = {
"",
"RTM_ADD: Add Route",
"RTM_DELETE: Delete Route",
@@ -1318,8 +1324,8 @@ char ifnetflags[] =
char addrnames[] =
"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
-void
-print_rtmsg(struct rt_msghdr *rtm, int msglen)
+static void
+print_rtmsg(struct rt_msghdr *rtm, int msglen __unused)
{
struct if_msghdr *ifm;
struct ifa_msghdr *ifam;
@@ -1327,7 +1333,7 @@ print_rtmsg(struct rt_msghdr *rtm, int msglen)
struct ifma_msghdr *ifmam;
#endif
struct if_announcemsghdr *ifan;
- char *state;
+ const char *state;
if (verbose == 0)
return;
@@ -1399,7 +1405,7 @@ print_rtmsg(struct rt_msghdr *rtm, int msglen)
}
}
-void
+static void
print_getmsg(struct rt_msghdr *rtm, int msglen)
{
struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
@@ -1493,7 +1499,7 @@ print_getmsg(struct rt_msghdr *rtm, int msglen)
#undef RTA_IGN
}
-void
+static void
pmsg_common(struct rt_msghdr *rtm)
{
(void) printf("\nlocks: ");
@@ -1503,7 +1509,7 @@ pmsg_common(struct rt_msghdr *rtm)
pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
}
-void
+static void
pmsg_addrs(char *cp, int addrs)
{
struct sockaddr *sa;
@@ -1516,7 +1522,7 @@ pmsg_addrs(char *cp, int addrs)
(void) printf("\nsockaddrs: ");
bprintf(stdout, addrs, addrnames);
(void) putchar('\n');
- for (i = 1; i; i <<= 1)
+ for (i = 1; i != 0; i <<= 1)
if (i & addrs) {
sa = (struct sockaddr *)cp;
(void) printf(" %s", routename(sa));
@@ -1526,15 +1532,15 @@ pmsg_addrs(char *cp, int addrs)
(void) fflush(stdout);
}
-void
-bprintf(FILE *fp, int b, u_char *s)
+static void
+bprintf(FILE *fp, int b, u_char *str)
{
int i;
int gotsome = 0;
if (b == 0)
return;
- while ((i = *s++) != 0) {
+ while ((i = *str++) != 0) {
if (b & (1 << (i-1))) {
if (gotsome == 0)
i = '<';
@@ -1542,28 +1548,28 @@ bprintf(FILE *fp, int b, u_char *s)
i = ',';
(void) putc(i, fp);
gotsome = 1;
- for (; (i = *s) > 32; s++)
+ for (; (i = *str) > 32; str++)
(void) putc(i, fp);
} else
- while (*s > 32)
- s++;
+ while (*str > 32)
+ str++;
}
if (gotsome)
(void) putc('>', fp);
}
int
-keyword(char *cp)
+keyword(const char *cp)
{
struct keytab *kt = keywords;
- while (kt->kt_cp && strcmp(kt->kt_cp, cp))
+ while (kt->kt_cp != NULL && strcmp(kt->kt_cp, cp) != 0)
kt++;
- return kt->kt_i;
+ return (kt->kt_i);
}
-void
-sodump(sup su, char *which)
+static void
+sodump(sup su, const char *which)
{
switch (su->sa.sa_family) {
case AF_LINK:
@@ -1591,7 +1597,7 @@ sodump(sup su, char *which)
#define END (4*1)
#define DELIM (4*2)
-void
+static void
sockaddr(char *addr, struct sockaddr *sa)
{
char *cp = (char *)sa;
@@ -1608,7 +1614,7 @@ sockaddr(char *addr, struct sockaddr *sa)
new = *addr - 'a' + 10;
} else if ((*addr >= 'A') && (*addr <= 'F')) {
new = *addr - 'A' + 10;
- } else if (*addr == 0)
+ } else if (*addr == '\0')
state |= END;
else
state |= DELIM;
@@ -1633,7 +1639,7 @@ sockaddr(char *addr, struct sockaddr *sa)
sa->sa_len = cp - (char *)sa;
}
-int
+static int
atalk_aton(const char *text, struct at_addr *addr)
{
u_int net, node;
@@ -1646,7 +1652,7 @@ atalk_aton(const char *text, struct at_addr *addr)
return(1);
}
-char *
+static char *
atalk_ntoa(struct at_addr at)
{
static char buf[20];
diff --git a/sbin/routed/Makefile b/sbin/routed/Makefile
index 89d04c8..8f2a819 100644
--- a/sbin/routed/Makefile
+++ b/sbin/routed/Makefile
@@ -1,15 +1,13 @@
# Make `routed` for FreeBSD
# $FreeBSD$
-PROG= routed
-SRCS= if.c input.c main.c output.c parms.c radix.c rdisc.c table.c trace.c
-MAN= routed.8
-SUBDIR= rtquery
-LDADD= -lmd
+PROG= routed
+MAN= routed.8
+SRCS= if.c input.c main.c output.c parms.c radix.c rdisc.c table.c trace.c
+WARNS?= 3
DPADD= ${LIBMD}
-# XXX this is verboten
-.if ${MACHINE_CPUARCH} != "i386" && ${MACHINE_CPUARCH} != "amd64"
-WARNS?= 0
-.endif
+LDADD= -lmd
+
+SUBDIR= rtquery
.include <bsd.prog.mk>
diff --git a/sbin/routed/if.c b/sbin/routed/if.c
index 1c185d7..9160e6f 100644
--- a/sbin/routed/if.c
+++ b/sbin/routed/if.c
@@ -29,6 +29,8 @@
* $FreeBSD$
*/
+#include <stdint.h>
+
#include "defs.h"
#include "pathnames.h"
@@ -948,9 +950,9 @@ ifinit(void)
} else if (now.tv_sec>(ifp->int_data.ts
+ CHECK_BAD_INTERVAL)) {
trace_act("interface %s has been off"
- " %ld seconds; forget it",
+ " %jd seconds; forget it",
ifp->int_name,
- (long)now.tv_sec-
+ (intmax_t)now.tv_sec -
ifp->int_data.ts);
ifdel(ifp);
}
diff --git a/sbin/routed/rtquery/Makefile b/sbin/routed/rtquery/Makefile
index 7076158..458d1ca 100644
--- a/sbin/routed/rtquery/Makefile
+++ b/sbin/routed/rtquery/Makefile
@@ -6,6 +6,6 @@ PROG= rtquery
MAN= rtquery.8
LDADD= -lmd
DPADD= ${LIBMD}
-WARNS?= 0
+WARNS?= 3
.include <bsd.prog.mk>
diff --git a/sbin/rtsol/Makefile b/sbin/rtsol/Makefile
index 2086c68..413b6d5 100644
--- a/sbin/rtsol/Makefile
+++ b/sbin/rtsol/Makefile
@@ -21,8 +21,8 @@ SRCDIR= ${.CURDIR}/../../usr.sbin/rtsold
PROG= rtsol
SRCS= rtsold.c rtsol.c if.c probe.c rtsock.c
NO_MAN=
-WARNS?= 0
+WARNS?= 3
CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H -DSMALL
.include <bsd.prog.mk>
diff --git a/secure/libexec/sftp-server/Makefile b/secure/libexec/sftp-server/Makefile
index 7947028..7069cff 100644
--- a/secure/libexec/sftp-server/Makefile
+++ b/secure/libexec/sftp-server/Makefile
@@ -5,8 +5,11 @@ SRCS= sftp-server.c sftp-common.c sftp-server-main.c
MAN= sftp-server.8
CFLAGS+=-I${SSHDIR} -include ssh_namespace.h
+# required when linking with a dynamic libssh
+SRCS+= roaming_dummy.c
+
DPADD= ${LIBSSH} ${LIBCRYPT} ${LIBCRYPTO} ${LIBZ}
-LDADD= -lcrypt -lcrypto -lz -static -lssh
+LDADD= -lssh -lcrypt -lcrypto -lz
.include <bsd.prog.mk>
diff --git a/secure/usr.sbin/sshd/Makefile b/secure/usr.sbin/sshd/Makefile
index 52d064e..d7a37a3 100644
--- a/secure/usr.sbin/sshd/Makefile
+++ b/secure/usr.sbin/sshd/Makefile
@@ -34,8 +34,8 @@ LDADD+= -lbsm
.if ${MK_KERBEROS_SUPPORT} != "no"
CFLAGS+= -DGSSAPI -DHAVE_GSSAPI_GSSAPI_H=1 -DHAVE_GSSAPI_GSSAPI_KRB5_H=1 -DKRB5 -DHEIMDAL
-DPADD+= ${LIBGSSAPI} ${LIBGSSAPI_KRB5}
-LDADD+= -lgssapi -lgssapi_krb5
+DPADD+= ${LIBGSSAPI_KRB5} ${LIBGSSAPI} ${LIBKRB5} ${LIBASN1}
+LDADD+= -lgssapi_krb5 -lgssapi -lkrb5 -lasn1
.endif
.if defined(X11BASE)
diff --git a/share/examples/Makefile b/share/examples/Makefile
index 315eb91..99d92c0 100644
--- a/share/examples/Makefile
+++ b/share/examples/Makefile
@@ -13,6 +13,7 @@ LDIRS= BSD_daemon \
drivers \
etc \
find_interface \
+ hast \
ibcs2 \
ipfw \
kld \
@@ -69,6 +70,11 @@ XFILES= BSD_daemon/FreeBSD.pfa \
find_interface/Makefile \
find_interface/README \
find_interface/find_interface.c \
+ hast/ucarp.sh \
+ hast/ucarp_down.sh \
+ hast/ucarp_up.sh \
+ hast/vip-down.sh \
+ hast/vip-up.sh \
ibcs2/README \
ibcs2/hello.uu \
ipfw/change_rules.sh \
diff --git a/share/examples/autofs/driver/Makefile b/share/examples/autofs/driver/Makefile
index 7a0f159..d577668 100644
--- a/share/examples/autofs/driver/Makefile
+++ b/share/examples/autofs/driver/Makefile
@@ -1,11 +1,11 @@
# $Id: Makefile,v 1.5 2004/09/08 08:27:12 bright Exp $
# $FreeBSD$
-PROG=autodriver
+PROG= autodriver
+NO_MAN=
SRCS= autodriver.c
-NO_MAN=
-WARNS= 4
+WARNS?= 4
CFLAGS+= -g
BINDIR?= /sbin
diff --git a/share/examples/hast/ucarp.sh b/share/examples/hast/ucarp.sh
new file mode 100755
index 0000000..6a02c89
--- /dev/null
+++ b/share/examples/hast/ucarp.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 The FreeBSD Foundation
+# All rights reserved.
+#
+# This software was developed by Pawel Jakub Dawidek under sponsorship from
+# the FreeBSD Foundation.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 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 AUTHORS 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 AUTHORS 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$
+
+# Shared IP address, unused for now.
+addr="10.99.0.3"
+# Password for UCARP communication.
+pass="password"
+# First node IP and interface for UCARP communication.
+nodea_srcip="10.99.0.1"
+nodea_ifnet="bge0"
+# Second node IP and interface for UCARP communication.
+nodeb_srcip="10.99.0.2"
+nodeb_ifnet="em3"
+
+export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
+
+vhid="1"
+upscript="/root/hast/sbin/hastd/vip-up.sh"
+downscript="/root/hast/sbin/hastd/vip-down.sh"
+
+ifconfig "${nodea_ifnet}" 2>/dev/null | grep -q "inet ${nodea_srcip} "
+if [ $? -eq 0 ]; then
+ srcip="${nodea_srcip}"
+ ifnet="${nodea_ifnet}"
+ node="node A"
+fi
+ifconfig "${nodeb_ifnet}" 2>/dev/null | grep -q "inet ${nodeb_srcip} "
+if [ $? -eq 0 ]; then
+ if [ -n "${srcip}" -o -n "${ifnet}" ]; then
+ echo "Unable to determine which node is this (both match)." >/dev/stderr
+ exit 1
+ fi
+ srcip="${nodeb_srcip}"
+ ifnet="${nodeb_ifnet}"
+ node="node B"
+fi
+if [ -z "${srcip}" -o -z "${ifnet}" ]; then
+ echo "Unable to determine which node is this (none match)." >/dev/stderr
+ exit 1
+fi
+ucarp -i ${ifnet} -s ${srcip} -v ${vhid} -a ${addr} -p ${pass} -u "${upscript}" -d "${downscript}"
diff --git a/share/examples/hast/ucarp_down.sh b/share/examples/hast/ucarp_down.sh
new file mode 100755
index 0000000..a5b3428
--- /dev/null
+++ b/share/examples/hast/ucarp_down.sh
@@ -0,0 +1,98 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 The FreeBSD Foundation
+# All rights reserved.
+#
+# This software was developed by Pawel Jakub Dawidek under sponsorship from
+# the FreeBSD Foundation.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 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 AUTHORS 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 AUTHORS 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$
+
+# Resource name as defined in /etc/hast.conf.
+resource="test"
+# Supported file system types: UFS, ZFS
+fstype="UFS"
+# ZFS pool name. Required only when fstype == ZFS.
+pool="test"
+# File system mount point. Required only when fstype == UFS.
+mountpoint="/mnt/test"
+# Name of HAST provider as defined in /etc/hast.conf.
+# Required only when fstype == UFS.
+device="/dev/hast/${resource}"
+
+export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
+
+# KIll UP script if it still runs in the background.
+sig="TERM"
+for i in `jot 30`; do
+ pgid=`pgrep -f ucarp_up.sh | head -1`
+ [ -n "${pgid}" ] || break
+ kill -${sig} -- -${pgid}
+ sig="KILL"
+ sleep 1
+done
+if [ -n "${pgid}" ]; then
+ logger -p local0.error -t hast "UCARP UP process for resource ${resource} is still running after 30 seconds."
+ exit 1
+fi
+logger -p local0.debug -t hast "UCARP UP is not running."
+
+case "${fstype}" in
+UFS)
+ mount | egrep -q "^${device} on "
+ if [ $? -eq 0 ]; then
+ # Forcibly unmount file system.
+ out=`umount -f "${mountpoint}" 2>&1`
+ if [ $? -ne 0 ]; then
+ logger -p local0.error -t hast "Unable to unmount file system for resource ${resource}: ${out}."
+ exit 1
+ fi
+ logger -p local0.debug -t hast "File system for resource ${resource} unmounted."
+ fi
+ ;;
+ZFS)
+ zpool list | egrep -q "^${pool} "
+ if [ $? -eq 0 ]; then
+ # Forcibly export file pool.
+ out=`zpool export -f "${pool}" 2>&1`
+ if [ $? -ne 0 ]; then
+ logger -p local0.error -t hast "Unable to export pool for resource ${resource}: ${out}."
+ exit 1
+ fi
+ logger -p local0.debug -t hast "ZFS pool for resource ${resource} exported."
+ fi
+ ;;
+esac
+
+# Change role to secondary for our resource.
+out=`hastctl role secondary "${resource}" 2>&1`
+if [ $? -ne 0 ]; then
+ logger -p local0.error -t hast "Unable to change to role to secondary for resource ${resource}: ${out}."
+ exit 1
+fi
+logger -p local0.debug -t hast "Role for resource ${resource} changed to secondary."
+
+logger -p local0.info -t hast "Successfully switched to secondary for resource ${resource}."
+
+exit 0
diff --git a/share/examples/hast/ucarp_up.sh b/share/examples/hast/ucarp_up.sh
new file mode 100755
index 0000000..9e56040
--- /dev/null
+++ b/share/examples/hast/ucarp_up.sh
@@ -0,0 +1,105 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 The FreeBSD Foundation
+# All rights reserved.
+#
+# This software was developed by Pawel Jakub Dawidek under sponsorship from
+# the FreeBSD Foundation.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 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 AUTHORS 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 AUTHORS 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$
+
+# Resource name as defined in /etc/hast.conf.
+resource="test"
+# Supported file system types: UFS, ZFS
+fstype="UFS"
+# ZFS pool name. Required only when fstype == ZFS.
+pool="test"
+# File system mount point. Required only when fstype == UFS.
+mountpoint="/mnt/test"
+# Name of HAST provider as defined in /etc/hast.conf.
+device="/dev/hast/${resource}"
+
+export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
+
+# If there is secondary worker process, it means that remote primary process is
+# still running. We have to wait for it to terminate.
+for i in `jot 30`; do
+ pgrep -f "hastd: ${resource} \(secondary\)" >/dev/null 2>&1 || break
+ sleep 1
+done
+if pgrep -f "hastd: ${resource} \(secondary\)" >/dev/null 2>&1; then
+ logger -p local0.error -t hast "Secondary process for resource ${resource} is still running after 30 seconds."
+ exit 1
+fi
+logger -p local0.debug -t hast "Secondary process in not running."
+
+# Change role to primary for our resource.
+out=`hastctl role primary "${resource}" 2>&1`
+if [ $? -ne 0 ]; then
+ logger -p local0.error -t hast "Unable to change to role to primary for resource ${resource}: ${out}."
+ exit 1
+fi
+# Wait few seconds for provider to appear.
+for i in `jot 50`; do
+ [ -c "${device}" ] && break
+ sleep 0.1
+done
+if [ ! -c "${device}" ]; then
+ logger -p local0.error -t hast "Device ${device} didn't appear."
+ exit 1
+fi
+logger -p local0.debug -t hast "Role for resource ${resource} changed to primary."
+
+case "${fstype}" in
+UFS)
+ # Check the file system.
+ fsck -y -t ufs "${device}" >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ logger -p local0.error -t hast "File system check for resource ${resource} failed."
+ exit 1
+ fi
+ logger -p local0.debug -t hast "File system check for resource ${resource} finished."
+ # Mount the file system.
+ out=`mount -t ufs "${device}" "${mountpoint}" 2>&1`
+ if [ $? -ne 0 ]; then
+ logger -p local0.error -t hast "File system mount for resource ${resource} failed: ${out}."
+ exit 1
+ fi
+ logger -p local0.debug -t hast "File system for resource ${resource} mounted."
+ ;;
+ZFS)
+ # Import ZFS pool. Do it forcibly as it remembers hostid of
+ # the other cluster node.
+ out=`zpool import -f "${pool}" 2>&1`
+ if [ $? -ne 0 ]; then
+ logger -p local0.error -t hast "ZFS pool import for resource ${resource} failed: ${out}."
+ exit 1
+ fi
+ logger -p local0.debug -t hast "ZFS pool for resource ${resource} imported."
+ ;;
+esac
+
+logger -p local0.info -t hast "Successfully switched to primary for resource ${resource}."
+
+exit 0
diff --git a/share/examples/hast/vip-down.sh b/share/examples/hast/vip-down.sh
new file mode 100755
index 0000000..5e47609
--- /dev/null
+++ b/share/examples/hast/vip-down.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# $FreeBSD$
+
+/root/hast/sbin/hastd/ucarp_down.sh
+exit 0
diff --git a/share/examples/hast/vip-up.sh b/share/examples/hast/vip-up.sh
new file mode 100755
index 0000000..61dabe9
--- /dev/null
+++ b/share/examples/hast/vip-up.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+# $FreeBSD$
+
+set -m
+/root/hast/sbin/hastd/ucarp_up.sh &
+set +m
+exit 0
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index ceb3859..ac78c83 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -62,6 +62,7 @@ MAN= aac.4 \
bridge.4 \
bt.4 \
bwi.4 \
+ bwn.4 \
cardbus.4 \
carp.4 \
cas.4 \
diff --git a/share/man/man4/ahci.4 b/share/man/man4/ahci.4
index b3d2e23..675bab6 100644
--- a/share/man/man4/ahci.4
+++ b/share/man/man4/ahci.4
@@ -48,9 +48,10 @@ module at boot time, place the following line in
ahci_load="YES"
.Ed
.Pp
-The following tunables are settable from the loader:
+The following tunables are settable from the
+.Xr loader 8 :
.Bl -ohang
-.It Va hint.ahci.X.msi
+.It Va hint.ahci. Ns Ar X Ns Va .msi
controls Message Signaled Interrupts (MSI) usage by the specified controller
.Bl -tag -compact
.It 0
@@ -60,15 +61,15 @@ single MSI vector used, if supported (default);
.It 2
multiple MSI vectors used, if supported;
.El
-.It Va hint.ahci.X.ccc
+.It Va hint.ahci. Ns Ar X Ns Va .ccc
controls Command Completion Coalescing (CCC) usage by the specified controller.
Non-zero value enables CCC and defines maximum time (in ms), request can wait
for interrupt, if there are some more requests present on controller queue.
CCC reduces number of context switches on systems with many parallel requests,
but it can decrease disk performance on some workloads due to additional
command latency.
-.It Va hint.ahcich.X.pm_level
-controls SATA interface Power Management for specified channel,
+.It Va hint.ahcich. Ns Ar X Ns Va .pm_level
+controls SATA interface Power Management for the specified channel,
allowing some power to be saved at the cost of additional command
latency.
Possible values:
@@ -92,18 +93,20 @@ Because of artificial entering latency, performance degradation in modes
.Pp
Note that interface Power Management is not compatible with
device presence detection.
-You will have to reset bus manually on device hot-plug.
-.It Va hint.ahcich.X.sata_rev
+A manual bus reset is needed on device hot-plug.
+.It Va hint.ahcich. Ns Ar X Ns Va .sata_rev
setting to nonzero value limits maximum SATA revision (speed).
Values 1, 2 and 3 are respectively 1.5, 3 and 6Gbps.
.El
.Sh DESCRIPTION
-This driver provides the CAM subsystem with native access to the
+This driver provides the
+.Xr CAM 4
+subsystem with native access to the
.Tn SATA
ports of AHCI-compatible controllers.
Each SATA port found is represented to CAM as a separate bus with one
target, or, if HBA supports Port Multipliers, 16 targets.
-Most of the bus-management details are handled by the SATA-specific
+Most of the bus-management details are handled by the SATA-specific
transport of CAM.
Connected ATA disks are handled by the ATA protocol disk peripheral driver
.Xr ada 4 .
@@ -121,7 +124,8 @@ and Message Signaled Interrupts.
.Pp
AHCI hardware is also supported by ataahci driver from
.Xr ata 4
-subsystem. If both drivers are loaded at the same time, this one will be
+subsystem.
+If both drivers are loaded at the same time, this one will be
given precedence as the more functional of the two.
.Sh HARDWARE
The
@@ -134,11 +138,11 @@ it supports AHCI part of legacy-PATA + AHCI-SATA combined controllers,
such as JMicron JMB36x and Marvell 88SX61xx.
.Sh SEE ALSO
.Xr ada 4 ,
+.Xr ata 4 ,
.Xr cd 4 ,
.Xr da 4 ,
.Xr sa 4 ,
-.Xr scsi 4 ,
-.Xr ata 4
+.Xr scsi 4
.Sh HISTORY
The
.Nm
diff --git a/share/man/man4/bwn.4 b/share/man/man4/bwn.4
index 8237112..1293c36 100644
--- a/share/man/man4/bwn.4
+++ b/share/man/man4/bwn.4
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 15, 2010
+.Dd February 25, 2010
.Dt BWN 4
.Os
.Sh NAME
@@ -69,6 +69,8 @@ The
port needs to be installed before
.Xr ifconfig 8
will work.
+Most cases you need to use bwn_v4_ucode module but if you are a
+LP (low power) PHY user please uses bwn_v4_lp_ucode module.
.Sh HARDWARE
The
.Nm
diff --git a/share/man/man4/man4.powerpc/Makefile b/share/man/man4/man4.powerpc/Makefile
index d213d83..57196a3 100644
--- a/share/man/man4/man4.powerpc/Makefile
+++ b/share/man/man4/man4.powerpc/Makefile
@@ -7,6 +7,7 @@ MAN= adb.4 \
cuda.4 \
pmu.4 \
powermac_nvram.4 \
+ smu.4 \
snd_ai2s.4 \
snd_davbus.4 \
tsec.4
diff --git a/share/man/man4/man4.powerpc/smu.4 b/share/man/man4/man4.powerpc/smu.4
new file mode 100644
index 0000000..893522c
--- /dev/null
+++ b/share/man/man4/man4.powerpc/smu.4
@@ -0,0 +1,125 @@
+.\"-
+.\" Copyright (c) 2010 Nathan Whitehorn <nwhitehorn@FreeBSD.org>
+.\" 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 THE AUTHOR 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$
+.\"
+.Dd February 22, 2010
+.Dt SMU 4
+.Os
+.Sh NAME
+.Nm smu
+.Nd Apple System Management Unit Driver
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device smu"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the System Management Unit (SMU) found in many
+Apple G5 systems.
+This includes most Power Macintosh G5 and all iMac G5 systems.
+.Pp
+The Apple SMU controller provides software power management and thermal
+control functionality, and is responsible for managing system cooling
+devices.
+.Sh HARDWARE
+Chips supported by the
+.Nm
+driver include:
+.Pp
+.Bl -bullet -compact
+.It
+Apple System Management Unit
+.El
+.Sh THERMAL MANAGEMENT
+The
+.Nm
+driver provides basic automatic thermal management. Without a userspace
+daemon providing more advanced control, the driver will attempt to maintain
+system temperatures in a conservative range through coarse-grained control of
+system cooling devices (see below). Automatic kernel-level thermal control
+will take over if more than 3 seconds elapses between userspace cooling
+setting adjustments.
+.Sh SYSCTL VARIABLES
+The
+.Nm
+driver provides power management services and thermal readout through a
+sysctl interface.
+The following sysctls can be used to control the
+power management behavior and to examine current system power and
+thermal conditions.
+.Bl -tag -width indent
+.It Va dev.smu.%d.server_mode
+Restart after power failure behavior (1 causes system to reboot after power
+cut, 0 causes system to remain off).
+.It Va dev.smu.%d.target_temp
+Target system temperature, in degrees Celsius. The
+.Nm
+driver will attempt to adjust fans to maintain the temperature of the
+warmest component in the system at or below this level.
+.It Va dev.smu.%d.critical_temp
+System critical temperature, in degrees Celsius. If any component in
+the system exceeds this temperature, the machine will be shut down within
+500 ms.
+.It Va dev.smu.%d.fans.%s.minrpm
+Minimum allowed speed for this fan.
+.It Va dev.smu.%d.fans.%s.maxrpm
+Maximum allowed speed for this fan.
+.It Va dev.smu.%d.fans.%s.rpm
+Current speed for this fan. The fan speed can be adjusted by changing this
+sysctl. If more than 3 seconds elapses between fan speed adjustments, the
+kernel will resume automatic control of the fan.
+.It Va dev.smu.%d.sensors.%s
+Current reading from this sensor. Four sensor types are supported. Temperature
+sensors are in units of degrees Celsius, current sensors in milliamps, voltage
+sensors in millivolts, and power sensors in milliwatts.
+.El
+.Sh LED INTERFACE
+The
+.Nm
+driver provides an
+.Xr led 4
+annunciator interface at
+.Pa /dev/led/sleepled .
+.Sh SEE ALSO
+.Xr acpi 4 ,
+.Xr pmu 4 ,
+.Xr led 4
+.Sh HISTORY
+The
+.Nm
+device driver appeared in
+.Fx 8.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Nathan Whitehorn
+.Aq nwhitehorn@FreeBSD.org .
diff --git a/share/man/man4/msk.4 b/share/man/man4/msk.4
index f0991e9..7a842f5 100644
--- a/share/man/man4/msk.4
+++ b/share/man/man4/msk.4
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 6, 2009
+.Dd March 1, 2010
.Dt MSK 4
.Os
.Sh NAME
@@ -235,6 +235,12 @@ variables and
.Xr loader 8
tunables:
.Bl -tag -width indent
+.It Va dev.mskc.%d.int_holdoff
+Maximum number of time to delay interrupts.
+The valid range is 0 to 34359738 for 125MHz clock in units of 1us,
+the default is 100 (100us).
+The interface need to be brought down and up again before a change
+takes effect.
.It Va dev.mskc.%d.process_limit
Maximum amount of Rx events to be processed in the event loop before
rescheduling a taskqueue.
diff --git a/share/man/man4/ng_ipfw.4 b/share/man/man4/ng_ipfw.4
index a1249db..9a9099e 100644
--- a/share/man/man4/ng_ipfw.4
+++ b/share/man/man4/ng_ipfw.4
@@ -24,13 +24,14 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 10, 2009
+.Dd March 2, 2010
.Dt NG_IPFW 4
.Os
.Sh NAME
.Nm ng_ipfw
.Nd interface between netgraph and IP firewall
.Sh SYNOPSIS
+.In netinet/ip_var.h
.In netgraph/ng_ipfw.h
.Sh DESCRIPTION
The
@@ -73,30 +74,18 @@ If no hook matches, packets are discarded.
Packets injected via the
.Cm netgraph
command are tagged with
-.Vt "struct ng_ipfw_tag" .
+.Vt "struct ipfw_rule_ref" .
This tag contains information that helps the packet to re-enter
.Xr ipfw 4
processing, should the packet come back from
.Xr netgraph 4
to
.Xr ipfw 4 .
-.Bd -literal -offset 4n
-struct ng_ipfw_tag {
- struct m_tag mt; /* tag header */
- struct ip_fw *rule; /* matching rule */
- uint32_t rule_id; /* matching rule id */
- uint32_t chain_id; /* ruleset id */
- struct ifnet *ifp; /* interface, for ip_output */
- int dir; /* packet direction */
-#define NG_IPFW_OUT 0
-#define NG_IPFW_IN 1
-};
-.Ed
.Pp
Packets received by a node from
.Xr netgraph 4
-must be tagged with
-.Vt "struct ng_ipfw_tag"
+subsystem must be tagged with
+.Vt "struct ipfw_rule_ref"
tag.
Packets re-enter IP firewall processing at the next rule.
If no tag is supplied, packets are discarded.
diff --git a/share/man/man4/siis.4 b/share/man/man4/siis.4
index ab67cbc..8f70839 100644
--- a/share/man/man4/siis.4
+++ b/share/man/man4/siis.4
@@ -48,12 +48,13 @@ module at boot time, place the following line in
siis_load="YES"
.Ed
.Pp
-The following tunables are settable from the loader:
+The following tunables are settable from the
+.Xr loader 8 :
.Bl -ohang
-.It Va hint.siis.X.msi
+.It Va hint.siis. Ns Ar X Ns Va .msi
controls Message Signaled Interrupts (MSI) usage by the specified controller.
-.It Va hint.siisch.X.pm_level
-controls SATA interface Power Management for specified channel,
+.It Va hint.siisch. Ns Ar X Ns Va .pm_level
+controls SATA interface Power Management for the specified channel,
allowing some power to be saved at the cost of additional command
latency.
Possible values:
@@ -65,13 +66,15 @@ device is allowed to initiate PM state change, host is passive.
.El
Note that interface Power Management is not compatible with
device presence detection.
-You will have to reset bus manually on device hot-plug.
-.It Va hint.siisch.X.sata_rev
+A manual bus reset is needed on device hot-plug.
+.It Va hint.siisch. Ns Ar X Ns Va .sata_rev
setting to nonzero value limits maximum SATA revision (speed).
Values 1, 2 and 3 are respectively 1.5, 3 and 6Gbps.
.El
.Sh DESCRIPTION
-This driver provides the CAM subsystem native access to the
+This driver provides the
+.Xr CAM 4
+subsystem with native access to the
.Tn SATA
ports of controller.
Each SATA port is represented to CAM as a separate bus with 16 targets.
@@ -90,14 +93,15 @@ Port Multipliers (including FIS-based switching), hardware command queues
(31 command per port), Native Command Queuing, SATA interface Power Management,
device hot-plug and Message Signaled Interrupts.
.Pp
-Same hardware is also supported by atasiliconimage driver from
+Same hardware is also supported by the atasiliconimage driver from
.Xr ata 4
-subsystem. If both drivers are loaded at the same time, this one will be
+subsystem.
+If both drivers are loaded at the same time, this one will be
given precedence as the more functional of the two.
.Sh HARDWARE
The
.Nm
-driver supports following controllers:
+driver supports the following controllers:
.Bl -bullet -compact
.It
SiI3124
@@ -108,11 +112,11 @@ SiI3531
.El
.Sh SEE ALSO
.Xr ada 4 ,
+.Xr ata 4 ,
.Xr cd 4 ,
.Xr da 4 ,
.Xr sa 4 ,
-.Xr scsi 4 ,
-.Xr ata 4
+.Xr scsi 4
.Sh HISTORY
The
.Nm
diff --git a/share/man/man5/core.5 b/share/man/man5/core.5
index 2a1e16b..b2b57f1 100644
--- a/share/man/man5/core.5
+++ b/share/man/man5/core.5
@@ -68,13 +68,27 @@ the core image to.
This filename can be absolute, or relative (which
will resolve to the current working directory of the program
generating it).
-Any sequence of
-.Em \&%N
-in this filename template will be replaced by the process name,
-.Em \&%P
-by the processes PID, and
-.Em \&%U
-by the UID.
+.Pp
+The following format specifiers may be used in the
+.Va kern.corefile
+sysctl to insert additional information into the resulting core file
+name:
+.Bl -tag -width "1234567890" -compact -offset "12345"
+.It Em \&%H
+Machine hostname.
+.It Em \&%I
+An index starting at zero until the sysctl
+.Em debug.num_cores
+is reached. This can be useful for limiting the number of corefiles
+generated by a particular process.
+.It Em \&%N
+process name.
+.It Em \&%P
+processes PID.
+.It Em \&%U
+process UID.
+.El
+.Pp
The name defaults to
.Em \&%N.core ,
yielding the traditional
@@ -89,6 +103,26 @@ changed to generate a core dump by setting the
variable
.Va kern.sugid_coredump
to 1.
+.Pp
+Corefiles can be compressed by the kernel if the following items
+are included in the kernel configuration file:
+.Bl -tag -width "1234567890" -compact -offset "12345"
+.It options
+COMPRESS_USER_CORES
+.It devices
+gzio
+.El
+.Pp
+When COMPRESS_USER_CORES is included the following sysctls can control
+if core files will be compressed:
+.Bl -tag -width "kern.compress_user_cores_gzlevel" -compact -offset "12345"
+.It Em kern.compress_user_cores_gzlevel
+Gzip compression level. Defaults to -1.
+.It Em kern.compress_user_cores
+Actually compress user cores. Core files will have the suffix
+.Em .gz
+appended to them.
+.El
.Sh EXAMPLES
In order to store all core images in per-user private areas under
.Pa /var/coredumps ,
diff --git a/share/man/man5/devfs.rules.5 b/share/man/man5/devfs.rules.5
index c1e5d93..8a7b3d6 100644
--- a/share/man/man5/devfs.rules.5
+++ b/share/man/man5/devfs.rules.5
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 30, 2006
+.Dd February 21, 2010
.Dt DEVFS.RULES 5
.Os
.Sh NAME
@@ -83,8 +83,16 @@ devfs_system_ruleset="localrules"
.Ed
.Sh FILES
.Bl -tag -compact
-.It Pa /etc/devfs.rules
.It Pa /etc/defaults/devfs.rules
+Default
+.Nm
+configuration file.
+.It Pa /etc/devfs.rules
+Local
+.Nm
+configuration file. Rulesets in here override those in
+.Pa /etc/defaults/devfs.rules
+with the same ruleset number, otherwise the two files are effectively merged.
.El
.Sh EXAMPLES
To make all the partitions of
diff --git a/share/man/man5/rc.conf.5 b/share/man/man5/rc.conf.5
index f8d265b..96f64d3 100644
--- a/share/man/man5/rc.conf.5
+++ b/share/man/man5/rc.conf.5
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 11, 2009
+.Dd February 12, 2010
.Dt RC.CONF 5
.Os
.Sh NAME
@@ -1746,6 +1746,27 @@ is set to
.Dq Li YES ,
these are the flags to pass to
.Xr inetd 8 .
+.It Va hastd_enable
+.Pq Vt bool
+If set to
+.Dq Li YES ,
+run the
+.Xr hastd 8
+daemon.
+.It Va hastd_program
+.Pq Vt str
+Path to
+.Xr hastd 8
+(default
+.Pa /sbin/hastd ) .
+.It Va hastd_flags
+.Pq Vt str
+If
+.Va hastd_enable
+is set to
+.Dq Li YES ,
+these are the flags to pass to
+.Xr hastd 8 .
.It Va named_enable
.Pq Vt bool
If set to
diff --git a/share/man/man9/BUF_ISLOCKED.9 b/share/man/man9/BUF_ISLOCKED.9
index 7344869..d55f2f5 100644
--- a/share/man/man9/BUF_ISLOCKED.9
+++ b/share/man/man9/BUF_ISLOCKED.9
@@ -57,6 +57,7 @@ An exclusive lock is held by someone other than curthread
A shared lock is held.
.It Li 0
The lock is not held by anyone.
+.El
.Sh SEE ALSO
.Xr lockstatus 9 ,
.Xr buf 9 ,
diff --git a/share/man/man9/BUF_RECURSED.9 b/share/man/man9/BUF_RECURSED.9
index dfe818f..2e369ea 100644
--- a/share/man/man9/BUF_RECURSED.9
+++ b/share/man/man9/BUF_RECURSED.9
@@ -54,6 +54,7 @@ The buffer linked to the lock.
See
.Xr lockmgr_recursed 9
for details.
+.El
.Sh SEE ALSO
.Xr buf 9 ,
.Xr BUF_LOCK 9 ,
diff --git a/share/man/man9/DEVICE_PROBE.9 b/share/man/man9/DEVICE_PROBE.9
index b159fd2..7b400e7 100644
--- a/share/man/man9/DEVICE_PROBE.9
+++ b/share/man/man9/DEVICE_PROBE.9
@@ -127,6 +127,7 @@ The driver expects its parent to tell it which children to manage
and no probing is really done.
The device only matches if its parent bus specifically said to use
this driver.
+.El
.Sh SEE ALSO
.Xr device 9 ,
.Xr DEVICE_ATTACH 9 ,
diff --git a/share/man/man9/VOP_LOCK.9 b/share/man/man9/VOP_LOCK.9
index cdf1714..6c54a38 100644
--- a/share/man/man9/VOP_LOCK.9
+++ b/share/man/man9/VOP_LOCK.9
@@ -114,6 +114,7 @@ directly.
.Fn vn_lock
also does not want a thread specified as argument but it
assumes curthread to be used.
+.El
.Sh RETURN VALUES
Zero is returned on success, otherwise an error is returned.
.Sh SEE ALSO
diff --git a/share/man/man9/devfs_set_cdevpriv.9 b/share/man/man9/devfs_set_cdevpriv.9
index 934e494..0896d4d 100644
--- a/share/man/man9/devfs_set_cdevpriv.9
+++ b/share/man/man9/devfs_set_cdevpriv.9
@@ -108,7 +108,7 @@ The private driver data was not associated with current
filedescriptor, or
.Fn devfs_clear_cdevpriv
was called.
-.Pp
+.El
.Sh SEE ALSO
.Xr open 2 ,
.Xr close 2 ,
diff --git a/share/man/man9/ieee80211_scan.9 b/share/man/man9/ieee80211_scan.9
index 7ac41bd..018f70f 100644
--- a/share/man/man9/ieee80211_scan.9
+++ b/share/man/man9/ieee80211_scan.9
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd August 4, 2009
+.Dd February 20, 2010
.Dt IEEE80211_SCAN 9
.Os
.Sh NAME
@@ -177,8 +177,8 @@ Scanning is not tied to the
state machine that governs vaps except for linkage to the
.Dv IEEE80211_S_SCAN
state.
-One one vap at a time may be scanning; this scheduling policy
-is handle in
+Only one vap at a time may be scanning; this scheduling policy
+is handled in
.Fn ieee80211_new_state
and is transparent to scanning code.
.Pp
diff --git a/share/man/man9/namei.9 b/share/man/man9/namei.9
index 1ffabff..0325c36 100644
--- a/share/man/man9/namei.9
+++ b/share/man/man9/namei.9
@@ -333,7 +333,7 @@ or an entire pathname exceeded 1023 characters.
.It Bq Er ENOENT
A component of the specified pathname does not exist,
or the pathname is an empty string.
-.It Bq Er ACCES
+.It Bq Er EACCES
An attempt is made to access a file in a way forbidden by its file access
permissions.
.It Bq Er ELOOP
diff --git a/share/man/man9/netisr.9 b/share/man/man9/netisr.9
index ed2a84e..37fd367 100644
--- a/share/man/man9/netisr.9
+++ b/share/man/man9/netisr.9
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 26, 2009
+.Dd February 22, 2010
.Dt NETISR 9
.Os
.Sh NAME
@@ -66,6 +66,8 @@ The
.Nm
kernel interface suite allows device drivers (and other packet sources) to
direct packets to protocols for directly dispatched or deferred processing.
+Protocol registration and work stream statistics may be monitored using
+.Xr netstat 1 .
.Ss Protocol registration
Protocols register and unregister handlers using
.Fn netisr_register
@@ -209,6 +211,7 @@ IPv6
.It Dv NETISR_NATM
ATM
.It Dv NETISR_EPAIR
+.Xr netstat 1 ,
.Xr epair 4
.El
.Sh AUTHORS
diff --git a/share/man/man9/vm_page_alloc.9 b/share/man/man9/vm_page_alloc.9
index 02e2b93..81070d6 100644
--- a/share/man/man9/vm_page_alloc.9
+++ b/share/man/man9/vm_page_alloc.9
@@ -26,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 13, 2001
+.Dd February 27, 2010
.Dt VM_PAGE_ALLOC 9
.Os
.Sh NAME
@@ -48,16 +48,26 @@ within
.Fa object .
It is assumed that a page has not already been allocated at
.Fa pindex .
-The page returned is inserted into the object, but is not inserted
-into the pmap.
+The page returned is inserted into the object, unless
+.Dv VM_ALLOC_NOOBJ
+is specified in the
+.Fa page_req ,
+but is not inserted into a pmap.
+The page may exists in the vm object cache, in which case it will
+be reactivated instead, moving from the cache into the object page list.
.Pp
.Fn vm_page_alloc
-will not block.
+will not sleep.
.Pp
Its arguments are:
.Bl -tag -width ".Fa page_req"
.It Fa object
The VM object to allocate the page for.
+The
+.Fa object
+must be locked if
+.Dv VM_ALLOC_NOOBJ
+is not specified.
.It Fa pindex
The index into the object at which the page should be inserted.
.It Fa page_req
@@ -82,12 +92,24 @@ than zero.
.It Dv VM_ALLOC_ZERO
Indicate a preference for a pre-zeroed page.
There is no guarantee that the page thus returned will be zeroed, but
-it will be marked as such.
+it will be marked by
+.Dv PG_ZERO
+flag if it is zeroed.
.It Dv VM_ALLOC_NOOBJ
-The page is associated with an unmanaged memory region, that is, there
-is no backing VM object.
-This is typically used to allocate pages within the kernel virtual
-address space.
+Do not associate the allocated page with a vm object.
+The
+.Fa object
+argument is ignored.
+.It Dv VM_ALLOC_NOBUSY
+The page returned will not be busied.
+.It Dv VM_ALLOC_WIRED
+The returned page is wired.
+.It Dv VM_ALLOC_IFNOTCACHED
+Only allocate the page if it is not cached in the
+.Fa object .
+If the page at the specified
+.Fa pindex
+is cached, NULL is returned instead.
.El
.El
.Sh RETURN VALUES
diff --git a/share/mk/bsd.cpu.mk b/share/mk/bsd.cpu.mk
index 06b7af1..2ef272c 100644
--- a/share/mk/bsd.cpu.mk
+++ b/share/mk/bsd.cpu.mk
@@ -202,16 +202,7 @@ MACHINE_CPU = itanium
#.endif
.if ${MACHINE_CPUARCH} == "mips"
-#. if defined(TARGET_BIG_ENDIAN)
-#CFLAGS += -EB
-#LDFLAGS += -Wl,-EB
-#LD += -EB
-#. else
-#CFLAGS += -EL
-#LDFLAGS += -Wl,-EL
-#LD += -EL
-#. endif
-CFLAGS += -msoft-float -G0 -mabicalls
+CFLAGS += -G0
.endif
# NB: COPTFLAGS is handled in /usr/src/sys/conf/kern.pre.mk
diff --git a/share/mk/bsd.libnames.mk b/share/mk/bsd.libnames.mk
index ab2a872..c80fe23 100644
--- a/share/mk/bsd.libnames.mk
+++ b/share/mk/bsd.libnames.mk
@@ -135,6 +135,8 @@ LIBRADIUS?= ${DESTDIR}${LIBDIR}/libradius.a
LIBREADLINE?= ${DESTDIR}${LIBDIR}/libreadline.a
LIBROKEN?= ${DESTDIR}${LIBDIR}/libroken.a
LIBRPCSVC?= ${DESTDIR}${LIBDIR}/librpcsvc.a
+LIBRPCSEC_GSS?= ${DESTDIR}${LIBDIR}/librpcsec_gss.a
+LIBRT?= ${DESTDIR}${LIBDIR}/librt.a
LIBSBUF?= ${DESTDIR}${LIBDIR}/libsbuf.a
LIBSDP?= ${DESTDIR}${LIBDIR}/libsdp.a
LIBSMB?= ${DESTDIR}${LIBDIR}/libsmb.a
diff --git a/share/zoneinfo/Makefile b/share/zoneinfo/Makefile
index 6bbc989..6de8ef5 100644
--- a/share/zoneinfo/Makefile
+++ b/share/zoneinfo/Makefile
@@ -29,6 +29,8 @@
#
CLEANFILES+= yearistype
+CONTRIBDIR= ${.CURDIR}/../../contrib/tzdata/
+.PATH: ${CONTRIBDIR}
.if defined(LEAPSECONDS)
LEAPFILE= -L leapseconds
@@ -44,6 +46,8 @@ POSIXRULES= America/New_York
TZFILES+= backward systemv
.endif
+TZFILES:= ${TZFILES:S/^/${CONTRIBDIR}/}
+
all: yearistype
beforeinstall:
@@ -52,7 +56,7 @@ beforeinstall:
-u ${BINOWN} -g ${BINGRP} -m ${NOBINMODE} \
${LEAPFILE} -y ${.OBJDIR}/yearistype ${TZFILES}
${INSTALL} -o ${BINOWN} -g ${BINGRP} -m ${NOBINMODE} \
- ${.CURDIR}/zone.tab ${DESTDIR}/usr/share/zoneinfo/
+ ${CONTRIBDIR}/zone.tab ${DESTDIR}/usr/share/zoneinfo/
afterinstall:
#
diff --git a/sys/amd64/isa/atpic_vector.S b/sys/amd64/amd64/atpic_vector.S
index e7dcbc3..e7dcbc3 100644
--- a/sys/amd64/isa/atpic_vector.S
+++ b/sys/amd64/amd64/atpic_vector.S
diff --git a/sys/amd64/amd64/busdma_machdep.c b/sys/amd64/amd64/busdma_machdep.c
index 3197d15..fae6ef3 100644
--- a/sys/amd64/amd64/busdma_machdep.c
+++ b/sys/amd64/amd64/busdma_machdep.c
@@ -239,8 +239,7 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
newtag->alignment = alignment;
newtag->boundary = boundary;
newtag->lowaddr = trunc_page((vm_paddr_t)lowaddr) + (PAGE_SIZE - 1);
- newtag->highaddr = trunc_page((vm_paddr_t)highaddr) +
- (PAGE_SIZE - 1);
+ newtag->highaddr = trunc_page((vm_paddr_t)highaddr) + (PAGE_SIZE - 1);
newtag->filter = filter;
newtag->filterarg = filterarg;
newtag->maxsize = maxsize;
@@ -605,13 +604,18 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat,
vendaddr = (vm_offset_t)buf + buflen;
while (vaddr < vendaddr) {
+ bus_size_t sg_len;
+
+ sg_len = PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK);
if (pmap)
paddr = pmap_extract(pmap, vaddr);
else
paddr = pmap_kextract(vaddr);
- if (run_filter(dmat, paddr) != 0)
+ if (run_filter(dmat, paddr) != 0) {
+ sg_len = roundup2(sg_len, dmat->alignment);
map->pagesneeded++;
- vaddr += (PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK));
+ }
+ vaddr += sg_len;
}
CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded);
}
@@ -644,6 +648,8 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat,
bmask = ~(dmat->boundary - 1);
for (seg = *segp; buflen > 0 ; ) {
+ bus_size_t max_sgsize;
+
/*
* Get the physical address for this segment.
*/
@@ -655,11 +661,15 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat,
/*
* Compute the segment size, and adjust counts.
*/
- sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK);
- if (sgsize > dmat->maxsegsz)
- sgsize = dmat->maxsegsz;
- if (buflen < sgsize)
- sgsize = buflen;
+ max_sgsize = MIN(buflen, dmat->maxsegsz);
+ sgsize = PAGE_SIZE - ((vm_offset_t)curaddr & PAGE_MASK);
+ if (map->pagesneeded != 0 && run_filter(dmat, curaddr)) {
+ sgsize = roundup2(sgsize, dmat->alignment);
+ sgsize = MIN(sgsize, max_sgsize);
+ curaddr = add_bounce_page(dmat, map, vaddr, sgsize);
+ } else {
+ sgsize = MIN(sgsize, max_sgsize);
+ }
/*
* Make sure we don't cross any boundaries.
@@ -670,9 +680,6 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat,
sgsize = (baddr - curaddr);
}
- if (map->pagesneeded != 0 && run_filter(dmat, curaddr))
- curaddr = add_bounce_page(dmat, map, vaddr, sgsize);
-
/*
* Insert chunk into a segment, coalescing with
* previous segment if possible.
diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S
index 3d1a20e..16d50c5 100644
--- a/sys/amd64/amd64/exception.S
+++ b/sys/amd64/amd64/exception.S
@@ -595,7 +595,7 @@ MCOUNT_LABEL(bintr)
.text
SUPERALIGN_TEXT
-#include <amd64/isa/atpic_vector.S>
+#include <amd64/amd64/atpic_vector.S>
#endif
.text
diff --git a/sys/amd64/amd64/identcpu.c b/sys/amd64/amd64/identcpu.c
index 3cd2f5e..aecec7a 100644
--- a/sys/amd64/amd64/identcpu.c
+++ b/sys/amd64/amd64/identcpu.c
@@ -61,7 +61,7 @@ __FBSDID("$FreeBSD$");
#include <machine/specialreg.h>
#include <machine/md_var.h>
-#include <amd64/isa/icu.h>
+#include <x86/isa/icu.h>
/* XXX - should be in header file: */
void printcpuinfo(void);
diff --git a/sys/amd64/amd64/intr_machdep.c b/sys/amd64/amd64/intr_machdep.c
index 6ab80df..8360aca 100644
--- a/sys/amd64/amd64/intr_machdep.c
+++ b/sys/amd64/amd64/intr_machdep.c
@@ -62,8 +62,8 @@
#include <machine/segments.h>
#include <machine/frame.h>
#include <dev/ic/i8259.h>
-#include <amd64/isa/icu.h>
-#include <amd64/isa/isa.h>
+#include <x86/isa/icu.h>
+#include <x86/isa/isa.h>
#endif
#define MAX_STRAY_LOG 5
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 93c0183..2318975 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -128,7 +128,7 @@ __FBSDID("$FreeBSD$");
#endif
#ifdef DEV_ATPIC
-#include <amd64/isa/icu.h>
+#include <x86/isa/icu.h>
#else
#include <machine/apicvar.h>
#endif
diff --git a/sys/amd64/amd64/mca.c b/sys/amd64/amd64/mca.c
index 0403de4..b0e842a 100644
--- a/sys/amd64/amd64/mca.c
+++ b/sys/amd64/amd64/mca.c
@@ -288,6 +288,8 @@ mca_log(const struct mca_record *rec)
printf("\n");
if (rec->mr_status & MC_STATUS_ADDRV)
printf("MCA: Address 0x%llx\n", (long long)rec->mr_addr);
+ if (rec->mr_status & MC_STATUS_MISCV)
+ printf("MCA: Misc 0x%llx\n", (long long)rec->mr_misc);
}
static int __nonnull(2)
diff --git a/sys/amd64/amd64/nexus.c b/sys/amd64/amd64/nexus.c
index 61cb587..4c701a0 100644
--- a/sys/amd64/amd64/nexus.c
+++ b/sys/amd64/amd64/nexus.c
@@ -69,7 +69,7 @@ __FBSDID("$FreeBSD$");
#ifdef DEV_ISA
#include <isa/isavar.h>
-#include <amd64/isa/isa.h>
+#include <x86/isa/isa.h>
#endif
#include <sys/rtprio.h>
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
index bbb50a8..07db5d1 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -573,8 +573,6 @@ pmap_bootstrap(vm_paddr_t *firstaddr)
virtual_avail = va;
- *CMAP1 = 0;
-
invltlb();
/* Initialize the PAT MSR. */
@@ -688,6 +686,15 @@ pmap_init(void)
pv_entry_high_water = 9 * (pv_entry_max / 10);
/*
+ * Disable large page mappings by default if the kernel is running in
+ * a virtual machine on an AMD Family 10h processor. This is a work-
+ * around for Erratum 383.
+ */
+ if (vm_guest == VM_GUEST_VM && cpu_vendor_id == CPU_VENDOR_AMD &&
+ CPUID_TO_FAMILY(cpu_id) == 0x10)
+ pg_ps_enabled = 0;
+
+ /*
* Are large page mappings enabled?
*/
TUNABLE_INT_FETCH("vm.pmap.pg_ps_enabled", &pg_ps_enabled);
diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
index a99fdaa..2c670a4 100644
--- a/sys/amd64/amd64/vm_machdep.c
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -80,7 +80,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_map.h>
#include <vm/vm_param.h>
-#include <amd64/isa/isa.h>
+#include <x86/isa/isa.h>
static void cpu_reset_real(void);
#ifdef SMP
diff --git a/sys/amd64/include/sysarch.h b/sys/amd64/include/sysarch.h
index 6c3e6c9..7b95a8b 100644
--- a/sys/amd64/include/sysarch.h
+++ b/sys/amd64/include/sysarch.h
@@ -35,6 +35,8 @@
#ifndef _MACHINE_SYSARCH_H_
#define _MACHINE_SYSARCH_H_
+#include <sys/cdefs.h>
+
#define I386_GET_LDT 0
#define I386_SET_LDT 1
#define LDT_AUTO_ALLOC 0xffffffff
@@ -68,8 +70,6 @@ struct i386_ioperm_args {
};
#ifndef _KERNEL
-#include <sys/cdefs.h>
-
__BEGIN_DECLS
int amd64_get_fsbase(void **);
int amd64_get_gsbase(void **);
diff --git a/sys/amd64/isa/atpic.c b/sys/amd64/isa/atpic.c
deleted file mode 100644
index 7edaba2..0000000
--- a/sys/amd64/isa/atpic.c
+++ /dev/null
@@ -1,613 +0,0 @@
-/*-
- * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
- * 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.
- * 3. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * 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.
- */
-
-/*
- * PIC driver for the 8259A Master and Slave PICs in PC/AT machines.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_auto_eoi.h"
-#include "opt_isa.h"
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/interrupt.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/module.h>
-
-#include <machine/cpufunc.h>
-#include <machine/frame.h>
-#include <machine/intr_machdep.h>
-#include <machine/md_var.h>
-#include <machine/resource.h>
-#include <machine/segments.h>
-
-#include <dev/ic/i8259.h>
-#include <amd64/isa/icu.h>
-#include <amd64/isa/isa.h>
-
-#include <isa/isavar.h>
-
-#define MASTER 0
-#define SLAVE 1
-
-/*
- * PC-AT machines wire the slave PIC to pin 2 on the master PIC.
- */
-#define ICU_SLAVEID 2
-
-/*
- * Determine the base master and slave modes not including auto EOI support.
- * All machines that FreeBSD supports use 8086 mode.
- */
-#define BASE_MASTER_MODE ICW4_8086
-#define BASE_SLAVE_MODE ICW4_8086
-
-/* Enable automatic EOI if requested. */
-#ifdef AUTO_EOI_1
-#define MASTER_MODE (BASE_MASTER_MODE | ICW4_AEOI)
-#else
-#define MASTER_MODE BASE_MASTER_MODE
-#endif
-#ifdef AUTO_EOI_2
-#define SLAVE_MODE (BASE_SLAVE_MODE | ICW4_AEOI)
-#else
-#define SLAVE_MODE BASE_SLAVE_MODE
-#endif
-
-#define IRQ_MASK(irq) (1 << (irq))
-#define IMEN_MASK(ai) (IRQ_MASK((ai)->at_irq))
-
-#define NUM_ISA_IRQS 16
-
-static void atpic_init(void *dummy);
-
-unsigned int imen; /* XXX */
-
-inthand_t
- IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
- IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
- IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
- IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
- IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
- IDTVEC(atpic_intr15);
-
-#define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq)
-
-#define ATPIC(io, base, eoi, imenptr) \
- { { atpic_enable_source, atpic_disable_source, (eoi), \
- atpic_enable_intr, atpic_disable_intr, atpic_vector, \
- atpic_source_pending, NULL, atpic_resume, atpic_config_intr,\
- atpic_assign_cpu }, (io), (base), IDT_IO_INTS + (base), \
- (imenptr) }
-
-#define INTSRC(irq) \
- { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \
- (irq) % 8 }
-
-struct atpic {
- struct pic at_pic;
- int at_ioaddr;
- int at_irqbase;
- uint8_t at_intbase;
- uint8_t *at_imen;
-};
-
-struct atpic_intsrc {
- struct intsrc at_intsrc;
- inthand_t *at_intr;
- int at_irq; /* Relative to PIC base. */
- enum intr_trigger at_trigger;
- u_long at_count;
- u_long at_straycount;
-};
-
-static void atpic_enable_source(struct intsrc *isrc);
-static void atpic_disable_source(struct intsrc *isrc, int eoi);
-static void atpic_eoi_master(struct intsrc *isrc);
-static void atpic_eoi_slave(struct intsrc *isrc);
-static void atpic_enable_intr(struct intsrc *isrc);
-static void atpic_disable_intr(struct intsrc *isrc);
-static int atpic_vector(struct intsrc *isrc);
-static void atpic_resume(struct pic *pic);
-static int atpic_source_pending(struct intsrc *isrc);
-static int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
- enum intr_polarity pol);
-static int atpic_assign_cpu(struct intsrc *isrc, u_int apic_id);
-static void i8259_init(struct atpic *pic, int slave);
-
-static struct atpic atpics[] = {
- ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen),
- ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1)
-};
-
-static struct atpic_intsrc atintrs[] = {
- INTSRC(0),
- INTSRC(1),
- INTSRC(2),
- INTSRC(3),
- INTSRC(4),
- INTSRC(5),
- INTSRC(6),
- INTSRC(7),
- INTSRC(8),
- INTSRC(9),
- INTSRC(10),
- INTSRC(11),
- INTSRC(12),
- INTSRC(13),
- INTSRC(14),
- INTSRC(15),
-};
-
-CTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS);
-
-static __inline void
-_atpic_eoi_master(struct intsrc *isrc)
-{
-
- KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
- ("%s: mismatched pic", __func__));
-#ifndef AUTO_EOI_1
- outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
-#endif
-}
-
-/*
- * The data sheet says no auto-EOI on slave, but it sometimes works.
- * So, if AUTO_EOI_2 is enabled, we use it.
- */
-static __inline void
-_atpic_eoi_slave(struct intsrc *isrc)
-{
-
- KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
- ("%s: mismatched pic", __func__));
-#ifndef AUTO_EOI_2
- outb(atpics[SLAVE].at_ioaddr, OCW2_EOI);
-#ifndef AUTO_EOI_1
- outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
-#endif
-#endif
-}
-
-static void
-atpic_enable_source(struct intsrc *isrc)
-{
- struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
- struct atpic *ap = (struct atpic *)isrc->is_pic;
-
- spinlock_enter();
- if (*ap->at_imen & IMEN_MASK(ai)) {
- *ap->at_imen &= ~IMEN_MASK(ai);
- outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
- }
- spinlock_exit();
-}
-
-static void
-atpic_disable_source(struct intsrc *isrc, int eoi)
-{
- struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
- struct atpic *ap = (struct atpic *)isrc->is_pic;
-
- spinlock_enter();
- if (ai->at_trigger != INTR_TRIGGER_EDGE) {
- *ap->at_imen |= IMEN_MASK(ai);
- outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
- }
-
- /*
- * Take care to call these functions directly instead of through
- * a function pointer. All of the referenced variables should
- * still be hot in the cache.
- */
- if (eoi == PIC_EOI) {
- if (isrc->is_pic == &atpics[MASTER].at_pic)
- _atpic_eoi_master(isrc);
- else
- _atpic_eoi_slave(isrc);
- }
-
- spinlock_exit();
-}
-
-static void
-atpic_eoi_master(struct intsrc *isrc)
-{
-#ifndef AUTO_EOI_1
- spinlock_enter();
- _atpic_eoi_master(isrc);
- spinlock_exit();
-#endif
-}
-
-static void
-atpic_eoi_slave(struct intsrc *isrc)
-{
-#ifndef AUTO_EOI_2
- spinlock_enter();
- _atpic_eoi_slave(isrc);
- spinlock_exit();
-#endif
-}
-
-static void
-atpic_enable_intr(struct intsrc *isrc)
-{
-}
-
-static void
-atpic_disable_intr(struct intsrc *isrc)
-{
-}
-
-
-static int
-atpic_vector(struct intsrc *isrc)
-{
- struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
- struct atpic *ap = (struct atpic *)isrc->is_pic;
-
- return (IRQ(ap, ai));
-}
-
-static int
-atpic_source_pending(struct intsrc *isrc)
-{
- struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
- struct atpic *ap = (struct atpic *)isrc->is_pic;
-
- return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
-}
-
-static void
-atpic_resume(struct pic *pic)
-{
- struct atpic *ap = (struct atpic *)pic;
-
- i8259_init(ap, ap == &atpics[SLAVE]);
- if (ap == &atpics[SLAVE] && elcr_found)
- elcr_resume();
-}
-
-static int
-atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
- enum intr_polarity pol)
-{
- struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
- u_int vector;
-
- /* Map conforming values to edge/hi and sanity check the values. */
- if (trig == INTR_TRIGGER_CONFORM)
- trig = INTR_TRIGGER_EDGE;
- if (pol == INTR_POLARITY_CONFORM)
- pol = INTR_POLARITY_HIGH;
- vector = atpic_vector(isrc);
- if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
- (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
- printf(
- "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
- vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
- pol == INTR_POLARITY_HIGH ? "high" : "low");
- return (EINVAL);
- }
-
- /* If there is no change, just return. */
- if (ai->at_trigger == trig)
- return (0);
-
- /*
- * Certain IRQs can never be level/lo, so don't try to set them
- * that way if asked. At least some ELCR registers ignore setting
- * these bits as well.
- */
- if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
- trig == INTR_TRIGGER_LEVEL) {
- if (bootverbose)
- printf(
- "atpic: Ignoring invalid level/low configuration for IRQ%u\n",
- vector);
- return (EINVAL);
- }
- if (!elcr_found) {
- if (bootverbose)
- printf("atpic: No ELCR to configure IRQ%u as %s\n",
- vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
- "level/low");
- return (ENXIO);
- }
- if (bootverbose)
- printf("atpic: Programming IRQ%u as %s\n", vector,
- trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
- spinlock_enter();
- elcr_write_trigger(atpic_vector(isrc), trig);
- ai->at_trigger = trig;
- spinlock_exit();
- return (0);
-}
-
-static int
-atpic_assign_cpu(struct intsrc *isrc, u_int apic_id)
-{
-
- /*
- * 8259A's are only used in UP in which case all interrupts always
- * go to the sole CPU and this function shouldn't even be called.
- */
- panic("%s: bad cookie", __func__);
-}
-
-static void
-i8259_init(struct atpic *pic, int slave)
-{
- int imr_addr;
-
- /* Reset the PIC and program with next four bytes. */
- spinlock_enter();
- outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
- imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
-
- /* Start vector. */
- outb(imr_addr, pic->at_intbase);
-
- /*
- * Setup slave links. For the master pic, indicate what line
- * the slave is configured on. For the slave indicate
- * which line on the master we are connected to.
- */
- if (slave)
- outb(imr_addr, ICU_SLAVEID);
- else
- outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
-
- /* Set mode. */
- if (slave)
- outb(imr_addr, SLAVE_MODE);
- else
- outb(imr_addr, MASTER_MODE);
-
- /* Set interrupt enable mask. */
- outb(imr_addr, *pic->at_imen);
-
- /* Reset is finished, default to IRR on read. */
- outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
-
- /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
- if (!slave)
- outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
- spinlock_exit();
-}
-
-void
-atpic_startup(void)
-{
- struct atpic_intsrc *ai;
- int i;
-
- /* Start off with all interrupts disabled. */
- imen = 0xffff;
- i8259_init(&atpics[MASTER], 0);
- i8259_init(&atpics[SLAVE], 1);
- atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
-
- /* Install low-level interrupt handlers for all of our IRQs. */
- for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
- if (i == ICU_SLAVEID)
- continue;
- ai->at_intsrc.is_count = &ai->at_count;
- ai->at_intsrc.is_straycount = &ai->at_straycount;
- setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
- ai->at_irq, ai->at_intr, SDT_SYSIGT, SEL_KPL, 0);
- }
-
- /*
- * Look for an ELCR. If we find one, update the trigger modes.
- * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
- * edge triggered and that everything else is level triggered.
- * We only use the trigger information to reprogram the ELCR if
- * we have one and as an optimization to avoid masking edge
- * triggered interrupts. For the case that we don't have an ELCR,
- * it doesn't hurt to mask an edge triggered interrupt, so we
- * assume level trigger for any interrupt that we aren't sure is
- * edge triggered.
- */
- if (elcr_found) {
- for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
- ai->at_trigger = elcr_read_trigger(i);
- } else {
- for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
- switch (i) {
- case 0:
- case 1:
- case 2:
- case 8:
- case 13:
- ai->at_trigger = INTR_TRIGGER_EDGE;
- break;
- default:
- ai->at_trigger = INTR_TRIGGER_LEVEL;
- break;
- }
- }
-}
-
-static void
-atpic_init(void *dummy __unused)
-{
- struct atpic_intsrc *ai;
- int i;
-
- /*
- * Register our PICs, even if we aren't going to use any of their
- * pins so that they are suspended and resumed.
- */
- if (intr_register_pic(&atpics[0].at_pic) != 0 ||
- intr_register_pic(&atpics[1].at_pic) != 0)
- panic("Unable to register ATPICs");
-
- /*
- * If any of the ISA IRQs have an interrupt source already, then
- * assume that the APICs are being used and don't register any
- * of our interrupt sources. This makes sure we don't accidentally
- * use mixed mode. The "accidental" use could otherwise occur on
- * machines that route the ACPI SCI interrupt to a different ISA
- * IRQ (at least one machines routes it to IRQ 13) thus disabling
- * that APIC ISA routing and allowing the ATPIC source for that IRQ
- * to leak through. We used to depend on this feature for routing
- * IRQ0 via mixed mode, but now we don't use mixed mode at all.
- */
- for (i = 0; i < NUM_ISA_IRQS; i++)
- if (intr_lookup_source(i) != NULL)
- return;
-
- /* Loop through all interrupt sources and add them. */
- for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
- if (i == ICU_SLAVEID)
- continue;
- intr_register_source(&ai->at_intsrc);
- }
-}
-SYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL);
-
-void
-atpic_handle_intr(u_int vector, struct trapframe *frame)
-{
- struct intsrc *isrc;
-
- KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector));
- isrc = &atintrs[vector].at_intsrc;
-
- /*
- * If we don't have an event, see if this is a spurious
- * interrupt.
- */
- if (isrc->is_event == NULL && (vector == 7 || vector == 15)) {
- int port, isr;
-
- /*
- * Read the ISR register to see if IRQ 7/15 is really
- * pending. Reset read register back to IRR when done.
- */
- port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
- spinlock_enter();
- outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
- isr = inb(port);
- outb(port, OCW3_SEL | OCW3_RR);
- spinlock_exit();
- if ((isr & IRQ_MASK(7)) == 0)
- return;
- }
- intr_execute_handlers(isrc, frame);
-}
-
-#ifdef DEV_ISA
-/*
- * Bus attachment for the ISA PIC.
- */
-static struct isa_pnp_id atpic_ids[] = {
- { 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
- { 0 }
-};
-
-static int
-atpic_probe(device_t dev)
-{
- int result;
-
- result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
- if (result <= 0)
- device_quiet(dev);
- return (result);
-}
-
-/*
- * We might be granted IRQ 2, as this is typically consumed by chaining
- * between the two PIC components. If we're using the APIC, however,
- * this may not be the case, and as such we should free the resource.
- * (XXX untested)
- *
- * The generic ISA attachment code will handle allocating any other resources
- * that we don't explicitly claim here.
- */
-static int
-atpic_attach(device_t dev)
-{
- struct resource *res;
- int rid;
-
- /* Try to allocate our IRQ and then free it. */
- rid = 0;
- res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
- if (res != NULL)
- bus_release_resource(dev, SYS_RES_IRQ, rid, res);
- return (0);
-}
-
-static device_method_t atpic_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, atpic_probe),
- DEVMETHOD(device_attach, atpic_attach),
- DEVMETHOD(device_detach, bus_generic_detach),
- DEVMETHOD(device_shutdown, bus_generic_shutdown),
- DEVMETHOD(device_suspend, bus_generic_suspend),
- DEVMETHOD(device_resume, bus_generic_resume),
- { 0, 0 }
-};
-
-static driver_t atpic_driver = {
- "atpic",
- atpic_methods,
- 1, /* no softc */
-};
-
-static devclass_t atpic_devclass;
-
-DRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
-DRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
-
-/*
- * Return a bitmap of the current interrupt requests. This is 8259-specific
- * and is only suitable for use at probe time.
- */
-intrmask_t
-isa_irq_pending(void)
-{
- u_char irr1;
- u_char irr2;
-
- irr1 = inb(IO_ICU1);
- irr2 = inb(IO_ICU2);
- return ((irr2 << 8) | irr1);
-}
-#endif /* DEV_ISA */
diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c
deleted file mode 100644
index bf379f3..0000000
--- a/sys/amd64/isa/clock.c
+++ /dev/null
@@ -1,665 +0,0 @@
-/*-
- * Copyright (c) 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * William Jolitz and Don Ahn.
- *
- * 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.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * Routines to handle clock hardware.
- */
-
-#include "opt_clock.h"
-#include "opt_isa.h"
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/lock.h>
-#include <sys/kdb.h>
-#include <sys/mutex.h>
-#include <sys/proc.h>
-#include <sys/timetc.h>
-#include <sys/kernel.h>
-#include <sys/module.h>
-#include <sys/sched.h>
-#include <sys/smp.h>
-#include <sys/sysctl.h>
-
-#include <machine/clock.h>
-#include <machine/cpu.h>
-#include <machine/intr_machdep.h>
-#include <machine/md_var.h>
-#include <machine/apicvar.h>
-#include <machine/ppireg.h>
-#include <machine/timerreg.h>
-#include <machine/smp.h>
-
-#include <isa/rtc.h>
-#ifdef DEV_ISA
-#include <isa/isareg.h>
-#include <isa/isavar.h>
-#endif
-
-#define TIMER_DIV(x) ((i8254_freq + (x) / 2) / (x))
-
-int clkintr_pending;
-static int pscnt = 1;
-static int psdiv = 1;
-#ifndef TIMER_FREQ
-#define TIMER_FREQ 1193182
-#endif
-u_int i8254_freq = TIMER_FREQ;
-TUNABLE_INT("hw.i8254.freq", &i8254_freq);
-int i8254_max_count;
-static int i8254_real_max_count;
-
-struct mtx clock_lock;
-static struct intsrc *i8254_intsrc;
-static u_int32_t i8254_lastcount;
-static u_int32_t i8254_offset;
-static int (*i8254_pending)(struct intsrc *);
-static int i8254_ticked;
-static int using_atrtc_timer;
-static enum lapic_clock using_lapic_timer = LAPIC_CLOCK_NONE;
-
-/* Values for timerX_state: */
-#define RELEASED 0
-#define RELEASE_PENDING 1
-#define ACQUIRED 2
-#define ACQUIRE_PENDING 3
-
-static u_char timer2_state;
-
-static unsigned i8254_get_timecount(struct timecounter *tc);
-static unsigned i8254_simple_get_timecount(struct timecounter *tc);
-static void set_i8254_freq(u_int freq, int intr_freq);
-
-static struct timecounter i8254_timecounter = {
- i8254_get_timecount, /* get_timecount */
- 0, /* no poll_pps */
- ~0u, /* counter_mask */
- 0, /* frequency */
- "i8254", /* name */
- 0 /* quality */
-};
-
-int
-hardclockintr(struct trapframe *frame)
-{
-
- if (PCPU_GET(cpuid) == 0)
- hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
- else
- hardclock_cpu(TRAPF_USERMODE(frame));
- return (FILTER_HANDLED);
-}
-
-int
-statclockintr(struct trapframe *frame)
-{
-
- profclockintr(frame);
- statclock(TRAPF_USERMODE(frame));
- return (FILTER_HANDLED);
-}
-
-int
-profclockintr(struct trapframe *frame)
-{
-
- if (!using_atrtc_timer)
- hardclockintr(frame);
- if (profprocs != 0)
- profclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
- return (FILTER_HANDLED);
-}
-
-static int
-clkintr(struct trapframe *frame)
-{
-
- if (timecounter->tc_get_timecount == i8254_get_timecount) {
- mtx_lock_spin(&clock_lock);
- if (i8254_ticked)
- i8254_ticked = 0;
- else {
- i8254_offset += i8254_max_count;
- i8254_lastcount = 0;
- }
- clkintr_pending = 0;
- mtx_unlock_spin(&clock_lock);
- }
- KASSERT(using_lapic_timer == LAPIC_CLOCK_NONE,
- ("clk interrupt enabled with lapic timer"));
-
- if (using_atrtc_timer) {
-#ifdef SMP
- if (smp_started)
- ipi_all_but_self(IPI_HARDCLOCK);
-#endif
- hardclockintr(frame);
- } else {
- if (--pscnt <= 0) {
- pscnt = psratio;
-#ifdef SMP
- if (smp_started)
- ipi_all_but_self(IPI_STATCLOCK);
-#endif
- statclockintr(frame);
- } else {
-#ifdef SMP
- if (smp_started)
- ipi_all_but_self(IPI_PROFCLOCK);
-#endif
- profclockintr(frame);
- }
- }
-
- return (FILTER_HANDLED);
-}
-
-int
-timer_spkr_acquire(void)
-{
- int mode;
-
- mode = TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT;
-
- if (timer2_state != RELEASED)
- return (-1);
- timer2_state = ACQUIRED;
-
- /*
- * This access to the timer registers is as atomic as possible
- * because it is a single instruction. We could do better if we
- * knew the rate. Use of splclock() limits glitches to 10-100us,
- * and this is probably good enough for timer2, so we aren't as
- * careful with it as with timer0.
- */
- outb(TIMER_MODE, TIMER_SEL2 | (mode & 0x3f));
- ppi_spkr_on(); /* enable counter2 output to speaker */
- return (0);
-}
-
-int
-timer_spkr_release(void)
-{
-
- if (timer2_state != ACQUIRED)
- return (-1);
- timer2_state = RELEASED;
- outb(TIMER_MODE, TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT);
- ppi_spkr_off(); /* disable counter2 output to speaker */
- return (0);
-}
-
-void
-timer_spkr_setfreq(int freq)
-{
-
- freq = i8254_freq / freq;
- mtx_lock_spin(&clock_lock);
- outb(TIMER_CNTR2, freq & 0xff);
- outb(TIMER_CNTR2, freq >> 8);
- mtx_unlock_spin(&clock_lock);
-}
-
-/*
- * This routine receives statistical clock interrupts from the RTC.
- * As explained above, these occur at 128 interrupts per second.
- * When profiling, we receive interrupts at a rate of 1024 Hz.
- *
- * This does not actually add as much overhead as it sounds, because
- * when the statistical clock is active, the hardclock driver no longer
- * needs to keep (inaccurate) statistics on its own. This decouples
- * statistics gathering from scheduling interrupts.
- *
- * The RTC chip requires that we read status register C (RTC_INTR)
- * to acknowledge an interrupt, before it will generate the next one.
- * Under high interrupt load, rtcintr() can be indefinitely delayed and
- * the clock can tick immediately after the read from RTC_INTR. In this
- * case, the mc146818A interrupt signal will not drop for long enough
- * to register with the 8259 PIC. If an interrupt is missed, the stat
- * clock will halt, considerably degrading system performance. This is
- * why we use 'while' rather than a more straightforward 'if' below.
- * Stat clock ticks can still be lost, causing minor loss of accuracy
- * in the statistics, but the stat clock will no longer stop.
- */
-static int
-rtcintr(struct trapframe *frame)
-{
- int flag = 0;
-
- while (rtcin(RTC_INTR) & RTCIR_PERIOD) {
- flag = 1;
- if (--pscnt <= 0) {
- pscnt = psdiv;
-#ifdef SMP
- if (smp_started)
- ipi_all_but_self(IPI_STATCLOCK);
-#endif
- statclockintr(frame);
- } else {
-#ifdef SMP
- if (smp_started)
- ipi_all_but_self(IPI_PROFCLOCK);
-#endif
- profclockintr(frame);
- }
- }
- return(flag ? FILTER_HANDLED : FILTER_STRAY);
-}
-
-static int
-getit(void)
-{
- int high, low;
-
- mtx_lock_spin(&clock_lock);
-
- /* Select timer0 and latch counter value. */
- outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
-
- low = inb(TIMER_CNTR0);
- high = inb(TIMER_CNTR0);
-
- mtx_unlock_spin(&clock_lock);
- return ((high << 8) | low);
-}
-
-/*
- * Wait "n" microseconds.
- * Relies on timer 1 counting down from (i8254_freq / hz)
- * Note: timer had better have been programmed before this is first used!
- */
-void
-DELAY(int n)
-{
- int delta, prev_tick, tick, ticks_left;
-
-#ifdef DELAYDEBUG
- int getit_calls = 1;
- int n1;
- static int state = 0;
-#endif
-
- if (tsc_freq != 0 && !tsc_is_broken) {
- uint64_t start, end, now;
-
- sched_pin();
- start = rdtsc();
- end = start + (tsc_freq * n) / 1000000;
- do {
- cpu_spinwait();
- now = rdtsc();
- } while (now < end || (now > start && end < start));
- sched_unpin();
- return;
- }
-#ifdef DELAYDEBUG
- if (state == 0) {
- state = 1;
- for (n1 = 1; n1 <= 10000000; n1 *= 10)
- DELAY(n1);
- state = 2;
- }
- if (state == 1)
- printf("DELAY(%d)...", n);
-#endif
- /*
- * Read the counter first, so that the rest of the setup overhead is
- * counted. Guess the initial overhead is 20 usec (on most systems it
- * takes about 1.5 usec for each of the i/o's in getit(). The loop
- * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
- * multiplications and divisions to scale the count take a while).
- *
- * However, if ddb is active then use a fake counter since reading
- * the i8254 counter involves acquiring a lock. ddb must not do
- * locking for many reasons, but it calls here for at least atkbd
- * input.
- */
-#ifdef KDB
- if (kdb_active)
- prev_tick = 1;
- else
-#endif
- prev_tick = getit();
- n -= 0; /* XXX actually guess no initial overhead */
- /*
- * Calculate (n * (i8254_freq / 1e6)) without using floating point
- * and without any avoidable overflows.
- */
- if (n <= 0)
- ticks_left = 0;
- else if (n < 256)
- /*
- * Use fixed point to avoid a slow division by 1000000.
- * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest.
- * 2^15 is the first power of 2 that gives exact results
- * for n between 0 and 256.
- */
- ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15;
- else
- /*
- * Don't bother using fixed point, although gcc-2.7.2
- * generates particularly poor code for the long long
- * division, since even the slow way will complete long
- * before the delay is up (unless we're interrupted).
- */
- ticks_left = ((u_int)n * (long long)i8254_freq + 999999)
- / 1000000;
-
- while (ticks_left > 0) {
-#ifdef KDB
- if (kdb_active) {
- inb(0x84);
- tick = prev_tick - 1;
- if (tick <= 0)
- tick = i8254_max_count;
- } else
-#endif
- tick = getit();
-#ifdef DELAYDEBUG
- ++getit_calls;
-#endif
- delta = prev_tick - tick;
- prev_tick = tick;
- if (delta < 0) {
- delta += i8254_max_count;
- /*
- * Guard against i8254_max_count being wrong.
- * This shouldn't happen in normal operation,
- * but it may happen if set_i8254_freq() is
- * traced.
- */
- if (delta < 0)
- delta = 0;
- }
- ticks_left -= delta;
- }
-#ifdef DELAYDEBUG
- if (state == 1)
- printf(" %d calls to getit() at %d usec each\n",
- getit_calls, (n + 5) / getit_calls);
-#endif
-}
-
-static void
-set_i8254_freq(u_int freq, int intr_freq)
-{
- int new_i8254_real_max_count;
-
- i8254_timecounter.tc_frequency = freq;
- mtx_lock_spin(&clock_lock);
- i8254_freq = freq;
- if (using_lapic_timer != LAPIC_CLOCK_NONE)
- new_i8254_real_max_count = 0x10000;
- else
- new_i8254_real_max_count = TIMER_DIV(intr_freq);
- if (new_i8254_real_max_count != i8254_real_max_count) {
- i8254_real_max_count = new_i8254_real_max_count;
- if (i8254_real_max_count == 0x10000)
- i8254_max_count = 0xffff;
- else
- i8254_max_count = i8254_real_max_count;
- outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
- outb(TIMER_CNTR0, i8254_real_max_count & 0xff);
- outb(TIMER_CNTR0, i8254_real_max_count >> 8);
- }
- mtx_unlock_spin(&clock_lock);
-}
-
-static void
-i8254_restore(void)
-{
-
- mtx_lock_spin(&clock_lock);
- outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
- outb(TIMER_CNTR0, i8254_real_max_count & 0xff);
- outb(TIMER_CNTR0, i8254_real_max_count >> 8);
- mtx_unlock_spin(&clock_lock);
-}
-
-/* This is separate from startrtclock() so that it can be called early. */
-void
-i8254_init(void)
-{
-
- mtx_init(&clock_lock, "clk", NULL, MTX_SPIN | MTX_NOPROFILE);
- set_i8254_freq(i8254_freq, hz);
-}
-
-void
-startrtclock()
-{
-
- atrtc_start();
-
- set_i8254_freq(i8254_freq, hz);
- tc_init(&i8254_timecounter);
-
- init_TSC();
-}
-
-/*
- * Start both clocks running.
- */
-void
-cpu_initclocks()
-{
-
- using_lapic_timer = lapic_setup_clock();
- /*
- * If we aren't using the local APIC timer to drive the kernel
- * clocks, setup the interrupt handler for the 8254 timer 0 so
- * that it can drive hardclock(). Otherwise, change the 8254
- * timecounter to user a simpler algorithm.
- */
- if (using_lapic_timer == LAPIC_CLOCK_NONE) {
- intr_add_handler("clk", 0, (driver_filter_t *)clkintr, NULL,
- NULL, INTR_TYPE_CLK, NULL);
- i8254_intsrc = intr_lookup_source(0);
- if (i8254_intsrc != NULL)
- i8254_pending =
- i8254_intsrc->is_pic->pic_source_pending;
- } else {
- i8254_timecounter.tc_get_timecount =
- i8254_simple_get_timecount;
- i8254_timecounter.tc_counter_mask = 0xffff;
- set_i8254_freq(i8254_freq, hz);
- }
-
- /* Initialize RTC. */
- atrtc_start();
-
- /*
- * If the separate statistics clock hasn't been explicility disabled
- * and we aren't already using the local APIC timer to drive the
- * kernel clocks, then setup the RTC to periodically interrupt to
- * drive statclock() and profclock().
- */
- if (using_lapic_timer != LAPIC_CLOCK_ALL) {
- using_atrtc_timer = atrtc_setup_clock();
- if (using_atrtc_timer) {
- /* Enable periodic interrupts from the RTC. */
- intr_add_handler("rtc", 8,
- (driver_filter_t *)rtcintr, NULL, NULL,
- INTR_TYPE_CLK, NULL);
- atrtc_enable_intr();
- } else {
- profhz = hz;
- if (hz < 128)
- stathz = hz;
- else
- stathz = hz / (hz / 128);
- }
- }
-
- init_TSC_tc();
-}
-
-void
-cpu_startprofclock(void)
-{
-
- if (using_lapic_timer == LAPIC_CLOCK_ALL || !using_atrtc_timer)
- return;
- atrtc_rate(RTCSA_PROF);
- psdiv = pscnt = psratio;
-}
-
-void
-cpu_stopprofclock(void)
-{
-
- if (using_lapic_timer == LAPIC_CLOCK_ALL || !using_atrtc_timer)
- return;
- atrtc_rate(RTCSA_NOPROF);
- psdiv = pscnt = 1;
-}
-
-static int
-sysctl_machdep_i8254_freq(SYSCTL_HANDLER_ARGS)
-{
- int error;
- u_int freq;
-
- /*
- * Use `i8254' instead of `timer' in external names because `timer'
- * is is too generic. Should use it everywhere.
- */
- freq = i8254_freq;
- error = sysctl_handle_int(oidp, &freq, 0, req);
- if (error == 0 && req->newptr != NULL)
- set_i8254_freq(freq, hz);
- return (error);
-}
-
-SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW,
- 0, sizeof(u_int), sysctl_machdep_i8254_freq, "IU", "");
-
-static unsigned
-i8254_simple_get_timecount(struct timecounter *tc)
-{
-
- return (i8254_max_count - getit());
-}
-
-static unsigned
-i8254_get_timecount(struct timecounter *tc)
-{
- u_int count;
- u_int high, low;
- u_long rflags;
-
- rflags = read_rflags();
- mtx_lock_spin(&clock_lock);
-
- /* Select timer0 and latch counter value. */
- outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
-
- low = inb(TIMER_CNTR0);
- high = inb(TIMER_CNTR0);
- count = i8254_max_count - ((high << 8) | low);
- if (count < i8254_lastcount ||
- (!i8254_ticked && (clkintr_pending ||
- ((count < 20 || (!(rflags & PSL_I) &&
- count < i8254_max_count / 2u)) &&
- i8254_pending != NULL && i8254_pending(i8254_intsrc))))) {
- i8254_ticked = 1;
- i8254_offset += i8254_max_count;
- }
- i8254_lastcount = count;
- count += i8254_offset;
- mtx_unlock_spin(&clock_lock);
- return (count);
-}
-
-#ifdef DEV_ISA
-/*
- * Attach to the ISA PnP descriptors for the timer
- */
-static struct isa_pnp_id attimer_ids[] = {
- { 0x0001d041 /* PNP0100 */, "AT timer" },
- { 0 }
-};
-
-static int
-attimer_probe(device_t dev)
-{
- int result;
-
- result = ISA_PNP_PROBE(device_get_parent(dev), dev, attimer_ids);
- if (result <= 0)
- device_quiet(dev);
- return(result);
-}
-
-static int
-attimer_attach(device_t dev)
-{
- return(0);
-}
-
-static int
-attimer_resume(device_t dev)
-{
-
- i8254_restore();
- return(0);
-}
-
-static device_method_t attimer_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, attimer_probe),
- DEVMETHOD(device_attach, attimer_attach),
- DEVMETHOD(device_detach, bus_generic_detach),
- DEVMETHOD(device_shutdown, bus_generic_shutdown),
- DEVMETHOD(device_suspend, bus_generic_suspend),
- DEVMETHOD(device_resume, attimer_resume),
- { 0, 0 }
-};
-
-static driver_t attimer_driver = {
- "attimer",
- attimer_methods,
- 1, /* no softc */
-};
-
-static devclass_t attimer_devclass;
-
-DRIVER_MODULE(attimer, isa, attimer_driver, attimer_devclass, 0, 0);
-DRIVER_MODULE(attimer, acpi, attimer_driver, attimer_devclass, 0, 0);
-
-#endif /* DEV_ISA */
diff --git a/sys/amd64/isa/isa.c b/sys/amd64/isa/isa.c
deleted file mode 100644
index 1f20226..0000000
--- a/sys/amd64/isa/isa.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*-
- * Copyright (c) 1998 Doug Rabson
- * 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$");
-
-/*-
- * Modifications for Intel architecture by Garrett A. Wollman.
- * Copyright 1998 Massachusetts Institute of Technology
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that both the above copyright notice and this
- * permission notice appear in all copies, that both the above
- * copyright notice and this permission notice appear in all
- * supporting documentation, and that the name of M.I.T. not be used
- * in advertising or publicity pertaining to distribution of the
- * software without specific, written prior permission. M.I.T. makes
- * no representations about the suitability of this software for any
- * purpose. It is provided "as is" without express or implied
- * warranty.
- *
- * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
- * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
- * SHALL M.I.T. 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/param.h>
-#include <sys/bus.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/module.h>
-#include <machine/bus.h>
-#include <sys/rman.h>
-
-#include <machine/resource.h>
-
-#include <isa/isavar.h>
-#include <isa/isa_common.h>
-
-void
-isa_init(device_t dev)
-{
-}
-
-/*
- * This implementation simply passes the request up to the parent
- * bus, which in our case is the special i386 nexus, substituting any
- * configured values if the caller defaulted. We can get away with
- * this because there is no special mapping for ISA resources on an Intel
- * platform. When porting this code to another architecture, it may be
- * necessary to interpose a mapping layer here.
- */
-struct resource *
-isa_alloc_resource(device_t bus, device_t child, int type, int *rid,
- u_long start, u_long end, u_long count, u_int flags)
-{
- /*
- * Consider adding a resource definition.
- */
- int passthrough = (device_get_parent(child) != bus);
- int isdefault = (start == 0UL && end == ~0UL);
- struct isa_device* idev = DEVTOISA(child);
- struct resource_list *rl = &idev->id_resources;
- struct resource_list_entry *rle;
-
- if (!passthrough && !isdefault) {
- rle = resource_list_find(rl, type, *rid);
- if (!rle) {
- if (*rid < 0)
- return 0;
- switch (type) {
- case SYS_RES_IRQ:
- if (*rid >= ISA_NIRQ)
- return 0;
- break;
- case SYS_RES_DRQ:
- if (*rid >= ISA_NDRQ)
- return 0;
- break;
- case SYS_RES_MEMORY:
- if (*rid >= ISA_NMEM)
- return 0;
- break;
- case SYS_RES_IOPORT:
- if (*rid >= ISA_NPORT)
- return 0;
- break;
- default:
- return 0;
- }
- resource_list_add(rl, type, *rid, start, end, count);
- }
- }
-
- return resource_list_alloc(rl, bus, child, type, rid,
- start, end, count, flags);
-}
-
-int
-isa_release_resource(device_t bus, device_t child, int type, int rid,
- struct resource *r)
-{
- struct isa_device* idev = DEVTOISA(child);
- struct resource_list *rl = &idev->id_resources;
-
- return resource_list_release(rl, bus, child, type, rid, r);
-}
-
-/*
- * We can't use the bus_generic_* versions of these methods because those
- * methods always pass the bus param as the requesting device, and we need
- * to pass the child (the i386 nexus knows about this and is prepared to
- * deal).
- */
-int
-isa_setup_intr(device_t bus, device_t child, struct resource *r, int flags,
- driver_filter_t *filter, void (*ihand)(void *), void *arg,
- void **cookiep)
-{
- return (BUS_SETUP_INTR(device_get_parent(bus), child, r, flags,
- filter, ihand, arg, cookiep));
-}
-
-int
-isa_teardown_intr(device_t bus, device_t child, struct resource *r,
- void *cookie)
-{
- return (BUS_TEARDOWN_INTR(device_get_parent(bus), child, r, cookie));
-}
-
-/*
- * On this platform, isa can also attach to the legacy bus.
- */
-DRIVER_MODULE(isa, legacy, isa_driver, isa_devclass, 0, 0);
diff --git a/sys/amd64/isa/isa.h b/sys/amd64/isa/isa.h
deleted file mode 100644
index 3c58e6c..0000000
--- a/sys/amd64/isa/isa.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*-
- * Copyright (c) 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * William Jolitz.
- *
- * 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.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- * from: @(#)isa.h 5.7 (Berkeley) 5/9/91
- * $FreeBSD$
- */
-
-#ifndef _I386_ISA_ISA_H_
-#define _I386_ISA_ISA_H_
-
-/* BEWARE: Included in both assembler and C code */
-
-/*
- * ISA Bus conventions
- */
-
-/*
- * Input / Output Port Assignments
- */
-#ifndef IO_ISABEGIN
-#define IO_ISABEGIN 0x000 /* 0x000 - Beginning of I/O Registers */
-
- /* CPU Board */
-#define IO_ICU1 0x020 /* 8259A Interrupt Controller #1 */
-#define IO_PMP1 0x026 /* 82347 Power Management Peripheral */
-#define IO_KBD 0x060 /* 8042 Keyboard */
-#define IO_RTC 0x070 /* RTC */
-#define IO_NMI IO_RTC /* NMI Control */
-#define IO_ICU2 0x0A0 /* 8259A Interrupt Controller #2 */
-
- /* Cards */
-#define IO_VGA 0x3C0 /* E/VGA Ports */
-#define IO_CGA 0x3D0 /* CGA Ports */
-#define IO_MDA 0x3B0 /* Monochome Adapter */
-
-#define IO_ISAEND 0x3FF /* End (actually Max) of I/O Regs */
-#endif /* !IO_ISABEGIN */
-
-/*
- * Input / Output Port Sizes - these are from several sources, and tend
- * to be the larger of what was found.
- */
-#ifndef IO_ISASIZES
-#define IO_ISASIZES
-
-#define IO_CGASIZE 12 /* CGA controllers */
-#define IO_MDASIZE 12 /* Monochrome display controllers */
-#define IO_VGASIZE 16 /* VGA controllers */
-
-#endif /* !IO_ISASIZES */
-
-#endif /* !_I386_ISA_ISA_H_ */
diff --git a/sys/amd64/isa/nmi.c b/sys/amd64/isa/nmi.c
deleted file mode 100644
index 887879a..0000000
--- a/sys/amd64/isa/nmi.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * William Jolitz.
- *
- * 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.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- * from: @(#)isa.c 7.2 (Berkeley) 5/13/91
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_mca.h"
-
-#include <sys/types.h>
-#include <sys/syslog.h>
-#include <sys/systm.h>
-
-#include <machine/md_var.h>
-
-#define NMI_PARITY (1 << 7)
-#define NMI_IOCHAN (1 << 6)
-#define ENMI_WATCHDOG (1 << 7)
-#define ENMI_BUSTIMER (1 << 6)
-#define ENMI_IOSTATUS (1 << 5)
-
-/*
- * Handle a NMI, possibly a machine check.
- * return true to panic system, false to ignore.
- */
-int
-isa_nmi(int cd)
-{
- int retval = 0;
- int isa_port = inb(0x61);
- int eisa_port = inb(0x461);
-
- log(LOG_CRIT, "NMI ISA %x, EISA %x\n", isa_port, eisa_port);
-
- if (isa_port & NMI_PARITY) {
- log(LOG_CRIT, "RAM parity error, likely hardware failure.");
- retval = 1;
- }
-
- if (isa_port & NMI_IOCHAN) {
- log(LOG_CRIT, "I/O channel check, likely hardware failure.");
- retval = 1;
- }
-
- /*
- * On a real EISA machine, this will never happen. However it can
- * happen on ISA machines which implement XT style floating point
- * error handling (very rare). Save them from a meaningless panic.
- */
- if (eisa_port == 0xff)
- return(retval);
-
- if (eisa_port & ENMI_WATCHDOG) {
- log(LOG_CRIT, "EISA watchdog timer expired, likely hardware failure.");
- retval = 1;
- }
-
- if (eisa_port & ENMI_BUSTIMER) {
- log(LOG_CRIT, "EISA bus timeout, likely hardware failure.");
- retval = 1;
- }
-
- if (eisa_port & ENMI_IOSTATUS) {
- log(LOG_CRIT, "EISA I/O port status error.");
- retval = 1;
- }
-
- return(retval);
-}
diff --git a/sys/arm/arm/cpufunc.c b/sys/arm/arm/cpufunc.c
index 4354f0a..2f4c3a1 100644
--- a/sys/arm/arm/cpufunc.c
+++ b/sys/arm/arm/cpufunc.c
@@ -2119,7 +2119,8 @@ fa526_setup(char *args)
cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
| CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
| CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
- | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_LABT_ENABLE;
+ | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_LABT_ENABLE
+ | CPU_CONTROL_BPRD_ENABLE;
cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
| CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
| CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
diff --git a/sys/arm/arm/identcpu.c b/sys/arm/arm/identcpu.c
index 294d5a9..55e342f 100644
--- a/sys/arm/arm/identcpu.c
+++ b/sys/arm/arm/identcpu.c
@@ -220,6 +220,9 @@ const struct cpuidtab cpuids[] = {
generic_steppings },
{ CPU_ID_ARM966ESR1, CPU_CLASS_ARM9ES, "ARM966E-S",
generic_steppings },
+ { CPU_ID_FA526, CPU_CLASS_ARM9, "FA526",
+ generic_steppings },
+
{ CPU_ID_TI925T, CPU_CLASS_ARM9TDMI, "TI ARM925T",
generic_steppings },
@@ -317,6 +320,7 @@ const struct cpu_classtab cpu_classes[] = {
{ "ARM7", "CPU_ARM7" }, /* CPU_CLASS_ARM7 */
{ "ARM7TDMI", "CPU_ARM7TDMI" }, /* CPU_CLASS_ARM7TDMI */
{ "ARM8", "CPU_ARM8" }, /* CPU_CLASS_ARM8 */
+ { "ARM9", "CPU_ARM9" }, /* CPU_CLASS_ARM9 */
{ "ARM9TDMI", "CPU_ARM9TDMI" }, /* CPU_CLASS_ARM9TDMI */
{ "ARM9E-S", "CPU_ARM9E" }, /* CPU_CLASS_ARM9ES */
{ "ARM9EJ-S", "CPU_ARM9E" }, /* CPU_CLASS_ARM9EJS */
diff --git a/sys/arm/at91/if_ate.c b/sys/arm/at91/if_ate.c
index 6412515..2f6b741 100644
--- a/sys/arm/at91/if_ate.c
+++ b/sys/arm/at91/if_ate.c
@@ -380,6 +380,16 @@ ate_load_rx_buf(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
bus_dmamap_sync(sc->rxtag, sc->rx_map[i], BUS_DMASYNC_PREREAD);
}
+static uint32_t
+ate_mac_hash(const uint8_t *buf)
+{
+ uint32_t index = 0;
+ for (int i = 0; i < 48; i++) {
+ index ^= ((buf[i >> 3] >> (i & 7)) & 1) << (i % 6);
+ }
+ return (index);
+}
+
/*
* Compute the multicast filter for this device using the standard
* algorithm. I wonder why this isn't in ether somewhere as a lot
@@ -414,8 +424,8 @@ ate_setmcast(struct ate_softc *sc)
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_LINK)
continue;
- index = ether_crc32_be(LLADDR((struct sockaddr_dl *)
- ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
+ index = ate_mac_hash(LLADDR((struct sockaddr_dl *)
+ ifma->ifma_addr));
af[index >> 3] |= 1 << (index & 7);
}
if_maddr_runlock(ifp);
diff --git a/sys/arm/conf/BWCT b/sys/arm/conf/BWCT
index 51aab2b..0fb3b87 100644
--- a/sys/arm/conf/BWCT
+++ b/sys/arm/conf/BWCT
@@ -63,7 +63,7 @@ options SYSVSHM #SYSV-style shared memory
options SYSVMSG #SYSV-style message queues
options SYSVSEM #SYSV-style semaphores
options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
-#options SYSCTL_OMIT_DESCR
+#options NO_SYSCTL_DESCR
options MUTEX_NOINLINE
options RWLOCK_NOINLINE
options NO_FFS_SNAPSHOT
diff --git a/sys/arm/conf/HL200 b/sys/arm/conf/HL200
index c5abcbc..f50f64c 100644
--- a/sys/arm/conf/HL200
+++ b/sys/arm/conf/HL200
@@ -59,7 +59,7 @@ options SYSVSHM #SYSV-style shared memory
options SYSVMSG #SYSV-style message queues
options SYSVSEM #SYSV-style semaphores
options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
-#options SYSCTL_OMIT_DESCR
+#options NO_SYSCTL_DESCR
options MUTEX_NOINLINE
options RWLOCK_NOINLINE
options NO_FFS_SNAPSHOT
diff --git a/sys/arm/conf/KB920X b/sys/arm/conf/KB920X
index 5e3c848..8d5274d 100644
--- a/sys/arm/conf/KB920X
+++ b/sys/arm/conf/KB920X
@@ -57,7 +57,7 @@ options SYSVSHM #SYSV-style shared memory
options SYSVMSG #SYSV-style message queues
options SYSVSEM #SYSV-style semaphores
options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
-#options SYSCTL_OMIT_DESCR
+#options NO_SYSCTL_DESCR
# Disable the inlining of mutex, rwlock and sx locks. These eat up a lot
# of space.
options MUTEX_NOINLINE
diff --git a/sys/arm/include/armreg.h b/sys/arm/include/armreg.h
index 706377a..0d42ae4 100644
--- a/sys/arm/include/armreg.h
+++ b/sys/arm/include/armreg.h
@@ -151,8 +151,8 @@
#define CPU_ID_MV88FR131 0x56251310 /* Marvell Feroceon 88FR131 Core */
#define CPU_ID_MV88FR571_VD 0x56155710 /* Marvell Feroceon 88FR571-VD Core (ID from datasheet) */
#define CPU_ID_MV88FR571_41 0x41159260 /* Marvell Feroceon 88FR571-VD Core (actual ID from CPU reg) */
-#define CPU_ID_FA526 0x66015261
-#define CPU_ID_FA626TE 0x66056261
+#define CPU_ID_FA526 0x66015260
+#define CPU_ID_FA626TE 0x66056260
#define CPU_ID_SA1110 0x6901b110
#define CPU_ID_IXP1200 0x6901c120
#define CPU_ID_80200 0x69052000
diff --git a/sys/arm/include/md_var.h b/sys/arm/include/md_var.h
index 1f622e2..7a19d33 100644
--- a/sys/arm/include/md_var.h
+++ b/sys/arm/include/md_var.h
@@ -57,6 +57,7 @@ enum cpu_class {
CPU_CLASS_ARM7,
CPU_CLASS_ARM7TDMI,
CPU_CLASS_ARM8,
+ CPU_CLASS_ARM9,
CPU_CLASS_ARM9TDMI,
CPU_CLASS_ARM9ES,
CPU_CLASS_ARM9EJS,
diff --git a/sys/arm/mv/mv_machdep.c b/sys/arm/mv/mv_machdep.c
index 10890f7..479a105 100644
--- a/sys/arm/mv/mv_machdep.c
+++ b/sys/arm/mv/mv_machdep.c
@@ -406,8 +406,7 @@ initarm(void *mdp, void *unused __unused)
}
availmem_regions_sz = i;
} else {
- /* Fall back to hardcoded boothowto flags and metadata. */
- boothowto = RB_VERBOSE | RB_SINGLE;
+ /* Fall back to hardcoded metadata. */
lastaddr = fake_preload_metadata();
/*
diff --git a/sys/arm/xscale/ixp425/cambria_fled.c b/sys/arm/xscale/ixp425/cambria_fled.c
index 7faa310..7f678c8 100644
--- a/sys/arm/xscale/ixp425/cambria_fled.c
+++ b/sys/arm/xscale/ixp425/cambria_fled.c
@@ -74,7 +74,7 @@ fled_attach(device_t dev)
sc->sc_led = led_create(fled_cb, dev, "front");
- led_func(sc, 1); /* Turn on LED */
+ fled_cb(sc, 1); /* Turn on LED */
return 0;
}
diff --git a/sys/boot/forth/loader.conf b/sys/boot/forth/loader.conf
index f7e01ac..d7f1323 100644
--- a/sys/boot/forth/loader.conf
+++ b/sys/boot/forth/loader.conf
@@ -225,6 +225,7 @@ if_axe_load="NO" # ASIX Electronics AX88172 USB Ethernet
if_bce_load="NO" # Broadcom NetXtreme II Gigabit Ethernet
if_bfe_load="NO" # Broadcom BCM4401
if_bge_load="NO" # Broadcom BCM570x PCI Gigabit Ethernet
+if_bwn_load="NO" # Broadcom BCM43xx IEEE 802.11 wireless NICs
if_cas_load="NO" # Sun Cassini/Cassini+ and NS DP83065 Saturn
if_cm_load="NO" # SMC (90c26, 90c56, 90c66)
if_cs_load="NO" # Crystal Semiconductor CS8920
diff --git a/sys/boot/powerpc/ofw/Makefile b/sys/boot/powerpc/ofw/Makefile
index dfc80db..d42fa92 100644
--- a/sys/boot/powerpc/ofw/Makefile
+++ b/sys/boot/powerpc/ofw/Makefile
@@ -56,6 +56,11 @@ CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/powerpc
LIBFICL= ${.OBJDIR}/../../ficl/libficl.a
.endif
+# Avoid the open-close-dance for every file access as some firmwares perform
+# an auto-negotiation on every open of the network interface and thus causes
+# netbooting to take horribly long.
+CFLAGS+= -DNETIF_OPEN_CLOSE_ONCE
+
# Always add MI sources
.PATH: ${.CURDIR}/../../common
.include "${.CURDIR}/../../common/Makefile.inc"
diff --git a/sys/boot/powerpc/uboot/Makefile b/sys/boot/powerpc/uboot/Makefile
index efb401e..62a2868 100644
--- a/sys/boot/powerpc/uboot/Makefile
+++ b/sys/boot/powerpc/uboot/Makefile
@@ -9,8 +9,8 @@ NO_MAN=
# Architecture-specific loader code
SRCS= start.S conf.c vers.c
-LOADER_DISK_SUPPORT?= no
-LOADER_UFS_SUPPORT?= no
+LOADER_DISK_SUPPORT?= yes
+LOADER_UFS_SUPPORT?= yes
LOADER_CD9660_SUPPORT?= no
LOADER_EXT2FS_SUPPORT?= no
LOADER_NET_SUPPORT?= yes
@@ -85,11 +85,11 @@ LDADD= ${LIBFICL} ${LIBUBOOT} -lstand
vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version
sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT}
-${PROG}.help: help.common help.uboot
+loader.help: help.common help.uboot
cat ${.ALLSRC} | \
awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET}
.PATH: ${.CURDIR}/../../forth
-FILES= ${PROG}.help
+FILES= loader.help
.include <bsd.prog.mk>
diff --git a/sys/boot/powerpc/uboot/conf.c b/sys/boot/powerpc/uboot/conf.c
index 5a9515a..3530537 100644
--- a/sys/boot/powerpc/uboot/conf.c
+++ b/sys/boot/powerpc/uboot/conf.c
@@ -47,7 +47,7 @@ __FBSDID("$FreeBSD$");
/* Exported for libstand */
struct devsw *devsw[] = {
#if defined(LOADER_DISK_SUPPORT) || defined(LOADER_CD9660_SUPPORT)
- &uboot_disk,
+ &uboot_storage,
#endif
#if defined(LOADER_NET_SUPPORT)
&netdev,
diff --git a/sys/boot/sparc64/loader/main.c b/sys/boot/sparc64/loader/main.c
index 7204169..2afbfee 100644
--- a/sys/boot/sparc64/loader/main.c
+++ b/sys/boot/sparc64/loader/main.c
@@ -137,7 +137,7 @@ struct tlb_entry *dtlb_store;
struct tlb_entry *itlb_store;
u_int dtlb_slot;
u_int itlb_slot;
-int cpu_impl;
+static int cpu_impl;
static u_int dtlb_slot_max;
static u_int itlb_slot_max;
diff --git a/sys/boot/uboot/common/main.c b/sys/boot/uboot/common/main.c
index 1ebb097..7d068ee 100644
--- a/sys/boot/uboot/common/main.c
+++ b/sys/boot/uboot/common/main.c
@@ -117,6 +117,7 @@ main(void)
{
struct api_signature *sig = NULL;
int i;
+ struct open_file f;
if (!api_search_sig(&sig))
return (-1);
@@ -168,18 +169,28 @@ main(void)
printf("(%s, %s)\n", bootprog_maker, bootprog_date);
meminfo();
- /* XXX only support netbooting for now */
- for (i = 0; devsw[i] != NULL; i++)
+ for (i = 0; devsw[i] != NULL; i++) {
+ printf("\nDevice %d: %s\n", i, devsw[i]->dv_name);
+
+ currdev.d_dev = devsw[i];
+ currdev.d_type = currdev.d_dev->dv_type;
+ currdev.d_unit = 0;
+
+ if (strncmp(devsw[i]->dv_name, "disk",
+ strlen(devsw[i]->dv_name)) == 0) {
+ f.f_devdata = &currdev;
+ currdev.d_disk.pnum = 0;
+ if (devsw[i]->dv_open(&f,&currdev) == 0)
+ break;
+ }
+
if (strncmp(devsw[i]->dv_name, "net",
strlen(devsw[i]->dv_name)) == 0)
break;
+ }
if (devsw[i] == NULL)
- panic("no network devices?!");
-
- currdev.d_dev = devsw[i];
- currdev.d_type = currdev.d_dev->dv_type;
- currdev.d_unit = 0;
+ panic("No boot device found!");
env_setenv("currdev", EV_VOLATILE, uboot_fmtdev(&currdev),
uboot_setcurrdev, env_nounset);
diff --git a/sys/boot/uboot/lib/disk.c b/sys/boot/uboot/lib/disk.c
index 4cbdbea..3af4c79 100644
--- a/sys/boot/uboot/lib/disk.c
+++ b/sys/boot/uboot/lib/disk.c
@@ -376,6 +376,14 @@ stor_open_gpt(struct open_dev *od, struct uboot_devdesc *dev)
}
dev->d_disk.ptype = PTYPE_GPT;
+ /*
+ * If index of partition to open (dev->d_disk.pnum) is not defined
+ * we set it to the index of the first existing partition. This
+ * handles cases when only a disk device is specified (without full
+ * partition information) by the caller.
+ */
+ if ((od->od_nparts > 0) && (dev->d_disk.pnum == 0))
+ dev->d_disk.pnum = od->od_partitions[0].gp_index;
for (i = 0; i < od->od_nparts; i++)
if (od->od_partitions[i].gp_index == dev->d_disk.pnum)
diff --git a/sys/boot/uboot/lib/time.c b/sys/boot/uboot/lib/time.c
index b7c3fe8..9083675 100644
--- a/sys/boot/uboot/lib/time.c
+++ b/sys/boot/uboot/lib/time.c
@@ -48,7 +48,7 @@ time(time_t *tloc)
}
int
-getsecs()
+getsecs(void)
{
return (time(NULL));
diff --git a/sys/boot/zfs/zfs.c b/sys/boot/zfs/zfs.c
index 52df773..99bb60a 100644
--- a/sys/boot/zfs/zfs.c
+++ b/sys/boot/zfs/zfs.c
@@ -397,7 +397,7 @@ zfs_dev_init(void)
/*
* Open all the disks we can find and see if we can reconstruct
* ZFS pools from them. Bogusly assumes that the disks are named
- * diskN or diskNsM.
+ * diskN, diskNpM or diskNsM.
*/
zfs_init();
for (unit = 0; unit < 32 /* XXX */; unit++) {
diff --git a/sys/cam/ata/ata_xpt.c b/sys/cam/ata/ata_xpt.c
index 92ba027..d5e0b32 100644
--- a/sys/cam/ata/ata_xpt.c
+++ b/sys/cam/ata/ata_xpt.c
@@ -178,11 +178,13 @@ static void ata_dev_async(u_int32_t async_code,
struct cam_ed *device,
void *async_arg);
static void ata_action(union ccb *start_ccb);
+static void ata_announce_periph(struct cam_periph *periph);
static struct xpt_xport ata_xport = {
.alloc_device = ata_alloc_device,
.action = ata_action,
.async = ata_dev_async,
+ .announce = ata_announce_periph,
};
struct xpt_xport *
@@ -786,11 +788,10 @@ noerror:
ata_btrim(ident_buf->serial, sizeof(ident_buf->serial));
ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial));
/* Device may need spin-up before IDENTIFY become valid. */
- if ((ident_buf->config & ATA_RESP_INCOMPLETE) ||
- ((ident_buf->support.command2 & ATA_SUPPORT_STANDBY) &&
- (ident_buf->enabled.command2 & ATA_SUPPORT_STANDBY) &&
- (ident_buf->support.command2 & ATA_SUPPORT_SPINUP) &&
- softc->spinup == 0)) {
+ if ((ident_buf->specconf == 0x37c8 ||
+ ident_buf->specconf == 0x738c) &&
+ ((ident_buf->config & ATA_RESP_INCOMPLETE) ||
+ softc->spinup == 0)) {
PROBE_SET_ACTION(softc, PROBE_SPINUP);
xpt_release_ccb(done_ccb);
xpt_schedule(periph, priority);
@@ -1641,3 +1642,82 @@ ata_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
}
}
+static void
+ata_announce_periph(struct cam_periph *periph)
+{
+ struct ccb_pathinq cpi;
+ struct ccb_trans_settings cts;
+ struct cam_path *path = periph->path;
+ u_int speed;
+ u_int mb;
+
+ mtx_assert(periph->sim->mtx, MA_OWNED);
+
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+ cts.type = CTS_TYPE_CURRENT_SETTINGS;
+ xpt_action((union ccb*)&cts);
+ if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
+ return;
+ /* Ask the SIM for its base transfer speed */
+ xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
+ cpi.ccb_h.func_code = XPT_PATH_INQ;
+ xpt_action((union ccb *)&cpi);
+ /* Report connection speed */
+ speed = cpi.base_transfer_speed;
+ if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
+ struct ccb_trans_settings_ata *ata =
+ &cts.xport_specific.ata;
+
+ if (ata->valid & CTS_ATA_VALID_MODE)
+ speed = ata_mode2speed(ata->mode);
+ }
+ if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
+ struct ccb_trans_settings_sata *sata =
+ &cts.xport_specific.sata;
+
+ if (sata->valid & CTS_SATA_VALID_REVISION)
+ speed = ata_revision2speed(sata->revision);
+ }
+ mb = speed / 1000;
+ if (mb > 0)
+ printf("%s%d: %d.%03dMB/s transfers",
+ periph->periph_name, periph->unit_number,
+ mb, speed % 1000);
+ else
+ printf("%s%d: %dKB/s transfers", periph->periph_name,
+ periph->unit_number, speed);
+ /* Report additional information about connection */
+ if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
+ struct ccb_trans_settings_ata *ata =
+ &cts.xport_specific.ata;
+
+ printf(" (");
+ if (ata->valid & CTS_ATA_VALID_MODE)
+ printf("%s, ", ata_mode2string(ata->mode));
+ if ((ata->valid & CTS_ATA_VALID_ATAPI) && ata->atapi != 0)
+ printf("ATAPI %dbytes, ", ata->atapi);
+ if (ata->valid & CTS_ATA_VALID_BYTECOUNT)
+ printf("PIO %dbytes", ata->bytecount);
+ printf(")");
+ }
+ if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
+ struct ccb_trans_settings_sata *sata =
+ &cts.xport_specific.sata;
+
+ printf(" (");
+ if (sata->valid & CTS_SATA_VALID_REVISION)
+ printf("SATA %d.x, ", sata->revision);
+ else
+ printf("SATA, ");
+ if (sata->valid & CTS_SATA_VALID_MODE)
+ printf("%s, ", ata_mode2string(sata->mode));
+ if ((sata->valid & CTS_ATA_VALID_ATAPI) && sata->atapi != 0)
+ printf("ATAPI %dbytes, ", sata->atapi);
+ if (sata->valid & CTS_SATA_VALID_BYTECOUNT)
+ printf("PIO %dbytes", sata->bytecount);
+ printf(")");
+ }
+ printf("\n");
+}
+
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index 7aa04a8..4871e85 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -866,7 +866,8 @@ xpt_rescan(union ccb *ccb)
struct ccb_hdr *hdr;
/* Prepare request */
- if(ccb->ccb_h.path->target->target_id == CAM_TARGET_WILDCARD)
+ if (ccb->ccb_h.path->target->target_id == CAM_TARGET_WILDCARD ||
+ ccb->ccb_h.path->device->lun_id == CAM_LUN_WILDCARD)
ccb->ccb_h.func_code = XPT_SCAN_BUS;
else
ccb->ccb_h.func_code = XPT_SCAN_LUN;
@@ -1065,20 +1066,10 @@ xpt_remove_periph(struct cam_periph *periph)
void
xpt_announce_periph(struct cam_periph *periph, char *announce_string)
{
- struct ccb_pathinq cpi;
- struct ccb_trans_settings cts;
- struct cam_path *path;
- u_int speed;
- u_int freq;
- u_int mb;
+ struct cam_path *path = periph->path;
mtx_assert(periph->sim->mtx, MA_OWNED);
- path = periph->path;
- /*
- * To ensure that this is printed in one piece,
- * mask out CAM interrupts.
- */
printf("%s%d at %s%d bus %d scbus%d target %d lun %d\n",
periph->periph_name, periph->unit_number,
path->bus->sim->sim_name,
@@ -1089,155 +1080,26 @@ xpt_announce_periph(struct cam_periph *periph, char *announce_string)
path->device->lun_id);
printf("%s%d: ", periph->periph_name, periph->unit_number);
if (path->device->protocol == PROTO_SCSI)
- scsi_print_inquiry(&path->device->inq_data);
+ scsi_print_inquiry(&path->device->inq_data);
else if (path->device->protocol == PROTO_ATA ||
path->device->protocol == PROTO_SATAPM)
ata_print_ident(&path->device->ident_data);
else
- printf("Unknown protocol device\n");
+ printf("Unknown protocol device\n");
if (bootverbose && path->device->serial_num_len > 0) {
/* Don't wrap the screen - print only the first 60 chars */
printf("%s%d: Serial Number %.60s\n", periph->periph_name,
periph->unit_number, path->device->serial_num);
}
- xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
- cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
- cts.type = CTS_TYPE_CURRENT_SETTINGS;
- xpt_action((union ccb*)&cts);
- if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
- return;
- }
-
- /* Ask the SIM for its base transfer speed */
- xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
- cpi.ccb_h.func_code = XPT_PATH_INQ;
- xpt_action((union ccb *)&cpi);
-
- speed = cpi.base_transfer_speed;
- freq = 0;
- if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SPI) {
- struct ccb_trans_settings_spi *spi =
- &cts.xport_specific.spi;
-
- if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0
- && spi->sync_offset != 0) {
- freq = scsi_calc_syncsrate(spi->sync_period);
- speed = freq;
- }
- if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0)
- speed *= (0x01 << spi->bus_width);
- }
- if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_FC) {
- struct ccb_trans_settings_fc *fc =
- &cts.xport_specific.fc;
-
- if (fc->valid & CTS_FC_VALID_SPEED)
- speed = fc->bitrate;
- }
- if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SAS) {
- struct ccb_trans_settings_sas *sas =
- &cts.xport_specific.sas;
-
- if (sas->valid & CTS_SAS_VALID_SPEED)
- speed = sas->bitrate;
- }
- if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
- struct ccb_trans_settings_ata *ata =
- &cts.xport_specific.ata;
-
- if (ata->valid & CTS_ATA_VALID_MODE)
- speed = ata_mode2speed(ata->mode);
- }
- if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
- struct ccb_trans_settings_sata *sata =
- &cts.xport_specific.sata;
-
- if (sata->valid & CTS_SATA_VALID_REVISION)
- speed = ata_revision2speed(sata->revision);
- }
-
- mb = speed / 1000;
- if (mb > 0)
- printf("%s%d: %d.%03dMB/s transfers",
- periph->periph_name, periph->unit_number,
- mb, speed % 1000);
- else
- printf("%s%d: %dKB/s transfers", periph->periph_name,
- periph->unit_number, speed);
- /* Report additional information about SPI connections */
- if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SPI) {
- struct ccb_trans_settings_spi *spi;
-
- spi = &cts.xport_specific.spi;
- if (freq != 0) {
- printf(" (%d.%03dMHz%s, offset %d", freq / 1000,
- freq % 1000,
- (spi->ppr_options & MSG_EXT_PPR_DT_REQ) != 0
- ? " DT" : "",
- spi->sync_offset);
- }
- if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0
- && spi->bus_width > 0) {
- if (freq != 0) {
- printf(", ");
- } else {
- printf(" (");
- }
- printf("%dbit)", 8 * (0x01 << spi->bus_width));
- } else if (freq != 0) {
- printf(")");
- }
- }
- if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_FC) {
- struct ccb_trans_settings_fc *fc;
-
- fc = &cts.xport_specific.fc;
- if (fc->valid & CTS_FC_VALID_WWNN)
- printf(" WWNN 0x%llx", (long long) fc->wwnn);
- if (fc->valid & CTS_FC_VALID_WWPN)
- printf(" WWPN 0x%llx", (long long) fc->wwpn);
- if (fc->valid & CTS_FC_VALID_PORT)
- printf(" PortID 0x%x", fc->port);
- }
- if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
- struct ccb_trans_settings_ata *ata =
- &cts.xport_specific.ata;
-
- printf(" (");
- if (ata->valid & CTS_ATA_VALID_MODE)
- printf("%s, ", ata_mode2string(ata->mode));
- if ((ata->valid & CTS_ATA_VALID_ATAPI) && ata->atapi != 0)
- printf("ATAPI %dbytes, ", ata->atapi);
- if (ata->valid & CTS_ATA_VALID_BYTECOUNT)
- printf("PIO %dbytes", ata->bytecount);
- printf(")");
- }
- if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
- struct ccb_trans_settings_sata *sata =
- &cts.xport_specific.sata;
-
- printf(" (");
- if (sata->valid & CTS_SATA_VALID_REVISION)
- printf("SATA %d.x, ", sata->revision);
- if (sata->valid & CTS_SATA_VALID_MODE)
- printf("%s, ", ata_mode2string(sata->mode));
- if ((sata->valid & CTS_ATA_VALID_ATAPI) && sata->atapi != 0)
- printf("ATAPI %dbytes, ", sata->atapi);
- if (sata->valid & CTS_SATA_VALID_BYTECOUNT)
- printf("PIO %dbytes", sata->bytecount);
- printf(")");
- }
+ /* Announce transport details. */
+ (*(path->bus->xport->announce))(periph);
+ /* Announce command queueing. */
if (path->device->inq_flags & SID_CmdQue
|| path->device->flags & CAM_DEV_TAG_AFTER_COUNT) {
- printf("\n%s%d: Command Queueing enabled",
+ printf("%s%d: Command Queueing enabled\n",
periph->periph_name, periph->unit_number);
}
- printf("\n");
-
- /*
- * We only want to print the caller's announce string if they've
- * passed one in..
- */
+ /* Announce caller's details if they've passed in. */
if (announce_string != NULL)
printf("%s%d: %s\n", periph->periph_name,
periph->unit_number, announce_string);
diff --git a/sys/cam/cam_xpt_internal.h b/sys/cam/cam_xpt_internal.h
index b1fbaaf..5fa4b5e 100644
--- a/sys/cam/cam_xpt_internal.h
+++ b/sys/cam/cam_xpt_internal.h
@@ -44,8 +44,7 @@ typedef void (*xpt_dev_async_func)(u_int32_t async_code,
struct cam_et *target,
struct cam_ed *device,
void *async_arg);
-typedef void (*xpt_announce_periph_func)(struct cam_periph *periph,
- char *announce_string);
+typedef void (*xpt_announce_periph_func)(struct cam_periph *periph);
struct xpt_xport {
xpt_alloc_device_func alloc_device;
diff --git a/sys/cam/scsi/scsi_xpt.c b/sys/cam/scsi/scsi_xpt.c
index 7639377..b907965 100644
--- a/sys/cam/scsi/scsi_xpt.c
+++ b/sys/cam/scsi/scsi_xpt.c
@@ -552,11 +552,13 @@ static void scsi_dev_async(u_int32_t async_code,
struct cam_ed *device,
void *async_arg);
static void scsi_action(union ccb *start_ccb);
+static void scsi_announce_periph(struct cam_periph *periph);
static struct xpt_xport scsi_xport = {
.alloc_device = scsi_alloc_device,
.action = scsi_action,
.async = scsi_dev_async,
+ .announce = scsi_announce_periph,
};
struct xpt_xport *
@@ -2414,3 +2416,100 @@ scsi_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
}
}
+static void
+scsi_announce_periph(struct cam_periph *periph)
+{
+ struct ccb_pathinq cpi;
+ struct ccb_trans_settings cts;
+ struct cam_path *path = periph->path;
+ u_int speed;
+ u_int freq;
+ u_int mb;
+
+ mtx_assert(periph->sim->mtx, MA_OWNED);
+
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+ cts.type = CTS_TYPE_CURRENT_SETTINGS;
+ xpt_action((union ccb*)&cts);
+ if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
+ return;
+ /* Ask the SIM for its base transfer speed */
+ xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
+ cpi.ccb_h.func_code = XPT_PATH_INQ;
+ xpt_action((union ccb *)&cpi);
+ /* Report connection speed */
+ speed = cpi.base_transfer_speed;
+ freq = 0;
+ if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SPI) {
+ struct ccb_trans_settings_spi *spi =
+ &cts.xport_specific.spi;
+
+ if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0
+ && spi->sync_offset != 0) {
+ freq = scsi_calc_syncsrate(spi->sync_period);
+ speed = freq;
+ }
+ if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0)
+ speed *= (0x01 << spi->bus_width);
+ }
+ if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_FC) {
+ struct ccb_trans_settings_fc *fc =
+ &cts.xport_specific.fc;
+
+ if (fc->valid & CTS_FC_VALID_SPEED)
+ speed = fc->bitrate;
+ }
+ if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SAS) {
+ struct ccb_trans_settings_sas *sas =
+ &cts.xport_specific.sas;
+
+ if (sas->valid & CTS_SAS_VALID_SPEED)
+ speed = sas->bitrate;
+ }
+ mb = speed / 1000;
+ if (mb > 0)
+ printf("%s%d: %d.%03dMB/s transfers",
+ periph->periph_name, periph->unit_number,
+ mb, speed % 1000);
+ else
+ printf("%s%d: %dKB/s transfers", periph->periph_name,
+ periph->unit_number, speed);
+ /* Report additional information about SPI connections */
+ if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SPI) {
+ struct ccb_trans_settings_spi *spi;
+
+ spi = &cts.xport_specific.spi;
+ if (freq != 0) {
+ printf(" (%d.%03dMHz%s, offset %d", freq / 1000,
+ freq % 1000,
+ (spi->ppr_options & MSG_EXT_PPR_DT_REQ) != 0
+ ? " DT" : "",
+ spi->sync_offset);
+ }
+ if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0
+ && spi->bus_width > 0) {
+ if (freq != 0) {
+ printf(", ");
+ } else {
+ printf(" (");
+ }
+ printf("%dbit)", 8 * (0x01 << spi->bus_width));
+ } else if (freq != 0) {
+ printf(")");
+ }
+ }
+ if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_FC) {
+ struct ccb_trans_settings_fc *fc;
+
+ fc = &cts.xport_specific.fc;
+ if (fc->valid & CTS_FC_VALID_WWNN)
+ printf(" WWNN 0x%llx", (long long) fc->wwnn);
+ if (fc->valid & CTS_FC_VALID_WWPN)
+ printf(" WWPN 0x%llx", (long long) fc->wwpn);
+ if (fc->valid & CTS_FC_VALID_PORT)
+ printf(" PortID 0x%x", fc->port);
+ }
+ printf("\n");
+}
+
diff --git a/sys/cddl/contrib/opensolaris/common/atomic/ia64/opensolaris_atomic.S b/sys/cddl/contrib/opensolaris/common/atomic/ia64/opensolaris_atomic.S
index 409d759..1b7c580 100644
--- a/sys/cddl/contrib/opensolaris/common/atomic/ia64/opensolaris_atomic.S
+++ b/sys/cddl/contrib/opensolaris/common/atomic/ia64/opensolaris_atomic.S
@@ -76,7 +76,7 @@ ENTRY(atomic_or_8_nv, 2)
END(atomic_or_8_nv)
ENTRY(membar_producer, 0)
- mf.a
+ mf
;;
br.ret.sptk rp
END(membar_producer)
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
index 163b215..90861ba 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
@@ -62,6 +62,14 @@
#include "zfs_prop.h"
#include "zfs_comutil.h"
+/* Check hostid on import? */
+static int check_hostid = 1;
+
+SYSCTL_DECL(_vfs_zfs);
+TUNABLE_INT("vfs.zfs.check_hostid", &check_hostid);
+SYSCTL_INT(_vfs_zfs, OID_AUTO, check_hostid, CTLFLAG_RW, &check_hostid, 0,
+ "Check hostid on import?");
+
int zio_taskq_threads[ZIO_TYPES][ZIO_TASKQ_TYPES] = {
/* ISSUE INTR */
{ 1, 1 }, /* ZIO_TYPE_NULL */
@@ -1168,7 +1176,7 @@ spa_load(spa_t *spa, nvlist_t *config, spa_load_state_t state, int mosconfig)
ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
(void) ddi_strtoul(hw_serial, NULL, 10, &myhostid);
- if (hostid != 0 && myhostid != 0 &&
+ if (check_hostid && hostid != 0 && myhostid != 0 &&
(unsigned long)hostid != myhostid) {
cmn_err(CE_WARN, "pool '%s' could not be "
"loaded as it was last accessed by "
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
index 1132483..ad8165b 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
@@ -214,7 +214,7 @@ blksz_changed_cb(void *arg, uint64_t newval)
newval = SPA_MAXBLOCKSIZE;
zfsvfs->z_max_blksz = newval;
- zfsvfs->z_vfs->vfs_bsize = newval;
+ zfsvfs->z_vfs->mnt_stat.f_iosize = newval;
}
static void
@@ -577,7 +577,8 @@ zfs_domount(vfs_t *vfsp, char *osname)
if (error = dsl_prop_get_integer(osname, "recordsize", &recordsize,
NULL))
goto out;
- zfsvfs->z_vfs->vfs_bsize = recordsize;
+ zfsvfs->z_vfs->vfs_bsize = SPA_MINBLOCKSIZE;
+ zfsvfs->z_vfs->mnt_stat.f_iosize = recordsize;
vfsp->vfs_data = zfsvfs;
vfsp->mnt_flag |= MNT_LOCAL;
@@ -817,8 +818,8 @@ zfs_statfs(vfs_t *vfsp, struct statfs *statp)
* We report the fragsize as the smallest block size we support,
* and we report our blocksize as the filesystem's maximum blocksize.
*/
- statp->f_bsize = zfsvfs->z_vfs->vfs_bsize;
- statp->f_iosize = zfsvfs->z_vfs->vfs_bsize;
+ statp->f_bsize = SPA_MINBLOCKSIZE;
+ statp->f_iosize = zfsvfs->z_vfs->mnt_stat.f_iosize;
/*
* The following report "total" blocks of various kinds in the
@@ -826,7 +827,7 @@ zfs_statfs(vfs_t *vfsp, struct statfs *statp)
* "fragment" size.
*/
- statp->f_blocks = (refdbytes + availbytes) / statp->f_bsize;
+ statp->f_blocks = (refdbytes + availbytes) >> SPA_MINBLOCKSHIFT;
statp->f_bfree = availbytes / statp->f_bsize;
statp->f_bavail = statp->f_bfree; /* no root reservation */
diff --git a/sys/compat/linux/linux_getcwd.c b/sys/compat/linux/linux_getcwd.c
index afd30c8..cad5a22 100644
--- a/sys/compat/linux/linux_getcwd.c
+++ b/sys/compat/linux/linux_getcwd.c
@@ -15,13 +15,6 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/sys/compat/linux/linux_stats.c b/sys/compat/linux/linux_stats.c
index 4d21a32..8e8936c 100644
--- a/sys/compat/linux/linux_stats.c
+++ b/sys/compat/linux/linux_stats.c
@@ -58,8 +58,6 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_util.h>
#include <compat/linux/linux_file.h>
-#include <security/mac/mac_framework.h>
-
static void
translate_vnhook_major_minor(struct vnode *vp, struct stat *sb)
{
diff --git a/sys/compat/linux/linux_time.c b/sys/compat/linux/linux_time.c
index e9bc71b..8800d67 100644
--- a/sys/compat/linux/linux_time.c
+++ b/sys/compat/linux/linux_time.c
@@ -15,13 +15,6 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index f7ab101..5142551 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2816,6 +2816,11 @@ options SHMMNI=33
# a single process at one time.
options SHMSEG=9
+# Compress user core dumps.
+options COMPRESS_USER_CORES
+# required to compress file output from kernel for COMPRESS_USER_CORES.
+device gzio
+
# Set the amount of time (in seconds) the system will wait before
# rebooting automatically when a kernel panic occurs. If set to (-1),
# the system will wait indefinitely until a key is pressed on the
diff --git a/sys/conf/files b/sys/conf/files
index 7793ec7..811b893 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -2053,6 +2053,7 @@ kern/kern_exec.c standard
kern/kern_exit.c standard
kern/kern_fail.c standard
kern/kern_fork.c standard
+kern/kern_gzio.c optional gzio
kern/kern_idle.c standard
kern/kern_intr.c standard
kern/kern_jail.c standard
@@ -2084,7 +2085,6 @@ kern/kern_sdt.c optional kdtrace_hooks
kern/kern_sema.c standard
kern/kern_shutdown.c standard
kern/kern_sig.c standard
-kern/kern_subr.c standard
kern/kern_switch.c standard
kern/kern_sx.c standard
kern/kern_synch.c standard
@@ -2121,6 +2121,7 @@ kern/subr_disk.c standard
kern/subr_eventhandler.c standard
kern/subr_fattime.c standard
kern/subr_firmware.c optional firmware
+kern/subr_hash.c standard
kern/subr_hints.c standard
kern/subr_kdb.c standard
kern/subr_kobj.c standard
@@ -2146,6 +2147,7 @@ kern/subr_stack.c optional ddb | stack | ktr
kern/subr_taskqueue.c standard
kern/subr_trap.c standard
kern/subr_turnstile.c standard
+kern/subr_uio.c standard
kern/subr_unit.c standard
kern/subr_witness.c optional witness
kern/sys_generic.c standard
@@ -2343,7 +2345,7 @@ net/slcompress.c optional netgraph_vjc | sppp | \
net/vnet.c optional vimage
net/zlib.c optional crypto | geom_uzip | ipsec | \
mxge | netgraph_deflate | \
- ddb_ctf
+ ddb_ctf | gzio
net80211/ieee80211.c optional wlan
net80211/ieee80211_acl.c optional wlan wlan_acl
net80211/ieee80211_action.c optional wlan
@@ -2486,7 +2488,14 @@ netinet/in_proto.c optional inet \
compile-with "${NORMAL_C} -I$S/contrib/pf"
netinet/in_rmx.c optional inet
netinet/ip_divert.c optional inet ipdivert ipfirewall
+netinet/ipfw/dn_heap.c optional inet dummynet
+netinet/ipfw/dn_sched_fifo.c optional inet dummynet
+netinet/ipfw/dn_sched_rr.c optional inet dummynet
+netinet/ipfw/dn_sched_wf2q.c optional inet dummynet
+netinet/ipfw/dn_sched_qfq.c optional inet dummynet
netinet/ipfw/ip_dummynet.c optional inet dummynet
+netinet/ipfw/ip_dn_io.c optional inet dummynet
+netinet/ipfw/ip_dn_glue.c optional inet dummynet
netinet/ip_ecn.c optional inet | inet6
netinet/ip_encap.c optional inet | inet6
netinet/ip_fastfwd.c optional inet
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index 1734358..9300f89 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -131,13 +131,6 @@ amd64/amd64/tsc.c standard
amd64/amd64/uio_machdep.c standard
amd64/amd64/uma_machdep.c standard
amd64/amd64/vm_machdep.c standard
-amd64/isa/atpic.c optional atpic isa
-#amd64/isa/atpic_vector.S optional atpic isa
-amd64/isa/clock.c standard
-amd64/isa/elcr.c standard
-amd64/isa/isa.c standard
-amd64/isa/isa_dma.c standard
-amd64/isa/nmi.c standard
amd64/pci/pci_bus.c optional pci
amd64/pci/pci_cfgreg.c optional pci
crypto/blowfish/bf_enc.c optional crypto | ipsec
@@ -228,8 +221,6 @@ dev/syscons/scvgarndr.c optional sc vga
dev/syscons/scvtb.c optional sc
dev/uart/uart_cpu_amd64.c optional uart
dev/wpi/if_wpi.c optional wpi
-isa/atrtc.c standard
-isa/orm.c optional isa
isa/syscons_isa.c optional sc
isa/vga_isa.c optional vga
kern/link_elf_obj.c standard
@@ -289,12 +280,6 @@ compat/ndis/subr_ntoskrnl.c optional ndisapi pci
compat/ndis/subr_pe.c optional ndisapi pci
compat/ndis/subr_usbd.c optional ndisapi pci
compat/ndis/winx64_wrap.S optional ndisapi pci
-i386/bios/smbios.c optional smbios
-i386/bios/vpd.c optional vpd
-i386/cpufreq/powernow.c optional cpufreq
-i386/cpufreq/est.c optional cpufreq
-i386/cpufreq/hwpstate.c optional cpufreq
-i386/cpufreq/p4tcc.c optional cpufreq
#
libkern/memmove.c standard
libkern/memset.c standard
@@ -303,3 +288,20 @@ libkern/memset.c standard
#
compat/x86bios/x86bios.c optional x86bios | atkbd | dpms | vesa
contrib/x86emu/x86emu.c optional x86bios | atkbd | dpms | vesa
+#
+# x86 shared code between IA32, AMD64 and PC98 architectures
+#
+x86/bios/smbios.c optional smbios
+x86/bios/vpd.c optional vpd
+x86/cpufreq/powernow.c optional cpufreq
+x86/cpufreq/est.c optional cpufreq
+x86/cpufreq/hwpstate.c optional cpufreq
+x86/cpufreq/p4tcc.c optional cpufreq
+x86/isa/atpic.c optional atpic isa
+x86/isa/atrtc.c standard
+x86/isa/clock.c standard
+x86/isa/elcr.c standard
+x86/isa/isa.c standard
+x86/isa/isa_dma.c standard
+x86/isa/nmi.c standard
+x86/isa/orm.c optional isa
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
index 6c440ea..a61dca2 100644
--- a/sys/conf/files.i386
+++ b/sys/conf/files.i386
@@ -244,13 +244,6 @@ i386/bios/apm.c optional apm
i386/bios/mca_machdep.c optional mca
i386/bios/smapi.c optional smapi
i386/bios/smapi_bios.S optional smapi
-i386/bios/smbios.c optional smbios
-i386/bios/vpd.c optional vpd
-i386/cpufreq/est.c optional cpufreq
-i386/cpufreq/hwpstate.c optional cpufreq
-i386/cpufreq/p4tcc.c optional cpufreq
-i386/cpufreq/powernow.c optional cpufreq
-i386/cpufreq/smist.c optional cpufreq
#i386/i386/apic_vector.s optional apic
i386/i386/atomic.c standard \
compile-with "${CC} -c ${CFLAGS} ${DEFINED_PROF:S/^$/-fomit-frame-pointer/} ${.IMPSRC}"
@@ -329,17 +322,10 @@ i386/ibcs2/ibcs2_util.c optional ibcs2
i386/ibcs2/ibcs2_xenix.c optional ibcs2
i386/ibcs2/ibcs2_xenix_sysent.c optional ibcs2
i386/ibcs2/imgact_coff.c optional ibcs2
-i386/isa/atpic.c optional atpic
-#i386/isa/atpic_vector.s standard
-i386/isa/clock.c optional native
i386/xen/clock.c optional xen
i386/xen/xen_clock_util.c optional xen
i386/xen/xen_rtc.c optional xen
-i386/isa/elcr.c standard
i386/isa/elink.c optional ep | ie
-i386/isa/isa.c optional isa
-i386/isa/isa_dma.c optional isa
-i386/isa/nmi.c standard
i386/isa/npx.c optional npx
i386/isa/pmtimer.c optional pmtimer
i386/isa/prof_machdep.c optional profiling-routine
@@ -362,8 +348,6 @@ i386/svr4/svr4_locore.s optional compat_svr4 \
warning "COMPAT_SVR4 is broken and should be avoided"
i386/svr4/svr4_machdep.c optional compat_svr4
#
-isa/atrtc.c optional atpic
-isa/orm.c optional isa
isa/syscons_isa.c optional sc
isa/vga_isa.c optional vga
kern/imgact_aout.c optional compat_aout
@@ -387,3 +371,21 @@ i386/xbox/pic16l.s optional xbox
#
compat/x86bios/x86bios.c optional x86bios | atkbd | dpms | vesa
contrib/x86emu/x86emu.c optional x86bios | atkbd | dpms | vesa
+#
+# x86 shared code between IA32, AMD64 and PC98 architectures
+#
+x86/bios/smbios.c optional smbios
+x86/bios/vpd.c optional vpd
+x86/cpufreq/est.c optional cpufreq
+x86/cpufreq/hwpstate.c optional cpufreq
+x86/cpufreq/p4tcc.c optional cpufreq
+x86/cpufreq/powernow.c optional cpufreq
+x86/cpufreq/smist.c optional cpufreq
+x86/isa/atpic.c optional atpic
+x86/isa/atrtc.c optional atpic
+x86/isa/clock.c optional native
+x86/isa/elcr.c standard
+x86/isa/isa.c optional isa
+x86/isa/isa_dma.c optional isa
+x86/isa/nmi.c standard
+x86/isa/orm.c optional isa
diff --git a/sys/conf/files.mips b/sys/conf/files.mips
index 63d93ef..4b6c54a 100644
--- a/sys/conf/files.mips
+++ b/sys/conf/files.mips
@@ -97,6 +97,7 @@ dev/cfe/cfe_env.c optional cfe_env
#dev/cfe/cfe_resource.c optional cfe # not yet needed
dev/siba/siba.c optional siba
-dev/siba/siba_pcib.c optional siba pci
dev/siba/siba_cc.c optional siba
+dev/siba/siba_core.c optional siba
+dev/siba/siba_pcib.c optional siba pci
#mips/sentry5/siba_mips.c optional siba # not yet
diff --git a/sys/conf/files.pc98 b/sys/conf/files.pc98
index b4e171d..314b16e 100644
--- a/sys/conf/files.pc98
+++ b/sys/conf/files.pc98
@@ -194,10 +194,7 @@ i386/ibcs2/ibcs2_util.c optional ibcs2
i386/ibcs2/ibcs2_xenix.c optional ibcs2
i386/ibcs2/ibcs2_xenix_sysent.c optional ibcs2
i386/ibcs2/imgact_coff.c optional ibcs2
-i386/isa/atpic.c optional atpic
-#i386/isa/atpic_vector.s standard
i386/isa/elink.c optional ep | ie
-i386/isa/isa.c optional isa
i386/isa/npx.c optional npx
i386/isa/pmtimer.c optional pmtimer
i386/isa/prof_machdep.c optional profiling-routine
@@ -255,3 +252,8 @@ pc98/pc98/canbus.c optional canbus
pc98/pc98/canbus_if.m optional canbus
pc98/pc98/machdep.c standard
pc98/pc98/pc98_machdep.c standard
+#
+# x86 shared code between IA32, AMD64 and PC98 architectures
+#
+x86/isa/atpic.c optional atpic
+x86/isa/isa.c optional isa
diff --git a/sys/conf/ldscript.mips.cfe b/sys/conf/ldscript.mips.cfe
index 0a50e9d..6341d9b 100644
--- a/sys/conf/ldscript.mips.cfe
+++ b/sys/conf/ldscript.mips.cfe
@@ -61,7 +61,7 @@ PHDRS
SECTIONS
{
/* Read-only sections, merged into text segment: */
- . = 0x80100000 ;
+ . = KERNLOADADDR ;
.interp : { *(.interp) } :interp
.hash : { *(.hash) } :text
.dynsym : { *(.dynsym) }
diff --git a/sys/conf/options b/sys/conf/options
index 84bfbd1..7869add 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -71,6 +71,7 @@ COMPAT_FREEBSD5 opt_compat.h
COMPAT_FREEBSD6 opt_compat.h
COMPAT_FREEBSD7 opt_compat.h
COMPILING_LINT opt_global.h
+COMPRESS_USER_CORES opt_core.h
CY_PCI_FASTINTR
DEADLKRES opt_watchdog.h
DIRECTIO
diff --git a/sys/conf/options.mips b/sys/conf/options.mips
index d3b8767..1e30872 100644
--- a/sys/conf/options.mips
+++ b/sys/conf/options.mips
@@ -34,6 +34,7 @@ CPU_MIPS64 opt_global.h
CPU_SENTRY5 opt_global.h
CPU_HAVEFPU opt_global.h
CPU_SB1 opt_global.h
+CPU_CNMIPS opt_global.h
ISA_MIPS1 opt_cputype.h
ISA_MIPS3 opt_cputype.h
@@ -48,10 +49,6 @@ CFE_CONSOLE opt_global.h
CFE_ENV opt_global.h
CFE_ENV_SIZE opt_global.h
-KERNPHYSADDR opt_global.h
-KERNVIRTADDR opt_global.h
-PHYSADDR opt_global.h
-PHYS_ADDR_64BIT opt_global.h
NOFPU opt_global.h
TARGET_OCTEON opt_global.h
TARGET_EMULATOR opt_ddb.h
diff --git a/sys/contrib/libfdt/fdt.c b/sys/contrib/libfdt/fdt.c
new file mode 100644
index 0000000..b1130c2
--- /dev/null
+++ b/sys/contrib/libfdt/fdt.c
@@ -0,0 +1,213 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_check_header(const void *fdt)
+{
+ if (fdt_magic(fdt) == FDT_MAGIC) {
+ /* Complete tree */
+ if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+ return -FDT_ERR_BADVERSION;
+ if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
+ return -FDT_ERR_BADVERSION;
+ } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+ /* Unfinished sequential-write blob */
+ if (fdt_size_dt_struct(fdt) == 0)
+ return -FDT_ERR_BADSTATE;
+ } else {
+ return -FDT_ERR_BADMAGIC;
+ }
+
+ return 0;
+}
+
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
+{
+ const char *p;
+
+ if (fdt_version(fdt) >= 0x11)
+ if (((offset + len) < offset)
+ || ((offset + len) > fdt_size_dt_struct(fdt)))
+ return NULL;
+
+ p = _fdt_offset_ptr(fdt, offset);
+
+ if (p + len < p)
+ return NULL;
+ return p;
+}
+
+uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
+{
+ const uint32_t *tagp, *lenp;
+ uint32_t tag;
+ int offset = startoffset;
+ const char *p;
+
+ *nextoffset = -FDT_ERR_TRUNCATED;
+ tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
+ if (!tagp)
+ return FDT_END; /* premature end */
+ tag = fdt32_to_cpu(*tagp);
+ offset += FDT_TAGSIZE;
+
+ *nextoffset = -FDT_ERR_BADSTRUCTURE;
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ /* skip name */
+ do {
+ p = fdt_offset_ptr(fdt, offset++, 1);
+ } while (p && (*p != '\0'));
+ if (!p)
+ return FDT_END; /* premature end */
+ break;
+
+ case FDT_PROP:
+ lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
+ if (!lenp)
+ return FDT_END; /* premature end */
+ /* skip-name offset, length and value */
+ offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ + fdt32_to_cpu(*lenp);
+ break;
+
+ case FDT_END:
+ case FDT_END_NODE:
+ case FDT_NOP:
+ break;
+
+ default:
+ return FDT_END;
+ }
+
+ if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
+ return FDT_END; /* premature end */
+
+ *nextoffset = FDT_TAGALIGN(offset);
+ return tag;
+}
+
+int _fdt_check_node_offset(const void *fdt, int offset)
+{
+ if ((offset < 0) || (offset % FDT_TAGSIZE)
+ || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
+ return -FDT_ERR_BADOFFSET;
+
+ return offset;
+}
+
+int fdt_next_node(const void *fdt, int offset, int *depth)
+{
+ int nextoffset = 0;
+ uint32_t tag;
+
+ if (offset >= 0)
+ if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
+ return nextoffset;
+
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+ switch (tag) {
+ case FDT_PROP:
+ case FDT_NOP:
+ break;
+
+ case FDT_BEGIN_NODE:
+ if (depth)
+ (*depth)++;
+ break;
+
+ case FDT_END_NODE:
+ if (depth && ((--(*depth)) < 0))
+ return nextoffset;
+ break;
+
+ case FDT_END:
+ if ((nextoffset >= 0)
+ || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
+ return -FDT_ERR_NOTFOUND;
+ else
+ return nextoffset;
+ }
+ } while (tag != FDT_BEGIN_NODE);
+
+ return offset;
+}
+
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
+{
+ int len = strlen(s) + 1;
+ const char *last = strtab + tabsize - len;
+ const char *p;
+
+ for (p = strtab; p <= last; p++)
+ if (memcmp(p, s, len) == 0)
+ return p;
+ return NULL;
+}
+
+int fdt_move(const void *fdt, void *buf, int bufsize)
+{
+ FDT_CHECK_HEADER(fdt);
+
+ if (fdt_totalsize(fdt) > bufsize)
+ return -FDT_ERR_NOSPACE;
+
+ memmove(buf, fdt, fdt_totalsize(fdt));
+ return 0;
+}
diff --git a/sys/contrib/libfdt/fdt.h b/sys/contrib/libfdt/fdt.h
new file mode 100644
index 0000000..48ccfd9
--- /dev/null
+++ b/sys/contrib/libfdt/fdt.h
@@ -0,0 +1,60 @@
+#ifndef _FDT_H
+#define _FDT_H
+
+#ifndef __ASSEMBLY__
+
+struct fdt_header {
+ uint32_t magic; /* magic word FDT_MAGIC */
+ uint32_t totalsize; /* total size of DT block */
+ uint32_t off_dt_struct; /* offset to structure */
+ uint32_t off_dt_strings; /* offset to strings */
+ uint32_t off_mem_rsvmap; /* offset to memory reserve map */
+ uint32_t version; /* format version */
+ uint32_t last_comp_version; /* last compatible version */
+
+ /* version 2 fields below */
+ uint32_t boot_cpuid_phys; /* Which physical CPU id we're
+ booting on */
+ /* version 3 fields below */
+ uint32_t size_dt_strings; /* size of the strings block */
+
+ /* version 17 fields below */
+ uint32_t size_dt_struct; /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+ uint64_t address;
+ uint64_t size;
+};
+
+struct fdt_node_header {
+ uint32_t tag;
+ char name[0];
+};
+
+struct fdt_property {
+ uint32_t tag;
+ uint32_t len;
+ uint32_t nameoff;
+ char data[0];
+};
+
+#endif /* !__ASSEMBLY */
+
+#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
+#define FDT_TAGSIZE sizeof(uint32_t)
+
+#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
+#define FDT_END_NODE 0x2 /* End node */
+#define FDT_PROP 0x3 /* Property: name off,
+ size, content */
+#define FDT_NOP 0x4 /* nop */
+#define FDT_END 0x9
+
+#define FDT_V1_SIZE (7*sizeof(uint32_t))
+#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t))
+#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t))
+#define FDT_V16_SIZE FDT_V3_SIZE
+#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t))
+
+#endif /* _FDT_H */
diff --git a/sys/contrib/libfdt/fdt_ro.c b/sys/contrib/libfdt/fdt_ro.c
new file mode 100644
index 0000000..951cc74
--- /dev/null
+++ b/sys/contrib/libfdt/fdt_ro.c
@@ -0,0 +1,523 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_nodename_eq(const void *fdt, int offset,
+ const char *s, int len)
+{
+ const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
+
+ if (! p)
+ /* short match */
+ return 0;
+
+ if (memcmp(p, s, len) != 0)
+ return 0;
+
+ if (p[len] == '\0')
+ return 1;
+ else if (!memchr(s, '@', len) && (p[len] == '@'))
+ return 1;
+ else
+ return 0;
+}
+
+const char *fdt_string(const void *fdt, int stroffset)
+{
+ return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+}
+
+static int _fdt_string_eq(const void *fdt, int stroffset,
+ const char *s, int len)
+{
+ const char *p = fdt_string(fdt, stroffset);
+
+ return (strlen(p) == len) && (memcmp(p, s, len) == 0);
+}
+
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
+{
+ FDT_CHECK_HEADER(fdt);
+ *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
+ *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
+ return 0;
+}
+
+int fdt_num_mem_rsv(const void *fdt)
+{
+ int i = 0;
+
+ while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
+ i++;
+ return i;
+}
+
+int fdt_subnode_offset_namelen(const void *fdt, int offset,
+ const char *name, int namelen)
+{
+ int depth;
+
+ FDT_CHECK_HEADER(fdt);
+
+ for (depth = 0;
+ (offset >= 0) && (depth >= 0);
+ offset = fdt_next_node(fdt, offset, &depth))
+ if ((depth == 1)
+ && _fdt_nodename_eq(fdt, offset, name, namelen))
+ return offset;
+
+ if (depth < 0)
+ return -FDT_ERR_NOTFOUND;
+ return offset; /* error */
+}
+
+int fdt_subnode_offset(const void *fdt, int parentoffset,
+ const char *name)
+{
+ return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_path_offset(const void *fdt, const char *path)
+{
+ const char *end = path + strlen(path);
+ const char *p = path;
+ int offset = 0;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* see if we have an alias */
+ if (*path != '/') {
+ const char *q = strchr(path, '/');
+
+ if (!q)
+ q = end;
+
+ p = fdt_get_alias_namelen(fdt, p, q - p);
+ if (!p)
+ return -FDT_ERR_BADPATH;
+ offset = fdt_path_offset(fdt, p);
+
+ p = q;
+ }
+
+ while (*p) {
+ const char *q;
+
+ while (*p == '/')
+ p++;
+ if (! *p)
+ return offset;
+ q = strchr(p, '/');
+ if (! q)
+ q = end;
+
+ offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
+ if (offset < 0)
+ return offset;
+
+ p = q;
+ }
+
+ return offset;
+}
+
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
+{
+ const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
+ int err;
+
+ if (((err = fdt_check_header(fdt)) != 0)
+ || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+ goto fail;
+
+ if (len)
+ *len = strlen(nh->name);
+
+ return nh->name;
+
+ fail:
+ if (len)
+ *len = err;
+ return NULL;
+}
+
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+ int nodeoffset,
+ const char *name,
+ int namelen, int *lenp)
+{
+ uint32_t tag;
+ const struct fdt_property *prop;
+ int offset, nextoffset;
+ int err;
+
+ if (((err = fdt_check_header(fdt)) != 0)
+ || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+ goto fail;
+
+ nextoffset = err;
+ do {
+ offset = nextoffset;
+
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ switch (tag) {
+ case FDT_END:
+ if (nextoffset < 0)
+ err = nextoffset;
+ else
+ /* FDT_END tag with unclosed nodes */
+ err = -FDT_ERR_BADSTRUCTURE;
+ goto fail;
+
+ case FDT_PROP:
+ prop = _fdt_offset_ptr(fdt, offset);
+ if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
+ name, namelen)) {
+ /* Found it! */
+ if (lenp)
+ *lenp = fdt32_to_cpu(prop->len);
+
+ return prop;
+ }
+ break;
+ }
+ } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
+
+ err = -FDT_ERR_NOTFOUND;
+ fail:
+ if (lenp)
+ *lenp = err;
+ return NULL;
+}
+
+const struct fdt_property *fdt_get_property(const void *fdt,
+ int nodeoffset,
+ const char *name, int *lenp)
+{
+ return fdt_get_property_namelen(fdt, nodeoffset, name,
+ strlen(name), lenp);
+}
+
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+ const char *name, int namelen, int *lenp)
+{
+ const struct fdt_property *prop;
+
+ prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
+ if (! prop)
+ return NULL;
+
+ return prop->data;
+}
+
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+ const char *name, int *lenp)
+{
+ return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
+}
+
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
+{
+ const uint32_t *php;
+ int len;
+
+ /* FIXME: This is a bit sub-optimal, since we potentially scan
+ * over all the properties twice. */
+ php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
+ if (!php || (len != sizeof(*php))) {
+ php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
+ if (!php || (len != sizeof(*php)))
+ return 0;
+ }
+
+ return fdt32_to_cpu(*php);
+}
+
+const char *fdt_get_alias_namelen(const void *fdt,
+ const char *name, int namelen)
+{
+ int aliasoffset;
+
+ aliasoffset = fdt_path_offset(fdt, "/aliases");
+ if (aliasoffset < 0)
+ return NULL;
+
+ return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
+}
+
+const char *fdt_get_alias(const void *fdt, const char *name)
+{
+ return fdt_get_alias_namelen(fdt, name, strlen(name));
+}
+
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
+{
+ int pdepth = 0, p = 0;
+ int offset, depth, namelen;
+ const char *name;
+
+ FDT_CHECK_HEADER(fdt);
+
+ if (buflen < 2)
+ return -FDT_ERR_NOSPACE;
+
+ for (offset = 0, depth = 0;
+ (offset >= 0) && (offset <= nodeoffset);
+ offset = fdt_next_node(fdt, offset, &depth)) {
+ while (pdepth > depth) {
+ do {
+ p--;
+ } while (buf[p-1] != '/');
+ pdepth--;
+ }
+
+ if (pdepth >= depth) {
+ name = fdt_get_name(fdt, offset, &namelen);
+ if (!name)
+ return namelen;
+ if ((p + namelen + 1) <= buflen) {
+ memcpy(buf + p, name, namelen);
+ p += namelen;
+ buf[p++] = '/';
+ pdepth++;
+ }
+ }
+
+ if (offset == nodeoffset) {
+ if (pdepth < (depth + 1))
+ return -FDT_ERR_NOSPACE;
+
+ if (p > 1) /* special case so that root path is "/", not "" */
+ p--;
+ buf[p] = '\0';
+ return 0;
+ }
+ }
+
+ if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+ return -FDT_ERR_BADOFFSET;
+ else if (offset == -FDT_ERR_BADOFFSET)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ return offset; /* error from fdt_next_node() */
+}
+
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+ int supernodedepth, int *nodedepth)
+{
+ int offset, depth;
+ int supernodeoffset = -FDT_ERR_INTERNAL;
+
+ FDT_CHECK_HEADER(fdt);
+
+ if (supernodedepth < 0)
+ return -FDT_ERR_NOTFOUND;
+
+ for (offset = 0, depth = 0;
+ (offset >= 0) && (offset <= nodeoffset);
+ offset = fdt_next_node(fdt, offset, &depth)) {
+ if (depth == supernodedepth)
+ supernodeoffset = offset;
+
+ if (offset == nodeoffset) {
+ if (nodedepth)
+ *nodedepth = depth;
+
+ if (supernodedepth > depth)
+ return -FDT_ERR_NOTFOUND;
+ else
+ return supernodeoffset;
+ }
+ }
+
+ if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+ return -FDT_ERR_BADOFFSET;
+ else if (offset == -FDT_ERR_BADOFFSET)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_depth(const void *fdt, int nodeoffset)
+{
+ int nodedepth;
+ int err;
+
+ err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
+ if (err)
+ return (err < 0) ? err : -FDT_ERR_INTERNAL;
+ return nodedepth;
+}
+
+int fdt_parent_offset(const void *fdt, int nodeoffset)
+{
+ int nodedepth = fdt_node_depth(fdt, nodeoffset);
+
+ if (nodedepth < 0)
+ return nodedepth;
+ return fdt_supernode_atdepth_offset(fdt, nodeoffset,
+ nodedepth - 1, NULL);
+}
+
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+ const char *propname,
+ const void *propval, int proplen)
+{
+ int offset;
+ const void *val;
+ int len;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* FIXME: The algorithm here is pretty horrible: we scan each
+ * property of a node in fdt_getprop(), then if that didn't
+ * find what we want, we scan over them again making our way
+ * to the next node. Still it's the easiest to implement
+ * approach; performance can come later. */
+ for (offset = fdt_next_node(fdt, startoffset, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ val = fdt_getprop(fdt, offset, propname, &len);
+ if (val && (len == proplen)
+ && (memcmp(val, propval, len) == 0))
+ return offset;
+ }
+
+ return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
+{
+ int offset;
+
+ if ((phandle == 0) || (phandle == -1))
+ return -FDT_ERR_BADPHANDLE;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* FIXME: The algorithm here is pretty horrible: we
+ * potentially scan each property of a node in
+ * fdt_get_phandle(), then if that didn't find what
+ * we want, we scan over them again making our way to the next
+ * node. Still it's the easiest to implement approach;
+ * performance can come later. */
+ for (offset = fdt_next_node(fdt, -1, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ if (fdt_get_phandle(fdt, offset) == phandle)
+ return offset;
+ }
+
+ return offset; /* error from fdt_next_node() */
+}
+
+static int _fdt_stringlist_contains(const char *strlist, int listlen,
+ const char *str)
+{
+ int len = strlen(str);
+ const char *p;
+
+ while (listlen >= len) {
+ if (memcmp(str, strlist, len+1) == 0)
+ return 1;
+ p = memchr(strlist, '\0', listlen);
+ if (!p)
+ return 0; /* malformed strlist.. */
+ listlen -= (p-strlist) + 1;
+ strlist = p + 1;
+ }
+ return 0;
+}
+
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+ const char *compatible)
+{
+ const void *prop;
+ int len;
+
+ prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
+ if (!prop)
+ return len;
+ if (_fdt_stringlist_contains(prop, len, compatible))
+ return 0;
+ else
+ return 1;
+}
+
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+ const char *compatible)
+{
+ int offset, err;
+
+ FDT_CHECK_HEADER(fdt);
+
+ /* FIXME: The algorithm here is pretty horrible: we scan each
+ * property of a node in fdt_node_check_compatible(), then if
+ * that didn't find what we want, we scan over them again
+ * making our way to the next node. Still it's the easiest to
+ * implement approach; performance can come later. */
+ for (offset = fdt_next_node(fdt, startoffset, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ err = fdt_node_check_compatible(fdt, offset, compatible);
+ if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
+ return err;
+ else if (err == 0)
+ return offset;
+ }
+
+ return offset; /* error from fdt_next_node() */
+}
diff --git a/sys/contrib/libfdt/fdt_rw.c b/sys/contrib/libfdt/fdt_rw.c
new file mode 100644
index 0000000..994037b
--- /dev/null
+++ b/sys/contrib/libfdt/fdt_rw.c
@@ -0,0 +1,465 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_blocks_misordered(const void *fdt,
+ int mem_rsv_size, int struct_size)
+{
+ return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
+ || (fdt_off_dt_struct(fdt) <
+ (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
+ || (fdt_off_dt_strings(fdt) <
+ (fdt_off_dt_struct(fdt) + struct_size))
+ || (fdt_totalsize(fdt) <
+ (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
+}
+
+static int _fdt_rw_check_header(void *fdt)
+{
+ FDT_CHECK_HEADER(fdt);
+
+ if (fdt_version(fdt) < 17)
+ return -FDT_ERR_BADVERSION;
+ if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
+ fdt_size_dt_struct(fdt)))
+ return -FDT_ERR_BADLAYOUT;
+ if (fdt_version(fdt) > 17)
+ fdt_set_version(fdt, 17);
+
+ return 0;
+}
+
+#define FDT_RW_CHECK_HEADER(fdt) \
+ { \
+ int err; \
+ if ((err = _fdt_rw_check_header(fdt)) != 0) \
+ return err; \
+ }
+
+static inline int _fdt_data_size(void *fdt)
+{
+ return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+}
+
+static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
+{
+ char *p = splicepoint;
+ char *end = (char *)fdt + _fdt_data_size(fdt);
+
+ if (((p + oldlen) < p) || ((p + oldlen) > end))
+ return -FDT_ERR_BADOFFSET;
+ if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
+ return -FDT_ERR_NOSPACE;
+ memmove(p + newlen, p + oldlen, end - p - oldlen);
+ return 0;
+}
+
+static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
+ int oldn, int newn)
+{
+ int delta = (newn - oldn) * sizeof(*p);
+ int err;
+ err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
+ if (err)
+ return err;
+ fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
+ fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+ return 0;
+}
+
+static int _fdt_splice_struct(void *fdt, void *p,
+ int oldlen, int newlen)
+{
+ int delta = newlen - oldlen;
+ int err;
+
+ if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
+ return err;
+
+ fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
+ fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+ return 0;
+}
+
+static int _fdt_splice_string(void *fdt, int newlen)
+{
+ void *p = (char *)fdt
+ + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+ int err;
+
+ if ((err = _fdt_splice(fdt, p, 0, newlen)))
+ return err;
+
+ fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
+ return 0;
+}
+
+static int _fdt_find_add_string(void *fdt, const char *s)
+{
+ char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
+ const char *p;
+ char *new;
+ int len = strlen(s) + 1;
+ int err;
+
+ p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
+ if (p)
+ /* found it */
+ return (p - strtab);
+
+ new = strtab + fdt_size_dt_strings(fdt);
+ err = _fdt_splice_string(fdt, len);
+ if (err)
+ return err;
+
+ memcpy(new, s, len);
+ return (new - strtab);
+}
+
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
+{
+ struct fdt_reserve_entry *re;
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
+ err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
+ if (err)
+ return err;
+
+ re->address = cpu_to_fdt64(address);
+ re->size = cpu_to_fdt64(size);
+ return 0;
+}
+
+int fdt_del_mem_rsv(void *fdt, int n)
+{
+ struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ if (n >= fdt_num_mem_rsv(fdt))
+ return -FDT_ERR_NOTFOUND;
+
+ err = _fdt_splice_mem_rsv(fdt, re, 1, 0);
+ if (err)
+ return err;
+ return 0;
+}
+
+static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
+ int len, struct fdt_property **prop)
+{
+ int oldlen;
+ int err;
+
+ *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+ if (! (*prop))
+ return oldlen;
+
+ if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
+ FDT_TAGALIGN(len))))
+ return err;
+
+ (*prop)->len = cpu_to_fdt32(len);
+ return 0;
+}
+
+static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
+ int len, struct fdt_property **prop)
+{
+ int proplen;
+ int nextoffset;
+ int namestroff;
+ int err;
+
+ if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+ return nextoffset;
+
+ namestroff = _fdt_find_add_string(fdt, name);
+ if (namestroff < 0)
+ return namestroff;
+
+ *prop = _fdt_offset_ptr_w(fdt, nextoffset);
+ proplen = sizeof(**prop) + FDT_TAGALIGN(len);
+
+ err = _fdt_splice_struct(fdt, *prop, 0, proplen);
+ if (err)
+ return err;
+
+ (*prop)->tag = cpu_to_fdt32(FDT_PROP);
+ (*prop)->nameoff = cpu_to_fdt32(namestroff);
+ (*prop)->len = cpu_to_fdt32(len);
+ return 0;
+}
+
+int fdt_set_name(void *fdt, int nodeoffset, const char *name)
+{
+ char *namep;
+ int oldlen, newlen;
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
+ if (!namep)
+ return oldlen;
+
+ newlen = strlen(name);
+
+ err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
+ FDT_TAGALIGN(newlen+1));
+ if (err)
+ return err;
+
+ memcpy(namep, name, newlen+1);
+ return 0;
+}
+
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ struct fdt_property *prop;
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
+ if (err == -FDT_ERR_NOTFOUND)
+ err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+ if (err)
+ return err;
+
+ memcpy(prop->data, val, len);
+ return 0;
+}
+
+int fdt_delprop(void *fdt, int nodeoffset, const char *name)
+{
+ struct fdt_property *prop;
+ int len, proplen;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+ if (! prop)
+ return len;
+
+ proplen = sizeof(*prop) + FDT_TAGALIGN(len);
+ return _fdt_splice_struct(fdt, prop, proplen, 0);
+}
+
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+ const char *name, int namelen)
+{
+ struct fdt_node_header *nh;
+ int offset, nextoffset;
+ int nodelen;
+ int err;
+ uint32_t tag;
+ uint32_t *endtag;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
+ if (offset >= 0)
+ return -FDT_ERR_EXISTS;
+ else if (offset != -FDT_ERR_NOTFOUND)
+ return offset;
+
+ /* Try to place the new node after the parent's properties */
+ fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ } while ((tag == FDT_PROP) || (tag == FDT_NOP));
+
+ nh = _fdt_offset_ptr_w(fdt, offset);
+ nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
+
+ err = _fdt_splice_struct(fdt, nh, 0, nodelen);
+ if (err)
+ return err;
+
+ nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+ memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
+ memcpy(nh->name, name, namelen);
+ endtag = (uint32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
+ *endtag = cpu_to_fdt32(FDT_END_NODE);
+
+ return offset;
+}
+
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
+{
+ return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_del_node(void *fdt, int nodeoffset)
+{
+ int endoffset;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+ if (endoffset < 0)
+ return endoffset;
+
+ return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
+ endoffset - nodeoffset, 0);
+}
+
+static void _fdt_packblocks(const char *old, char *new,
+ int mem_rsv_size, int struct_size)
+{
+ int mem_rsv_off, struct_off, strings_off;
+
+ mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
+ struct_off = mem_rsv_off + mem_rsv_size;
+ strings_off = struct_off + struct_size;
+
+ memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
+ fdt_set_off_mem_rsvmap(new, mem_rsv_off);
+
+ memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
+ fdt_set_off_dt_struct(new, struct_off);
+ fdt_set_size_dt_struct(new, struct_size);
+
+ memmove(new + strings_off, old + fdt_off_dt_strings(old),
+ fdt_size_dt_strings(old));
+ fdt_set_off_dt_strings(new, strings_off);
+ fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
+}
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize)
+{
+ int err;
+ int mem_rsv_size, struct_size;
+ int newsize;
+ const char *fdtstart = fdt;
+ const char *fdtend = fdtstart + fdt_totalsize(fdt);
+ char *tmp;
+
+ FDT_CHECK_HEADER(fdt);
+
+ mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+ * sizeof(struct fdt_reserve_entry);
+
+ if (fdt_version(fdt) >= 17) {
+ struct_size = fdt_size_dt_struct(fdt);
+ } else {
+ struct_size = 0;
+ while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
+ ;
+ if (struct_size < 0)
+ return struct_size;
+ }
+
+ if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
+ /* no further work necessary */
+ err = fdt_move(fdt, buf, bufsize);
+ if (err)
+ return err;
+ fdt_set_version(buf, 17);
+ fdt_set_size_dt_struct(buf, struct_size);
+ fdt_set_totalsize(buf, bufsize);
+ return 0;
+ }
+
+ /* Need to reorder */
+ newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+ + struct_size + fdt_size_dt_strings(fdt);
+
+ if (bufsize < newsize)
+ return -FDT_ERR_NOSPACE;
+
+ /* First attempt to build converted tree at beginning of buffer */
+ tmp = buf;
+ /* But if that overlaps with the old tree... */
+ if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
+ /* Try right after the old tree instead */
+ tmp = (char *)(uintptr_t)fdtend;
+ if ((tmp + newsize) > ((char *)buf + bufsize))
+ return -FDT_ERR_NOSPACE;
+ }
+
+ _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
+ memmove(buf, tmp, newsize);
+
+ fdt_set_magic(buf, FDT_MAGIC);
+ fdt_set_totalsize(buf, bufsize);
+ fdt_set_version(buf, 17);
+ fdt_set_last_comp_version(buf, 16);
+ fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
+
+ return 0;
+}
+
+int fdt_pack(void *fdt)
+{
+ int mem_rsv_size;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+ * sizeof(struct fdt_reserve_entry);
+ _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+ fdt_set_totalsize(fdt, _fdt_data_size(fdt));
+
+ return 0;
+}
diff --git a/sys/contrib/libfdt/fdt_strerror.c b/sys/contrib/libfdt/fdt_strerror.c
new file mode 100644
index 0000000..e6c3cee
--- /dev/null
+++ b/sys/contrib/libfdt/fdt_strerror.c
@@ -0,0 +1,96 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+struct fdt_errtabent {
+ const char *str;
+};
+
+#define FDT_ERRTABENT(val) \
+ [(val)] = { .str = #val, }
+
+static struct fdt_errtabent fdt_errtable[] = {
+ FDT_ERRTABENT(FDT_ERR_NOTFOUND),
+ FDT_ERRTABENT(FDT_ERR_EXISTS),
+ FDT_ERRTABENT(FDT_ERR_NOSPACE),
+
+ FDT_ERRTABENT(FDT_ERR_BADOFFSET),
+ FDT_ERRTABENT(FDT_ERR_BADPATH),
+ FDT_ERRTABENT(FDT_ERR_BADSTATE),
+
+ FDT_ERRTABENT(FDT_ERR_TRUNCATED),
+ FDT_ERRTABENT(FDT_ERR_BADMAGIC),
+ FDT_ERRTABENT(FDT_ERR_BADVERSION),
+ FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
+ FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
+};
+#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
+
+const char *fdt_strerror(int errval)
+{
+ if (errval > 0)
+ return "<valid offset/length>";
+ else if (errval == 0)
+ return "<no error>";
+ else if (errval > -FDT_ERRTABSIZE) {
+ const char *s = fdt_errtable[-errval].str;
+
+ if (s)
+ return s;
+ }
+
+ return "<unknown error>";
+}
diff --git a/sys/contrib/libfdt/fdt_sw.c b/sys/contrib/libfdt/fdt_sw.c
new file mode 100644
index 0000000..55ebebf
--- /dev/null
+++ b/sys/contrib/libfdt/fdt_sw.c
@@ -0,0 +1,256 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_sw_check_header(void *fdt)
+{
+ if (fdt_magic(fdt) != FDT_SW_MAGIC)
+ return -FDT_ERR_BADMAGIC;
+ /* FIXME: should check more details about the header state */
+ return 0;
+}
+
+#define FDT_SW_CHECK_HEADER(fdt) \
+ { \
+ int err; \
+ if ((err = _fdt_sw_check_header(fdt)) != 0) \
+ return err; \
+ }
+
+static void *_fdt_grab_space(void *fdt, size_t len)
+{
+ int offset = fdt_size_dt_struct(fdt);
+ int spaceleft;
+
+ spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
+ - fdt_size_dt_strings(fdt);
+
+ if ((offset + len < offset) || (offset + len > spaceleft))
+ return NULL;
+
+ fdt_set_size_dt_struct(fdt, offset + len);
+ return _fdt_offset_ptr_w(fdt, offset);
+}
+
+int fdt_create(void *buf, int bufsize)
+{
+ void *fdt = buf;
+
+ if (bufsize < sizeof(struct fdt_header))
+ return -FDT_ERR_NOSPACE;
+
+ memset(buf, 0, bufsize);
+
+ fdt_set_magic(fdt, FDT_SW_MAGIC);
+ fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+ fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+ fdt_set_totalsize(fdt, bufsize);
+
+ fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
+ sizeof(struct fdt_reserve_entry)));
+ fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
+ fdt_set_off_dt_strings(fdt, bufsize);
+
+ return 0;
+}
+
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
+{
+ struct fdt_reserve_entry *re;
+ int offset;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ if (fdt_size_dt_struct(fdt))
+ return -FDT_ERR_BADSTATE;
+
+ offset = fdt_off_dt_struct(fdt);
+ if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
+ return -FDT_ERR_NOSPACE;
+
+ re = (struct fdt_reserve_entry *)((char *)fdt + offset);
+ re->address = cpu_to_fdt64(addr);
+ re->size = cpu_to_fdt64(size);
+
+ fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
+
+ return 0;
+}
+
+int fdt_finish_reservemap(void *fdt)
+{
+ return fdt_add_reservemap_entry(fdt, 0, 0);
+}
+
+int fdt_begin_node(void *fdt, const char *name)
+{
+ struct fdt_node_header *nh;
+ int namelen = strlen(name) + 1;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
+ if (! nh)
+ return -FDT_ERR_NOSPACE;
+
+ nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+ memcpy(nh->name, name, namelen);
+ return 0;
+}
+
+int fdt_end_node(void *fdt)
+{
+ uint32_t *en;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ en = _fdt_grab_space(fdt, FDT_TAGSIZE);
+ if (! en)
+ return -FDT_ERR_NOSPACE;
+
+ *en = cpu_to_fdt32(FDT_END_NODE);
+ return 0;
+}
+
+static int _fdt_find_add_string(void *fdt, const char *s)
+{
+ char *strtab = (char *)fdt + fdt_totalsize(fdt);
+ const char *p;
+ int strtabsize = fdt_size_dt_strings(fdt);
+ int len = strlen(s) + 1;
+ int struct_top, offset;
+
+ p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
+ if (p)
+ return p - strtab;
+
+ /* Add it */
+ offset = -strtabsize - len;
+ struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+ if (fdt_totalsize(fdt) + offset < struct_top)
+ return 0; /* no more room :( */
+
+ memcpy(strtab + offset, s, len);
+ fdt_set_size_dt_strings(fdt, strtabsize + len);
+ return offset;
+}
+
+int fdt_property(void *fdt, const char *name, const void *val, int len)
+{
+ struct fdt_property *prop;
+ int nameoff;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ nameoff = _fdt_find_add_string(fdt, name);
+ if (nameoff == 0)
+ return -FDT_ERR_NOSPACE;
+
+ prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
+ if (! prop)
+ return -FDT_ERR_NOSPACE;
+
+ prop->tag = cpu_to_fdt32(FDT_PROP);
+ prop->nameoff = cpu_to_fdt32(nameoff);
+ prop->len = cpu_to_fdt32(len);
+ memcpy(prop->data, val, len);
+ return 0;
+}
+
+int fdt_finish(void *fdt)
+{
+ char *p = (char *)fdt;
+ uint32_t *end;
+ int oldstroffset, newstroffset;
+ uint32_t tag;
+ int offset, nextoffset;
+
+ FDT_SW_CHECK_HEADER(fdt);
+
+ /* Add terminator */
+ end = _fdt_grab_space(fdt, sizeof(*end));
+ if (! end)
+ return -FDT_ERR_NOSPACE;
+ *end = cpu_to_fdt32(FDT_END);
+
+ /* Relocate the string table */
+ oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
+ newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+ memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
+ fdt_set_off_dt_strings(fdt, newstroffset);
+
+ /* Walk the structure, correcting string offsets */
+ offset = 0;
+ while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
+ if (tag == FDT_PROP) {
+ struct fdt_property *prop =
+ _fdt_offset_ptr_w(fdt, offset);
+ int nameoff;
+
+ nameoff = fdt32_to_cpu(prop->nameoff);
+ nameoff += fdt_size_dt_strings(fdt);
+ prop->nameoff = cpu_to_fdt32(nameoff);
+ }
+ offset = nextoffset;
+ }
+ if (nextoffset < 0)
+ return nextoffset;
+
+ /* Finally, adjust the header */
+ fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+ fdt_set_magic(fdt, FDT_MAGIC);
+ return 0;
+}
diff --git a/sys/contrib/libfdt/fdt_wip.c b/sys/contrib/libfdt/fdt_wip.c
new file mode 100644
index 0000000..6025fa1
--- /dev/null
+++ b/sys/contrib/libfdt/fdt_wip.c
@@ -0,0 +1,118 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ void *propval;
+ int proplen;
+
+ propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
+ if (! propval)
+ return proplen;
+
+ if (proplen != len)
+ return -FDT_ERR_NOSPACE;
+
+ memcpy(propval, val, len);
+ return 0;
+}
+
+static void _fdt_nop_region(void *start, int len)
+{
+ uint32_t *p;
+
+ for (p = start; (char *)p < ((char *)start + len); p++)
+ *p = cpu_to_fdt32(FDT_NOP);
+}
+
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
+{
+ struct fdt_property *prop;
+ int len;
+
+ prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+ if (! prop)
+ return len;
+
+ _fdt_nop_region(prop, len + sizeof(*prop));
+
+ return 0;
+}
+
+int _fdt_node_end_offset(void *fdt, int offset)
+{
+ int depth = 0;
+
+ while ((offset >= 0) && (depth >= 0))
+ offset = fdt_next_node(fdt, offset, &depth);
+
+ return offset;
+}
+
+int fdt_nop_node(void *fdt, int nodeoffset)
+{
+ int endoffset;
+
+ endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+ if (endoffset < 0)
+ return endoffset;
+
+ _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
+ endoffset - nodeoffset);
+ return 0;
+}
diff --git a/sys/contrib/libfdt/libfdt.h b/sys/contrib/libfdt/libfdt.h
new file mode 100644
index 0000000..18de52b
--- /dev/null
+++ b/sys/contrib/libfdt/libfdt.h
@@ -0,0 +1,1132 @@
+#ifndef _LIBFDT_H
+#define _LIBFDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 <libfdt_env.h>
+#include <fdt.h>
+
+#define FDT_FIRST_SUPPORTED_VERSION 0x10
+#define FDT_LAST_SUPPORTED_VERSION 0x11
+
+/* Error codes: informative error codes */
+#define FDT_ERR_NOTFOUND 1
+ /* FDT_ERR_NOTFOUND: The requested node or property does not exist */
+#define FDT_ERR_EXISTS 2
+ /* FDT_ERR_EXISTS: Attemped to create a node or property which
+ * already exists */
+#define FDT_ERR_NOSPACE 3
+ /* FDT_ERR_NOSPACE: Operation needed to expand the device
+ * tree, but its buffer did not have sufficient space to
+ * contain the expanded tree. Use fdt_open_into() to move the
+ * device tree to a buffer with more space. */
+
+/* Error codes: codes for bad parameters */
+#define FDT_ERR_BADOFFSET 4
+ /* FDT_ERR_BADOFFSET: Function was passed a structure block
+ * offset which is out-of-bounds, or which points to an
+ * unsuitable part of the structure for the operation. */
+#define FDT_ERR_BADPATH 5
+ /* FDT_ERR_BADPATH: Function was passed a badly formatted path
+ * (e.g. missing a leading / for a function which requires an
+ * absolute path) */
+#define FDT_ERR_BADPHANDLE 6
+ /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle
+ * value. phandle values of 0 and -1 are not permitted. */
+#define FDT_ERR_BADSTATE 7
+ /* FDT_ERR_BADSTATE: Function was passed an incomplete device
+ * tree created by the sequential-write functions, which is
+ * not sufficiently complete for the requested operation. */
+
+/* Error codes: codes for bad device tree blobs */
+#define FDT_ERR_TRUNCATED 8
+ /* FDT_ERR_TRUNCATED: Structure block of the given device tree
+ * ends without an FDT_END tag. */
+#define FDT_ERR_BADMAGIC 9
+ /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
+ * device tree at all - it is missing the flattened device
+ * tree magic number. */
+#define FDT_ERR_BADVERSION 10
+ /* FDT_ERR_BADVERSION: Given device tree has a version which
+ * can't be handled by the requested operation. For
+ * read-write functions, this may mean that fdt_open_into() is
+ * required to convert the tree to the expected version. */
+#define FDT_ERR_BADSTRUCTURE 11
+ /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
+ * structure block or other serious error (e.g. misnested
+ * nodes, or subnodes preceding properties). */
+#define FDT_ERR_BADLAYOUT 12
+ /* FDT_ERR_BADLAYOUT: For read-write functions, the given
+ * device tree has it's sub-blocks in an order that the
+ * function can't handle (memory reserve map, then structure,
+ * then strings). Use fdt_open_into() to reorganize the tree
+ * into a form suitable for the read-write operations. */
+
+/* "Can't happen" error indicating a bug in libfdt */
+#define FDT_ERR_INTERNAL 13
+ /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
+ * Should never be returned, if it is, it indicates a bug in
+ * libfdt itself. */
+
+#define FDT_ERR_MAX 13
+
+/**********************************************************************/
+/* Low-level functions (you probably don't need these) */
+/**********************************************************************/
+
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
+static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
+{
+ return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
+
+/**********************************************************************/
+/* Traversal functions */
+/**********************************************************************/
+
+int fdt_next_node(const void *fdt, int offset, int *depth);
+
+/**********************************************************************/
+/* General functions */
+/**********************************************************************/
+
+#define fdt_get_header(fdt, field) \
+ (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
+#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
+#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
+#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings))
+#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap))
+#define fdt_version(fdt) (fdt_get_header(fdt, version))
+#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys))
+#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
+#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct))
+
+#define __fdt_set_hdr(name) \
+ static inline void fdt_set_##name(void *fdt, uint32_t val) \
+ { \
+ struct fdt_header *fdth = (struct fdt_header*)fdt; \
+ fdth->name = cpu_to_fdt32(val); \
+ }
+__fdt_set_hdr(magic);
+__fdt_set_hdr(totalsize);
+__fdt_set_hdr(off_dt_struct);
+__fdt_set_hdr(off_dt_strings);
+__fdt_set_hdr(off_mem_rsvmap);
+__fdt_set_hdr(version);
+__fdt_set_hdr(last_comp_version);
+__fdt_set_hdr(boot_cpuid_phys);
+__fdt_set_hdr(size_dt_strings);
+__fdt_set_hdr(size_dt_struct);
+#undef __fdt_set_hdr
+
+/**
+ * fdt_check_header - sanity check a device tree or possible device tree
+ * @fdt: pointer to data which might be a flattened device tree
+ *
+ * fdt_check_header() checks that the given buffer contains what
+ * appears to be a flattened device tree with sane information in its
+ * header.
+ *
+ * returns:
+ * 0, if the buffer appears to contain a valid device tree
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings, as above
+ */
+int fdt_check_header(const void *fdt);
+
+/**
+ * fdt_move - move a device tree around in memory
+ * @fdt: pointer to the device tree to move
+ * @buf: pointer to memory where the device is to be moved
+ * @bufsize: size of the memory space at buf
+ *
+ * fdt_move() relocates, if possible, the device tree blob located at
+ * fdt to the buffer at buf of size bufsize. The buffer may overlap
+ * with the existing device tree blob at fdt. Therefore,
+ * fdt_move(fdt, fdt, fdt_totalsize(fdt))
+ * should always succeed.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_move(const void *fdt, void *buf, int bufsize);
+
+/**********************************************************************/
+/* Read-only functions */
+/**********************************************************************/
+
+/**
+ * fdt_string - retrieve a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ *
+ * fdt_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt.
+ *
+ * returns:
+ * a pointer to the string, on success
+ * NULL, if stroffset is out of bounds
+ */
+const char *fdt_string(const void *fdt, int stroffset);
+
+/**
+ * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
+ * @fdt: pointer to the device tree blob
+ *
+ * Returns the number of entries in the device tree blob's memory
+ * reservation map. This does not include the terminating 0,0 entry
+ * or any other (0,0) entries reserved for expansion.
+ *
+ * returns:
+ * the number of entries
+ */
+int fdt_num_mem_rsv(const void *fdt);
+
+/**
+ * fdt_get_mem_rsv - retrieve one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: pointers to 64-bit variables
+ *
+ * On success, *address and *size will contain the address and size of
+ * the n-th reserve map entry from the device tree blob, in
+ * native-endian format.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
+
+/**
+ * fdt_subnode_offset_namelen - find a subnode based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_subnode_offset(), but only examine the first
+ * namelen characters of name for matching the subnode name. This is
+ * useful for finding subnodes based on a portion of a larger string,
+ * such as a full path.
+ */
+int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+ const char *name, int namelen);
+/**
+ * fdt_subnode_offset - find a subnode of a given node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node at structure block
+ * offset parentoffset with the given name. name may include a unit
+ * address, in which case fdt_subnode_offset() will find the subnode
+ * with that unit address, or the unit address may be omitted, in
+ * which case fdt_subnode_offset() will find an arbitrary subnode
+ * whose name excluding unit address matches the given name.
+ *
+ * returns:
+ * structure block offset of the requested subnode (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_path_offset - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ *
+ * fdt_path_offset() finds a node of a given path in the device tree.
+ * Each path component may omit the unit address portion, but the
+ * results of this are undefined if any such path component is
+ * ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit
+ * address).
+ *
+ * returns:
+ * structure block offset of the node with the requested path (>=0), on success
+ * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ * -FDT_ERR_NOTFOUND, if the requested node does not exist
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_path_offset(const void *fdt, const char *path);
+
+/**
+ * fdt_get_name - retrieve the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the starting node
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_name() retrieves the name (including unit address) of the
+ * device tree node at structure block offset nodeoffset. If lenp is
+ * non-NULL, the length of this name is also returned, in the integer
+ * pointed to by lenp.
+ *
+ * returns:
+ * pointer to the node's name, on success
+ * If lenp is non-NULL, *lenp contains the length of that name (>=0)
+ * NULL, on error
+ * if lenp is non-NULL *lenp contains an error code (<0):
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
+
+/**
+ * fdt_get_property_namelen - find a property based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_get_property_namelen(), but only examine the first
+ * namelen characters of name for matching the property name.
+ */
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+ int nodeoffset,
+ const char *name,
+ int namelen, int *lenp);
+
+/**
+ * fdt_get_property - find a given property in a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property() retrieves a pointer to the fdt_property
+ * structure within the device tree blob corresponding to the property
+ * named 'name' of the node at offset nodeoffset. If lenp is
+ * non-NULL, the length of the property value is also returned, in the
+ * integer pointed to by lenp.
+ *
+ * returns:
+ * pointer to the structure representing the property
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_NOTFOUND, node does not have named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset,
+ const char *name, int *lenp);
+static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
+ const char *name,
+ int *lenp)
+{
+ return (struct fdt_property *)(uintptr_t)
+ fdt_get_property(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_getprop_namelen - get property value based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_getprop(), but only examine the first namelen
+ * characters of name for matching the property name.
+ */
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+ const char *name, int namelen, int *lenp);
+
+/**
+ * fdt_getprop - retrieve the value of a given property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ * pointer to the property's value
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_NOTFOUND, node does not have named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+ const char *name, int *lenp);
+static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
+ const char *name, int *lenp)
+{
+ return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_get_phandle - retrieve the phandle of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the node
+ *
+ * fdt_get_phandle() retrieves the phandle of the device tree node at
+ * structure block offset nodeoffset.
+ *
+ * returns:
+ * the phandle of the node at nodeoffset, on success (!= 0, != -1)
+ * 0, if the node has no phandle, or another error occurs
+ */
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_get_alias_namelen - get alias based on substring
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_get_alias(), but only examine the first namelen
+ * characters of name for matching the alias name.
+ */
+const char *fdt_get_alias_namelen(const void *fdt,
+ const char *name, int namelen);
+
+/**
+ * fdt_get_alias - retreive the path referenced by a given alias
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ *
+ * fdt_get_alias() retrieves the value of a given alias. That is, the
+ * value of the property named 'name' in the node /aliases.
+ *
+ * returns:
+ * a pointer to the expansion of the alias named 'name', of it exists
+ * NULL, if the given alias or the /aliases node does not exist
+ */
+const char *fdt_get_alias(const void *fdt, const char *name);
+
+/**
+ * fdt_get_path - determine the full path of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose path to find
+ * @buf: character buffer to contain the returned path (will be overwritten)
+ * @buflen: size of the character buffer at buf
+ *
+ * fdt_get_path() computes the full path of the node at offset
+ * nodeoffset, and records that path in the buffer at buf.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ * 0, on success
+ * buf contains the absolute path of the node at
+ * nodeoffset, as a NUL-terminated string.
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
+ * characters and will not fit in the given buffer.
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
+
+/**
+ * fdt_supernode_atdepth_offset - find a specific ancestor of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ * @supernodedepth: depth of the ancestor to find
+ * @nodedepth: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_supernode_atdepth_offset() finds an ancestor of the given node
+ * at a specific depth from the root (where the root itself has depth
+ * 0, its immediate subnodes depth 1 and so forth). So
+ * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL);
+ * will always return 0, the offset of the root node. If the node at
+ * nodeoffset has depth D, then:
+ * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL);
+ * will return nodeoffset itself.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+
+ * structure block offset of the node at node offset's ancestor
+ * of depth supernodedepth (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+ int supernodedepth, int *nodedepth);
+
+/**
+ * fdt_node_depth - find the depth of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_node_depth() finds the depth of a given node. The root node
+ * has depth 0, its immediate subnodes depth 1 and so forth.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ * depth of the node at nodeoffset (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_depth(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_parent_offset - find the parent of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_parent_offset() locates the parent node of a given node (that
+ * is, it finds the offset of the node which contains the node at
+ * nodeoffset as a subnode).
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset, *twice*.
+ *
+ * returns:
+ * structure block offset of the parent of the node at nodeoffset
+ * (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_parent_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_node_offset_by_prop_value - find nodes with a given property value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the first
+ * node after startoffset, which has a property named propname whose
+ * value is of length proplen and has value equal to propval; or if
+ * startoffset is -1, the very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ * offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
+ * propval, proplen);
+ * while (offset != -FDT_ERR_NOTFOUND) {
+ * // other code here
+ * offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
+ * propval, proplen);
+ * }
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0, >startoffset),
+ * on success
+ * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ * tree after startoffset
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+ const char *propname,
+ const void *propval, int proplen);
+
+/**
+ * fdt_node_offset_by_phandle - find the node with a given phandle
+ * @fdt: pointer to the device tree blob
+ * @phandle: phandle value
+ *
+ * fdt_node_offset_by_phandle() returns the offset of the node
+ * which has the given phandle value. If there is more than one node
+ * in the tree with the given phandle (an invalid tree), results are
+ * undefined.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0), on success
+ * -FDT_ERR_NOTFOUND, no node with that phandle exists
+ * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1)
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
+
+/**
+ * fdt_node_check_compatible: check a node's compatible property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @compatible: string to match against
+ *
+ *
+ * fdt_node_check_compatible() returns 0 if the given node contains a
+ * 'compatible' property with the given string as one of its elements,
+ * it returns non-zero otherwise, or on error.
+ *
+ * returns:
+ * 0, if the node has a 'compatible' property listing the given string
+ * 1, if the node has a 'compatible' property, but it does not list
+ * the given string
+ * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
+ * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+ const char *compatible);
+
+/**
+ * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @compatible: 'compatible' string to match against
+ *
+ * fdt_node_offset_by_compatible() returns the offset of the first
+ * node after startoffset, which has a 'compatible' property which
+ * lists the given compatible string; or if startoffset is -1, the
+ * very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ * offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ * while (offset != -FDT_ERR_NOTFOUND) {
+ * // other code here
+ * offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
+ * }
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0, >startoffset),
+ * on success
+ * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ * tree after startoffset
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+ const char *compatible);
+
+/**********************************************************************/
+/* Write-in-place functions */
+/**********************************************************************/
+
+/**
+ * fdt_setprop_inplace - change a property's value, but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * fdt_setprop_inplace() replaces the value of a given property with
+ * the data in val, of length len. This function cannot change the
+ * size of a property, and so will only work if len is equal to the
+ * current length of the property.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if len is not equal to the property's current length
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len);
+
+/**
+ * fdt_setprop_inplace_cell - change the value of a single-cell property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: cell (32-bit integer) value to replace the property with
+ *
+ * fdt_setprop_inplace_cell() replaces the value of a given property
+ * with the 32-bit integer cell value in val, converting val to
+ * big-endian if necessary. This function cannot change the size of a
+ * property, and so will only work if the property already exists and
+ * has length 4.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if the property's length is not equal to 4
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
+ const char *name, uint32_t val)
+{
+ val = cpu_to_fdt32(val);
+ return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_nop_property - replace a property with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_nop_property() will replace a given property's representation
+ * in the blob with FDT_NOP tags, effectively removing it from the
+ * tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the property, and will not alter or move any other part of the
+ * tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_nop_node - replace a node (subtree) with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_nop_node() will replace a given node's representation in the
+ * blob, including all its subnodes, if any, with FDT_NOP tags,
+ * effectively removing it from the tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the node and its properties and subnodes, and will not alter or
+ * move any other part of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Sequential write functions */
+/**********************************************************************/
+
+int fdt_create(void *buf, int bufsize);
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
+int fdt_finish_reservemap(void *fdt);
+int fdt_begin_node(void *fdt, const char *name);
+int fdt_property(void *fdt, const char *name, const void *val, int len);
+static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
+{
+ val = cpu_to_fdt32(val);
+ return fdt_property(fdt, name, &val, sizeof(val));
+}
+#define fdt_property_string(fdt, name, str) \
+ fdt_property(fdt, name, str, strlen(str)+1)
+int fdt_end_node(void *fdt);
+int fdt_finish(void *fdt);
+
+/**********************************************************************/
+/* Read-write functions */
+/**********************************************************************/
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize);
+int fdt_pack(void *fdt);
+
+/**
+ * fdt_add_mem_rsv - add one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: 64-bit values (native endian)
+ *
+ * Adds a reserve map entry to the given blob reserving a region at
+ * address address of length size.
+ *
+ * This function will insert data into the reserve map and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new reservation entry
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size);
+
+/**
+ * fdt_del_mem_rsv - remove a memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @n: entry to remove
+ *
+ * fdt_del_mem_rsv() removes the n-th memory reserve map entry from
+ * the blob.
+ *
+ * This function will delete data from the reservation table and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
+ * are less than n+1 reserve map entries)
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_mem_rsv(void *fdt, int n);
+
+/**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string. NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ * to contain the new name
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_setprop - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len);
+
+/**
+ * fdt_setprop_cell - set a property to a single cell value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_cell() sets the value of the named property in the
+ * given node to the given cell value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
+ uint32_t val)
+{
+ val = cpu_to_fdt32(val);
+ return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_setprop_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value for the property
+ *
+ * fdt_setprop_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_string(fdt, nodeoffset, name, str) \
+ fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_delprop - delete a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_del_property() will delete the given property.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_delprop(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_add_subnode_namelen - creates a new node based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_add_subnode(), but use only the first namelen
+ * characters of name as the name of the new node. This is useful for
+ * creating subnodes based on a portion of a larger string, such as a
+ * full path.
+ */
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+ const char *name, int namelen);
+
+/**
+ * fdt_add_subnode - creates a new node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_add_subnode() creates a new node as a subnode of the node at
+ * structure block offset parentoffset, with the given name (which
+ * should include the unit address, if any).
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+
+ * returns:
+ * structure block offset of the created nodeequested subnode (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ * the given name
+ * -FDT_ERR_NOSPACE, if there is insufficient free space in the
+ * blob to contain the new node
+ * -FDT_ERR_NOSPACE
+ * -FDT_ERR_BADLAYOUT
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_del_node - delete a node (subtree)
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_del_node() will remove the given node, including all its
+ * subnodes if any, from the blob.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Debugging / informational functions */
+/**********************************************************************/
+
+const char *fdt_strerror(int errval);
+
+#endif /* _LIBFDT_H */
diff --git a/sys/contrib/libfdt/libfdt_env.h b/sys/contrib/libfdt/libfdt_env.h
new file mode 100644
index 0000000..449bf60
--- /dev/null
+++ b/sys/contrib/libfdt/libfdt_env.h
@@ -0,0 +1,23 @@
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#define _B(n) ((unsigned long long)((uint8_t *)&x)[n])
+static inline uint32_t fdt32_to_cpu(uint32_t x)
+{
+ return (_B(0) << 24) | (_B(1) << 16) | (_B(2) << 8) | _B(3);
+}
+#define cpu_to_fdt32(x) fdt32_to_cpu(x)
+
+static inline uint64_t fdt64_to_cpu(uint64_t x)
+{
+ return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32)
+ | (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7);
+}
+#define cpu_to_fdt64(x) fdt64_to_cpu(x)
+#undef _B
+
+#endif /* _LIBFDT_ENV_H */
diff --git a/sys/contrib/libfdt/libfdt_internal.h b/sys/contrib/libfdt/libfdt_internal.h
new file mode 100644
index 0000000..d2dcbd6
--- /dev/null
+++ b/sys/contrib/libfdt/libfdt_internal.h
@@ -0,0 +1,94 @@
+#ifndef _LIBFDT_INTERNAL_H
+#define _LIBFDT_INTERNAL_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 <fdt.h>
+
+#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
+#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
+
+#define FDT_CHECK_HEADER(fdt) \
+ { \
+ int err; \
+ if ((err = fdt_check_header(fdt)) != 0) \
+ return err; \
+ }
+
+int _fdt_check_node_offset(const void *fdt, int offset);
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
+int _fdt_node_end_offset(void *fdt, int nodeoffset);
+
+static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
+{
+ return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
+}
+
+static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
+{
+ return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
+}
+
+static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
+{
+ const struct fdt_reserve_entry *rsv_table =
+ (const struct fdt_reserve_entry *)
+ ((const char *)fdt + fdt_off_mem_rsvmap(fdt));
+
+ return rsv_table + n;
+}
+static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
+{
+ return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
+}
+
+#define FDT_SW_MAGIC (~FDT_MAGIC)
+
+#endif /* _LIBFDT_INTERNAL_H */
diff --git a/sys/dev/aac/aac.c b/sys/dev/aac/aac.c
index fb9ef63..363972d 100644
--- a/sys/dev/aac/aac.c
+++ b/sys/dev/aac/aac.c
@@ -1195,7 +1195,6 @@ aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
cm->cm_complete = aac_bio_complete;
cm->cm_private = bp;
cm->cm_timestamp = time_uptime;
- cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
/* build the FIB */
fib = cm->cm_fib;
@@ -1350,7 +1349,6 @@ aac_wait_command(struct aac_command *cm)
fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
/* Put the command on the ready queue and get things going */
- cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
aac_enqueue_ready(cm);
aac_startio(sc);
error = msleep(cm, &sc->aac_io_lock, PRIBIO, "aacwait", 0);
@@ -1400,6 +1398,7 @@ aac_release_command(struct aac_command *cm)
cm->cm_flags = 0;
cm->cm_complete = NULL;
cm->cm_private = NULL;
+ cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY;
cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB;
cm->cm_fib->Header.Flags = 0;
diff --git a/sys/dev/aac/aac_cam.c b/sys/dev/aac/aac_cam.c
index ba3fb9d..c1164aa 100644
--- a/sys/dev/aac/aac_cam.c
+++ b/sys/dev/aac/aac_cam.c
@@ -453,7 +453,6 @@ aac_cam_action(struct cam_sim *sim, union ccb *ccb)
cm->cm_complete = aac_cam_complete;
cm->cm_private = ccb;
cm->cm_timestamp = time_uptime;
- cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE;
fib->Header.XferState =
AAC_FIBSTATE_HOSTOWNED |
diff --git a/sys/dev/age/if_age.c b/sys/dev/age/if_age.c
index 01d68b2..3c5a107 100644
--- a/sys/dev/age/if_age.c
+++ b/sys/dev/age/if_age.c
@@ -74,9 +74,6 @@ __FBSDID("$FreeBSD$");
/* "device miibus" required. See GENERIC if you get errors here. */
#include "miibus_if.h"
-#ifndef IFCAP_VLAN_HWTSO
-#define IFCAP_VLAN_HWTSO 0
-#endif
#define AGE_CSUM_FEATURES (CSUM_TCP | CSUM_UDP)
MODULE_DEPEND(age, pci, 1, 1, 1);
@@ -633,8 +630,8 @@ age_attach(device_t dev)
ether_ifattach(ifp, sc->age_eaddr);
/* VLAN capability setup. */
- ifp->if_capabilities |= IFCAP_VLAN_MTU;
- ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM;
+ ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |
+ IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO;
ifp->if_capenable = ifp->if_capabilities;
/* Tell the upper layer(s) we support long frames. */
@@ -1892,29 +1889,19 @@ age_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if ((mask & IFCAP_WOL_MAGIC) != 0 &&
(ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0)
ifp->if_capenable ^= IFCAP_WOL_MAGIC;
-
- if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
- (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) {
- ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
- age_rxvlan(sc);
- }
if ((mask & IFCAP_VLAN_HWCSUM) != 0 &&
(ifp->if_capabilities & IFCAP_VLAN_HWCSUM) != 0)
ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
if ((mask & IFCAP_VLAN_HWTSO) != 0 &&
(ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0)
ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
- /*
- * VLAN hardware tagging is required to do checksum
- * offload or TSO on VLAN interface. Checksum offload
- * on VLAN interface also requires hardware assistance
- * of parent interface.
- */
- if ((ifp->if_capenable & IFCAP_TXCSUM) == 0)
- ifp->if_capenable &= ~IFCAP_VLAN_HWCSUM;
- if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0)
- ifp->if_capenable &=
- ~(IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM);
+ if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
+ (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) {
+ ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
+ if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0)
+ ifp->if_capenable &= ~IFCAP_VLAN_HWTSO;
+ age_rxvlan(sc);
+ }
AGE_UNLOCK(sc);
VLAN_CAPABILITIES(ifp);
break;
diff --git a/sys/dev/alc/if_alc.c b/sys/dev/alc/if_alc.c
index a483f16..e95b044 100644
--- a/sys/dev/alc/if_alc.c
+++ b/sys/dev/alc/if_alc.c
@@ -84,9 +84,6 @@ __FBSDID("$FreeBSD$");
#else
#define ALC_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP)
#endif
-#ifndef IFCAP_VLAN_HWTSO
-#define IFCAP_VLAN_HWTSO 0
-#endif
MODULE_DEPEND(alc, pci, 1, 1, 1);
MODULE_DEPEND(alc, ether, 1, 1, 1);
@@ -756,8 +753,8 @@ alc_attach(device_t dev)
ether_ifattach(ifp, sc->alc_eaddr);
/* VLAN capability setup. */
- ifp->if_capabilities |= IFCAP_VLAN_MTU;
- ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM;
+ ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |
+ IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO;
ifp->if_capenable = ifp->if_capabilities;
/*
* XXX
@@ -1791,7 +1788,7 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head)
struct tcphdr *tcp;
bus_dma_segment_t txsegs[ALC_MAXTXSEGS];
bus_dmamap_t map;
- uint32_t cflags, hdrlen, ip_off, poff, vtag;
+ uint32_t cflags, hdrlen, poff, vtag;
int error, idx, nsegs, prod;
ALC_LOCK_ASSERT(sc);
@@ -1801,7 +1798,7 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head)
m = *m_head;
ip = NULL;
tcp = NULL;
- ip_off = poff = 0;
+ poff = 0;
if ((m->m_pkthdr.csum_flags & (ALC_CSUM_FEATURES | CSUM_TSO)) != 0) {
/*
* AR8131/AR8132 requires offset of TCP/UDP header in its
@@ -1811,7 +1808,6 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head)
* cycles on FreeBSD so fast host CPU is required to get
* smooth TSO performance.
*/
- struct ether_header *eh;
if (M_WRITABLE(m) == 0) {
/* Get a writable copy. */
@@ -1825,32 +1821,13 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head)
*m_head = m;
}
- ip_off = sizeof(struct ether_header);
- m = m_pullup(m, ip_off);
- if (m == NULL) {
- *m_head = NULL;
- return (ENOBUFS);
- }
- eh = mtod(m, struct ether_header *);
- /*
- * Check if hardware VLAN insertion is off.
- * Additional check for LLC/SNAP frame?
- */
- if (eh->ether_type == htons(ETHERTYPE_VLAN)) {
- ip_off = sizeof(struct ether_vlan_header);
- m = m_pullup(m, ip_off);
- if (m == NULL) {
- *m_head = NULL;
- return (ENOBUFS);
- }
- }
- m = m_pullup(m, ip_off + sizeof(struct ip));
+ m = m_pullup(m, sizeof(struct ether_header) + sizeof(struct ip));
if (m == NULL) {
*m_head = NULL;
return (ENOBUFS);
}
- ip = (struct ip *)(mtod(m, char *) + ip_off);
- poff = ip_off + (ip->ip_hl << 2);
+ ip = (struct ip *)(mtod(m, char *) + sizeof(struct ether_header));
+ poff = sizeof(struct ether_header) + (ip->ip_hl << 2);
if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
m = m_pullup(m, poff + sizeof(struct tcphdr));
if (m == NULL) {
@@ -2133,6 +2110,7 @@ alc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
(ifp->if_capenable & IFCAP_TSO4) != 0) {
ifp->if_capenable &= ~IFCAP_TSO4;
ifp->if_hwassist &= ~CSUM_TSO;
+ VLAN_CAPABILITIES(ifp);
}
ALC_UNLOCK(sc);
}
@@ -2204,14 +2182,6 @@ alc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if ((mask & IFCAP_VLAN_HWTSO) != 0 &&
(ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0)
ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
- /*
- * VLAN hardware tagging is required to do checksum
- * offload or TSO on VLAN interface. Checksum offload
- * on VLAN interface also requires hardware checksum
- * offload of parent interface.
- */
- if ((ifp->if_capenable & IFCAP_TXCSUM) == 0)
- ifp->if_capenable &= ~IFCAP_VLAN_HWCSUM;
if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0)
ifp->if_capenable &=
~(IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM);
diff --git a/sys/dev/ale/if_ale.c b/sys/dev/ale/if_ale.c
index 305eda4..76f1b74 100644
--- a/sys/dev/ale/if_ale.c
+++ b/sys/dev/ale/if_ale.c
@@ -78,9 +78,6 @@ __FBSDID("$FreeBSD$");
/* For more information about Tx checksum offload issues see ale_encap(). */
#define ALE_CSUM_FEATURES (CSUM_TCP | CSUM_UDP)
-#ifndef IFCAP_VLAN_HWTSO
-#define IFCAP_VLAN_HWTSO 0
-#endif
MODULE_DEPEND(ale, pci, 1, 1, 1);
MODULE_DEPEND(ale, ether, 1, 1, 1);
@@ -617,8 +614,8 @@ ale_attach(device_t dev)
ether_ifattach(ifp, sc->ale_eaddr);
/* VLAN capability setup. */
- ifp->if_capabilities |= IFCAP_VLAN_MTU;
- ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM;
+ ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |
+ IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO;
ifp->if_capenable = ifp->if_capabilities;
/*
* Even though controllers supported by ale(3) have Rx checksum
@@ -2003,29 +2000,19 @@ ale_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if ((mask & IFCAP_WOL_MAGIC) != 0 &&
(ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0)
ifp->if_capenable ^= IFCAP_WOL_MAGIC;
-
- if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
- (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) {
- ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
- ale_rxvlan(sc);
- }
if ((mask & IFCAP_VLAN_HWCSUM) != 0 &&
(ifp->if_capabilities & IFCAP_VLAN_HWCSUM) != 0)
ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
if ((mask & IFCAP_VLAN_HWTSO) != 0 &&
(ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0)
ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
- /*
- * VLAN hardware tagging is required to do checksum
- * offload or TSO on VLAN interface. Checksum offload
- * on VLAN interface also requires hardware checksum
- * offload of parent interface.
- */
- if ((ifp->if_capenable & IFCAP_TXCSUM) == 0)
- ifp->if_capenable &= ~IFCAP_VLAN_HWCSUM;
- if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0)
- ifp->if_capenable &=
- ~(IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM);
+ if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
+ (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) {
+ ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
+ if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0)
+ ifp->if_capenable &= ~IFCAP_VLAN_HWTSO;
+ ale_rxvlan(sc);
+ }
ALE_UNLOCK(sc);
VLAN_CAPABILITIES(ifp);
break;
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c
index 6de8fda..73dfa94 100644
--- a/sys/dev/ata/ata-all.c
+++ b/sys/dev/ata/ata-all.c
@@ -289,15 +289,13 @@ static void
ata_conn_event(void *context, int dummy)
{
device_t dev = (device_t)context;
- struct ata_channel *ch = device_get_softc(dev);
#ifdef ATA_CAM
+ struct ata_channel *ch = device_get_softc(dev);
union ccb *ccb;
-#endif
mtx_lock(&ch->state_mtx);
ata_reinit(dev);
mtx_unlock(&ch->state_mtx);
-#ifdef ATA_CAM
if ((ccb = xpt_alloc_ccb()) == NULL)
return;
if (xpt_create_path(&ccb->ccb_h.path, NULL,
@@ -307,6 +305,8 @@ ata_conn_event(void *context, int dummy)
return;
}
xpt_rescan(ccb);
+#else
+ ata_reinit(dev);
#endif
}
@@ -1160,6 +1160,7 @@ ata_satarev2str(int rev)
case 1: return "SATA 1.5Gb/s";
case 2: return "SATA 3Gb/s";
case 3: return "SATA 6Gb/s";
+ case 0xff: return "SATA";
default: return "???";
}
}
@@ -1536,6 +1537,7 @@ ataaction(struct cam_sim *sim, union ccb *ccb)
if (ch->flags & ATA_SATA) {
cts->transport = XPORT_SATA;
cts->transport_version = XPORT_VERSION_UNSPECIFIED;
+ cts->xport_specific.sata.valid = 0;
cts->xport_specific.sata.mode = d->mode;
cts->xport_specific.sata.valid |= CTS_SATA_VALID_MODE;
cts->xport_specific.sata.bytecount = d->bytecount;
@@ -1543,14 +1545,20 @@ ataaction(struct cam_sim *sim, union ccb *ccb)
if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
cts->xport_specific.sata.revision =
ATA_GETREV(dev, ccb->ccb_h.target_id);
- } else
+ if (cts->xport_specific.sata.revision != 0xff) {
+ cts->xport_specific.sata.valid |=
+ CTS_SATA_VALID_REVISION;
+ }
+ } else {
cts->xport_specific.sata.revision = d->revision;
- cts->xport_specific.sata.valid |= CTS_SATA_VALID_REVISION;
+ cts->xport_specific.sata.valid |= CTS_SATA_VALID_REVISION;
+ }
cts->xport_specific.sata.atapi = d->atapi;
cts->xport_specific.sata.valid |= CTS_SATA_VALID_ATAPI;
} else {
cts->transport = XPORT_ATA;
cts->transport_version = XPORT_VERSION_UNSPECIFIED;
+ cts->xport_specific.ata.valid = 0;
cts->xport_specific.ata.mode = d->mode;
cts->xport_specific.ata.valid |= CTS_ATA_VALID_MODE;
cts->xport_specific.ata.bytecount = d->bytecount;
diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c
index 8c4c01f..5271073 100644
--- a/sys/dev/ata/ata-pci.c
+++ b/sys/dev/ata/ata-pci.c
@@ -714,10 +714,14 @@ static int
ata_pcichannel_getrev(device_t dev, int target)
{
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
-
- if (ctlr->getrev)
- return (ctlr->getrev(dev, target));
- else
+ struct ata_channel *ch = device_get_softc(dev);
+
+ if (ch->flags & ATA_SATA) {
+ if (ctlr->getrev)
+ return (ctlr->getrev(dev, target));
+ else
+ return (0xff);
+ } else
return (0);
}
diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h
index b9c535c..1378f87 100644
--- a/sys/dev/ata/ata-pci.h
+++ b/sys/dev/ata/ata-pci.h
@@ -84,6 +84,7 @@ struct ata_pci_controller {
#define ATA_ACER_LABS_ID 0x10b9
#define ATA_ALI_1533 0x153310b9
+#define ATA_ALI_5228 0x522810b9
#define ATA_ALI_5229 0x522910b9
#define ATA_ALI_5281 0x528110b9
#define ATA_ALI_5287 0x528710b9
diff --git a/sys/dev/ata/ata-sata.c b/sys/dev/ata/ata-sata.c
index 9e3f7e8..d4c52fd 100644
--- a/sys/dev/ata/ata-sata.c
+++ b/sys/dev/ata/ata-sata.c
@@ -223,7 +223,7 @@ ata_sata_getrev(device_t dev, int target)
if (ch->r_io[ATA_SSTATUS].res)
return ((ATA_IDX_INL(ch, ATA_SSTATUS) & 0x0f0) >> 4);
- return (0);
+ return (0xff);
}
int
diff --git a/sys/dev/ata/chipsets/ata-acerlabs.c b/sys/dev/ata/chipsets/ata-acerlabs.c
index b5036d7..b7f1147 100644
--- a/sys/dev/ata/chipsets/ata-acerlabs.c
+++ b/sys/dev/ata/chipsets/ata-acerlabs.c
@@ -79,6 +79,7 @@ ata_ali_probe(device_t dev)
{ ATA_ALI_5288, 0x00, 4, ALI_SATA, ATA_SA300, "M5288" },
{ ATA_ALI_5287, 0x00, 4, ALI_SATA, ATA_SA150, "M5287" },
{ ATA_ALI_5281, 0x00, 2, ALI_SATA, ATA_SA150, "M5281" },
+ { ATA_ALI_5228, 0xc5, 0, ALI_NEW, ATA_UDMA6, "M5228" },
{ ATA_ALI_5229, 0xc5, 0, ALI_NEW, ATA_UDMA6, "M5229" },
{ ATA_ALI_5229, 0xc4, 0, ALI_NEW, ATA_UDMA5, "M5229" },
{ ATA_ALI_5229, 0xc2, 0, ALI_NEW, ATA_UDMA4, "M5229" },
@@ -208,7 +209,7 @@ ata_ali_sata_ch_attach(device_t dev)
io = res->bars[0];
ctlio = res->bars[1];
}
-
+ ata_pci_dmainit(dev);
for (i = ATA_DATA; i <= ATA_COMMAND; i ++) {
ch->r_io[i].res = io;
ch->r_io[i].offset = i + (unit10 ? 8 : 0);
diff --git a/sys/dev/ata/chipsets/ata-intel.c b/sys/dev/ata/chipsets/ata-intel.c
index ec05f30..4c15013 100644
--- a/sys/dev/ata/chipsets/ata-intel.c
+++ b/sys/dev/ata/chipsets/ata-intel.c
@@ -140,6 +140,22 @@ ata_intel_probe(device_t dev)
{ ATA_I82801JI_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" },
{ ATA_I82801JI_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" },
{ ATA_I82801JI_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" },
+ { 0x3a208086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
+ { 0x3a218086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
+ { 0x3a228086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
+ { 0x3a238086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
+ { 0x3a248086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
+ { 0x3a258086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
+ { 0x3a268086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
+ { 0x3a278086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
+ { 0x3a288086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
+ { 0x3a298086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
+ { 0x3a2a8086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
+ { 0x3a2b8086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
+ { 0x3a2c8086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
+ { 0x3a2d8086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
+ { 0x3a2e8086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
+ { 0x3a2f8086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" },
{ ATA_I31244, 0, 0, 2, ATA_SA150, "31244" },
{ ATA_ISCH, 0, 0, 1, ATA_UDMA5, "SCH" },
{ 0, 0, 0, 0, 0, 0}};
diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212.h b/sys/dev/ath/ath_hal/ar5212/ar5212.h
index 4f60c3b..6590eb4 100644
--- a/sys/dev/ath/ath_hal/ar5212/ar5212.h
+++ b/sys/dev/ath/ath_hal/ar5212/ar5212.h
@@ -327,6 +327,9 @@ struct ath_hal_5212 {
uint16_t *ah_pcdacTable;
u_int ah_pcdacTableSize;
uint16_t ah_ratesArray[16];
+
+ uint8_t ah_txTrigLev; /* current Tx trigger level */
+ uint8_t ah_maxTxTrigLev; /* max tx trigger level */
};
#define AH5212(_ah) ((struct ath_hal_5212 *)(_ah))
diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c
index ace6989..7857122 100644
--- a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c
+++ b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c
@@ -248,6 +248,9 @@ ar5212InitState(struct ath_hal_5212 *ahp, uint16_t devid, HAL_SOFTC sc,
ahp->ah_acktimeout = (u_int) -1;
ahp->ah_ctstimeout = (u_int) -1;
ahp->ah_sifstime = (u_int) -1;
+ ahp->ah_txTrigLev = INIT_TX_FIFO_THRESHOLD,
+ ahp->ah_maxTxTrigLev = MAX_TX_FIFO_THRESHOLD,
+
OS_MEMCPY(&ahp->ah_bssidmask, defbssidmask, IEEE80211_ADDR_LEN);
#undef N
}
diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c b/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c
index ecdf34e..ed9de14 100644
--- a/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c
+++ b/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c
@@ -48,16 +48,19 @@ ar5212UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel)
uint32_t txcfg, curLevel, newLevel;
HAL_INT omask;
+ if (ahp->ah_txTrigLev >= ahp->ah_maxTxTrigLev)
+ return AH_FALSE;
+
/*
* Disable interrupts while futzing with the fifo level.
*/
- omask = ar5212SetInterrupts(ah, ahp->ah_maskReg &~ HAL_INT_GLOBAL);
+ omask = ah->ah_setInterrupts(ah, ahp->ah_maskReg &~ HAL_INT_GLOBAL);
txcfg = OS_REG_READ(ah, AR_TXCFG);
curLevel = MS(txcfg, AR_FTRIG);
newLevel = curLevel;
if (bIncTrigLevel) { /* increase the trigger level */
- if (curLevel < MAX_TX_FIFO_THRESHOLD)
+ if (curLevel < ahp->ah_maxTxTrigLev)
newLevel++;
} else if (curLevel > MIN_TX_FIFO_THRESHOLD)
newLevel--;
@@ -66,8 +69,10 @@ ar5212UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel)
OS_REG_WRITE(ah, AR_TXCFG,
(txcfg &~ AR_FTRIG) | SM(newLevel, AR_FTRIG));
+ ahp->ah_txTrigLev = newLevel;
+
/* re-enable chip interrupts */
- ar5212SetInterrupts(ah, omask);
+ ah->ah_setInterrupts(ah, omask);
return (newLevel != curLevel);
}
diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c b/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c
index 22ad3b7..d506a6a 100644
--- a/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c
+++ b/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c
@@ -436,6 +436,7 @@ ar5416ChannelChange(struct ath_hal *ah, const structu ieee80211_channel *chan)
static void
ar5416InitDMA(struct ath_hal *ah)
{
+ struct ath_hal_5212 *ahp = AH5212(ah);
/*
* set AHB_MODE not to do cacheline prefetches
@@ -454,7 +455,10 @@ ar5416InitDMA(struct ath_hal *ah)
OS_REG_WRITE(ah, AR_RXCFG,
(OS_REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK) | AR_RXCFG_DMASZ_128B);
- /* XXX restore TX trigger level */
+ /* restore TX trigger level */
+ OS_REG_WRITE(ah, AR_TXCFG,
+ (OS_REG_READ(ah, AR_TXCFG) &~ AR_FTRIG) |
+ SM(ahp->ah_txTrigLev, AR_FTRIG));
/*
* Setup receive FIFO threshold to hold off TX activities
diff --git a/sys/dev/ath/ath_hal/ar5416/ar9285_attach.c b/sys/dev/ath/ath_hal/ar5416/ar9285_attach.c
index a639652..946133a 100644
--- a/sys/dev/ath/ath_hal/ar5416/ar9285_attach.c
+++ b/sys/dev/ath/ath_hal/ar5416/ar9285_attach.c
@@ -121,6 +121,8 @@ ar9285Attach(uint16_t devid, HAL_SOFTC sc,
AH5416(ah)->ah_writeIni = ar9285WriteIni;
AH5416(ah)->ah_rx_chainmask = AR9285_DEFAULT_RXCHAINMASK;
AH5416(ah)->ah_tx_chainmask = AR9285_DEFAULT_TXCHAINMASK;
+
+ ahp->ah_maxTxTrigLev = MAX_TX_FIFO_THRESHOLD >> 1;
if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) {
/* reset chip */
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c
index e600111..d1ddb2d 100644
--- a/sys/dev/ath/if_ath.c
+++ b/sys/dev/ath/if_ath.c
@@ -42,9 +42,9 @@ __FBSDID("$FreeBSD$");
#include "opt_wlan.h"
#include <sys/param.h>
-#include <sys/systm.h>
+#include <sys/systm.h>
#include <sys/sysctl.h>
-#include <sys/mbuf.h>
+#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -60,7 +60,7 @@ __FBSDID("$FreeBSD$");
#include <sys/priv.h>
#include <machine/bus.h>
-
+
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>
@@ -81,7 +81,7 @@ __FBSDID("$FreeBSD$");
#include <net/bpf.h>
#ifdef INET
-#include <netinet/in.h>
+#include <netinet/in.h>
#include <netinet/if_ether.h>
#endif
@@ -467,7 +467,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
/*
* Allocate hardware transmit queues: one queue for
* beacon frames and one data queue for each QoS
- * priority. Note that the hal handles reseting
+ * priority. Note that the hal handles resetting
* these queues at the needed time.
*
* XXX PS-Poll
@@ -758,7 +758,7 @@ ath_detach(struct ath_softc *sc)
DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n",
__func__, ifp->if_flags);
- /*
+ /*
* NB: the order of these is important:
* o stop the chip so no more interrupts will fire
* o call the 802.11 layer before detaching the hal to
@@ -1475,7 +1475,7 @@ ath_bmiss_proc(void *arg, int pending)
DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending);
if (ath_hal_gethangstate(sc->sc_ah, 0xff, &hangs) && hangs != 0) {
- if_printf(ifp, "bb hang detected (0x%x), reseting\n", hangs);
+ if_printf(ifp, "bb hang detected (0x%x), resetting\n", hangs);
ath_reset(ifp);
} else
ieee80211_beacon_miss(ifp->if_l2com);
@@ -1838,7 +1838,7 @@ ath_start(struct ifnet *ifp)
* go out or none...
*/
STAILQ_INIT(&frags);
- if ((m->m_flags & M_FRAG) &&
+ if ((m->m_flags & M_FRAG) &&
!ath_txfrag_setup(sc, &frags, m, ni)) {
DPRINTF(sc, ATH_DEBUG_XMIT,
"%s: out of txfrag buffers\n", __func__);
@@ -3356,7 +3356,7 @@ ath_descdma_setup(struct ath_softc *sc,
}
error = bus_dmamem_alloc(dd->dd_dmat, (void**) &dd->dd_desc,
- BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
+ BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
&dd->dd_dmamap);
if (error != 0) {
if_printf(ifp, "unable to alloc memory for %u %s descriptors, "
@@ -3792,7 +3792,7 @@ ath_rx_proc(void *arg, int npending)
/*
* If mbuf allocation failed previously there
* will be no mbuf; try again to re-populate it.
- */
+ */
/* XXX make debug msg */
if_printf(ifp, "%s: no mbuf!\n", __func__);
STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list);
@@ -3863,7 +3863,7 @@ ath_rx_proc(void *arg, int npending)
bus_dmamap_sync(sc->sc_dmat,
bf->bf_dmamap,
BUS_DMASYNC_POSTREAD);
- ath_handle_micerror(ic,
+ ath_handle_micerror(ic,
mtod(m, struct ieee80211_frame *),
sc->sc_splitmic ?
rs->rs_keyix-32 : rs->rs_keyix);
@@ -4040,7 +4040,7 @@ rx_accept:
*/
if (type == IEEE80211_FC0_TYPE_DATA) {
const HAL_RATE_TABLE *rt = sc->sc_currates;
- ath_led_event(sc,
+ ath_led_event(sc,
rt->rateCodeToIndex[rs->rs_rate]);
} else if (ticks - sc->sc_ledevent >= sc->sc_ledidle)
ath_led_event(sc, 0);
@@ -5322,7 +5322,7 @@ ath_startrecv(struct ath_softc *sc)
return 0;
}
-/*
+/*
* Update internal state after a channel change.
*/
static void
@@ -5342,7 +5342,7 @@ ath_chan_change(struct ath_softc *sc, struct ieee80211_channel *chan)
/*
* Set/change channels. If the channel is really being changed,
- * it's done by reseting the chip. To accomplish this we must
+ * it's done by resetting the chip. To accomplish this we must
* first cleanup any pending DMA, then restart stuff after a la
* ath_init.
*/
@@ -5541,7 +5541,7 @@ ath_set_channel(struct ieee80211com *ic)
sc->sc_syncbeacon = 1;
}
-/*
+/*
* Walk the vap list and check if there any vap's in RUN state.
*/
static int
@@ -5803,7 +5803,7 @@ ath_newassoc(struct ieee80211_node *ni, int isnew)
an->an_mgmtrix = ath_tx_findrix(sc, tp->mgmtrate);
ath_rate_newassoc(sc, an, isnew);
- if (isnew &&
+ if (isnew &&
(vap->iv_flags & IEEE80211_F_PRIVACY) == 0 && sc->sc_hasclrkey &&
ni->ni_ucastkey.wk_keyix == IEEE80211_KEYIX_NONE)
ath_setup_stationkey(ni);
@@ -6048,7 +6048,7 @@ ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode)
sc->sc_protrix = ath_tx_findrix(sc, 2*2);
else
sc->sc_protrix = ath_tx_findrix(sc, 2*1);
- /* NB: caller is responsible for reseting rate control state */
+ /* NB: caller is responsible for resetting rate control state */
#undef N
}
@@ -6123,7 +6123,7 @@ ath_watchdog(void *arg)
if (ath_hal_gethangstate(sc->sc_ah, 0xffff, &hangs) &&
hangs != 0) {
if_printf(ifp, "%s hang detected (0x%x)\n",
- hangs & 0xff ? "bb" : "mac", hangs);
+ hangs & 0xff ? "bb" : "mac", hangs);
} else
if_printf(ifp, "device timeout\n");
ath_reset(ifp);
@@ -6804,7 +6804,7 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT))
ieee80211_dump_pkt(ic, mtod(m0, caddr_t), m0->m_len,
sc->sc_hwmap[rix].ieeerate, -1);
-
+
if (ieee80211_radiotap_active_vap(vap)) {
u_int64_t tsf = ath_hal_gettsf64(ah);
diff --git a/sys/dev/bce/if_bce.c b/sys/dev/bce/if_bce.c
index 94198e8..8b6f222 100644
--- a/sys/dev/bce/if_bce.c
+++ b/sys/dev/bce/if_bce.c
@@ -403,6 +403,7 @@ static void bce_fill_pg_chain (struct bce_softc *);
static void bce_free_pg_chain (struct bce_softc *);
#endif
+static struct mbuf *bce_tso_setup (struct bce_softc *, struct mbuf **, u16 *);
static int bce_tx_encap (struct bce_softc *, struct mbuf **);
static void bce_start_locked (struct ifnet *);
static void bce_start (struct ifnet *);
@@ -1057,7 +1058,8 @@ bce_attach(device_t dev)
if (bce_tso_enable) {
ifp->if_hwassist = BCE_IF_HWASSIST | CSUM_TSO;
- ifp->if_capabilities = BCE_IF_CAPABILITIES | IFCAP_TSO4;
+ ifp->if_capabilities = BCE_IF_CAPABILITIES | IFCAP_TSO4 |
+ IFCAP_VLAN_HWTSO;
} else {
ifp->if_hwassist = BCE_IF_HWASSIST;
ifp->if_capabilities = BCE_IF_CAPABILITIES;
@@ -5886,6 +5888,7 @@ bce_rx_intr(struct bce_softc *sc)
{
struct ifnet *ifp = sc->bce_ifp;
struct l2_fhdr *l2fhdr;
+ struct ether_vlan_header *vh;
unsigned int pkt_len;
u16 sw_rx_cons, sw_rx_cons_idx, hw_rx_cons;
u32 status;
@@ -6141,12 +6144,37 @@ bce_rx_intr(struct bce_softc *sc)
/* Attach the VLAN tag. */
if (status & L2_FHDR_STATUS_L2_VLAN_TAG) {
+ if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) {
#if __FreeBSD_version < 700000
- VLAN_INPUT_TAG(ifp, m0, l2fhdr->l2_fhdr_vlan_tag, continue);
+ VLAN_INPUT_TAG(ifp, m0,
+ l2fhdr->l2_fhdr_vlan_tag, continue);
#else
- m0->m_pkthdr.ether_vtag = l2fhdr->l2_fhdr_vlan_tag;
- m0->m_flags |= M_VLANTAG;
+ m0->m_pkthdr.ether_vtag =
+ l2fhdr->l2_fhdr_vlan_tag;
+ m0->m_flags |= M_VLANTAG;
#endif
+ } else {
+ /*
+ * bce(4) controllers can't disable VLAN
+ * tag stripping if management firmware
+ * (ASF/IPMI/UMP) is running. So we always
+ * strip VLAN tag and manually reconstruct
+ * the VLAN frame by appending stripped
+ * VLAN tag in driver if VLAN tag stripping
+ * was disabled.
+ *
+ * TODO: LLC SNAP handling.
+ */
+ bcopy(mtod(m0, uint8_t *),
+ mtod(m0, uint8_t *) - ETHER_VLAN_ENCAP_LEN,
+ ETHER_ADDR_LEN * 2);
+ m0->m_data -= ETHER_VLAN_ENCAP_LEN;
+ vh = mtod(m0, struct ether_vlan_header *);
+ vh->evl_encap_proto = htons(ETHERTYPE_VLAN);
+ vh->evl_tag = htons(l2fhdr->l2_fhdr_vlan_tag);
+ m0->m_pkthdr.len += ETHER_VLAN_ENCAP_LEN;
+ m0->m_len += ETHER_VLAN_ENCAP_LEN;
+ }
}
/* Increment received packet statistics. */
@@ -6559,6 +6587,110 @@ bce_init(void *xsc)
}
+static struct mbuf *
+bce_tso_setup(struct bce_softc *sc, struct mbuf **m_head, u16 *flags)
+{
+ struct mbuf *m;
+ struct ether_header *eh;
+ struct ip *ip;
+ struct tcphdr *th;
+ u16 etype;
+ int hdr_len, ip_hlen = 0, tcp_hlen = 0, ip_len = 0;
+
+ DBRUN(sc->requested_tso_frames++);
+ /* Controller requires to monify mbuf chains. */
+ if (M_WRITABLE(*m_head) == 0) {
+ m = m_dup(*m_head, M_DONTWAIT);
+ m_freem(*m_head);
+ if (m == NULL) {
+ sc->mbuf_alloc_failed_count++;
+ *m_head = NULL;
+ return (NULL);
+ }
+ *m_head = m;
+ }
+ /*
+ * For TSO the controller needs two pieces of info,
+ * the MSS and the IP+TCP options length.
+ */
+ m = m_pullup(*m_head, sizeof(struct ether_header) + sizeof(struct ip));
+ if (m == NULL) {
+ *m_head = NULL;
+ return (NULL);
+ }
+ eh = mtod(m, struct ether_header *);
+ etype = ntohs(eh->ether_type);
+
+ /* Check for supported TSO Ethernet types (only IPv4 for now) */
+ switch (etype) {
+ case ETHERTYPE_IP:
+ ip = (struct ip *)(m->m_data + sizeof(struct ether_header));
+ /* TSO only supported for TCP protocol. */
+ if (ip->ip_p != IPPROTO_TCP) {
+ BCE_PRINTF("%s(%d): TSO enabled for non-TCP frame!.\n",
+ __FILE__, __LINE__);
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (NULL);
+ }
+
+ /* Get IP header length in bytes (min 20) */
+ ip_hlen = ip->ip_hl << 2;
+ m = m_pullup(*m_head, sizeof(struct ether_header) + ip_hlen +
+ sizeof(struct tcphdr));
+ if (m == NULL) {
+ *m_head = NULL;
+ return (NULL);
+ }
+
+ /* Get the TCP header length in bytes (min 20) */
+ th = (struct tcphdr *)((caddr_t)ip + ip_hlen);
+ tcp_hlen = (th->th_off << 2);
+
+ /* Make sure all IP/TCP options live in the same buffer. */
+ m = m_pullup(*m_head, sizeof(struct ether_header)+ ip_hlen +
+ tcp_hlen);
+ if (m == NULL) {
+ *m_head = NULL;
+ return (NULL);
+ }
+
+ /* IP header length and checksum will be calc'd by hardware */
+ ip_len = ip->ip_len;
+ ip->ip_len = 0;
+ ip->ip_sum = 0;
+ break;
+ case ETHERTYPE_IPV6:
+ BCE_PRINTF("%s(%d): TSO over IPv6 not supported!.\n",
+ __FILE__, __LINE__);
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (NULL);
+ /* NOT REACHED */
+ default:
+ BCE_PRINTF("%s(%d): TSO enabled for unsupported protocol!.\n",
+ __FILE__, __LINE__);
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (NULL);
+ }
+
+ hdr_len = sizeof(struct ether_header) + ip_hlen + tcp_hlen;
+
+ DBPRINT(sc, BCE_EXTREME_SEND, "%s(): hdr_len = %d, e_hlen = %d, "
+ "ip_hlen = %d, tcp_hlen = %d, ip_len = %d\n",
+ __FUNCTION__, hdr_len, sizeof(struct ether_header), ip_hlen,
+ tcp_hlen, ip_len);
+
+ /* Set the LSO flag in the TX BD */
+ *flags |= TX_BD_FLAGS_SW_LSO;
+ /* Set the length of IP + TCP options (in 32 bit words) */
+ *flags |= (((ip_hlen + tcp_hlen - sizeof(struct ip) -
+ sizeof(struct tcphdr)) >> 2) << 8);
+ return (*m_head);
+}
+
+
/****************************************************************************/
/* Encapsultes an mbuf cluster into the tx_bd chain structure and makes the */
/* memory visible to the controller. */
@@ -6575,12 +6707,8 @@ bce_tx_encap(struct bce_softc *sc, struct mbuf **m_head)
bus_dmamap_t map;
struct tx_bd *txbd = NULL;
struct mbuf *m0;
- struct ether_vlan_header *eh;
- struct ip *ip;
- struct tcphdr *th;
- u16 prod, chain_prod, etype, mss = 0, vlan_tag = 0, flags = 0;
+ u16 prod, chain_prod, mss = 0, vlan_tag = 0, flags = 0;
u32 prod_bseq;
- int hdr_len = 0, e_hlen = 0, ip_hlen = 0, tcp_hlen = 0, ip_len = 0;
#ifdef BCE_DEBUG
u16 debug_prod;
@@ -6597,72 +6725,16 @@ bce_tx_encap(struct bce_softc *sc, struct mbuf **m_head)
/* Transfer any checksum offload flags to the bd. */
m0 = *m_head;
if (m0->m_pkthdr.csum_flags) {
- if (m0->m_pkthdr.csum_flags & CSUM_IP)
- flags |= TX_BD_FLAGS_IP_CKSUM;
- if (m0->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP))
- flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
if (m0->m_pkthdr.csum_flags & CSUM_TSO) {
- /* For TSO the controller needs two pieces of info, */
- /* the MSS and the IP+TCP options length. */
+ m0 = bce_tso_setup(sc, m_head, &flags);
+ if (m0 == NULL)
+ goto bce_tx_encap_exit;
mss = htole16(m0->m_pkthdr.tso_segsz);
-
- /* Map the header and find the Ethernet type & header length */
- eh = mtod(m0, struct ether_vlan_header *);
- if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
- etype = ntohs(eh->evl_proto);
- e_hlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
- } else {
- etype = ntohs(eh->evl_encap_proto);
- e_hlen = ETHER_HDR_LEN;
- }
-
- /* Check for supported TSO Ethernet types (only IPv4 for now) */
- switch (etype) {
- case ETHERTYPE_IP:
- ip = (struct ip *)(m0->m_data + e_hlen);
-
- /* TSO only supported for TCP protocol */
- if (ip->ip_p != IPPROTO_TCP) {
- BCE_PRINTF("%s(%d): TSO enabled for non-TCP frame!.\n",
- __FILE__, __LINE__);
- goto bce_tx_encap_skip_tso;
- }
-
- /* Get IP header length in bytes (min 20) */
- ip_hlen = ip->ip_hl << 2;
-
- /* Get the TCP header length in bytes (min 20) */
- th = (struct tcphdr *)((caddr_t)ip + ip_hlen);
- tcp_hlen = (th->th_off << 2);
-
- /* IP header length and checksum will be calc'd by hardware */
- ip_len = ip->ip_len;
- ip->ip_len = 0;
- ip->ip_sum = 0;
- break;
- case ETHERTYPE_IPV6:
- BCE_PRINTF("%s(%d): TSO over IPv6 not supported!.\n",
- __FILE__, __LINE__);
- goto bce_tx_encap_skip_tso;
- default:
- BCE_PRINTF("%s(%d): TSO enabled for unsupported protocol!.\n",
- __FILE__, __LINE__);
- goto bce_tx_encap_skip_tso;
- }
-
- hdr_len = e_hlen + ip_hlen + tcp_hlen;
-
- DBPRINT(sc, BCE_EXTREME_SEND,
- "%s(): hdr_len = %d, e_hlen = %d, ip_hlen = %d, tcp_hlen = %d, ip_len = %d\n",
- __FUNCTION__, hdr_len, e_hlen, ip_hlen, tcp_hlen, ip_len);
-
- /* Set the LSO flag in the TX BD */
- flags |= TX_BD_FLAGS_SW_LSO;
- /* Set the length of IP + TCP options (in 32 bit words) */
- flags |= (((ip_hlen + tcp_hlen - 40) >> 2) << 8);
-
-bce_tx_encap_skip_tso:
- DBRUN(sc->requested_tso_frames++);
+ } else {
+ if (m0->m_pkthdr.csum_flags & CSUM_IP)
+ flags |= TX_BD_FLAGS_IP_CKSUM;
+ if (m0->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP))
+ flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
}
}
@@ -6687,7 +6759,7 @@ bce_tx_encap_skip_tso:
sc->fragmented_mbuf_count++;
/* Try to defrag the mbuf. */
- m0 = m_defrag(*m_head, M_DONTWAIT);
+ m0 = m_collapse(*m_head, M_DONTWAIT, BCE_MAX_SEGMENTS);
if (m0 == NULL) {
/* Defrag was unsuccessful */
m_freem(*m_head);
@@ -6963,7 +7035,7 @@ bce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
struct bce_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *) data;
struct mii_data *mii;
- int mask, error = 0;
+ int mask, error = 0, reinit;
DBENTER(BCE_VERBOSE_MISC);
@@ -6984,7 +7056,16 @@ bce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
BCE_LOCK(sc);
ifp->if_mtu = ifr->ifr_mtu;
- ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+ reinit = 0;
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ /*
+ * Because allocation size is used in RX
+ * buffer allocation, stop controller if
+ * it is already running.
+ */
+ bce_stop(sc);
+ reinit = 1;
+ }
#ifdef BCE_JUMBO_HDRSPLIT
/* No buffer allocation size changes are necessary. */
#else
@@ -7002,7 +7083,8 @@ bce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
}
#endif
- bce_init_locked(sc);
+ if (reinit != 0)
+ bce_init_locked(sc);
BCE_UNLOCK(sc);
break;
@@ -7036,7 +7118,6 @@ bce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
}
BCE_UNLOCK(sc);
- error = 0;
break;
@@ -7046,10 +7127,8 @@ bce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
DBPRINT(sc, BCE_VERBOSE_MISC, "Received SIOCADDMULTI/SIOCDELMULTI\n");
BCE_LOCK(sc);
- if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
bce_set_rx_mode(sc);
- error = 0;
- }
BCE_UNLOCK(sc);
break;
@@ -7069,50 +7148,53 @@ bce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
mask = ifr->ifr_reqcap ^ ifp->if_capenable;
DBPRINT(sc, BCE_INFO_MISC, "Received SIOCSIFCAP = 0x%08X\n", (u32) mask);
- /* Toggle the TX checksum capabilites enable flag. */
- if (mask & IFCAP_TXCSUM) {
+ /* Toggle the TX checksum capabilities enable flag. */
+ if (mask & IFCAP_TXCSUM &&
+ ifp->if_capabilities & IFCAP_TXCSUM) {
ifp->if_capenable ^= IFCAP_TXCSUM;
if (IFCAP_TXCSUM & ifp->if_capenable)
- ifp->if_hwassist = BCE_IF_HWASSIST;
+ ifp->if_hwassist |= BCE_IF_HWASSIST;
else
- ifp->if_hwassist = 0;
+ ifp->if_hwassist &= ~BCE_IF_HWASSIST;
}
/* Toggle the RX checksum capabilities enable flag. */
- if (mask & IFCAP_RXCSUM) {
+ if (mask & IFCAP_RXCSUM &&
+ ifp->if_capabilities & IFCAP_RXCSUM)
ifp->if_capenable ^= IFCAP_RXCSUM;
- if (IFCAP_RXCSUM & ifp->if_capenable)
- ifp->if_hwassist = BCE_IF_HWASSIST;
- else
- ifp->if_hwassist = 0;
- }
/* Toggle the TSO capabilities enable flag. */
- if (bce_tso_enable && (mask & IFCAP_TSO4)) {
+ if (bce_tso_enable && (mask & IFCAP_TSO4) &&
+ ifp->if_capabilities & IFCAP_TSO4) {
ifp->if_capenable ^= IFCAP_TSO4;
- if (IFCAP_RXCSUM & ifp->if_capenable)
- ifp->if_hwassist = BCE_IF_HWASSIST;
+ if (IFCAP_TSO4 & ifp->if_capenable)
+ ifp->if_hwassist |= CSUM_TSO;
else
- ifp->if_hwassist = 0;
+ ifp->if_hwassist &= ~CSUM_TSO;
}
- /* Toggle VLAN_MTU capabilities enable flag. */
- if (mask & IFCAP_VLAN_MTU) {
- BCE_PRINTF("%s(%d): Changing VLAN_MTU not supported.\n",
- __FILE__, __LINE__);
- }
+ if (mask & IFCAP_VLAN_HWCSUM &&
+ ifp->if_capabilities & IFCAP_VLAN_HWCSUM)
+ ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
- /* Toggle VLANHWTAG capabilities enabled flag. */
- if (mask & IFCAP_VLAN_HWTAGGING) {
- if (sc->bce_flags & BCE_MFW_ENABLE_FLAG)
- BCE_PRINTF("%s(%d): Cannot change VLAN_HWTAGGING while "
- "management firmware (ASF/IPMI/UMP) is running!\n",
- __FILE__, __LINE__);
- else
- BCE_PRINTF("%s(%d): Changing VLAN_HWTAGGING not supported!\n",
- __FILE__, __LINE__);
+ if ((mask & IFCAP_VLAN_HWTSO) != 0 &&
+ (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0)
+ ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
+ /*
+ * Don't actually disable VLAN tag stripping as
+ * management firmware (ASF/IPMI/UMP) requires the
+ * feature. If VLAN tag stripping is disabled driver
+ * will manually reconstruct the VLAN frame by
+ * appending stripped VLAN tag.
+ */
+ if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
+ (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING)) {
+ ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
+ if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
+ == 0)
+ ifp->if_capenable &= ~IFCAP_VLAN_HWTSO;
}
-
+ VLAN_CAPABILITIES(ifp);
break;
default:
/* We don't know how to handle the IOCTL, pass it on. */
diff --git a/sys/dev/bge/if_bge.c b/sys/dev/bge/if_bge.c
index 1eddbe0..9c47835 100644
--- a/sys/dev/bge/if_bge.c
+++ b/sys/dev/bge/if_bge.c
@@ -2656,9 +2656,11 @@ bge_attach(device_t dev)
/*
* BCM5754 and BCM5787 shares the same ASIC id so
* explicit device id check is required.
+ * Due to unknown reason TSO does not work on BCM5755M.
*/
if (pci_get_device(dev) != BCOM_DEVICEID_BCM5754 &&
- pci_get_device(dev) != BCOM_DEVICEID_BCM5754M)
+ pci_get_device(dev) != BCOM_DEVICEID_BCM5754M &&
+ pci_get_device(dev) != BCOM_DEVICEID_BCM5755M)
sc->bge_flags |= BGE_FLAG_TSO;
}
@@ -2816,7 +2818,7 @@ bge_attach(device_t dev)
IFCAP_VLAN_MTU;
if ((sc->bge_flags & BGE_FLAG_TSO) != 0) {
ifp->if_hwassist |= CSUM_TSO;
- ifp->if_capabilities |= IFCAP_TSO4;
+ ifp->if_capabilities |= IFCAP_TSO4 | IFCAP_VLAN_HWTSO;
}
#ifdef IFCAP_VLAN_HWCSUM
ifp->if_capabilities |= IFCAP_VLAN_HWCSUM;
@@ -3835,12 +3837,11 @@ bge_cksum_pad(struct mbuf *m)
static struct mbuf *
bge_setup_tso(struct bge_softc *sc, struct mbuf *m, uint16_t *mss)
{
- struct ether_header *eh;
struct ip *ip;
struct tcphdr *tcp;
struct mbuf *n;
uint16_t hlen;
- uint32_t ip_off, poff;
+ uint32_t poff;
if (M_WRITABLE(m) == 0) {
/* Get a writable copy. */
@@ -3850,28 +3851,16 @@ bge_setup_tso(struct bge_softc *sc, struct mbuf *m, uint16_t *mss)
return (NULL);
m = n;
}
- ip_off = sizeof(struct ether_header);
- m = m_pullup(m, ip_off);
+ m = m_pullup(m, sizeof(struct ether_header) + sizeof(struct ip));
if (m == NULL)
return (NULL);
- eh = mtod(m, struct ether_header *);
- /* Check the existence of VLAN tag. */
- if (eh->ether_type == htons(ETHERTYPE_VLAN)) {
- ip_off = sizeof(struct ether_vlan_header);
- m = m_pullup(m, ip_off);
- if (m == NULL)
- return (NULL);
- }
- m = m_pullup(m, ip_off + sizeof(struct ip));
- if (m == NULL)
- return (NULL);
- ip = (struct ip *)(mtod(m, char *) + ip_off);
- poff = ip_off + (ip->ip_hl << 2);
+ ip = (struct ip *)(mtod(m, char *) + sizeof(struct ether_header));
+ poff = sizeof(struct ether_header) + (ip->ip_hl << 2);
m = m_pullup(m, poff + sizeof(struct tcphdr));
if (m == NULL)
return (NULL);
tcp = (struct tcphdr *)(mtod(m, char *) + poff);
- m = m_pullup(m, poff + sizeof(struct tcphdr) + tcp->th_off);
+ m = m_pullup(m, poff + (tcp->th_off << 2));
if (m == NULL)
return (NULL);
/*
@@ -4526,9 +4515,6 @@ bge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
ifp->if_hwassist |= BGE_CSUM_FEATURES;
else
ifp->if_hwassist &= ~BGE_CSUM_FEATURES;
-#ifdef VLAN_CAPABILITIES
- VLAN_CAPABILITIES(ifp);
-#endif
}
if ((mask & IFCAP_TSO4) != 0 &&
@@ -4546,16 +4532,21 @@ bge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
bge_init(sc);
}
- if (mask & IFCAP_VLAN_HWTAGGING) {
+ if ((mask & IFCAP_VLAN_HWTSO) != 0 &&
+ (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0)
+ ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
+ if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
+ (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) {
ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
+ if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0)
+ ifp->if_capenable &= ~IFCAP_VLAN_HWTSO;
BGE_LOCK(sc);
bge_setvlan(sc);
BGE_UNLOCK(sc);
+ }
#ifdef VLAN_CAPABILITIES
- VLAN_CAPABILITIES(ifp);
+ VLAN_CAPABILITIES(ifp);
#endif
- }
-
break;
default:
error = ether_ioctl(ifp, command, data);
diff --git a/sys/dev/bwn/if_bwn.c b/sys/dev/bwn/if_bwn.c
index 6120474..7d1e663 100644
--- a/sys/dev/bwn/if_bwn.c
+++ b/sys/dev/bwn/if_bwn.c
@@ -536,6 +536,7 @@ static void bwn_phy_lp_gaintbl_write_r2(struct bwn_mac *, int,
struct bwn_txgain_entry);
static void bwn_phy_lp_gaintbl_write_r01(struct bwn_mac *, int,
struct bwn_txgain_entry);
+static void bwn_sysctl_node(struct bwn_softc *);
static struct resource_spec bwn_res_spec_legacy[] = {
{ SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE },
@@ -1066,9 +1067,6 @@ bwn_attach_post(struct bwn_softc *sc)
struct ifnet *ifp = sc->sc_ifp;
struct siba_dev_softc *sd = sc->sc_sd;
struct siba_sprom *sprom = &sd->sd_bus->siba_sprom;
-#ifdef BWN_DEBUG
- device_t dev = sc->sc_dev;
-#endif
ic = ifp->if_l2com;
ic->ic_ifp = ifp;
@@ -1078,6 +1076,7 @@ bwn_attach_post(struct bwn_softc *sc)
ic->ic_caps =
IEEE80211_C_STA /* station mode supported */
| IEEE80211_C_MONITOR /* monitor mode */
+ | IEEE80211_C_AHDEMO /* adhoc demo mode */
| IEEE80211_C_SHPREAMBLE /* short preamble supported */
| IEEE80211_C_SHSLOT /* short slot time supported */
| IEEE80211_C_WME /* WME/WMM supported */
@@ -1117,11 +1116,7 @@ bwn_attach_post(struct bwn_softc *sc)
&sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
BWN_RX_RADIOTAP_PRESENT);
-#ifdef BWN_DEBUG
- SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
- "debug", CTLFLAG_RW, &sc->sc_debug, 0, "Debug flags");
-#endif
+ bwn_sysctl_node(sc);
if (bootverbose)
ieee80211_announce(ic);
@@ -1496,6 +1491,7 @@ bwn_pio_select(struct bwn_mac *mac, uint8_t prio)
return (&mac->mac_method.pio.wme[WME_AC_VO]);
}
KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ return (NULL);
}
static int
@@ -1905,10 +1901,9 @@ bwn_setup_channels(struct bwn_mac *mac, int have_bg, int have_a)
static uint32_t
bwn_shm_read_4(struct bwn_mac *mac, uint16_t way, uint16_t offset)
{
- struct bwn_softc *sc = mac->mac_sc;
uint32_t ret;
- BWN_ASSERT_LOCKED(sc);
+ BWN_ASSERT_LOCKED(mac->mac_sc);
if (way == BWN_SHARED) {
KASSERT((offset & 0x0001) == 0,
@@ -1932,10 +1927,9 @@ out:
static uint16_t
bwn_shm_read_2(struct bwn_mac *mac, uint16_t way, uint16_t offset)
{
- struct bwn_softc *sc = mac->mac_sc;
uint16_t ret;
- BWN_ASSERT_LOCKED(sc);
+ BWN_ASSERT_LOCKED(mac->mac_sc);
if (way == BWN_SHARED) {
KASSERT((offset & 0x0001) == 0,
@@ -1970,9 +1964,7 @@ static void
bwn_shm_write_4(struct bwn_mac *mac, uint16_t way, uint16_t offset,
uint32_t value)
{
- struct bwn_softc *sc = mac->mac_sc;
-
- BWN_ASSERT_LOCKED(sc);
+ BWN_ASSERT_LOCKED(mac->mac_sc);
if (way == BWN_SHARED) {
KASSERT((offset & 0x0001) == 0,
@@ -1995,9 +1987,7 @@ static void
bwn_shm_write_2(struct bwn_mac *mac, uint16_t way, uint16_t offset,
uint16_t value)
{
- struct bwn_softc *sc = mac->mac_sc;
-
- BWN_ASSERT_LOCKED(sc);
+ BWN_ASSERT_LOCKED(mac->mac_sc);
if (way == BWN_SHARED) {
KASSERT((offset & 0x0001) == 0,
@@ -3335,10 +3325,9 @@ bwn_core_start(struct bwn_mac *mac)
static void
bwn_core_exit(struct bwn_mac *mac)
{
- struct bwn_softc *sc = mac->mac_sc;
uint32_t macctl;
- BWN_ASSERT_LOCKED(sc);
+ BWN_ASSERT_LOCKED(mac->mac_sc);
KASSERT(mac->mac_status <= BWN_MAC_STATUS_INITED,
("%s:%d: fail", __func__, __LINE__));
@@ -5198,6 +5187,8 @@ bwn_rf_init_bcm2050(struct bwn_mac *mac)
0x0e, 0x0f, 0x0d, 0x0f,
};
+ loctl = lomask = reg0 = classctl = crs0 = analogoverval = analogover =
+ rfoverval = rfover = cck3 = 0;
radio0 = BWN_RF_READ(mac, 0x43);
radio1 = BWN_RF_READ(mac, 0x51);
radio2 = BWN_RF_READ(mac, 0x52);
@@ -5891,7 +5882,6 @@ static void
bwn_dummy_transmission(struct bwn_mac *mac, int ofdm, int paon)
{
struct bwn_phy *phy = &mac->mac_phy;
- struct bwn_softc *sc = mac->mac_sc;
unsigned int i, max_loop;
uint16_t value;
uint32_t buffer[5] = {
@@ -5906,7 +5896,7 @@ bwn_dummy_transmission(struct bwn_mac *mac, int ofdm, int paon)
buffer[0] = 0x000b846e;
}
- BWN_ASSERT_LOCKED(sc);
+ BWN_ASSERT_LOCKED(mac->mac_sc);
for (i = 0; i < 5; i++)
bwn_ram_write(mac, i * 4, buffer[i]);
@@ -5972,10 +5962,9 @@ bwn_ram_write(struct bwn_mac *mac, uint16_t offset, uint32_t val)
static void
bwn_lo_write(struct bwn_mac *mac, struct bwn_loctl *ctl)
{
- struct bwn_phy *phy = &mac->mac_phy;
uint16_t value;
- KASSERT(phy->type == BWN_PHYTYPE_G,
+ KASSERT(mac->mac_phy.type == BWN_PHYTYPE_G,
("%s:%d: fail", __func__, __LINE__));
value = (uint8_t) (ctl->q);
@@ -6570,7 +6559,7 @@ bwn_lo_calibset(struct bwn_mac *mac,
struct bwn_phy_g *pg = &phy->phy_g;
struct bwn_loctl loctl = { 0, 0 };
struct bwn_lo_calib *cal;
- struct bwn_lo_g_value sval;
+ struct bwn_lo_g_value sval = { 0 };
int rxgain;
uint16_t pad, reg, value;
@@ -7800,8 +7789,9 @@ bwn_fw_get(struct bwn_mac *mac, enum bwn_fwtype type,
bwn_do_release_fw(bfw);
}
- snprintf(namebuf, sizeof(namebuf), "bwn%s_v4_%s",
- (type == BWN_FWTYPE_OPENSOURCE) ? "-open" : "", name);
+ snprintf(namebuf, sizeof(namebuf), "bwn%s_v4_%s%s",
+ (type == BWN_FWTYPE_OPENSOURCE) ? "-open" : "",
+ (mac->mac_phy.type == BWN_PHYTYPE_LP) ? "lp_" : "", name);
/* XXX Sleeping on "fwload" with the non-sleepable locks held */
fw = firmware_get(namebuf);
if (fw == NULL) {
@@ -8459,7 +8449,8 @@ bwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
}
}
- if (vap->iv_opmode == IEEE80211_M_MONITOR) {
+ if (vap->iv_opmode == IEEE80211_M_MONITOR ||
+ vap->iv_opmode == IEEE80211_M_AHDEMO) {
/* XXX nothing to do? */
} else if (nstate == IEEE80211_S_RUN) {
memcpy(sc->sc_bssid, vap->iv_bss->ni_bssid, IEEE80211_ADDR_LEN);
@@ -8984,9 +8975,7 @@ bwn_noise_gensample(struct bwn_mac *mac)
static int
bwn_dma_freeslot(struct bwn_dma_ring *dr)
{
- struct bwn_mac *mac = dr->dr_mac;
-
- BWN_ASSERT_LOCKED(mac->mac_sc);
+ BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
return (dr->dr_numslots - dr->dr_usedslot);
}
@@ -8994,9 +8983,7 @@ bwn_dma_freeslot(struct bwn_dma_ring *dr)
static int
bwn_dma_nextslot(struct bwn_dma_ring *dr, int slot)
{
- struct bwn_mac *mac = dr->dr_mac;
-
- BWN_ASSERT_LOCKED(mac->mac_sc);
+ BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
KASSERT(slot >= -1 && slot <= dr->dr_numslots - 1,
("%s:%d: fail", __func__, __LINE__));
@@ -9087,6 +9074,7 @@ bwn_handle_txeof(struct bwn_mac *mac, const struct bwn_txstatus *status)
struct bwn_pio_txqueue *tq;
struct bwn_pio_txpkt *tp = NULL;
struct bwn_softc *sc = mac->mac_sc;
+ struct bwn_stats *stats = &mac->mac_stats;
struct ieee80211_node *ni;
int slot;
@@ -9098,9 +9086,9 @@ bwn_handle_txeof(struct bwn_mac *mac, const struct bwn_txstatus *status)
device_printf(sc->sc_dev, "TODO: STATUS AMPDU\n");
if (status->rtscnt) {
if (status->rtscnt == 0xf)
- device_printf(sc->sc_dev, "TODO: RTS fail\n");
+ stats->rtsfail++;
else
- device_printf(sc->sc_dev, "TODO: RTS ok\n");
+ stats->rts++;
}
if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
@@ -9393,9 +9381,10 @@ bwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr)
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = ifp->if_l2com;
uint32_t macstat;
- int padding, rate, rssi, noise, type;
+ int padding, rate, rssi = 0, noise = 0, type;
uint16_t phytype, phystat0, phystat3, chanstat;
unsigned char *mp = mtod(m, unsigned char *);
+ static int rx_mac_dec_rpt = 0;
BWN_ASSERT_LOCKED(sc);
@@ -9409,26 +9398,29 @@ bwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr)
device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_FCS_CRC\n");
if (phystat0 & (BWN_RX_PHYST0_PLCPHCF | BWN_RX_PHYST0_PLCPFV))
device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_PLCP_CRC\n");
- if (phystat0 & BWN_RX_PHYST0_SHORTPRMBL)
- device_printf(sc->sc_dev, "TODO RX: RX_FLAG_SHORTPRE\n");
if (macstat & BWN_RX_MAC_DECERR)
goto drop;
padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
if (m->m_pkthdr.len < (sizeof(struct bwn_plcp6) + padding)) {
- device_printf(sc->sc_dev, "RX: Packet size underrun (1)\n");
+ device_printf(sc->sc_dev, "frame too short (length=%d)\n",
+ m->m_pkthdr.len);
goto drop;
}
plcp = (struct bwn_plcp6 *)(mp + padding);
m_adj(m, sizeof(struct bwn_plcp6) + padding);
if (m->m_pkthdr.len < IEEE80211_MIN_LEN) {
- device_printf(sc->sc_dev, "RX: Packet size underrun (2)\n");
+ device_printf(sc->sc_dev, "frame too short (length=%d)\n",
+ m->m_pkthdr.len);
goto drop;
}
wh = mtod(m, struct ieee80211_frame_min *);
- if (macstat & BWN_RX_MAC_DEC)
- device_printf(sc->sc_dev, "TODO: BWN_RX_MAC_DEC\n");
+ if (macstat & BWN_RX_MAC_DEC && rx_mac_dec_rpt++ < 50)
+ device_printf(sc->sc_dev,
+ "RX decryption attempted (old %d keyidx %#x)\n",
+ BWN_ISOLDFMT(mac),
+ (macstat & BWN_RX_MAC_KEYIDX) >> BWN_RX_MAC_KEYIDX_SHIFT);
/* XXX calculating RSSI & noise & antenna */
@@ -10081,15 +10073,15 @@ bwn_dma_select(struct bwn_mac *mac, uint8_t prio)
return (mac->mac_method.dma.wme[WME_AC_BK]);
}
KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ return (NULL);
}
static int
bwn_dma_getslot(struct bwn_dma_ring *dr)
{
- struct bwn_mac *mac = dr->dr_mac;
int slot;
- BWN_ASSERT_LOCKED(mac->mac_sc);
+ BWN_ASSERT_LOCKED(dr->dr_mac->mac_sc);
KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
KASSERT(!(dr->dr_stop), ("%s:%d: fail", __func__, __LINE__));
@@ -10574,6 +10566,7 @@ bwn_dma_parse_cookie(struct bwn_mac *mac, const struct bwn_txstatus *status,
dr = dma->mcast;
break;
default:
+ dr = NULL;
KASSERT(0 == 1,
("invalid cookie value %d", cookie & 0xf000));
}
@@ -11672,6 +11665,7 @@ bwn_phy_lp_set_txpctlmode(struct bwn_mac *mac, uint8_t mode)
ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_SW;
break;
default:
+ ctl = 0;
KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
}
BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD,
@@ -12852,7 +12846,6 @@ bwn_phy_lp_clear_deaf(struct bwn_mac *mac, uint8_t user)
static unsigned int
bwn_sqrt(struct bwn_mac *mac, unsigned int x)
{
- struct bwn_softc *sc = mac->mac_sc;
/* Table holding (10 * sqrt(x)) for x between 1 and 256. */
static uint8_t sqrt_table[256] = {
10, 14, 17, 20, 22, 24, 26, 28,
@@ -12892,9 +12885,11 @@ bwn_sqrt(struct bwn_mac *mac, unsigned int x)
if (x == 0)
return (0);
if (x >= 256) {
- device_printf(sc->sc_dev,
- "out of bounds of the square-root table (%d)\n", x);
- return (16);
+ unsigned int tmp;
+
+ for (tmp = 0; x >= (2 * tmp) + 1; x -= (2 * tmp++) + 1)
+ /* do nothing */ ;
+ return (tmp);
}
return (sqrt_table[x - 1] / 10);
}
@@ -14288,6 +14283,36 @@ bwn_phy_lp_gaintbl_write_r01(struct bwn_mac *mac, int offset,
}
static void
+bwn_sysctl_node(struct bwn_softc *sc)
+{
+ device_t dev = sc->sc_dev;
+ struct bwn_mac *mac;
+ struct bwn_stats *stats;
+
+ /* XXX assume that count of MAC is only 1. */
+
+ if ((mac = sc->sc_curmac) == NULL)
+ return;
+ stats = &mac->mac_stats;
+
+ SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "linknoise", CTLFLAG_RW, &stats->rts, 0, "Noise level");
+ SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "rts", CTLFLAG_RW, &stats->rts, 0, "RTS");
+ SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "rtsfail", CTLFLAG_RW, &stats->rtsfail, 0, "RTS failed to send");
+
+#ifdef BWN_DEBUG
+ SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "debug", CTLFLAG_RW, &sc->sc_debug, 0, "Debug flags");
+#endif
+}
+
+static void
bwn_identify(driver_t *driver, device_t parent)
{
diff --git a/sys/dev/bwn/if_bwnvar.h b/sys/dev/bwn/if_bwnvar.h
index 40b759e..61598c2 100644
--- a/sys/dev/bwn/if_bwnvar.h
+++ b/sys/dev/bwn/if_bwnvar.h
@@ -515,6 +515,8 @@ struct bwn_tx_radiotap_header {
};
struct bwn_stats {
+ int32_t rtsfail;
+ int32_t rts;
int32_t link_noise;
};
diff --git a/sys/dev/cm/if_cm_isa.c b/sys/dev/cm/if_cm_isa.c
index 2986c60..fb3660e 100644
--- a/sys/dev/cm/if_cm_isa.c
+++ b/sys/dev/cm/if_cm_isa.c
@@ -18,13 +18,6 @@ __FBSDID("$FreeBSD$");
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/sys/dev/cm/smc90cx6.c b/sys/dev/cm/smc90cx6.c
index a0dedd9..0e9015e 100644
--- a/sys/dev/cm/smc90cx6.c
+++ b/sys/dev/cm/smc90cx6.c
@@ -18,13 +18,6 @@ __FBSDID("$FreeBSD$");
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/sys/dev/cm/smc90cx6reg.h b/sys/dev/cm/smc90cx6reg.h
index b020c86..2fec634 100644
--- a/sys/dev/cm/smc90cx6reg.h
+++ b/sys/dev/cm/smc90cx6reg.h
@@ -16,13 +16,6 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/sys/dev/cm/smc90cx6var.h b/sys/dev/cm/smc90cx6var.h
index 65b06a8..f3fd24d 100644
--- a/sys/dev/cm/smc90cx6var.h
+++ b/sys/dev/cm/smc90cx6var.h
@@ -16,13 +16,6 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/sys/dev/cxgb/common/cxgb_common.h b/sys/dev/cxgb/common/cxgb_common.h
index 2f55e9f..1d325ae 100644
--- a/sys/dev/cxgb/common/cxgb_common.h
+++ b/sys/dev/cxgb/common/cxgb_common.h
@@ -392,11 +392,9 @@ struct adapter_params {
const struct adapter_info *info;
-#ifdef CONFIG_CHELSIO_T3_CORE
unsigned short mtus[NMTUS];
unsigned short a_wnd[NCCTRL_WIN];
unsigned short b_wnd[NCCTRL_WIN];
-#endif
unsigned int nports; /* # of ethernet ports */
unsigned int chan_map; /* bitmap of in-use Tx channels */
unsigned int stats_update_period; /* MAC stats accumulation period */
@@ -650,11 +648,7 @@ static inline int is_10G(const adapter_t *adap)
static inline int is_offload(const adapter_t *adap)
{
-#if defined(CONFIG_CHELSIO_T3_CORE)
return adap->params.offload;
-#else
- return 0;
-#endif
}
static inline unsigned int core_ticks_per_usec(const adapter_t *adap)
@@ -772,7 +766,6 @@ void t3_mc5_intr_handler(struct mc5 *mc5);
int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start, unsigned int n,
u32 *buf);
-#ifdef CONFIG_CHELSIO_T3_CORE
int t3_tp_set_coalescing_size(adapter_t *adap, unsigned int size, int psh);
void t3_tp_set_max_rxsize(adapter_t *adap, unsigned int size);
void t3_tp_get_mib_stats(adapter_t *adap, struct tp_mib_stats *tps);
@@ -793,7 +786,6 @@ void t3_get_tx_sched(adapter_t *adap, unsigned int sched, unsigned int *kbps,
void t3_read_pace_tbl(adapter_t *adap, unsigned int pace_vals[NTX_SCHED]);
void t3_set_pace_tbl(adapter_t *adap, unsigned int *pace_vals,
unsigned int start, unsigned int n);
-#endif
int t3_get_up_la(adapter_t *adapter, u32 *stopped, u32 *index,
u32 *size, void *data);
diff --git a/sys/dev/cxgb/common/cxgb_t3_hw.c b/sys/dev/cxgb/common/cxgb_t3_hw.c
index 2c205ec..188e467 100644
--- a/sys/dev/cxgb/common/cxgb_t3_hw.c
+++ b/sys/dev/cxgb/common/cxgb_t3_hw.c
@@ -3263,7 +3263,6 @@ static void tp_set_timers(adapter_t *adap, unsigned int core_clk)
#undef SECONDS
}
-#ifdef CONFIG_CHELSIO_T3_CORE
/**
* t3_tp_set_coalescing_size - set receive coalescing size
* @adap: the adapter
@@ -3566,7 +3565,6 @@ int t3_set_proto_sram(adapter_t *adap, const u8 *data)
}
return 0;
}
-#endif
/**
* t3_config_trace_filter - configure one of the tracing filters
@@ -4150,14 +4148,12 @@ int t3_init_hw(adapter_t *adapter, u32 fw_params)
if (tp_init(adapter, &adapter->params.tp))
goto out_err;
-#ifdef CONFIG_CHELSIO_T3_CORE
t3_tp_set_coalescing_size(adapter,
min(adapter->params.sge.max_pkt_size,
MAX_RX_COALESCING_LEN), 1);
t3_tp_set_max_rxsize(adapter,
min(adapter->params.sge.max_pkt_size, 16384U));
ulp_config(adapter, &adapter->params.tp);
-#endif
if (is_pcie(adapter))
config_pcie(adapter);
else
@@ -4508,10 +4504,8 @@ int __devinit t3_prep_adapter(adapter_t *adapter,
adapter->params.mc5.nroutes = 0;
t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT);
-#ifdef CONFIG_CHELSIO_T3_CORE
init_mtus(adapter->params.mtus);
init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
-#endif
}
early_hw_init(adapter, ai);
diff --git a/sys/dev/cxgb/common/cxgb_version.h b/sys/dev/cxgb/common/cxgb_version.h
deleted file mode 100644
index 3f4a652..0000000
--- a/sys/dev/cxgb/common/cxgb_version.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/**************************************************************************
-
-Copyright (c) 2007-2008, Chelsio Inc.
-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. Neither the name of the Chelsio Corporation nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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$
-
-***************************************************************************/
-/*
- * Note that although this driver doesn't contain all of the functionality of the Linux driver
- * the common code is 99% the same. Hence we keep the same version number to indicate what linux
- * driver the common code corresponds to.
- */
-#ifndef __CHELSIO_VERSION_H
-#define __CHELSIO_VERSION_H
-#define DRV_DESC "Chelsio T3 Network Driver"
-#define DRV_NAME "cxgb"
-#define DRV_VERSION "1.0.133"
-#endif
diff --git a/sys/dev/cxgb/cxgb_adapter.h b/sys/dev/cxgb/cxgb_adapter.h
index c5b366b..d4a66d6 100644
--- a/sys/dev/cxgb/cxgb_adapter.h
+++ b/sys/dev/cxgb/cxgb_adapter.h
@@ -46,6 +46,7 @@ $FreeBSD$
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_dl.h>
+#include <netinet/tcp_lro.h>
#include <machine/bus.h>
#include <machine/resource.h>
@@ -58,10 +59,6 @@ $FreeBSD$
#include <t3cdev.h>
#include <sys/mbufq.h>
-#ifdef LRO_SUPPORTED
-#include <netinet/tcp_lro.h>
-#endif
-
struct adapter;
struct sge_qset;
extern int cxgb_debug;
@@ -156,12 +153,10 @@ enum { TXQ_ETH = 0,
#define WR_LEN (WR_FLITS * 8)
#define PIO_LEN (WR_LEN - sizeof(struct cpl_tx_pkt_lso))
-#ifdef LRO_SUPPORTED
struct lro_state {
unsigned short enabled;
struct lro_ctrl ctrl;
};
-#endif
#define RX_BUNDLE_SIZE 8
@@ -284,9 +279,7 @@ enum {
struct sge_qset {
struct sge_rspq rspq;
struct sge_fl fl[SGE_RXQ_PER_SET];
-#ifdef LRO_SUPPORTED
struct lro_state lro;
-#endif
struct sge_txq txq[SGE_TXQ_PER_SET];
uint32_t txq_stopped; /* which Tx queues are stopped */
uint64_t port_stats[SGE_PSTAT_MAX];
diff --git a/sys/dev/cxgb/cxgb_config.h b/sys/dev/cxgb/cxgb_config.h
deleted file mode 100644
index 79af94c..0000000
--- a/sys/dev/cxgb/cxgb_config.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/**************************************************************************
-
-Copyright (c) 2007-2008, Chelsio Inc.
-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. Neither the name of the Chelsio Corporation nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 _CXGB_CONFIG_H_
-#define _CXGB_CONFIG_H_
-
-#define CONFIG_CHELSIO_T3_CORE
-
-#if __FreeBSD_version > 800053
-#define IFNET_MULTIQUEUE
-#endif
-#endif
diff --git a/sys/dev/cxgb/cxgb_main.c b/sys/dev/cxgb/cxgb_main.c
index 67dd07b..5493b75d 100644
--- a/sys/dev/cxgb/cxgb_main.c
+++ b/sys/dev/cxgb/cxgb_main.c
@@ -376,11 +376,7 @@ cxgb_controller_probe(device_t dev)
static int
upgrade_fw(adapter_t *sc)
{
-#ifdef FIRMWARE_LATEST
const struct firmware *fw;
-#else
- struct firmware *fw;
-#endif
int status;
if ((fw = firmware_get(FW_FNAME)) == NULL) {
@@ -390,7 +386,8 @@ upgrade_fw(adapter_t *sc)
device_printf(sc->dev, "updating firmware on card\n");
status = t3_load_fw(sc, (const uint8_t *)fw->data, fw->datasize);
- device_printf(sc->dev, "firmware update returned %s %d\n", (status == 0) ? "success" : "fail", status);
+ device_printf(sc->dev, "firmware update returned %s %d\n",
+ status == 0 ? "success" : "fail", status);
firmware_put(fw, FIRMWARE_UNLOAD);
@@ -432,9 +429,7 @@ cxgb_controller_attach(device_t dev)
int i, error = 0;
uint32_t vers;
int port_qsets = 1;
-#ifdef MSI_SUPPORTED
int msi_needed, reg;
-#endif
char buf[80];
sc = device_get_softc(dev);
@@ -442,10 +437,6 @@ cxgb_controller_attach(device_t dev)
sc->msi_count = 0;
ai = cxgb_get_adapter_info(dev);
- /*
- * XXX not really related but a recent addition
- */
-#ifdef MSI_SUPPORTED
/* find the PCIe link width and set max read request to 4KB*/
if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
uint16_t lnk, pectl;
@@ -463,7 +454,7 @@ cxgb_controller_attach(device_t dev)
"PCIe x%d Link, expect reduced performance\n",
sc->link_width);
}
-#endif
+
touch_bars(dev);
pci_enable_busmaster(dev);
/*
@@ -518,8 +509,6 @@ cxgb_controller_attach(device_t dev)
* back to MSI. If that fails, then try falling back to the legacy
* interrupt pin model.
*/
-#ifdef MSI_SUPPORTED
-
sc->msix_regs_rid = 0x20;
if ((msi_allowed >= 2) &&
(sc->msix_regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
@@ -565,20 +554,14 @@ cxgb_controller_attach(device_t dev)
device_printf(dev, "using MSI interrupts\n");
}
}
-#endif
if (sc->msi_count == 0) {
device_printf(dev, "using line interrupts\n");
sc->cxgb_intr = t3b_intr;
}
/* Create a private taskqueue thread for handling driver events */
-#ifdef TASKQUEUE_CURRENT
sc->tq = taskqueue_create("cxgb_taskq", M_NOWAIT,
taskqueue_thread_enqueue, &sc->tq);
-#else
- sc->tq = taskqueue_create_fast("cxgb_taskq", M_NOWAIT,
- taskqueue_thread_enqueue, &sc->tq);
-#endif
if (sc->tq == NULL) {
device_printf(dev, "failed to allocate controller task queue\n");
goto out;
@@ -764,7 +747,6 @@ cxgb_free(struct adapter *sc)
* Release all interrupt resources.
*/
cxgb_teardown_interrupts(sc);
-#ifdef MSI_SUPPORTED
if (sc->flags & (USING_MSI | USING_MSIX)) {
device_printf(sc->dev, "releasing msi message(s)\n");
pci_release_msi(sc->dev);
@@ -776,7 +758,6 @@ cxgb_free(struct adapter *sc)
bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid,
sc->msix_regs_res);
}
-#endif
/*
* Free the adapter's taskqueue.
@@ -910,11 +891,8 @@ cxgb_setup_interrupts(adapter_t *sc)
sc->irq_rid = 0;
} else {
err = bus_setup_intr(sc->dev, sc->irq_res,
- INTR_MPSAFE | INTR_TYPE_NET,
-#ifdef INTR_FILTERS
- NULL,
-#endif
- sc->cxgb_intr, sc, &sc->intr_tag);
+ INTR_MPSAFE | INTR_TYPE_NET, NULL,
+ sc->cxgb_intr, sc, &sc->intr_tag);
if (err) {
device_printf(sc->dev,
@@ -943,10 +921,7 @@ cxgb_setup_interrupts(adapter_t *sc)
}
err = bus_setup_intr(sc->dev, res, INTR_MPSAFE | INTR_TYPE_NET,
-#ifdef INTR_FILTERS
- NULL,
-#endif
- t3_intr_msix, &sc->sge.qs[i], &tag);
+ NULL, t3_intr_msix, &sc->sge.qs[i], &tag);
if (err) {
device_printf(sc->dev, "Cannot set up interrupt "
"for message %d (%d)\n", rid, err);
@@ -996,26 +971,10 @@ cxgb_makedev(struct port_info *pi)
return (0);
}
-#ifndef LRO_SUPPORTED
-#ifdef IFCAP_LRO
-#undef IFCAP_LRO
-#endif
-#define IFCAP_LRO 0x0
-#endif
-
-#ifdef TSO_SUPPORTED
-#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO)
-/* Don't enable TSO6 yet */
-#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO4 | IFCAP_JUMBO_MTU | IFCAP_LRO)
-#else
-#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU)
-/* Don't enable TSO6 yet */
-#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU)
-#define IFCAP_TSO4 0x0
-#define IFCAP_TSO6 0x0
-#define CSUM_TSO 0x0
-#endif
-
+#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \
+ IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \
+ IFCAP_VLAN_HWTSO)
+#define CXGB_CAP_ENABLE (CXGB_CAP & ~IFCAP_TSO6)
static int
cxgb_port_attach(device_t dev)
@@ -1024,8 +983,7 @@ cxgb_port_attach(device_t dev)
struct ifnet *ifp;
int err;
struct adapter *sc;
-
-
+
p = device_get_softc(dev);
sc = p->adapter;
snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d",
@@ -1039,9 +997,6 @@ cxgb_port_attach(device_t dev)
return (ENOMEM);
}
- /*
- * Note that there is currently no watchdog timer.
- */
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
ifp->if_init = cxgb_init;
ifp->if_softc = p;
@@ -1053,16 +1008,16 @@ cxgb_port_attach(device_t dev)
IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
IFQ_SET_READY(&ifp->if_snd);
- ifp->if_hwassist = ifp->if_capabilities = ifp->if_capenable = 0;
- ifp->if_capabilities |= CXGB_CAP;
- ifp->if_capenable |= CXGB_CAP_ENABLE;
- ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO);
+ ifp->if_capabilities = CXGB_CAP;
+ ifp->if_capenable = CXGB_CAP_ENABLE;
+ ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO;
+
/*
- * disable TSO on 4-port - it isn't supported by the firmware yet
+ * Disable TSO on 4-port - it isn't supported by the firmware.
*/
- if (p->adapter->params.nports > 2) {
- ifp->if_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6);
- ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TSO6);
+ if (sc->params.nports > 2) {
+ ifp->if_capabilities &= ~(IFCAP_TSO | IFCAP_VLAN_HWTSO);
+ ifp->if_capenable &= ~(IFCAP_TSO | IFCAP_VLAN_HWTSO);
ifp->if_hwassist &= ~CSUM_TSO;
}
@@ -1070,11 +1025,10 @@ cxgb_port_attach(device_t dev)
ifp->if_transmit = cxgb_transmit;
ifp->if_qflush = cxgb_qflush;
- /*
- * Only default to jumbo frames on 10GigE
- */
- if (p->adapter->params.nports <= 2)
+#ifdef DEFAULT_JUMBO
+ if (sc->params.nports <= 2)
ifp->if_mtu = ETHERMTU_JUMBO;
+#endif
if ((err = cxgb_makedev(p)) != 0) {
printf("makedev failed %d\n", err);
return (err);
@@ -1583,11 +1537,7 @@ bind_qsets(adapter_t *sc)
static void
update_tpeeprom(struct adapter *adap)
{
-#ifdef FIRMWARE_LATEST
const struct firmware *tpeeprom;
-#else
- struct firmware *tpeeprom;
-#endif
uint32_t version;
unsigned int major, minor;
@@ -1645,11 +1595,7 @@ release_tpeeprom:
static int
update_tpsram(struct adapter *adap)
{
-#ifdef FIRMWARE_LATEST
const struct firmware *tpsram;
-#else
- struct firmware *tpsram;
-#endif
int ret;
char rev, name[32];
@@ -1999,7 +1945,6 @@ cxgb_uninit_synchronized(struct port_info *pi)
return (0);
}
-#ifdef LRO_SUPPORTED
/*
* Mark lro enabled or disabled in all qsets for this port
*/
@@ -2017,7 +1962,6 @@ cxgb_set_lro(struct port_info *p, int enabled)
}
return (0);
}
-#endif
static int
cxgb_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data)
@@ -2102,37 +2046,41 @@ fail:
mask = ifr->ifr_reqcap ^ ifp->if_capenable;
if (mask & IFCAP_TXCSUM) {
- if (IFCAP_TXCSUM & ifp->if_capenable) {
- ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4);
- ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP
- | CSUM_IP | CSUM_TSO);
- } else {
- ifp->if_capenable |= IFCAP_TXCSUM;
- ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP
- | CSUM_IP);
+ ifp->if_capenable ^= IFCAP_TXCSUM;
+ ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP);
+
+ if (IFCAP_TSO & ifp->if_capenable &&
+ !(IFCAP_TXCSUM & ifp->if_capenable)) {
+ ifp->if_capenable &= ~IFCAP_TSO;
+ ifp->if_hwassist &= ~CSUM_TSO;
+ if_printf(ifp,
+ "tso disabled due to -txcsum.\n");
}
}
- if (mask & IFCAP_RXCSUM) {
+ if (mask & IFCAP_RXCSUM)
ifp->if_capenable ^= IFCAP_RXCSUM;
- }
if (mask & IFCAP_TSO4) {
- if (IFCAP_TSO4 & ifp->if_capenable) {
- ifp->if_capenable &= ~IFCAP_TSO4;
- ifp->if_hwassist &= ~CSUM_TSO;
- } else if (IFCAP_TXCSUM & ifp->if_capenable) {
- ifp->if_capenable |= IFCAP_TSO4;
- ifp->if_hwassist |= CSUM_TSO;
+ ifp->if_capenable ^= IFCAP_TSO4;
+
+ if (IFCAP_TSO & ifp->if_capenable) {
+ if (IFCAP_TXCSUM & ifp->if_capenable)
+ ifp->if_hwassist |= CSUM_TSO;
+ else {
+ ifp->if_capenable &= ~IFCAP_TSO;
+ ifp->if_hwassist &= ~CSUM_TSO;
+ if_printf(ifp,
+ "enable txcsum first.\n");
+ error = EAGAIN;
+ }
} else
- error = EINVAL;
+ ifp->if_hwassist &= ~CSUM_TSO;
}
-#ifdef LRO_SUPPORTED
if (mask & IFCAP_LRO) {
ifp->if_capenable ^= IFCAP_LRO;
/* Safe to do this even if cxgb_up not called yet */
cxgb_set_lro(p, ifp->if_capenable & IFCAP_LRO);
}
-#endif
if (mask & IFCAP_VLAN_HWTAGGING) {
ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
@@ -2149,6 +2097,8 @@ fail:
PORT_UNLOCK(p);
}
}
+ if (mask & IFCAP_VLAN_HWTSO)
+ ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
if (mask & IFCAP_VLAN_HWCSUM)
ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
diff --git a/sys/dev/cxgb/cxgb_offload.h b/sys/dev/cxgb/cxgb_offload.h
index dccefdc..a8b858e 100644
--- a/sys/dev/cxgb/cxgb_offload.h
+++ b/sys/dev/cxgb/cxgb_offload.h
@@ -33,8 +33,6 @@ $FreeBSD$
#ifndef _CXGB_OFFLOAD_H
#define _CXGB_OFFLOAD_H
-#include <common/cxgb_version.h>
-#include <cxgb_config.h>
#include <common/cxgb_tcb.h>
#include <t3cdev.h>
diff --git a/sys/dev/cxgb/cxgb_osdep.h b/sys/dev/cxgb/cxgb_osdep.h
index 9567890..5dc256d 100644
--- a/sys/dev/cxgb/cxgb_osdep.h
+++ b/sys/dev/cxgb/cxgb_osdep.h
@@ -41,9 +41,6 @@ $FreeBSD$
#include <dev/mii/mii.h>
-#define CONFIG_CHELSIO_T3_CORE
-#include <common/cxgb_version.h>
-
#ifndef _CXGB_OSDEP_H_
#define _CXGB_OSDEP_H_
@@ -91,33 +88,6 @@ struct t3_mbuf_hdr {
#define MT_DONTFREE 128
-#if __FreeBSD_version > 700030
-#define INTR_FILTERS
-#define FIRMWARE_LATEST
-#endif
-
-#if ((__FreeBSD_version > 602103) && (__FreeBSD_version < 700000))
-#define FIRMWARE_LATEST
-#endif
-
-#if __FreeBSD_version > 700000
-#define MSI_SUPPORTED
-#define TSO_SUPPORTED
-#define VLAN_SUPPORTED
-#define TASKQUEUE_CURRENT
-#else
-#define if_name(ifp) (ifp)->if_xname
-#define M_SANITY(m, n)
-#endif
-
-#if __FreeBSD_version >= 701000
-#include "opt_inet.h"
-#ifdef INET
-#define LRO_SUPPORTED
-#define TOE_SUPPORTED
-#endif
-#endif
-
#if __FreeBSD_version < 800054
#if defined (__GNUC__)
#if #cpu(i386) || defined __i386 || defined i386 || defined __i386__ || #cpu(x86_64) || defined __x86_64__
diff --git a/sys/dev/cxgb/cxgb_sge.c b/sys/dev/cxgb/cxgb_sge.c
index 27a7c89..184c5af 100644
--- a/sys/dev/cxgb/cxgb_sge.c
+++ b/sys/dev/cxgb/cxgb_sge.c
@@ -50,8 +50,12 @@ __FBSDID("$FreeBSD$");
#include <sys/smp.h>
#include <sys/systm.h>
#include <sys/syslog.h>
+#include <sys/socket.h>
#include <net/bpf.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_vlan_var.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
@@ -1145,10 +1149,9 @@ calc_tx_descs(const struct mbuf *m, int nsegs)
return 1;
flits = sgl_len(nsegs) + 2;
-#ifdef TSO_SUPPORTED
if (m->m_pkthdr.csum_flags & CSUM_TSO)
flits++;
-#endif
+
return flits_to_desc(flits);
}
@@ -1363,20 +1366,15 @@ write_wr_hdr_sgl(unsigned int ndesc, struct tx_desc *txd, struct txq_state *txqs
}
}
-/* sizeof(*eh) + sizeof(*vhdr) + sizeof(*ip) + sizeof(*tcp) */
-#define TCPPKTHDRSIZE (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + 20 + 20)
+/* sizeof(*eh) + sizeof(*ip) + sizeof(*tcp) */
+#define TCPPKTHDRSIZE (ETHER_HDR_LEN + 20 + 20)
-#ifdef VLAN_SUPPORTED
#define GET_VTAG(cntrl, m) \
do { \
if ((m)->m_flags & M_VLANTAG) \
cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN((m)->m_pkthdr.ether_vtag); \
} while (0)
-#else
-#define GET_VTAG(cntrl, m)
-#endif
-
static int
t3_encap(struct sge_qset *qs, struct mbuf **m)
{
@@ -1405,19 +1403,15 @@ t3_encap(struct sge_qset *qs, struct mbuf **m)
prefetch(txd);
m0 = *m;
-
- DPRINTF("t3_encap port_id=%d qsidx=%d ", pi->port_id, pi->first_qset);
- DPRINTF("mlen=%d txpkt_intf=%d tx_chan=%d\n", m[0]->m_pkthdr.len, pi->txpkt_intf, pi->tx_chan);
-
+
mtx_assert(&qs->lock, MA_OWNED);
cntrl = V_TXPKT_INTF(pi->txpkt_intf);
KASSERT(m0->m_flags & M_PKTHDR, ("not packet header\n"));
-#ifdef VLAN_SUPPORTED
if (m0->m_nextpkt == NULL && m0->m_next != NULL &&
m0->m_pkthdr.csum_flags & (CSUM_TSO))
tso_info = V_LSO_MSS(m0->m_pkthdr.tso_segsz);
-#endif
+
if (m0->m_nextpkt != NULL) {
busdma_map_sg_vec(txq->entry_tag, txsd->map, m0, segs, &nsegs);
ndesc = 1;
@@ -1477,15 +1471,16 @@ t3_encap(struct sge_qset *qs, struct mbuf **m)
V_WR_GEN(txqs.gen)) | htonl(V_WR_TID(txq->token));
set_wr_hdr(wrp, wr_hi, wr_lo);
wmb();
+ ETHER_BPF_MTAP(pi->ifp, m0);
wr_gen2(txd, txqs.gen);
check_ring_tx_db(sc, txq);
return (0);
} else if (tso_info) {
- int min_size = TCPPKTHDRSIZE, eth_type, tagged;
+ int eth_type;
struct cpl_tx_pkt_lso *hdr = (struct cpl_tx_pkt_lso *)txd;
+ struct ether_header *eh;
struct ip *ip;
struct tcphdr *tcp;
- char *pkthdr;
txd->flit[2] = 0;
GET_VTAG(cntrl, m0);
@@ -1493,13 +1488,7 @@ t3_encap(struct sge_qset *qs, struct mbuf **m)
hdr->cntrl = htonl(cntrl);
hdr->len = htonl(mlen | 0x80000000);
- DPRINTF("tso buf len=%d\n", mlen);
-
- tagged = m0->m_flags & M_VLANTAG;
- if (!tagged)
- min_size -= ETHER_VLAN_ENCAP_LEN;
-
- if (__predict_false(mlen < min_size)) {
+ if (__predict_false(mlen < TCPPKTHDRSIZE)) {
printf("mbuf=%p,len=%d,tso_segsz=%d,csum_flags=%#x,flags=%#x",
m0, mlen, m0->m_pkthdr.tso_segsz,
m0->m_pkthdr.csum_flags, m0->m_flags);
@@ -1507,25 +1496,23 @@ t3_encap(struct sge_qset *qs, struct mbuf **m)
}
/* Make sure that ether, ip, tcp headers are all in m0 */
- if (__predict_false(m0->m_len < min_size)) {
- m0 = m_pullup(m0, min_size);
+ if (__predict_false(m0->m_len < TCPPKTHDRSIZE)) {
+ m0 = m_pullup(m0, TCPPKTHDRSIZE);
if (__predict_false(m0 == NULL)) {
/* XXX panic probably an overreaction */
panic("couldn't fit header into mbuf");
}
}
- pkthdr = m0->m_data;
- if (tagged) {
+ eh = mtod(m0, struct ether_header *);
+ if (eh->ether_type == htons(ETHERTYPE_VLAN)) {
eth_type = CPL_ETH_II_VLAN;
- ip = (struct ip *)(pkthdr + ETHER_HDR_LEN +
- ETHER_VLAN_ENCAP_LEN);
+ ip = (struct ip *)((struct ether_vlan_header *)eh + 1);
} else {
eth_type = CPL_ETH_II;
- ip = (struct ip *)(pkthdr + ETHER_HDR_LEN);
+ ip = (struct ip *)(eh + 1);
}
- tcp = (struct tcphdr *)((uint8_t *)ip +
- sizeof(*ip));
+ tcp = (struct tcphdr *)(ip + 1);
tso_info |= V_LSO_ETH_TYPE(eth_type) |
V_LSO_IPHDR_WORDS(ip->ip_hl) |
@@ -1533,12 +1520,10 @@ t3_encap(struct sge_qset *qs, struct mbuf **m)
hdr->lso_info = htonl(tso_info);
if (__predict_false(mlen <= PIO_LEN)) {
- /* pkt not undersized but fits in PIO_LEN
+ /*
+ * pkt not undersized but fits in PIO_LEN
* Indicates a TSO bug at the higher levels.
- *
*/
- DPRINTF("**5592 Fix** mbuf=%p,len=%d,tso_segsz=%d,csum_flags=%#x,flags=%#x",
- m0, mlen, m0->m_pkthdr.tso_segsz, m0->m_pkthdr.csum_flags, m0->m_flags);
txsd->m = NULL;
m_copydata(m0, 0, mlen, (caddr_t)&txd->flit[3]);
flits = (mlen + 7) / 8 + 3;
@@ -1549,8 +1534,10 @@ t3_encap(struct sge_qset *qs, struct mbuf **m)
V_WR_GEN(txqs.gen) | V_WR_TID(txq->token));
set_wr_hdr(&hdr->wr, wr_hi, wr_lo);
wmb();
+ ETHER_BPF_MTAP(pi->ifp, m0);
wr_gen2(txd, txqs.gen);
check_ring_tx_db(sc, txq);
+ m_freem(m0);
return (0);
}
flits = 3;
@@ -1578,8 +1565,10 @@ t3_encap(struct sge_qset *qs, struct mbuf **m)
V_WR_GEN(txqs.gen) | V_WR_TID(txq->token));
set_wr_hdr(&cpl->wr, wr_hi, wr_lo);
wmb();
+ ETHER_BPF_MTAP(pi->ifp, m0);
wr_gen2(txd, txqs.gen);
check_ring_tx_db(sc, txq);
+ m_freem(m0);
return (0);
}
flits = 2;
@@ -1590,12 +1579,14 @@ t3_encap(struct sge_qset *qs, struct mbuf **m)
sgl_flits = sgl_len(nsegs);
+ ETHER_BPF_MTAP(pi->ifp, m0);
+
KASSERT(ndesc <= 4, ("ndesc too large %d", ndesc));
wr_hi = htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | txqs.compl);
wr_lo = htonl(V_WR_TID(txq->token));
write_wr_hdr_sgl(ndesc, txd, &txqs, txq, sgl, flits,
sgl_flits, wr_hi, wr_lo);
- check_ring_tx_db(pi->adapter, txq);
+ check_ring_tx_db(sc, txq);
return (0);
}
@@ -1674,16 +1665,6 @@ cxgb_start_locked(struct sge_qset *qs)
*/
if (t3_encap(qs, &m_head) || m_head == NULL)
break;
-
- /* Send a copy of the frame to the BPF listener */
- ETHER_BPF_MTAP(ifp, m_head);
-
- /*
- * We sent via PIO, no longer need a copy
- */
- if (m_head->m_nextpkt == NULL &&
- m_head->m_pkthdr.len <= PIO_LEN)
- m_freem(m_head);
m_head = NULL;
}
@@ -1726,17 +1707,6 @@ cxgb_transmit_locked(struct ifnet *ifp, struct sge_qset *qs, struct mbuf *m)
*/
txq->txq_direct_packets++;
txq->txq_direct_bytes += m->m_pkthdr.len;
- /*
- ** Send a copy of the frame to the BPF
- ** listener and set the watchdog on.
- */
- ETHER_BPF_MTAP(ifp, m);
- /*
- * We sent via PIO, no longer need a copy
- */
- if (m->m_pkthdr.len <= PIO_LEN)
- m_freem(m);
-
}
} else if ((error = drbr_enqueue(ifp, br, m)) != 0)
return (error);
@@ -2090,9 +2060,7 @@ t3_free_qset(adapter_t *sc, struct sge_qset *q)
MTX_DESTROY(&q->rspq.lock);
}
-#ifdef LRO_SUPPORTED
tcp_lro_free(&q->lro.ctrl);
-#endif
bzero(q, sizeof(*q));
}
@@ -2677,7 +2645,6 @@ t3_sge_alloc_qset(adapter_t *sc, u_int id, int nports, int irq_vec_idx,
q->fl[1].type = EXT_JUMBOP;
#endif
-#ifdef LRO_SUPPORTED
/* Allocate and setup the lro_ctrl structure */
q->lro.enabled = !!(pi->ifp->if_capenable & IFCAP_LRO);
ret = tcp_lro_init(&q->lro.ctrl);
@@ -2686,7 +2653,6 @@ t3_sge_alloc_qset(adapter_t *sc, u_int id, int nports, int irq_vec_idx,
goto err;
}
q->lro.ctrl.ifp = pi->ifp;
-#endif
mtx_lock_spin(&sc->sge.reg_lock);
ret = -t3_sge_init_rspcntxt(sc, q->rspq.cntxt_id, irq_vec_idx,
@@ -2787,16 +2753,12 @@ t3_rx_eth(struct adapter *adap, struct sge_rspq *rq, struct mbuf *m, int ethpad)
m->m_pkthdr.csum_flags = (CSUM_IP_CHECKED|CSUM_IP_VALID|CSUM_DATA_VALID|CSUM_PSEUDO_HDR);
m->m_pkthdr.csum_data = 0xffff;
}
- /*
- * XXX need to add VLAN support for 6.x
- */
-#ifdef VLAN_SUPPORTED
- if (__predict_false(cpl->vlan_valid)) {
+
+ if (cpl->vlan_valid) {
m->m_pkthdr.ether_vtag = ntohs(cpl->vlan);
m->m_flags |= M_VLANTAG;
}
-#endif
-
+
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.header = mtod(m, uint8_t *) + sizeof(*cpl) + ethpad;
/*
@@ -2976,11 +2938,9 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget)
struct rsp_desc *r = &rspq->desc[rspq->cidx];
int budget_left = budget;
unsigned int sleeping = 0;
-#ifdef LRO_SUPPORTED
int lro_enabled = qs->lro.enabled;
int skip_lro;
struct lro_ctrl *lro_ctrl = &qs->lro.ctrl;
-#endif
struct mbuf *offload_mbufs[RX_BUNDLE_SIZE];
int ngathered = 0;
#ifdef DEBUG
@@ -3089,7 +3049,6 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget)
t3_rx_eth(adap, rspq, m, ethpad);
-#ifdef LRO_SUPPORTED
/*
* The T304 sends incoming packets on any qset. If LRO
* is also enabled, we could end up sending packet up
@@ -3103,9 +3062,7 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget)
if (lro_enabled && lro_ctrl->lro_cnt && !skip_lro &&
(tcp_lro_rx(lro_ctrl, m, 0) == 0)) {
/* successfully queue'd for LRO */
- } else
-#endif
- {
+ } else {
/*
* LRO not enabled, packet unsuitable for LRO,
* or unable to queue. Pass it up right now in
@@ -3124,14 +3081,12 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget)
deliver_partial_bundle(&adap->tdev, rspq, offload_mbufs, ngathered);
-#ifdef LRO_SUPPORTED
/* Flush LRO */
while (!SLIST_EMPTY(&lro_ctrl->lro_active)) {
struct lro_entry *queued = SLIST_FIRST(&lro_ctrl->lro_active);
SLIST_REMOVE_HEAD(&lro_ctrl->lro_active, next);
tcp_lro_flush(lro_ctrl, queued);
}
-#endif
if (sleeping)
check_ring_db(adap, qs, sleeping);
@@ -3704,7 +3659,6 @@ t3_add_configured_sysctls(adapter_t *sc)
CTLTYPE_STRING | CTLFLAG_RD, &qs->txq[TXQ_CTRL],
0, t3_dump_txq_ctrl, "A", "dump of the transmit queue");
-#ifdef LRO_SUPPORTED
SYSCTL_ADD_INT(ctx, lropoidlist, OID_AUTO, "lro_queued",
CTLFLAG_RD, &qs->lro.ctrl.lro_queued, 0, NULL);
SYSCTL_ADD_INT(ctx, lropoidlist, OID_AUTO, "lro_flushed",
@@ -3713,7 +3667,6 @@ t3_add_configured_sysctls(adapter_t *sc)
CTLFLAG_RD, &qs->lro.ctrl.lro_bad_csum, 0, NULL);
SYSCTL_ADD_INT(ctx, lropoidlist, OID_AUTO, "lro_cnt",
CTLFLAG_RD, &qs->lro.ctrl.lro_cnt, 0, NULL);
-#endif
}
/* Now add a node for mac stats. */
diff --git a/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb.c b/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb.c
index cf42ea0..a4f2ff6 100644
--- a/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb.c
+++ b/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb.c
@@ -138,8 +138,7 @@ open_rnic_dev(struct t3cdev *tdev)
CTR2(KTR_IW_CXGB, "%s t3cdev %p", __FUNCTION__, tdev);
if (!vers_printed++)
- printf("Chelsio T3 RDMA Driver - version %s\n",
- DRV_VERSION);
+ printf("Chelsio T3 RDMA Driver - version x.xx\n");
rnicp = (struct iwch_dev *)ib_alloc_device(sizeof(*rnicp));
if (!rnicp) {
printf("Cannot allocate ib device\n");
diff --git a/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_qp.c b/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_qp.c
index 83c742f..fd51498 100644
--- a/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_qp.c
+++ b/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_qp.c
@@ -675,7 +675,7 @@ static void __flush_qp(struct iwch_qp *qhp)
qhp->refcnt++;
mtx_unlock(&qhp->lock);
- /* locking heirarchy: cq lock first, then qp lock. */
+ /* locking hierarchy: cq lock first, then qp lock. */
mtx_lock(&rchp->lock);
mtx_lock(&qhp->lock);
cxio_flush_hw_cq(&rchp->cq);
@@ -685,7 +685,7 @@ static void __flush_qp(struct iwch_qp *qhp)
mtx_unlock(&rchp->lock);
(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
- /* locking heirarchy: cq lock first, then qp lock. */
+ /* locking hierarchy: cq lock first, then qp lock. */
mtx_lock(&schp->lock);
mtx_lock(&qhp->lock);
cxio_flush_hw_cq(&schp->cq);
diff --git a/sys/dev/cxgb/ulp/tom/cxgb_cpl_socket.c b/sys/dev/cxgb/ulp/tom/cxgb_cpl_socket.c
index 76237fb..bbb594a 100644
--- a/sys/dev/cxgb/ulp/tom/cxgb_cpl_socket.c
+++ b/sys/dev/cxgb/ulp/tom/cxgb_cpl_socket.c
@@ -61,7 +61,6 @@ __FBSDID("$FreeBSD$");
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
-#include <cxgb_config.h>
#include <cxgb_osdep.h>
#include <sys/mbufq.h>
#include <ulp/tom/cxgb_tcp_offload.h>
diff --git a/sys/dev/fb/fb.c b/sys/dev/fb/fb.c
index 09fcebc..b201d29 100644
--- a/sys/dev/fb/fb.c
+++ b/sys/dev/fb/fb.c
@@ -653,7 +653,7 @@ fb_commonioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
((video_adapter_info_t *)arg)->va_mem_base = adp->va_mem_base;
((video_adapter_info_t *)arg)->va_mem_size = adp->va_mem_size;
((video_adapter_info_t *)arg)->va_window
-#ifdef __i386__
+#if defined(__amd64__) || defined(__i386__)
= vtophys(adp->va_window);
#else
= adp->va_window;
@@ -665,8 +665,8 @@ fb_commonioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
((video_adapter_info_t *)arg)->va_window_orig
= adp->va_window_orig;
((video_adapter_info_t *)arg)->va_unused0
-#ifdef __i386__
- = (adp->va_buffer) ? vtophys(adp->va_buffer) : 0;
+#if defined(__amd64__) || defined(__i386__)
+ = adp->va_buffer != 0 ? vtophys(adp->va_buffer) : 0;
#else
= adp->va_buffer;
#endif
diff --git a/sys/dev/fb/vesa.c b/sys/dev/fb/vesa.c
index ec08cfb7..2602440 100644
--- a/sys/dev/fb/vesa.c
+++ b/sys/dev/fb/vesa.c
@@ -165,7 +165,9 @@ static int int10_set_mode(int mode);
static int vesa_bios_post(void);
static int vesa_bios_get_mode(int mode, struct vesa_mode *vmode);
static int vesa_bios_set_mode(int mode);
+#if 0
static int vesa_bios_get_dac(void);
+#endif
static int vesa_bios_set_dac(int bits);
static int vesa_bios_save_palette(int start, int colors, u_char *palette,
int bits);
@@ -318,6 +320,7 @@ vesa_bios_set_mode(int mode)
return (regs.R_AX != 0x004f);
}
+#if 0
static int
vesa_bios_get_dac(void)
{
@@ -334,6 +337,7 @@ vesa_bios_get_dac(void)
return (regs.R_BH);
}
+#endif
static int
vesa_bios_set_dac(int bits)
@@ -919,9 +923,49 @@ vesa_bios_init(void)
vesa_vmode[modes].vi_buffer_size = bsize;
vesa_vmode[modes].vi_mem_model =
vesa_translate_mmodel(vmode.v_memmodel);
- if (vesa_vmode[modes].vi_mem_model == V_INFO_MM_PACKED ||
- vesa_vmode[modes].vi_mem_model == V_INFO_MM_DIRECT)
+ switch (vesa_vmode[modes].vi_mem_model) {
+ case V_INFO_MM_DIRECT:
+ if ((vmode.v_modeattr & V_MODELFB) != 0 &&
+ vers >= 0x0300) {
+ vesa_vmode[modes].vi_pixel_fields[0] =
+ vmode.v_linredfieldpos;
+ vesa_vmode[modes].vi_pixel_fields[1] =
+ vmode.v_lingreenfieldpos;
+ vesa_vmode[modes].vi_pixel_fields[2] =
+ vmode.v_linbluefieldpos;
+ vesa_vmode[modes].vi_pixel_fields[3] =
+ vmode.v_linresfieldpos;
+ vesa_vmode[modes].vi_pixel_fsizes[0] =
+ vmode.v_linredmasksize;
+ vesa_vmode[modes].vi_pixel_fsizes[1] =
+ vmode.v_lingreenmasksize;
+ vesa_vmode[modes].vi_pixel_fsizes[2] =
+ vmode.v_linbluemasksize;
+ vesa_vmode[modes].vi_pixel_fsizes[3] =
+ vmode.v_linresmasksize;
+ } else {
+ vesa_vmode[modes].vi_pixel_fields[0] =
+ vmode.v_redfieldpos;
+ vesa_vmode[modes].vi_pixel_fields[1] =
+ vmode.v_greenfieldpos;
+ vesa_vmode[modes].vi_pixel_fields[2] =
+ vmode.v_bluefieldpos;
+ vesa_vmode[modes].vi_pixel_fields[3] =
+ vmode.v_resfieldpos;
+ vesa_vmode[modes].vi_pixel_fsizes[0] =
+ vmode.v_redmasksize;
+ vesa_vmode[modes].vi_pixel_fsizes[1] =
+ vmode.v_greenmasksize;
+ vesa_vmode[modes].vi_pixel_fsizes[2] =
+ vmode.v_bluemasksize;
+ vesa_vmode[modes].vi_pixel_fsizes[3] =
+ vmode.v_resmasksize;
+ }
+ /* FALLTHROUGH */
+ case V_INFO_MM_PACKED:
vesa_vmode[modes].vi_pixel_size = (vmode.v_bpp + 7) / 8;
+ break;
+ }
vesa_vmode[modes].vi_flags =
vesa_translate_flags(vmode.v_modeattr) | V_INFO_VESA;
@@ -1158,6 +1202,10 @@ vesa_set_mode(video_adapter_t *adp, int mode)
if (VESA_MODE(adp->va_mode)) {
if (!VESA_MODE(mode) &&
(*prevvidsw->get_info)(adp, mode, &info) == 0) {
+ if ((adp->va_flags & V_ADP_DAC8) != 0) {
+ vesa_bios_set_dac(6);
+ adp->va_flags &= ~V_ADP_DAC8;
+ }
int10_set_mode(adp->va_initial_bios_mode);
if (adp->va_info.vi_flags & V_INFO_LINEAR)
pmap_unmapdev(adp->va_buffer,
@@ -1188,8 +1236,14 @@ vesa_set_mode(video_adapter_t *adp, int mode)
if (vesa_bios_set_mode(mode | ((info.vi_flags & V_INFO_LINEAR) ? 0x4000 : 0)))
return (1);
- if ((vesa_adp_info->v_flags & V_DAC8) != 0)
- vesa_bios_set_dac(8);
+ /* Palette format is reset by the above VBE function call. */
+ adp->va_flags &= ~V_ADP_DAC8;
+
+ if ((vesa_adp_info->v_flags & V_DAC8) != 0 &&
+ (info.vi_flags & V_INFO_GRAPHICS) != 0 &&
+ (info.vi_flags & V_INFO_NONVGA) != 0 &&
+ vesa_bios_set_dac(8) > 6)
+ adp->va_flags |= V_ADP_DAC8;
if (adp->va_info.vi_flags & V_INFO_LINEAR)
pmap_unmapdev(adp->va_buffer, adp->va_buffer_size);
@@ -1268,10 +1322,10 @@ vesa_save_palette(video_adapter_t *adp, u_char *palette)
{
int bits;
- if (adp == vesa_adp && VESA_MODE(adp->va_mode)) {
- bits = vesa_bios_get_dac();
- if ((adp->va_info.vi_flags & V_INFO_NONVGA) != 0 || bits > 6)
- return (vesa_bios_save_palette(0, 256, palette, bits));
+ if (adp == vesa_adp && VESA_MODE(adp->va_mode) &&
+ (adp->va_info.vi_flags & V_INFO_NONVGA) != 0) {
+ bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6;
+ return (vesa_bios_save_palette(0, 256, palette, bits));
}
return ((*prevvidsw->save_palette)(adp, palette));
@@ -1282,10 +1336,10 @@ vesa_load_palette(video_adapter_t *adp, u_char *palette)
{
int bits;
- if (adp == vesa_adp && VESA_MODE(adp->va_mode)) {
- bits = vesa_bios_get_dac();
- if ((adp->va_info.vi_flags & V_INFO_NONVGA) != 0 || bits > 6)
- return (vesa_bios_load_palette(0, 256, palette, bits));
+ if (adp == vesa_adp && VESA_MODE(adp->va_mode) &&
+ (adp->va_info.vi_flags & V_INFO_NONVGA) != 0) {
+ bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6;
+ return (vesa_bios_load_palette(0, 256, palette, bits));
}
return ((*prevvidsw->load_palette)(adp, palette));
@@ -1490,10 +1544,10 @@ get_palette(video_adapter_t *adp, int base, int count,
return (1);
if (!VESA_MODE(adp->va_mode))
return (1);
- bits = vesa_bios_get_dac();
- if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0 && bits <= 6)
+ if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0)
return (1);
+ bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6;
r = malloc(count * 3, M_DEVBUF, M_WAITOK);
g = r + count;
b = g + count;
@@ -1528,10 +1582,10 @@ set_palette(video_adapter_t *adp, int base, int count,
return (1);
if (!VESA_MODE(adp->va_mode))
return (1);
- bits = vesa_bios_get_dac();
- if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0 && bits <= 6)
+ if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0)
return (1);
+ bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6;
r = malloc(count * 3, M_DEVBUF, M_WAITOK);
g = r + count;
b = g + count;
@@ -1749,7 +1803,6 @@ vesa_unload(void)
{
u_char palette[256*3];
int error;
- int bits;
int s;
/* if the adapter is currently in a VESA mode, don't unload */
@@ -1763,15 +1816,11 @@ vesa_unload(void)
s = spltty();
if ((error = vesa_unload_ioctl()) == 0) {
if (vesa_adp != NULL) {
- if (vesa_adp_info->v_flags & V_DAC8) {
- bits = vesa_bios_get_dac();
- if (bits > 6) {
- vesa_bios_save_palette(0, 256,
- palette, bits);
- vesa_bios_set_dac(6);
- vesa_bios_load_palette(0, 256,
- palette, 6);
- }
+ if ((vesa_adp->va_flags & V_ADP_DAC8) != 0) {
+ vesa_bios_save_palette(0, 256, palette, 8);
+ vesa_bios_set_dac(6);
+ vesa_adp->va_flags &= ~V_ADP_DAC8;
+ vesa_bios_load_palette(0, 256, palette, 6);
}
vesa_adp->va_flags &= ~V_ADP_VESA;
vidsw[vesa_adp->va_index] = prevvidsw;
diff --git a/sys/dev/gem/if_gem.c b/sys/dev/gem/if_gem.c
index 9456383..7cba6e7 100644
--- a/sys/dev/gem/if_gem.c
+++ b/sys/dev/gem/if_gem.c
@@ -297,8 +297,11 @@ gem_attach(struct gem_softc *sc)
/*
* Fall back on an internal PHY if no external PHY was found.
+ * Note that with Apple (K2) GMACs GEM_MIF_CONFIG_MDI0 can't be
+ * trusted when the firmware has powered down the chip.
*/
- if (error != 0 && (v & GEM_MIF_CONFIG_MDI0) != 0) {
+ if (error != 0 &&
+ ((v & GEM_MIF_CONFIG_MDI0) != 0 || GEM_IS_APPLE(sc))) {
v &= ~GEM_MIF_CONFIG_PHY_SEL;
GEM_BANK1_WRITE_4(sc, GEM_MIF_CONFIG, v);
switch (sc->sc_variant) {
diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c
index 1945e4f..65e5d86 100644
--- a/sys/dev/isp/isp.c
+++ b/sys/dev/isp/isp.c
@@ -108,10 +108,11 @@ static const uint8_t alpa_map[] = {
* Local function prototypes.
*/
static int isp_parse_async(ispsoftc_t *, uint16_t);
+static int isp_parse_async_fc(ispsoftc_t *, uint16_t);
static int isp_handle_other_response(ispsoftc_t *, int, isphdr_t *, uint32_t *);
static void isp_parse_status(ispsoftc_t *, ispstatusreq_t *, XS_T *, long *); static void
isp_parse_status_24xx(ispsoftc_t *, isp24xx_statusreq_t *, XS_T *, long *);
-static void isp_fastpost_complete(ispsoftc_t *, uint16_t);
+static void isp_fastpost_complete(ispsoftc_t *, uint32_t);
static int isp_mbox_continue(ispsoftc_t *);
static void isp_scsi_init(ispsoftc_t *);
static void isp_scsi_channel_init(ispsoftc_t *, int);
@@ -1334,23 +1335,24 @@ isp_scsi_init(ispsoftc_t *isp)
}
/*
- * Turn on Fast Posting, LVD transitions
+ * Turn on LVD transitions for ULTRA2 or better and other features
*
- * Ultra2 F/W always has had fast posting (and LVD transitions)
- *
- * Ultra and older (i.e., SBus) cards may not. It's just safer
- * to assume not for them.
+ * Now that we have 32 bit handles, don't do any fast posting
+ * any more. For Ultra2/Ultra3 cards, we can turn on 32 bit RIO
+ * operation or use fast posting. To be conservative, we'll only
+ * do this for Ultra3 cards now because the other cards are so
+ * rare for this author to find and test with.
*/
MBSINIT(&mbs, MBOX_SET_FW_FEATURES, MBLOGALL, 0);
if (IS_ULTRA2(isp))
mbs.param[1] |= FW_FEATURE_LVD_NOTIFY;
-#ifndef ISP_NO_RIO
- if (IS_ULTRA2(isp) || IS_1240(isp))
- mbs.param[1] |= FW_FEATURE_RIO_16BIT;
-#else
- if (IS_ULTRA2(isp) || IS_1240(isp))
+#ifdef ISP_NO_RIO
+ if (IS_ULTRA3(isp))
mbs.param[1] |= FW_FEATURE_FAST_POST;
+#else
+ if (IS_ULTRA3(isp))
+ mbs.param[1] |= FW_FEATURE_RIO_32BIT;
#endif
if (mbs.param[1] != 0) {
uint16_t sfeat = mbs.param[1];
@@ -1604,25 +1606,15 @@ isp_fibre_init(ispsoftc_t *isp)
}
if (IS_2200(isp)) {
/*
- * There seems to just be too much breakage here
- * with RIO and Fast Posting- it probably actually
- * works okay but this driver is messing it up.
- * This card is really ancient by now, so let's
- * just opt for safety and not use the feature.
+ * We can't have Fast Posting any more- we now
+ * have 32 bit handles.
+ *
+ * RIO seemed to have to much breakage.
+ *
+ * Just opt for safety.
*/
-#if 0
- if (ISP_FW_NEWER_THAN(isp, 1, 17, 0)) {
- icbp->icb_xfwoptions |= ICBXOPT_RIO_16BIT;
- icbp->icb_fwoptions &= ~ICBOPT_FAST_POST;
- icbp->icb_racctimer = 4;
- icbp->icb_idelaytimer = 8;
- } else {
- icbp->icb_fwoptions |= ICBOPT_FAST_POST;
- }
-#else
icbp->icb_xfwoptions &= ~ICBXOPT_RIO_16BIT;
icbp->icb_fwoptions &= ~ICBOPT_FAST_POST;
-#endif
} else {
/*
* QLogic recommends that FAST Posting be turned
@@ -2182,9 +2174,7 @@ isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags
msg = "no Exchange Control Block";
break;
case PLOGX_IOCBERR_FAILED:
- ISP_SNPRINTF(buf, sizeof (buf),
- "reason 0x%x (last LOGIN state 0x%x)",
- parm1 & 0xff, (parm1 >> 8) & 0xff);
+ ISP_SNPRINTF(buf, sizeof (buf), "reason 0x%x (last LOGIN state 0x%x)", parm1 & 0xff, (parm1 >> 8) & 0xff);
msg = buf;
break;
case PLOGX_IOCBERR_NOFABRIC:
@@ -2194,8 +2184,7 @@ isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags
msg = "firmware not ready";
break;
case PLOGX_IOCBERR_NOLOGIN:
- ISP_SNPRINTF(buf, sizeof (buf), "not logged in (last state 0x%x)",
- parm1);
+ ISP_SNPRINTF(buf, sizeof (buf), "not logged in (last state 0x%x)", parm1);
msg = buf;
rval = MBOX_NOT_LOGGED_IN;
break;
@@ -2207,21 +2196,18 @@ isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags
msg = "no PCB allocated";
break;
case PLOGX_IOCBERR_EINVAL:
- ISP_SNPRINTF(buf, sizeof (buf), "invalid parameter at offset 0x%x",
- parm1);
+ ISP_SNPRINTF(buf, sizeof (buf), "invalid parameter at offset 0x%x", parm1);
msg = buf;
break;
case PLOGX_IOCBERR_PORTUSED:
lev = ISP_LOGSANCFG|ISP_LOGDEBUG0;
- ISP_SNPRINTF(buf, sizeof (buf),
- "already logged in with N-Port handle 0x%x", parm1);
+ ISP_SNPRINTF(buf, sizeof (buf), "already logged in with N-Port handle 0x%x", parm1);
msg = buf;
rval = MBOX_PORT_ID_USED | (parm1 << 16);
break;
case PLOGX_IOCBERR_HNDLUSED:
lev = ISP_LOGSANCFG|ISP_LOGDEBUG0;
- ISP_SNPRINTF(buf, sizeof (buf),
- "handle already used for PortID 0x%06x", parm1);
+ ISP_SNPRINTF(buf, sizeof (buf), "handle already used for PortID 0x%06x", parm1);
msg = buf;
rval = MBOX_LOOP_ID_USED;
break;
@@ -2232,15 +2218,12 @@ isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags
msg = "no FLOGI_ACC";
break;
default:
- ISP_SNPRINTF(buf, sizeof (buf), "status %x from %x",
- plp->plogx_status, flags);
+ ISP_SNPRINTF(buf, sizeof (buf), "status %x from %x", plp->plogx_status, flags);
msg = buf;
break;
}
if (msg) {
- isp_prt(isp, ISP_LOGERR,
- "Chan %d PLOGX PortID 0x%06x to N-Port handle 0x%x: %s",
- chan, portid, handle, msg);
+ isp_prt(isp, ISP_LOGERR, "Chan %d PLOGX PortID 0x%06x to N-Port handle 0x%x: %s", chan, portid, handle, msg);
}
out:
if (gs == 0) {
@@ -3901,8 +3884,7 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
* Find an unused handle and try and use to login to a port.
*/
static int
-isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p,
- uint16_t *ohp)
+isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, uint16_t *ohp)
{
int lim, i, r;
uint16_t handle;
@@ -3922,8 +3904,7 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p,
*/
r = isp_getpdb(isp, chan, handle, p, 0);
if (r == 0 && p->portid != portid) {
- (void) isp_plogx(isp, chan, handle, portid,
- PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT, 1);
+ (void) isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT | PLOGX_FLG_FREE_NPHDL, 1);
} else if (r == 0) {
break;
}
@@ -3933,8 +3914,7 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p,
/*
* Now try and log into the device
*/
- r = isp_plogx(isp, chan, handle, portid,
- PLOGX_FLG_CMD_PLOGI, 1);
+ r = isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_PLOGI, 1);
if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) {
return (-1);
}
@@ -3942,7 +3922,26 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p,
*ohp = handle;
break;
} else if ((r & 0xffff) == MBOX_PORT_ID_USED) {
- handle = r >> 16;
+ /*
+ * If we get here, then the firmwware still thinks we're logged into this device, but with a different
+ * handle. We need to break that association. We used to try and just substitute the handle, but then
+ * failed to get any data via isp_getpdb (below).
+ */
+ if (isp_plogx(isp, chan, r >> 16, portid, PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT | PLOGX_FLG_FREE_NPHDL, 1)) {
+ isp_prt(isp, ISP_LOGERR, "baw... logout of %x failed", r >> 16);
+ }
+ if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) {
+ return (-1);
+ }
+ r = isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_PLOGI, 1);
+ if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) {
+ return (-1);
+ }
+ if (r == 0) {
+ *ohp = handle;
+ } else {
+ i = lim;
+ }
break;
} else if (r != MBOX_LOOP_ID_USED) {
i = lim;
@@ -3956,8 +3955,7 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p,
}
if (i == lim) {
- isp_prt(isp, ISP_LOGWARN, "Chan %d PLOGI 0x%06x failed",
- chan, portid);
+ isp_prt(isp, ISP_LOGWARN, "Chan %d PLOGI 0x%06x failed", chan, portid);
return (-1);
}
@@ -3971,15 +3969,12 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p,
return (-1);
}
if (r != 0) {
- isp_prt(isp, ISP_LOGERR,
- "Chan %d new device 0x%06x@0x%x disappeared",
- chan, portid, handle);
+ isp_prt(isp, ISP_LOGERR, "Chan %d new device 0x%06x@0x%x disappeared", chan, portid, handle);
return (-1);
}
if (p->handle != handle || p->portid != portid) {
- isp_prt(isp, ISP_LOGERR,
- "Chan %d new device 0x%06x@0x%x changed (0x%06x@0x%0x)",
+ isp_prt(isp, ISP_LOGERR, "Chan %d new device 0x%06x@0x%x changed (0x%06x@0x%0x)",
chan, portid, handle, p->portid, p->handle);
return (-1);
}
@@ -4860,7 +4855,7 @@ again:
*/
if (sema) {
fmbox:
- if (mbox & 0x4000) {
+ if (mbox & MBOX_COMMAND_COMPLETE) {
isp->isp_intmboxc++;
if (isp->isp_mboxbsy) {
int obits = isp->isp_obits;
@@ -4880,10 +4875,13 @@ again:
} else {
isp_prt(isp, ISP_LOGWARN, "mailbox cmd (0x%x) with no waiters", mbox);
}
- } else if (isp_parse_async(isp, mbox) < 0) {
- return;
+ } else {
+ i = IS_FC(isp)? isp_parse_async_fc(isp, mbox) : isp_parse_async(isp, mbox);
+ if (i < 0) {
+ return;
+ }
}
- if ((IS_FC(isp) && mbox != ASYNC_RIO_RESP) || isp->isp_state != ISP_RUNSTATE) {
+ if ((IS_FC(isp) && mbox != ASYNC_RIOZIO_STALL) || isp->isp_state != ISP_RUNSTATE) {
goto out;
}
}
@@ -5065,9 +5063,9 @@ again:
req_status_flags = sp->req_status_flags;
req_state_flags = sp->req_state_flags;
resid = sp->req_resid;
- } else if (etype == RQSTYPE_RIO2) {
- isp_rio2_t *rio = (isp_rio2_t *)qe;
- isp_get_rio2(isp, (isp_rio2_t *) hp, rio);
+ } else if (etype == RQSTYPE_RIO1) {
+ isp_rio1_t *rio = (isp_rio1_t *) qe;
+ isp_get_rio1(isp, (isp_rio1_t *) hp, rio);
if (isp->isp_dblev & ISP_LOGDEBUG1) {
isp_print_bytes(isp, "Response Queue Entry", QENTRY_LEN, rio);
}
@@ -5079,6 +5077,10 @@ again:
}
ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */
continue;
+ } else if (etype == RQSTYPE_RIO2) {
+ isp_prt(isp, ISP_LOGERR, "dropping RIO2 response\n");
+ ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */
+ continue;
} else {
/*
* Somebody reachable via isp_handle_other_response
@@ -5391,40 +5393,35 @@ out:
* Support routines.
*/
-#define GET_24XX_BUS(isp, chan, msg) \
- if (IS_24XX(isp)) { \
- chan = ISP_READ(isp, OUTMAILBOX3) & 0xff; \
- if (chan >= isp->isp_nchan) { \
- isp_prt(isp, ISP_LOGERR, "bogus channel %u for %s at line %d", chan, msg, __LINE__); \
- break; \
- } \
- }
-
+/*
+ * Parse an ASYNC mailbox complete
+ *
+ * Return non-zero if the event has been acknowledged.
+ */
static int
isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
{
- int rval = 0;
- int pattern = 0;
- uint16_t chan;
+ int acked = 0;
+ uint32_t h1 = 0, h2 = 0;
+ uint16_t chan = 0;
- if (IS_DUALBUS(isp)) {
- chan = ISP_READ(isp, OUTMAILBOX6);
- } else {
- chan = 0;
+ /*
+ * Pick up the channel, but not if this is a ASYNC_RIO32_2,
+ * where Mailboxes 6/7 have the second handle.
+ */
+ if (mbox != ASYNC_RIO32_2) {
+ if (IS_DUALBUS(isp)) {
+ chan = ISP_READ(isp, OUTMAILBOX6);
+ }
}
isp_prt(isp, ISP_LOGDEBUG2, "Async Mbox 0x%x", mbox);
switch (mbox) {
case ASYNC_BUS_RESET:
- if (IS_FC(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "ILLEGAL ASYNC_BUS_RESET for FC card");
- break;
- }
ISP_SET_SENDMARKER(isp, chan, 1);
#ifdef ISP_TARGET_MODE
if (isp_target_async(isp, chan, mbox)) {
- rval = -1;
+ acked = 1;
}
#endif
isp_async(isp, ISPASYNC_BUS_RESET, chan);
@@ -5432,10 +5429,6 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
case ASYNC_SYSTEM_ERROR:
isp->isp_dead = 1;
isp->isp_state = ISP_CRASHED;
- if (IS_FC(isp)) {
- FCPARAM(isp, chan)->isp_loopstate = LOOP_NIL;
- FCPARAM(isp, chan)->isp_fwstate = FW_CONFIG_WAIT;
- }
/*
* Were we waiting for a mailbox command to complete?
* If so, it's dead, so wake up the waiter.
@@ -5450,7 +5443,7 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
* restart the firmware
*/
isp_async(isp, ISPASYNC_FW_CRASH);
- rval = -1;
+ acked = 1;
break;
case ASYNC_RQS_XFER_ERR:
@@ -5462,17 +5455,6 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
break;
case ASYNC_QWAKEUP:
-#ifdef ISP_TARGET_MODE
- if (IS_24XX(isp)) {
- isp_prt(isp, ISP_LOGERR, "ATIO Queue Transfer Error");
- break;
- }
-#endif
- if (IS_FC(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "ILLEGAL ASYNC_QWAKEUP for FC card");
- break;
- }
/*
* We've just been notified that the Queue has woken up.
* We don't need to be chatty about this- just unlatch things
@@ -5482,82 +5464,45 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
break;
case ASYNC_TIMEOUT_RESET:
- if (IS_FC(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "ILLEGAL ASYNC_TIMEOUT_RESET for FC card");
- break;
- }
- isp_prt(isp, ISP_LOGWARN,
- "timeout initiated SCSI bus reset of chan %d", chan);
+ isp_prt(isp, ISP_LOGWARN, "timeout initiated SCSI bus reset of chan %d", chan);
ISP_SET_SENDMARKER(isp, chan, 1);
#ifdef ISP_TARGET_MODE
if (isp_target_async(isp, chan, mbox)) {
- rval = -1;
+ acked = 1;
}
#endif
break;
case ASYNC_DEVICE_RESET:
- if (IS_FC(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "ILLEGAL DEVICE_RESET for FC card");
- break;
- }
isp_prt(isp, ISP_LOGINFO, "device reset on chan %d", chan);
ISP_SET_SENDMARKER(isp, chan, 1);
#ifdef ISP_TARGET_MODE
if (isp_target_async(isp, chan, mbox)) {
- rval = -1;
+ acked = 1;
}
#endif
break;
case ASYNC_EXTMSG_UNDERRUN:
- if (IS_FC(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "ILLEGAL ASYNC_EXTMSG_UNDERRUN for FC card");
- break;
- }
isp_prt(isp, ISP_LOGWARN, "extended message underrun");
break;
case ASYNC_SCAM_INT:
- if (IS_FC(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "ILLEGAL ASYNC_SCAM_INT for FC card");
- break;
- }
isp_prt(isp, ISP_LOGINFO, "SCAM interrupt");
break;
case ASYNC_HUNG_SCSI:
- if (IS_FC(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "ILLEGAL ASYNC_HUNG_SCSI for FC card");
- break;
- }
- isp_prt(isp, ISP_LOGERR,
- "stalled SCSI Bus after DATA Overrun");
+ isp_prt(isp, ISP_LOGERR, "stalled SCSI Bus after DATA Overrun");
/* XXX: Need to issue SCSI reset at this point */
break;
case ASYNC_KILLED_BUS:
- if (IS_FC(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "ILLEGAL ASYNC_KILLED_BUS for FC card");
- break;
- }
isp_prt(isp, ISP_LOGERR, "SCSI Bus reset after DATA Overrun");
break;
case ASYNC_BUS_TRANSIT:
- if (IS_FC(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "ILLEGAL ASYNC_BUS_TRANSIT for FC card");
- break;
- }
mbox = ISP_READ(isp, OUTMAILBOX2);
- switch (mbox & 0x1c00) {
+ switch (mbox & SXP_PINS_MODE_MASK) {
case SXP_PINS_LVD_MODE:
isp_prt(isp, ISP_LOGINFO, "Transition to LVD mode");
SDPARAM(isp, chan)->isp_diffmode = 0;
@@ -5590,70 +5535,142 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
ISP_SET_SENDMARKER(isp, chan, 1);
break;
- case ASYNC_RIO5:
- pattern = 0xce; /* outgoing mailbox regs 1-3, 6-7 */
+ case ASYNC_CMD_CMPLT:
+ case ASYNC_RIO32_1:
+ if (!IS_ULTRA3(isp)) {
+ isp_prt(isp, ISP_LOGERR, "unexpected fast posting completion");
+ break;
+ }
+ /* FALLTHROUGH */
+ h1 = (ISP_READ(isp, OUTMAILBOX2) << 16) | ISP_READ(isp, OUTMAILBOX1);
+ break;
+
+ case ASYNC_RIO32_2:
+ h1 = (ISP_READ(isp, OUTMAILBOX2) << 16) | ISP_READ(isp, OUTMAILBOX1);
+ h2 = (ISP_READ(isp, OUTMAILBOX7) << 16) | ISP_READ(isp, OUTMAILBOX6);
+ break;
+
+ case ASYNC_RIO16_5:
+ case ASYNC_RIO16_4:
+ case ASYNC_RIO16_3:
+ case ASYNC_RIO16_2:
+ case ASYNC_RIO16_1:
+ isp_prt(isp, ISP_LOGERR, "unexpected 16 bit RIO handle");
+ break;
+ default:
+ isp_prt(isp, ISP_LOGWARN, "%s: unhandled async code 0x%x", __func__, mbox);
+ break;
+ }
+
+ if (h1 || h2) {
+ isp_prt(isp, ISP_LOGDEBUG3, "fast post/rio completion of 0x%08x", h1);
+ isp_fastpost_complete(isp, h1);
+ if (h2) {
+ isp_prt(isp, ISP_LOGDEBUG3, "fast post/rio completion of 0x%08x", h2);
+ isp_fastpost_complete(isp, h2);
+ if (isp->isp_fpcchiwater < 2) {
+ isp->isp_fpcchiwater = 2;
+ }
+ } else {
+ if (isp->isp_fpcchiwater < 1) {
+ isp->isp_fpcchiwater = 1;
+ }
+ }
+ } else {
+ isp->isp_intoasync++;
+ }
+ return (acked);
+}
+
+#define GET_24XX_BUS(isp, chan, msg) \
+ if (IS_24XX(isp)) { \
+ chan = ISP_READ(isp, OUTMAILBOX3) & 0xff; \
+ if (chan >= isp->isp_nchan) { \
+ isp_prt(isp, ISP_LOGERR, "bogus channel %u for %s at line %d", chan, msg, __LINE__); \
+ break; \
+ } \
+ }
+
+
+static int
+isp_parse_async_fc(ispsoftc_t *isp, uint16_t mbox)
+{
+ int acked = 0;
+ uint16_t chan;
+
+ if (IS_DUALBUS(isp)) {
+ chan = ISP_READ(isp, OUTMAILBOX6);
+ } else {
+ chan = 0;
+ }
+ isp_prt(isp, ISP_LOGDEBUG2, "Async Mbox 0x%x", mbox);
+
+ switch (mbox) {
+ case ASYNC_SYSTEM_ERROR:
+ isp->isp_dead = 1;
+ isp->isp_state = ISP_CRASHED;
+ FCPARAM(isp, chan)->isp_loopstate = LOOP_NIL;
+ FCPARAM(isp, chan)->isp_fwstate = FW_CONFIG_WAIT;
+ /*
+ * Were we waiting for a mailbox command to complete?
+ * If so, it's dead, so wake up the waiter.
+ */
+ if (isp->isp_mboxbsy) {
+ isp->isp_obits = 1;
+ isp->isp_mboxtmp[0] = MBOX_HOST_INTERFACE_ERROR;
+ MBOX_NOTIFY_COMPLETE(isp);
+ }
+ /*
+ * It's up to the handler for isp_async to reinit stuff and
+ * restart the firmware
+ */
+ isp_async(isp, ISPASYNC_FW_CRASH);
+ acked = 1;
break;
- case ASYNC_RIO4:
- pattern = 0x4e; /* outgoing mailbox regs 1-3, 6 */
+ case ASYNC_RQS_XFER_ERR:
+ isp_prt(isp, ISP_LOGERR, "Request Queue Transfer Error");
break;
- case ASYNC_RIO3:
- pattern = 0x0e; /* outgoing mailbox regs 1-3 */
+ case ASYNC_RSP_XFER_ERR:
+ isp_prt(isp, ISP_LOGERR, "Response Queue Transfer Error");
break;
- case ASYNC_RIO2:
- pattern = 0x06; /* outgoing mailbox regs 1-2 */
+ case ASYNC_QWAKEUP:
+#ifdef ISP_TARGET_MODE
+ if (IS_24XX(isp)) {
+ isp_prt(isp, ISP_LOGERR, "ATIO Queue Transfer Error");
+ break;
+ }
+#endif
+ isp_prt(isp, ISP_LOGERR, "%s: unexpected ASYNC_QWAKEUP code", __func__);
break;
- case ASYNC_RIO1:
case ASYNC_CMD_CMPLT:
- pattern = 0x02; /* outgoing mailbox regs 1 */
+ isp_fastpost_complete(isp, (ISP_READ(isp, OUTMAILBOX2) << 16) | ISP_READ(isp, OUTMAILBOX1));
+ if (isp->isp_fpcchiwater < 1) {
+ isp->isp_fpcchiwater = 1;
+ }
break;
- case ASYNC_RIO_RESP:
- return (rval);
+ case ASYNC_RIOZIO_STALL:
+ break;
case ASYNC_CTIO_DONE:
- {
#ifdef ISP_TARGET_MODE
- int handle;
- if (IS_SCSI(isp) || IS_24XX(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "bad ASYNC_CTIO_DONE for %s cards",
- IS_SCSI(isp)? "SCSI" : "24XX");
- break;
- }
- handle =
- (ISP_READ(isp, OUTMAILBOX2) << 16) |
- (ISP_READ(isp, OUTMAILBOX1));
- if (isp_target_async(isp, handle, mbox)) {
- rval = -1;
+ if (isp_target_async(isp, (ISP_READ(isp, OUTMAILBOX2) << 16) | ISP_READ(isp, OUTMAILBOX1), mbox)) {
+ acked = 1;
} else {
- /* count it as a fast posting intr */
isp->isp_fphccmplt++;
}
#else
- if (IS_SCSI(isp) || IS_24XX(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "bad ASYNC_CTIO_DONE for %s cards",
- IS_SCSI(isp)? "SCSI" : "24XX");
- break;
- }
- isp_prt(isp, ISP_LOGINFO, "Fast Posting CTIO done");
- isp->isp_fphccmplt++; /* count it as a fast posting intr */
+ isp_prt(isp, ISP_LOGWARN, "unexpected ASYNC CTIO done");
#endif
break;
- }
case ASYNC_LIP_ERROR:
case ASYNC_LIP_F8:
case ASYNC_LIP_OCCURRED:
case ASYNC_PTPMODE:
- if (IS_SCSI(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "bad LIP event for SCSI cards");
- break;
- }
/*
* These are broadcast events that have to be sent across
* all active channels.
@@ -5673,7 +5690,7 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
isp_async(isp, ISPASYNC_LIP, chan);
#ifdef ISP_TARGET_MODE
if (isp_target_async(isp, chan, mbox)) {
- rval = -1;
+ acked = 1;
}
#endif
/*
@@ -5708,11 +5725,6 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
break;
case ASYNC_LOOP_UP:
- if (IS_SCSI(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "bad LOOP UP event for SCSI cards");
- break;
- }
/*
* This is a broadcast event that has to be sent across
* all active channels.
@@ -5732,18 +5744,13 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
isp_async(isp, ISPASYNC_LOOP_UP, chan);
#ifdef ISP_TARGET_MODE
if (isp_target_async(isp, chan, mbox)) {
- rval = -1;
+ acked = 1;
}
#endif
}
break;
case ASYNC_LOOP_DOWN:
- if (IS_SCSI(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "bad LOOP DOWN event for SCSI cards");
- break;
- }
/*
* This is a broadcast event that has to be sent across
* all active channels.
@@ -5762,18 +5769,13 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
isp_async(isp, ISPASYNC_LOOP_DOWN, chan);
#ifdef ISP_TARGET_MODE
if (isp_target_async(isp, chan, mbox)) {
- rval = -1;
+ acked = 1;
}
#endif
}
break;
case ASYNC_LOOP_RESET:
- if (IS_SCSI(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "bad LIP RESET event for SCSI cards");
- break;
- }
/*
* This is a broadcast event that has to be sent across
* all active channels.
@@ -5792,7 +5794,7 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
isp_async(isp, ISPASYNC_LOOP_RESET, chan);
#ifdef ISP_TARGET_MODE
if (isp_target_async(isp, chan, mbox)) {
- rval = -1;
+ acked = 1;
}
#endif
}
@@ -5801,11 +5803,6 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
case ASYNC_PDB_CHANGED:
{
int nphdl, nlstate, reason;
- if (IS_SCSI(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "bad PDB CHANGED event for SCSI cards");
- break;
- }
/*
* We *should* get a channel out of the 24XX, but we don't seem
* to get more than a PDB CHANGED on channel 0, so turn it into
@@ -5828,8 +5825,7 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
ISP_SET_SENDMARKER(isp, chan, 1);
fcp->isp_loopstate = LOOP_PDB_RCVD;
ISP_MARK_PORTDB(isp, chan, 1);
- isp_async(isp, ISPASYNC_CHANGE_NOTIFY, chan,
- ISPASYNC_CHANGE_PDB, nphdl, nlstate, reason);
+ isp_async(isp, ISPASYNC_CHANGE_NOTIFY, chan, ISPASYNC_CHANGE_PDB, nphdl, nlstate, reason);
}
break;
}
@@ -5837,11 +5833,6 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
{
int lochan, hichan;
- if (IS_SCSI(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "bad CHANGE NOTIFY event for SCSI cards");
- break;
- }
if (ISP_FW_NEWER_THAN(isp, 4, 0, 25) && ISP_CAP_MULTI_ID(isp)) {
GET_24XX_BUS(isp, chan, "ASYNC_CHANGE_NOTIFY");
lochan = chan;
@@ -5863,8 +5854,7 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
fcp->isp_loopstate = LOOP_PDB_RCVD;
}
ISP_MARK_PORTDB(isp, chan, 1);
- isp_async(isp, ISPASYNC_CHANGE_NOTIFY, chan,
- ISPASYNC_CHANGE_SNS);
+ isp_async(isp, ISPASYNC_CHANGE_NOTIFY, chan, ISPASYNC_CHANGE_SNS);
}
break;
}
@@ -5874,8 +5864,7 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
* This only applies to 2100 amd 2200 cards
*/
if (!IS_2200(isp) && !IS_2100(isp)) {
- isp_prt(isp, ISP_LOGWARN,
- "bad card for ASYNC_CONNMODE event");
+ isp_prt(isp, ISP_LOGWARN, "bad card for ASYNC_CONNMODE event");
break;
}
chan = 0;
@@ -5909,8 +5898,7 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
"Unknown connection mode (0x%x)", mbox);
break;
}
- isp_async(isp, ISPASYNC_CHANGE_NOTIFY, chan,
- ISPASYNC_CHANGE_OTHER);
+ isp_async(isp, ISPASYNC_CHANGE_NOTIFY, chan, ISPASYNC_CHANGE_OTHER);
FCPARAM(isp, chan)->sendmarker = 1;
FCPARAM(isp, chan)->isp_fwstate = FW_CONFIG_WAIT;
FCPARAM(isp, chan)->isp_loopstate = LOOP_LIP_RCVD;
@@ -5920,8 +5908,7 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
if (IS_24XX(isp)) {
isp_prt(isp, ISP_LOGWARN, "Receive Error");
} else {
- isp_prt(isp, ISP_LOGWARN,
- "Unknown Async Code 0x%x", mbox);
+ isp_prt(isp, ISP_LOGWARN, "unexpected ASYNC_RCV_ERR");
}
break;
case ASYNC_RJT_SENT: /* same as ASYNC_QFULL_SENT */
@@ -5937,29 +5924,10 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox)
isp_prt(isp, ISP_LOGWARN, "Unknown Async Code 0x%x", mbox);
break;
}
-
- if (pattern) {
- int i, nh;
- uint16_t handles[16];
-
- for (nh = 0, i = 1; i < MAX_MAILBOX(isp); i++) {
- if ((pattern & (1 << i)) == 0) {
- continue;
- }
- handles[nh++] = ISP_READ(isp, MBOX_OFF(i));
- }
- for (i = 0; i < nh; i++) {
- isp_fastpost_complete(isp, handles[i]);
- isp_prt(isp, ISP_LOGDEBUG3,
- "fast post completion of %u", handles[i]);
- }
- if (isp->isp_fpcchiwater < nh) {
- isp->isp_fpcchiwater = nh;
- }
- } else {
+ if (mbox != ASYNC_CTIO_DONE && mbox != ASYNC_CMD_CMPLT) {
isp->isp_intoasync++;
}
- return (rval);
+ return (acked);
}
/*
@@ -6591,7 +6559,7 @@ isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp,
}
static void
-isp_fastpost_complete(ispsoftc_t *isp, uint16_t fph)
+isp_fastpost_complete(ispsoftc_t *isp, uint32_t fph)
{
XS_T *xs;
@@ -7679,7 +7647,6 @@ isp_setdfltfcparm(ispsoftc_t *isp, int chan)
fcp->isp_fwoptions |= ICBOPT_FAIRNESS;
fcp->isp_fwoptions |= ICBOPT_PDBCHANGE_AE;
fcp->isp_fwoptions |= ICBOPT_HARD_ADDRESS;
- fcp->isp_fwoptions |= ICBOPT_FAST_POST;
if (isp->isp_confopts & ISP_CFG_FULL_DUPLEX) {
fcp->isp_fwoptions |= ICBOPT_FULL_DUPLEX;
}
diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c
index cd6ec09..902c827 100644
--- a/sys/dev/isp/isp_freebsd.c
+++ b/sys/dev/isp/isp_freebsd.c
@@ -2304,7 +2304,8 @@ isp_handle_platform_ctio(ispsoftc_t *isp, void *arg)
uint32_t tval, handle;
/*
- * CTIO, CTIO2 and CTIO7 are close enough....
+ * CTIO handles are 16 bits.
+ * CTIO2 and CTIO7 are 32 bits.
*/
if (IS_SCSI(isp)) {
@@ -3892,7 +3893,12 @@ isp_make_here(ispsoftc_t *isp, int chan, int tgt)
isp_prt(isp, ISP_LOGWARN, "Chan %d unable to alloc CCB for rescan", chan);
return;
}
- if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(fc->sim), tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
+ /*
+ * xpt_rescan only honors wildcard in the target field.
+ * Scan the whole bus instead of target, which will then
+ * force a scan of all luns.
+ */
+ if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(fc->sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
isp_prt(isp, ISP_LOGWARN, "unable to create path for rescan");
xpt_free_ccb(ccb);
return;
diff --git a/sys/dev/isp/isp_library.c b/sys/dev/isp/isp_library.c
index 57b8400..43c161d 100644
--- a/sys/dev/isp/isp_library.c
+++ b/sys/dev/isp/isp_library.c
@@ -668,7 +668,7 @@ isp_clear_commands(ispsoftc_t *isp)
ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
} else {
ct_entry_t *ctio = (ct_entry_t *) local;
- ctio->ct_syshandle = hdp->handle & 0xffff;
+ ctio->ct_syshandle = hdp->handle;
ctio->ct_status = CT_HBA_RESET & 0xff;
ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO;
}
@@ -1132,17 +1132,36 @@ isp_get_24xx_abrt(ispsoftc_t *isp, isp24xx_abrt_t *src, isp24xx_abrt_t *dst)
void
+isp_get_rio1(ispsoftc_t *isp, isp_rio1_t *r1src, isp_rio1_t *r1dst)
+{
+ const int lim = sizeof (r1dst->req_handles) / sizeof (r1dst->req_handles[0]);
+ int i;
+ isp_get_hdr(isp, &r1src->req_header, &r1dst->req_header);
+ if (r1dst->req_header.rqs_seqno > lim) {
+ r1dst->req_header.rqs_seqno = lim;
+ }
+ for (i = 0; i < r1dst->req_header.rqs_seqno; i++) {
+ ISP_IOXGET_32(isp, &r1src->req_handles[i], r1dst->req_handles[i]);
+ }
+ while (i < lim) {
+ r1dst->req_handles[i++] = 0;
+ }
+}
+
+void
isp_get_rio2(ispsoftc_t *isp, isp_rio2_t *r2src, isp_rio2_t *r2dst)
{
+ const int lim = sizeof (r2dst->req_handles) / sizeof (r2dst->req_handles[0]);
int i;
+
isp_get_hdr(isp, &r2src->req_header, &r2dst->req_header);
- if (r2dst->req_header.rqs_seqno > 30) {
- r2dst->req_header.rqs_seqno = 30;
+ if (r2dst->req_header.rqs_seqno > lim) {
+ r2dst->req_header.rqs_seqno = lim;
}
for (i = 0; i < r2dst->req_header.rqs_seqno; i++) {
ISP_IOXGET_16(isp, &r2src->req_handles[i], r2dst->req_handles[i]);
}
- while (i < 30) {
+ while (i < lim) {
r2dst->req_handles[i++] = 0;
}
}
@@ -2240,7 +2259,13 @@ isp_allocate_xs_tgt(ispsoftc_t *isp, void *xs, uint32_t *handlep)
hdp->cmd = xs;
hdp->handle = (hdp - isp->isp_tgtlist);
hdp->handle |= (ISP_HANDLE_TARGET << ISP_HANDLE_USAGE_SHIFT);
- hdp->handle |= (isp->isp_seqno++ << ISP_HANDLE_SEQ_SHIFT);
+ /*
+ * Target handles for SCSI cards are only 16 bits, so
+ * sequence number protection will be ommitted.
+ */
+ if (IS_FC(isp)) {
+ hdp->handle |= (isp->isp_seqno++ << ISP_HANDLE_SEQ_SHIFT);
+ }
*handlep = hdp->handle;
return (0);
}
diff --git a/sys/dev/isp/isp_library.h b/sys/dev/isp/isp_library.h
index b055dd8..4e0c7f8 100644
--- a/sys/dev/isp/isp_library.h
+++ b/sys/dev/isp/isp_library.h
@@ -108,6 +108,7 @@ void isp_put_cont64_req(ispsoftc_t *, ispcontreq64_t *, ispcontreq64_t *);
void isp_get_response(ispsoftc_t *, ispstatusreq_t *, ispstatusreq_t *);
void isp_get_24xx_response(ispsoftc_t *, isp24xx_statusreq_t *, isp24xx_statusreq_t *);
void isp_get_24xx_abrt(ispsoftc_t *, isp24xx_abrt_t *, isp24xx_abrt_t *);
+void isp_get_rio1(ispsoftc_t *, isp_rio1_t *, isp_rio1_t *);
void isp_get_rio2(ispsoftc_t *, isp_rio2_t *, isp_rio2_t *);
void isp_put_icb(ispsoftc_t *, isp_icb_t *, isp_icb_t *);
void isp_put_icb_2400(ispsoftc_t *, isp_icb_2400_t *, isp_icb_2400_t *);
diff --git a/sys/dev/isp/isp_pci.c b/sys/dev/isp/isp_pci.c
index 4eb2e0c..547f48e 100644
--- a/sys/dev/isp/isp_pci.c
+++ b/sys/dev/isp/isp_pci.c
@@ -1068,8 +1068,7 @@ isp_pci_rd_isr(ispsoftc_t *isp, uint32_t *isrp, uint16_t *semap, uint16_t *mbp)
}
static int
-isp_pci_rd_isr_2300(ispsoftc_t *isp, uint32_t *isrp,
- uint16_t *semap, uint16_t *mbox0p)
+isp_pci_rd_isr_2300(ispsoftc_t *isp, uint32_t *isrp, uint16_t *semap, uint16_t *mbox0p)
{
uint32_t hccr;
uint32_t r2hisr;
@@ -1096,7 +1095,7 @@ isp_pci_rd_isr_2300(ispsoftc_t *isp, uint32_t *isrp,
return (1);
case ISPR2HST_RIO_16:
*isrp = r2hisr & 0xffff;
- *mbox0p = ASYNC_RIO1;
+ *mbox0p = ASYNC_RIO16_1;
*semap = 1;
return (1);
case ISPR2HST_FPOST:
@@ -1118,21 +1117,17 @@ isp_pci_rd_isr_2300(ispsoftc_t *isp, uint32_t *isrp,
hccr = ISP_READ(isp, HCCR);
if (hccr & HCCR_PAUSE) {
ISP_WRITE(isp, HCCR, HCCR_RESET);
- isp_prt(isp, ISP_LOGERR,
- "RISC paused at interrupt (%x->%x)", hccr,
- ISP_READ(isp, HCCR));
+ isp_prt(isp, ISP_LOGERR, "RISC paused at interrupt (%x->%x)", hccr, ISP_READ(isp, HCCR));
ISP_WRITE(isp, BIU_ICR, 0);
} else {
- isp_prt(isp, ISP_LOGERR, "unknown interrupt 0x%x\n",
- r2hisr);
+ isp_prt(isp, ISP_LOGERR, "unknown interrupt 0x%x\n", r2hisr);
}
return (0);
}
}
static int
-isp_pci_rd_isr_2400(ispsoftc_t *isp, uint32_t *isrp,
- uint16_t *semap, uint16_t *mbox0p)
+isp_pci_rd_isr_2400(ispsoftc_t *isp, uint32_t *isrp, uint16_t *semap, uint16_t *mbox0p)
{
uint32_t r2hisr;
@@ -1177,8 +1172,7 @@ isp_pci_rd_reg(ispsoftc_t *isp, int regoff)
* We will assume that someone has paused the RISC processor.
*/
oldconf = BXR2(isp, IspVirt2Off(isp, BIU_CONF1));
- BXW2(isp, IspVirt2Off(isp, BIU_CONF1),
- oldconf | BIU_PCI_CONF1_SXP);
+ BXW2(isp, IspVirt2Off(isp, BIU_CONF1), oldconf | BIU_PCI_CONF1_SXP);
MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, BIU_CONF1), 2);
}
rv = BXR2(isp, IspVirt2Off(isp, regoff));
@@ -1529,7 +1523,7 @@ isp_pci_mbxdma(ispsoftc_t *isp)
}
isp->isp_xffree = isp->isp_xflist;
#ifdef ISP_TARGET_MODE
- len = sizeof (isp_hdl_t *) * isp->isp_maxcmds;
+ len = sizeof (isp_hdl_t) * isp->isp_maxcmds;
isp->isp_tgtlist = (isp_hdl_t *) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
if (isp->isp_tgtlist == NULL) {
free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
diff --git a/sys/dev/isp/isp_target.c b/sys/dev/isp/isp_target.c
index 68c42b4..8707961 100644
--- a/sys/dev/isp/isp_target.c
+++ b/sys/dev/isp/isp_target.c
@@ -826,7 +826,9 @@ isp_target_async(ispsoftc_t *isp, int bus, int event)
ct_entry_t *ct = (ct_entry_t *) storage;
ct->ct_header.rqs_entry_type = RQSTYPE_CTIO;
ct->ct_status = CT_OK;
- ct->ct_fwhandle = bus;
+ ct->ct_syshandle = bus;
+ /* we skip fwhandle here */
+ ct->ct_fwhandle = 0;
ct->ct_flags = CT_SENDSTATUS;
}
isp_async(isp, ISPASYNC_TARGET_ACTION, storage);
diff --git a/sys/dev/isp/ispmbox.h b/sys/dev/isp/ispmbox.h
index eb3ab63..36a7391 100644
--- a/sys/dev/isp/ispmbox.h
+++ b/sys/dev/isp/ispmbox.h
@@ -223,6 +223,8 @@
#define ASYNC_SECURITY_UPDATE 0x801B
#define ASYNC_CMD_CMPLT 0x8020
#define ASYNC_CTIO_DONE 0x8021
+#define ASYNC_RIO32_1 0x8021
+#define ASYNC_RIO32_2 0x8022
#define ASYNC_IP_XMIT_DONE 0x8022
#define ASYNC_IP_RECV_DONE 0x8023
#define ASYNC_IP_BROADCAST 0x8024
@@ -230,19 +232,19 @@
#define ASYNC_IP_RCVQ_EMPTY 0x8026
#define ASYNC_IP_RECV_DONE_ALIGNED 0x8027
#define ASYNC_PTPMODE 0x8030
-#define ASYNC_RIO1 0x8031
-#define ASYNC_RIO2 0x8032
-#define ASYNC_RIO3 0x8033
-#define ASYNC_RIO4 0x8034
-#define ASYNC_RIO5 0x8035
+#define ASYNC_RIO16_1 0x8031
+#define ASYNC_RIO16_2 0x8032
+#define ASYNC_RIO16_3 0x8033
+#define ASYNC_RIO16_4 0x8034
+#define ASYNC_RIO16_5 0x8035
#define ASYNC_CONNMODE 0x8036
#define ISP_CONN_LOOP 1
#define ISP_CONN_PTP 2
#define ISP_CONN_BADLIP 3
#define ISP_CONN_FATAL 4
#define ISP_CONN_LOOPBACK 5
-#define ASYNC_RIO_RESP 0x8040
-#define ASYNC_RIO_COMP 0x8042
+#define ASYNC_RIOZIO_STALL 0x8040 /* there's a RIO/ZIO entry that hasn't been serviced */
+#define ASYNC_RIO32_2_2200 0x8042 /* same as ASYNC_RIO32_2, but for 2100/2200 */
#define ASYNC_RCV_ERR 0x8048
/*
@@ -860,7 +862,7 @@ typedef struct {
(ISP_CAP_MULTI_ID(isp) ? tag : 0)
/*
- * Reduced Interrupt Operation Response Queue Entreis
+ * Reduced Interrupt Operation Response Queue Entries
*/
typedef struct {
diff --git a/sys/dev/isp/ispreg.h b/sys/dev/isp/ispreg.h
index 08df337..2d616ae 100644
--- a/sys/dev/isp/ispreg.h
+++ b/sys/dev/isp/ispreg.h
@@ -677,13 +677,13 @@ typedef struct {
#define SXP_PINS_LVD_MODE 0x1000
#define SXP_PINS_HVD_MODE 0x0800
#define SXP_PINS_SE_MODE 0x0400
+#define SXP_PINS_MODE_MASK (SXP_PINS_LVD_MODE|SXP_PINS_HVD_MODE|SXP_PINS_SE_MODE)
/* The above have to be put together with the DIFFM pin to make sense */
#define ISP1080_LVD_MODE (SXP_PINS_LVD_MODE)
#define ISP1080_HVD_MODE (SXP_PINS_HVD_MODE|SXP_PINS_DIFF_MODE)
#define ISP1080_SE_MODE (SXP_PINS_SE_MODE)
-#define ISP1080_MODE_MASK \
- (SXP_PINS_LVD_MODE|SXP_PINS_HVD_MODE|SXP_PINS_SE_MODE|SXP_PINS_DIFF_MODE)
+#define ISP1080_MODE_MASK (SXP_PINS_MODE_MASK|SXP_PINS_DIFF_MODE)
/*
* RISC and Host Command and Control Block Register Offsets
diff --git a/sys/dev/jme/if_jme.c b/sys/dev/jme/if_jme.c
index d6d17a7..4bfffa3 100644
--- a/sys/dev/jme/if_jme.c
+++ b/sys/dev/jme/if_jme.c
@@ -775,7 +775,7 @@ jme_attach(device_t dev)
/* VLAN capability setup */
ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |
- IFCAP_VLAN_HWCSUM;
+ IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO;
ifp->if_capenable = ifp->if_capabilities;
/* Tell the upper layer(s) we support long frames. */
@@ -1992,6 +1992,9 @@ jme_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if ((mask & IFCAP_VLAN_HWCSUM) != 0 &&
(ifp->if_capabilities & IFCAP_VLAN_HWCSUM) != 0)
ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
+ if ((mask & IFCAP_VLAN_HWTSO) != 0 &&
+ (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0)
+ ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
(IFCAP_VLAN_HWTAGGING & ifp->if_capabilities) != 0) {
ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c
index 2006099..78f2af3 100644
--- a/sys/dev/md/md.c
+++ b/sys/dev/md/md.c
@@ -814,6 +814,8 @@ mdcreate_preload(struct md_s *sc, struct md_ioctl *mdio)
if (mdio->md_options & ~(MD_AUTOUNIT | MD_FORCE))
return (EINVAL);
+ if (mdio->md_base == 0)
+ return (EINVAL);
sc->flags = mdio->md_options & MD_FORCE;
/* Cast to pointer size, then to pointer to avoid warning */
sc->pl_ptr = (u_char *)(uintptr_t)mdio->md_base;
diff --git a/sys/dev/mfi/mfi_cam.c b/sys/dev/mfi/mfi_cam.c
index 83a8e4e..fe1ffe5 100644
--- a/sys/dev/mfi/mfi_cam.c
+++ b/sys/dev/mfi/mfi_cam.c
@@ -95,6 +95,7 @@ static driver_t mfip_driver = {
};
DRIVER_MODULE(mfip, mfi, mfip_driver, mfip_devclass, 0, 0);
MODULE_DEPEND(mfip, cam, 1, 1, 1);
+MODULE_DEPEND(mfip, mfi, 1, 1, 1);
#define ccb_mfip_ptr sim_priv.entries[0].ptr
diff --git a/sys/dev/mfi/mfi_pci.c b/sys/dev/mfi/mfi_pci.c
index 5f0b341..685aa0b 100644
--- a/sys/dev/mfi/mfi_pci.c
+++ b/sys/dev/mfi/mfi_pci.c
@@ -105,6 +105,7 @@ static driver_t mfi_pci_driver = {
static devclass_t mfi_devclass;
DRIVER_MODULE(mfi, pci, mfi_pci_driver, mfi_devclass, 0, 0);
+MODULE_VERSION(mfi, 1);
struct mfi_ident {
uint16_t vendor;
diff --git a/sys/dev/mii/brgphy.c b/sys/dev/mii/brgphy.c
index 1f7d2eb..ddbec67 100644
--- a/sys/dev/mii/brgphy.c
+++ b/sys/dev/mii/brgphy.c
@@ -104,6 +104,7 @@ static void brgphy_reset(struct mii_softc *);
static void brgphy_enable_loopback(struct mii_softc *);
static void bcm5401_load_dspcode(struct mii_softc *);
static void bcm5411_load_dspcode(struct mii_softc *);
+static void bcm54k2_load_dspcode(struct mii_softc *);
static void brgphy_fixup_5704_a0_bug(struct mii_softc *);
static void brgphy_fixup_adc_bug(struct mii_softc *);
static void brgphy_fixup_adjust_trim(struct mii_softc *);
@@ -117,6 +118,7 @@ static const struct mii_phydesc brgphys[] = {
MII_PHY_DESC(xxBROADCOM, BCM5400),
MII_PHY_DESC(xxBROADCOM, BCM5401),
MII_PHY_DESC(xxBROADCOM, BCM5411),
+ MII_PHY_DESC(xxBROADCOM, BCM54K2),
MII_PHY_DESC(xxBROADCOM, BCM5701),
MII_PHY_DESC(xxBROADCOM, BCM5703),
MII_PHY_DESC(xxBROADCOM, BCM5704),
@@ -415,6 +417,9 @@ brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
case MII_MODEL_xxBROADCOM_BCM5411:
bcm5411_load_dspcode(sc);
break;
+ case MII_MODEL_xxBROADCOM_BCM54K2:
+ bcm54k2_load_dspcode(sc);
+ break;
}
break;
case MII_OUI_xxBROADCOM_ALT1:
@@ -730,6 +735,24 @@ bcm5411_load_dspcode(struct mii_softc *sc)
PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
}
+void
+bcm54k2_load_dspcode(struct mii_softc *sc)
+{
+ static const struct {
+ int reg;
+ uint16_t val;
+ } dspcode[] = {
+ { 4, 0x01e1 },
+ { 9, 0x0300 },
+ { 0, 0 },
+ };
+ int i;
+
+ for (i = 0; dspcode[i].reg != 0; i++)
+ PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
+
+}
+
static void
brgphy_fixup_5704_a0_bug(struct mii_softc *sc)
{
@@ -932,6 +955,9 @@ brgphy_reset(struct mii_softc *sc)
case MII_MODEL_xxBROADCOM_BCM5411:
bcm5411_load_dspcode(sc);
break;
+ case MII_MODEL_xxBROADCOM_BCM54K2:
+ bcm54k2_load_dspcode(sc);
+ break;
}
break;
case MII_OUI_xxBROADCOM_ALT1:
diff --git a/sys/dev/mii/miidevs b/sys/dev/mii/miidevs
index 325d733..06e07be 100644
--- a/sys/dev/mii/miidevs
+++ b/sys/dev/mii/miidevs
@@ -145,6 +145,7 @@ model xxBROADCOM BCM5703 0x0016 BCM5703 10/100/1000baseTX PHY
model xxBROADCOM BCM5704 0x0019 BCM5704 10/100/1000baseTX PHY
model xxBROADCOM BCM5705 0x001a BCM5705 10/100/1000baseTX PHY
model xxBROADCOM BCM5750 0x0018 BCM5750 10/100/1000baseTX PHY
+model xxBROADCOM BCM54K2 0x002e BCM54K2 10/100/1000baseTX PHY
model xxBROADCOM BCM5714 0x0034 BCM5714 10/100/1000baseTX PHY
model xxBROADCOM BCM5780 0x0035 BCM5780 10/100/1000baseTX PHY
model xxBROADCOM BCM5708C 0x0036 BCM5708C 10/100/1000baseTX PHY
diff --git a/sys/dev/mpt/mpt_raid.c b/sys/dev/mpt/mpt_raid.c
index 7d075e3..9e90dd3 100644
--- a/sys/dev/mpt/mpt_raid.c
+++ b/sys/dev/mpt/mpt_raid.c
@@ -690,7 +690,6 @@ mpt_raid_thread(void *arg)
if (mpt->raid_rescan != 0) {
union ccb *ccb;
- struct cam_path *path;
int error;
mpt->raid_rescan = 0;
@@ -699,7 +698,7 @@ mpt_raid_thread(void *arg)
ccb = xpt_alloc_ccb();
MPT_LOCK(mpt);
- error = xpt_create_path(&path, xpt_periph,
+ error = xpt_create_path(&ccb->ccb_h.path, xpt_periph,
cam_sim_path(mpt->phydisk_sim),
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
if (error != CAM_REQ_CMP) {
diff --git a/sys/dev/msk/if_msk.c b/sys/dev/msk/if_msk.c
index 3f349e8..d087195 100644
--- a/sys/dev/msk/if_msk.c
+++ b/sys/dev/msk/if_msk.c
@@ -113,7 +113,6 @@ __FBSDID("$FreeBSD$");
#include <sys/sockio.h>
#include <sys/queue.h>
#include <sys/sysctl.h>
-#include <sys/taskqueue.h>
#include <net/bpf.h>
#include <net/ethernet.h>
@@ -257,9 +256,7 @@ static int msk_attach(device_t);
static int msk_detach(device_t);
static void msk_tick(void *);
-static void msk_legacy_intr(void *);
-static int msk_intr(void *);
-static void msk_int_task(void *, int);
+static void msk_intr(void *);
static void msk_intr_phy(struct msk_if_softc *);
static void msk_intr_gmac(struct msk_if_softc *);
static __inline void msk_rxput(struct msk_if_softc *);
@@ -273,8 +270,8 @@ static void msk_rxeof(struct msk_if_softc *, uint32_t, uint32_t, int);
static void msk_jumbo_rxeof(struct msk_if_softc *, uint32_t, uint32_t, int);
static void msk_txeof(struct msk_if_softc *, int);
static int msk_encap(struct msk_if_softc *, struct mbuf **);
-static void msk_tx_task(void *, int);
static void msk_start(struct ifnet *);
+static void msk_start_locked(struct ifnet *);
static int msk_ioctl(struct ifnet *, u_long, caddr_t);
static void msk_set_prefetch(struct msk_softc *, int, bus_addr_t, uint32_t);
static void msk_set_rambuffer(struct msk_if_softc *);
@@ -393,12 +390,6 @@ static struct resource_spec msk_irq_spec_msi[] = {
{ -1, 0, 0 }
};
-static struct resource_spec msk_irq_spec_msi2[] = {
- { SYS_RES_IRQ, 1, RF_ACTIVE },
- { SYS_RES_IRQ, 2, RF_ACTIVE },
- { -1, 0, 0 }
-};
-
static int
msk_miibus_readreg(device_t dev, int phy, int reg)
{
@@ -538,28 +529,25 @@ msk_miibus_statchg(device_t dev)
break;
}
- if (((mii->mii_media_active & IFM_GMASK) & IFM_FDX) != 0)
- gmac |= GM_GPCR_DUP_FULL;
/* Disable Rx flow control. */
- if (((mii->mii_media_active & IFM_GMASK) & IFM_FLAG0) == 0)
+ if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FLAG0) == 0)
gmac |= GM_GPCR_FC_RX_DIS;
/* Disable Tx flow control. */
- if (((mii->mii_media_active & IFM_GMASK) & IFM_FLAG1) == 0)
+ if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FLAG1) == 0)
gmac |= GM_GPCR_FC_TX_DIS;
+ if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
+ gmac |= GM_GPCR_DUP_FULL;
+ else
+ gmac |= GM_GPCR_FC_RX_DIS | GM_GPCR_FC_TX_DIS;
gmac |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA;
GMAC_WRITE_2(sc, sc_if->msk_port, GM_GP_CTRL, gmac);
/* Read again to ensure writing. */
GMAC_READ_2(sc, sc_if->msk_port, GM_GP_CTRL);
-
- gmac = GMC_PAUSE_ON;
- if (((mii->mii_media_active & IFM_GMASK) &
- (IFM_FLAG0 | IFM_FLAG1)) == 0)
- gmac = GMC_PAUSE_OFF;
- /* Diable pause for 10/100 Mbps in half-duplex mode. */
- if ((((mii->mii_media_active & IFM_GMASK) & IFM_FDX) == 0) &&
- (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX ||
- IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T))
- gmac = GMC_PAUSE_OFF;
+ gmac = GMC_PAUSE_OFF;
+ if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
+ if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FLAG0) != 0)
+ gmac = GMC_PAUSE_ON;
+ }
CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, GMAC_CTRL), gmac);
/* Enable PHY interrupt for FIFO underrun/overflow. */
@@ -738,6 +726,7 @@ msk_init_tx_ring(struct msk_if_softc *sc_if)
int i;
sc_if->msk_cdata.msk_tso_mtu = 0;
+ sc_if->msk_cdata.msk_last_csum = 0;
sc_if->msk_cdata.msk_tx_prod = 0;
sc_if->msk_cdata.msk_tx_cons = 0;
sc_if->msk_cdata.msk_tx_cnt = 0;
@@ -1006,11 +995,6 @@ msk_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
if ((mask & IFCAP_RXCSUM) != 0 &&
(IFCAP_RXCSUM & ifp->if_capabilities) != 0)
ifp->if_capenable ^= IFCAP_RXCSUM;
- if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
- (IFCAP_VLAN_HWTAGGING & ifp->if_capabilities) != 0) {
- ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
- msk_setvlan(sc_if, ifp);
- }
if ((mask & IFCAP_VLAN_HWCSUM) != 0 &&
(IFCAP_VLAN_HWCSUM & ifp->if_capabilities) != 0)
ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
@@ -1022,6 +1006,16 @@ msk_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
else
ifp->if_hwassist &= ~CSUM_TSO;
}
+ if ((mask & IFCAP_VLAN_HWTSO) != 0 &&
+ (IFCAP_VLAN_HWTSO & ifp->if_capabilities) != 0)
+ ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
+ if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
+ (IFCAP_VLAN_HWTAGGING & ifp->if_capabilities) != 0) {
+ ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
+ if ((IFCAP_VLAN_HWTAGGING & ifp->if_capenable) == 0)
+ ifp->if_capenable &= ~IFCAP_VLAN_HWTSO;
+ msk_setvlan(sc_if, ifp);
+ }
if (ifp->if_mtu > ETHERMTU &&
(sc_if->msk_flags & MSK_FLAG_JUMBO_NOCSUM) != 0) {
ifp->if_hwassist &= ~(MSK_CSUM_FEATURES | CSUM_TSO);
@@ -1350,35 +1344,22 @@ mskc_reset(struct msk_softc *sc)
* On dual port PCI-X card, there is an problem where status
* can be received out of order due to split transactions.
*/
- if (sc->msk_bustype == MSK_PCIX_BUS && sc->msk_num_port > 1) {
- int pcix;
+ if (sc->msk_pcixcap != 0 && sc->msk_num_port > 1) {
uint16_t pcix_cmd;
- if (pci_find_extcap(sc->msk_dev, PCIY_PCIX, &pcix) == 0) {
- pcix_cmd = pci_read_config(sc->msk_dev, pcix + 2, 2);
- /* Clear Max Outstanding Split Transactions. */
- pcix_cmd &= ~0x70;
- CSR_WRITE_1(sc, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- pci_write_config(sc->msk_dev, pcix + 2, pcix_cmd, 2);
- CSR_WRITE_1(sc, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
- }
+ pcix_cmd = pci_read_config(sc->msk_dev,
+ sc->msk_pcixcap + PCIXR_COMMAND, 2);
+ /* Clear Max Outstanding Split Transactions. */
+ pcix_cmd &= ~PCIXM_COMMAND_MAX_SPLITS;
+ CSR_WRITE_1(sc, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+ pci_write_config(sc->msk_dev,
+ sc->msk_pcixcap + PCIXR_COMMAND, pcix_cmd, 2);
+ CSR_WRITE_1(sc, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
}
- if (sc->msk_bustype == MSK_PEX_BUS) {
- uint16_t v, width;
-
- v = pci_read_config(sc->msk_dev, PEX_DEV_CTRL, 2);
- /* Change Max. Read Request Size to 4096 bytes. */
- v &= ~PEX_DC_MAX_RRS_MSK;
- v |= PEX_DC_MAX_RD_RQ_SIZE(5);
- pci_write_config(sc->msk_dev, PEX_DEV_CTRL, v, 2);
- width = pci_read_config(sc->msk_dev, PEX_LNK_STAT, 2);
- width = (width & PEX_LS_LINK_WI_MSK) >> 4;
- v = pci_read_config(sc->msk_dev, PEX_LNK_CAP, 2);
- v = (v & PEX_LS_LINK_WI_MSK) >> 4;
- if (v != width)
- device_printf(sc->msk_dev,
- "negotiated width of link(x%d) != "
- "max. width of link(x%d)\n", width, v);
+ if (sc->msk_expcap != 0) {
+ /* Change Max. Read Request Size to 2048 bytes. */
+ if (pci_get_max_read_req(sc->msk_dev) == 512)
+ pci_set_max_read_req(sc->msk_dev, 2048);
}
/* Clear status list. */
@@ -1516,7 +1497,7 @@ msk_attach(device_t dev)
* Enable Rx checksum offloading if controller support new
* descriptor format.
*/
- if ((sc_if->msk_flags & MSK_FLAG_DESCV2) != 0 &&
+ if ((sc_if->msk_flags & MSK_FLAG_DESCV2) != 0 &&
(sc_if->msk_flags & MSK_FLAG_NORX_CSUM) == 0)
ifp->if_capabilities |= IFCAP_RXCSUM;
ifp->if_hwassist = MSK_CSUM_FEATURES | CSUM_TSO;
@@ -1527,9 +1508,6 @@ msk_attach(device_t dev)
IFQ_SET_MAXLEN(&ifp->if_snd, MSK_TX_RING_CNT - 1);
ifp->if_snd.ifq_drv_maxlen = MSK_TX_RING_CNT - 1;
IFQ_SET_READY(&ifp->if_snd);
-
- TASK_INIT(&sc_if->msk_tx_task, 1, msk_tx_task, ifp);
-
/*
* Get station address for this interface. Note that
* dual port cards actually come with three station
@@ -1559,12 +1537,12 @@ msk_attach(device_t dev)
* this workaround does not work so disable checksum offload
* for VLAN interface.
*/
- ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
+ ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWTSO;
/*
* Enable Rx checksum offloading for VLAN taggedd frames
* if controller support new descriptor format.
*/
- if ((sc_if->msk_flags & MSK_FLAG_DESCV2) != 0 &&
+ if ((sc_if->msk_flags & MSK_FLAG_DESCV2) != 0 &&
(sc_if->msk_flags & MSK_FLAG_NORX_CSUM) == 0)
ifp->if_capabilities |= IFCAP_VLAN_HWCSUM;
}
@@ -1675,6 +1653,14 @@ mskc_attach(device_t dev)
}
}
+ sc->msk_int_holdoff = MSK_INT_HOLDOFF_DEFAULT;
+ SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "int_holdoff", CTLFLAG_RW, &sc->msk_int_holdoff, 0,
+ "Maximum number of time to delay interrupts");
+ resource_int_value(device_get_name(dev), device_get_unit(dev),
+ "int_holdoff", &sc->msk_int_holdoff);
+
/* Soft reset. */
CSR_WRITE_2(sc, B0_CTST, CS_RST_SET);
CSR_WRITE_2(sc, B0_CTST, CS_RST_CLR);
@@ -1688,11 +1674,13 @@ mskc_attach(device_t dev)
}
/* Check bus type. */
- if (pci_find_extcap(sc->msk_dev, PCIY_EXPRESS, &reg) == 0)
+ if (pci_find_extcap(sc->msk_dev, PCIY_EXPRESS, &reg) == 0) {
sc->msk_bustype = MSK_PEX_BUS;
- else if (pci_find_extcap(sc->msk_dev, PCIY_PCIX, &reg) == 0)
+ sc->msk_expcap = reg;
+ } else if (pci_find_extcap(sc->msk_dev, PCIY_PCIX, &reg) == 0) {
sc->msk_bustype = MSK_PCIX_BUS;
- else
+ sc->msk_pcixcap = reg;
+ } else
sc->msk_bustype = MSK_PCI_BUS;
switch (sc->msk_hw_id) {
@@ -1762,37 +1750,16 @@ mskc_attach(device_t dev)
msic = pci_msi_count(dev);
if (bootverbose)
device_printf(dev, "MSI count : %d\n", msic);
- /*
- * The Yukon II reports it can handle two messages, one for each
- * possible port. We go ahead and allocate two messages and only
- * setup a handler for both if we have a dual port card.
- *
- * XXX: I haven't untangled the interrupt handler to handle dual
- * port cards with separate MSI messages, so for now I disable MSI
- * on dual port cards.
- */
if (legacy_intr != 0)
msi_disable = 1;
- if (msi_disable == 0) {
- switch (msic) {
- case 2:
- case 1: /* 88E8058 reports 1 MSI message */
- msir = msic;
- if (sc->msk_num_port == 1 &&
- pci_alloc_msi(dev, &msir) == 0) {
- if (msic == msir) {
- sc->msk_pflags |= MSK_FLAG_MSI;
- sc->msk_irq_spec = msic == 2 ?
- msk_irq_spec_msi2 :
- msk_irq_spec_msi;
- } else
- pci_release_msi(dev);
- }
- break;
- default:
- device_printf(dev,
- "Unexpected number of MSI messages : %d\n", msic);
- break;
+ if (msi_disable == 0 && msic > 0) {
+ msir = 1;
+ if (pci_alloc_msi(dev, &msir) == 0) {
+ if (msir == 1) {
+ sc->msk_pflags |= MSK_FLAG_MSI;
+ sc->msk_irq_spec = msk_irq_spec_msi;
+ } else
+ pci_release_msi(dev);
}
}
@@ -1863,25 +1830,10 @@ mskc_attach(device_t dev)
}
/* Hook interrupt last to avoid having to lock softc. */
- if (legacy_intr)
- error = bus_setup_intr(dev, sc->msk_irq[0], INTR_TYPE_NET |
- INTR_MPSAFE, NULL, msk_legacy_intr, sc,
- &sc->msk_intrhand[0]);
- else {
- TASK_INIT(&sc->msk_int_task, 0, msk_int_task, sc);
- sc->msk_tq = taskqueue_create_fast("msk_taskq", M_WAITOK,
- taskqueue_thread_enqueue, &sc->msk_tq);
- taskqueue_start_threads(&sc->msk_tq, 1, PI_NET, "%s taskq",
- device_get_nameunit(sc->msk_dev));
- error = bus_setup_intr(dev, sc->msk_irq[0], INTR_TYPE_NET |
- INTR_MPSAFE, msk_intr, NULL, sc, &sc->msk_intrhand[0]);
- }
-
+ error = bus_setup_intr(dev, sc->msk_irq[0], INTR_TYPE_NET |
+ INTR_MPSAFE, NULL, msk_intr, sc, &sc->msk_intrhand);
if (error != 0) {
device_printf(dev, "couldn't set up interrupt handler\n");
- if (legacy_intr == 0)
- taskqueue_free(sc->msk_tq);
- sc->msk_tq = NULL;
goto fail;
}
fail:
@@ -1918,7 +1870,6 @@ msk_detach(device_t dev)
/* Can't hold locks while calling detach. */
MSK_IF_UNLOCK(sc_if);
callout_drain(&sc_if->msk_tick_ch);
- taskqueue_drain(taskqueue_fast, &sc_if->msk_tx_task);
ether_ifdetach(ifp);
MSK_IF_LOCK(sc_if);
}
@@ -1983,18 +1934,9 @@ mskc_detach(device_t dev)
msk_status_dma_free(sc);
- if (legacy_intr == 0 && sc->msk_tq != NULL) {
- taskqueue_drain(sc->msk_tq, &sc->msk_int_task);
- taskqueue_free(sc->msk_tq);
- sc->msk_tq = NULL;
- }
- if (sc->msk_intrhand[0]) {
- bus_teardown_intr(dev, sc->msk_irq[0], sc->msk_intrhand[0]);
- sc->msk_intrhand[0] = NULL;
- }
- if (sc->msk_intrhand[1]) {
- bus_teardown_intr(dev, sc->msk_irq[0], sc->msk_intrhand[0]);
- sc->msk_intrhand[1] = NULL;
+ if (sc->msk_intrhand) {
+ bus_teardown_intr(dev, sc->msk_irq[0], sc->msk_intrhand);
+ sc->msk_intrhand = NULL;
}
bus_release_resources(dev, sc->msk_irq_spec, sc->msk_irq);
if ((sc->msk_pflags & MSK_FLAG_MSI) != 0)
@@ -2525,7 +2467,7 @@ msk_encap(struct msk_if_softc *sc_if, struct mbuf **m_head)
struct mbuf *m;
bus_dmamap_t map;
bus_dma_segment_t txsegs[MSK_MAXTXSEGS];
- uint32_t control, prod, si;
+ uint32_t control, csum, prod, si;
uint16_t offset, tcp_offset, tso_mtu;
int error, i, nseg, tso;
@@ -2686,7 +2628,7 @@ msk_encap(struct msk_if_softc *sc_if, struct mbuf **m_head)
}
/* Check if we have a VLAN tag to insert. */
if ((m->m_flags & M_VLANTAG) != 0) {
- if (tso == 0) {
+ if (tx_le == NULL) {
tx_le = &sc_if->msk_rdata.msk_tx_ring[prod];
tx_le->msk_addr = htole32(0);
tx_le->msk_control = htole32(OP_VLAN | HW_OWNER |
@@ -2704,17 +2646,22 @@ msk_encap(struct msk_if_softc *sc_if, struct mbuf **m_head)
if ((sc_if->msk_flags & MSK_FLAG_AUTOTX_CSUM) != 0)
control |= CALSUM;
else {
- tx_le = &sc_if->msk_rdata.msk_tx_ring[prod];
- tx_le->msk_addr = htole32(((tcp_offset +
- m->m_pkthdr.csum_data) & 0xffff) |
- ((uint32_t)tcp_offset << 16));
- tx_le->msk_control = htole32(1 << 16 |
- (OP_TCPLISW | HW_OWNER));
- control = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM;
+ control |= CALSUM | WR_SUM | INIT_SUM | LOCK_SUM;
if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0)
control |= UDPTCP;
- sc_if->msk_cdata.msk_tx_cnt++;
- MSK_INC(prod, MSK_TX_RING_CNT);
+ /* Checksum write position. */
+ csum = (tcp_offset + m->m_pkthdr.csum_data) & 0xffff;
+ /* Checksum start position. */
+ csum |= (uint32_t)tcp_offset << 16;
+ if (csum != sc_if->msk_cdata.msk_last_csum) {
+ tx_le = &sc_if->msk_rdata.msk_tx_ring[prod];
+ tx_le->msk_addr = htole32(csum);
+ tx_le->msk_control = htole32(1 << 16 |
+ (OP_TCPLISW | HW_OWNER));
+ sc_if->msk_cdata.msk_tx_cnt++;
+ MSK_INC(prod, MSK_TX_RING_CNT);
+ sc_if->msk_cdata.msk_last_csum = csum;
+ }
}
}
@@ -2766,30 +2713,29 @@ msk_encap(struct msk_if_softc *sc_if, struct mbuf **m_head)
}
static void
-msk_tx_task(void *arg, int pending)
+msk_start(struct ifnet *ifp)
{
- struct ifnet *ifp;
+ struct msk_if_softc *sc_if;
- ifp = arg;
- msk_start(ifp);
+ sc_if = ifp->if_softc;
+ MSK_IF_LOCK(sc_if);
+ msk_start_locked(ifp);
+ MSK_IF_UNLOCK(sc_if);
}
static void
-msk_start(struct ifnet *ifp)
+msk_start_locked(struct ifnet *ifp)
{
- struct msk_if_softc *sc_if;
- struct mbuf *m_head;
+ struct msk_if_softc *sc_if;
+ struct mbuf *m_head;
int enq;
sc_if = ifp->if_softc;
-
- MSK_IF_LOCK(sc_if);
+ MSK_IF_LOCK_ASSERT(sc_if);
if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
- IFF_DRV_RUNNING || (sc_if->msk_flags & MSK_FLAG_LINK) == 0) {
- MSK_IF_UNLOCK(sc_if);
+ IFF_DRV_RUNNING || (sc_if->msk_flags & MSK_FLAG_LINK) == 0)
return;
- }
for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
sc_if->msk_cdata.msk_tx_cnt <
@@ -2827,16 +2773,12 @@ msk_start(struct ifnet *ifp)
/* Set a timeout in case the chip goes out to lunch. */
sc_if->msk_watchdog_timer = MSK_TX_TIMEOUT;
}
-
- MSK_IF_UNLOCK(sc_if);
}
static void
msk_watchdog(struct msk_if_softc *sc_if)
{
struct ifnet *ifp;
- uint32_t ridx;
- int idx;
MSK_IF_LOCK_ASSERT(sc_if);
@@ -2853,30 +2795,12 @@ msk_watchdog(struct msk_if_softc *sc_if)
return;
}
- /*
- * Reclaim first as there is a possibility of losing Tx completion
- * interrupts.
- */
- ridx = sc_if->msk_port == MSK_PORT_A ? STAT_TXA1_RIDX : STAT_TXA2_RIDX;
- idx = CSR_READ_2(sc_if->msk_softc, ridx);
- if (sc_if->msk_cdata.msk_tx_cons != idx) {
- msk_txeof(sc_if, idx);
- if (sc_if->msk_cdata.msk_tx_cnt == 0) {
- if_printf(ifp, "watchdog timeout (missed Tx interrupts) "
- "-- recovering\n");
- if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
- taskqueue_enqueue(taskqueue_fast,
- &sc_if->msk_tx_task);
- return;
- }
- }
-
if_printf(ifp, "watchdog timeout\n");
ifp->if_oerrors++;
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
msk_init_locked(sc_if);
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
- taskqueue_enqueue(taskqueue_fast, &sc_if->msk_tx_task);
+ msk_start_locked(ifp);
}
static int
@@ -3200,6 +3124,7 @@ msk_tick(void *xsc_if)
mii_tick(mii);
if ((sc_if->msk_flags & MSK_FLAG_LINK) == 0)
msk_miibus_statchg(sc_if->msk_if_dev);
+ msk_handle_events(sc_if->msk_softc);
msk_watchdog(sc_if);
callout_reset(&sc_if->msk_tick_ch, hz, msk_tick, sc_if);
}
@@ -3398,32 +3323,20 @@ msk_handle_events(struct msk_softc *sc)
int rxput[2];
struct msk_stat_desc *sd;
uint32_t control, status;
- int cons, idx, len, port, rxprog;
-
- idx = CSR_READ_2(sc, STAT_PUT_IDX);
- if (idx == sc->msk_stat_cons)
- return (0);
+ int cons, len, port, rxprog;
/* Sync status LEs. */
bus_dmamap_sync(sc->msk_stat_tag, sc->msk_stat_map,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
- /* XXX Sync Rx LEs here. */
rxput[MSK_PORT_A] = rxput[MSK_PORT_B] = 0;
-
rxprog = 0;
- for (cons = sc->msk_stat_cons; cons != idx;) {
+ cons = sc->msk_stat_cons;
+ for (;;) {
sd = &sc->msk_stat_ring[cons];
control = le32toh(sd->msk_control);
if ((control & HW_OWNER) == 0)
break;
- /*
- * Marvell's FreeBSD driver updates status LE after clearing
- * HW_OWNER. However we don't have a way to sync single LE
- * with bus_dma(9) API. bus_dma(9) provides a way to sync
- * an entire DMA map. So don't sync LE until we have a better
- * way to sync LEs.
- */
control &= ~HW_OWNER;
sd->msk_control = htole32(control);
status = le32toh(sd->msk_status);
@@ -3484,24 +3397,25 @@ msk_handle_events(struct msk_softc *sc)
}
sc->msk_stat_cons = cons;
- /* XXX We should sync status LEs here. See above notes. */
+ bus_dmamap_sync(sc->msk_stat_tag, sc->msk_stat_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
if (rxput[MSK_PORT_A] > 0)
msk_rxput(sc->msk_if[MSK_PORT_A]);
if (rxput[MSK_PORT_B] > 0)
msk_rxput(sc->msk_if[MSK_PORT_B]);
- return (sc->msk_stat_cons != CSR_READ_2(sc, STAT_PUT_IDX));
+ return (rxprog > sc->msk_process_limit ? EAGAIN : 0);
}
-/* Legacy interrupt handler for shared interrupt. */
static void
-msk_legacy_intr(void *xsc)
+msk_intr(void *xsc)
{
struct msk_softc *sc;
struct msk_if_softc *sc_if0, *sc_if1;
struct ifnet *ifp0, *ifp1;
uint32_t status;
+ int domore;
sc = xsc;
MSK_LOCK(sc);
@@ -3546,9 +3460,8 @@ msk_legacy_intr(void *xsc)
if ((status & Y2_IS_HW_ERR) != 0)
msk_intr_hwerr(sc);
- while (msk_handle_events(sc) != 0)
- ;
- if ((status & Y2_IS_STAT_BMU) != 0)
+ domore = msk_handle_events(sc);
+ if ((status & Y2_IS_STAT_BMU) != 0 && domore == 0)
CSR_WRITE_4(sc, STAT_CTRL, SC_STAT_CLR_IRQ);
/* Reenable interrupts. */
@@ -3556,105 +3469,14 @@ msk_legacy_intr(void *xsc)
if (ifp0 != NULL && (ifp0->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
!IFQ_DRV_IS_EMPTY(&ifp0->if_snd))
- taskqueue_enqueue(taskqueue_fast, &sc_if0->msk_tx_task);
+ msk_start_locked(ifp0);
if (ifp1 != NULL && (ifp1->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
!IFQ_DRV_IS_EMPTY(&ifp1->if_snd))
- taskqueue_enqueue(taskqueue_fast, &sc_if1->msk_tx_task);
+ msk_start_locked(ifp1);
MSK_UNLOCK(sc);
}
-static int
-msk_intr(void *xsc)
-{
- struct msk_softc *sc;
- uint32_t status;
-
- sc = xsc;
- status = CSR_READ_4(sc, B0_Y2_SP_ISRC2);
- /* Reading B0_Y2_SP_ISRC2 masks further interrupts. */
- if (status == 0 || status == 0xffffffff) {
- CSR_WRITE_4(sc, B0_Y2_SP_ICR, 2);
- return (FILTER_STRAY);
- }
-
- taskqueue_enqueue(sc->msk_tq, &sc->msk_int_task);
- return (FILTER_HANDLED);
-}
-
-static void
-msk_int_task(void *arg, int pending)
-{
- struct msk_softc *sc;
- struct msk_if_softc *sc_if0, *sc_if1;
- struct ifnet *ifp0, *ifp1;
- uint32_t status;
- int domore;
-
- sc = arg;
- MSK_LOCK(sc);
-
- /* Get interrupt source. */
- status = CSR_READ_4(sc, B0_ISRC);
- if (status == 0 || status == 0xffffffff ||
- (sc->msk_pflags & MSK_FLAG_SUSPEND) != 0 ||
- (status & sc->msk_intrmask) == 0)
- goto done;
-
- sc_if0 = sc->msk_if[MSK_PORT_A];
- sc_if1 = sc->msk_if[MSK_PORT_B];
- ifp0 = ifp1 = NULL;
- if (sc_if0 != NULL)
- ifp0 = sc_if0->msk_ifp;
- if (sc_if1 != NULL)
- ifp1 = sc_if1->msk_ifp;
-
- if ((status & Y2_IS_IRQ_PHY1) != 0 && sc_if0 != NULL)
- msk_intr_phy(sc_if0);
- if ((status & Y2_IS_IRQ_PHY2) != 0 && sc_if1 != NULL)
- msk_intr_phy(sc_if1);
- if ((status & Y2_IS_IRQ_MAC1) != 0 && sc_if0 != NULL)
- msk_intr_gmac(sc_if0);
- if ((status & Y2_IS_IRQ_MAC2) != 0 && sc_if1 != NULL)
- msk_intr_gmac(sc_if1);
- if ((status & (Y2_IS_CHK_RX1 | Y2_IS_CHK_RX2)) != 0) {
- device_printf(sc->msk_dev, "Rx descriptor error\n");
- sc->msk_intrmask &= ~(Y2_IS_CHK_RX1 | Y2_IS_CHK_RX2);
- CSR_WRITE_4(sc, B0_IMSK, sc->msk_intrmask);
- CSR_READ_4(sc, B0_IMSK);
- }
- if ((status & (Y2_IS_CHK_TXA1 | Y2_IS_CHK_TXA2)) != 0) {
- device_printf(sc->msk_dev, "Tx descriptor error\n");
- sc->msk_intrmask &= ~(Y2_IS_CHK_TXA1 | Y2_IS_CHK_TXA2);
- CSR_WRITE_4(sc, B0_IMSK, sc->msk_intrmask);
- CSR_READ_4(sc, B0_IMSK);
- }
- if ((status & Y2_IS_HW_ERR) != 0)
- msk_intr_hwerr(sc);
-
- domore = msk_handle_events(sc);
- if ((status & Y2_IS_STAT_BMU) != 0)
- CSR_WRITE_4(sc, STAT_CTRL, SC_STAT_CLR_IRQ);
-
- if (ifp0 != NULL && (ifp0->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
- !IFQ_DRV_IS_EMPTY(&ifp0->if_snd))
- taskqueue_enqueue(taskqueue_fast, &sc_if0->msk_tx_task);
- if (ifp1 != NULL && (ifp1->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
- !IFQ_DRV_IS_EMPTY(&ifp1->if_snd))
- taskqueue_enqueue(taskqueue_fast, &sc_if1->msk_tx_task);
-
- if (domore > 0) {
- taskqueue_enqueue(sc->msk_tq, &sc->msk_int_task);
- MSK_UNLOCK(sc);
- return;
- }
-done:
- MSK_UNLOCK(sc);
-
- /* Reenable interrupts. */
- CSR_WRITE_4(sc, B0_Y2_SP_ICR, 2);
-}
-
static void
msk_set_tx_stfwd(struct msk_if_softc *sc_if)
{
@@ -3713,10 +3535,10 @@ msk_init_locked(struct msk_if_softc *sc_if)
struct msk_softc *sc;
struct ifnet *ifp;
struct mii_data *mii;
- uint16_t eaddr[ETHER_ADDR_LEN / 2];
+ uint8_t *eaddr;
uint16_t gmac;
uint32_t reg;
- int error, i;
+ int error;
MSK_IF_LOCK_ASSERT(sc_if);
@@ -3750,7 +3572,7 @@ msk_init_locked(struct msk_if_softc *sc_if)
CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, GMAC_CTRL),
GMC_BYP_MACSECRX_ON | GMC_BYP_MACSECTX_ON |
GMC_BYP_RETR_ON);
-
+
/*
* Initialize GMAC first such that speed/duplex/flow-control
* parameters are renegotiated when interface is brought up.
@@ -3785,13 +3607,19 @@ msk_init_locked(struct msk_if_softc *sc_if)
GMAC_WRITE_2(sc, sc_if->msk_port, GM_SERIAL_MODE, gmac);
/* Set station address. */
- bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN);
- for (i = 0; i < ETHER_ADDR_LEN /2; i++)
- GMAC_WRITE_2(sc, sc_if->msk_port, GM_SRC_ADDR_1L + i * 4,
- eaddr[i]);
- for (i = 0; i < ETHER_ADDR_LEN /2; i++)
- GMAC_WRITE_2(sc, sc_if->msk_port, GM_SRC_ADDR_2L + i * 4,
- eaddr[i]);
+ eaddr = IF_LLADDR(ifp);
+ GMAC_WRITE_2(sc, sc_if->msk_port, GM_SRC_ADDR_1L,
+ eaddr[0] | (eaddr[1] << 8));
+ GMAC_WRITE_2(sc, sc_if->msk_port, GM_SRC_ADDR_1M,
+ eaddr[2] | (eaddr[3] << 8));
+ GMAC_WRITE_2(sc, sc_if->msk_port, GM_SRC_ADDR_1H,
+ eaddr[4] | (eaddr[5] << 8));
+ GMAC_WRITE_2(sc, sc_if->msk_port, GM_SRC_ADDR_2L,
+ eaddr[0] | (eaddr[1] << 8));
+ GMAC_WRITE_2(sc, sc_if->msk_port, GM_SRC_ADDR_2M,
+ eaddr[2] | (eaddr[3] << 8));
+ GMAC_WRITE_2(sc, sc_if->msk_port, GM_SRC_ADDR_2H,
+ eaddr[4] | (eaddr[5] << 8));
/* Disable interrupts for counter overflows. */
GMAC_WRITE_2(sc, sc_if->msk_port, GM_TX_IRQ_MSK, 0);
@@ -3939,6 +3767,17 @@ msk_init_locked(struct msk_if_softc *sc_if)
sc->msk_intrmask |= Y2_IS_PORT_B;
sc->msk_intrhwemask |= Y2_HWE_L2_MASK;
}
+ /* Configure IRQ moderation mask. */
+ CSR_WRITE_4(sc, B2_IRQM_MSK, sc->msk_intrmask);
+ if (sc->msk_int_holdoff > 0) {
+ /* Configure initial IRQ moderation timer value. */
+ CSR_WRITE_4(sc, B2_IRQM_INI,
+ MSK_USECS(sc, sc->msk_int_holdoff));
+ CSR_WRITE_4(sc, B2_IRQM_VAL,
+ MSK_USECS(sc, sc->msk_int_holdoff));
+ /* Start IRQ moderation. */
+ CSR_WRITE_1(sc, B2_IRQM_CTRL, TIM_START);
+ }
CSR_WRITE_4(sc, B0_HWE_IMSK, sc->msk_intrhwemask);
CSR_READ_4(sc, B0_HWE_IMSK);
CSR_WRITE_4(sc, B0_IMSK, sc->msk_intrmask);
diff --git a/sys/dev/msk/if_mskreg.h b/sys/dev/msk/if_mskreg.h
index 2f4e216..9c18ba7 100644
--- a/sys/dev/msk/if_mskreg.h
+++ b/sys/dev/msk/if_mskreg.h
@@ -2361,6 +2361,7 @@ struct msk_chain_data {
bus_dmamap_t msk_jumbo_rx_ring_map;
bus_dmamap_t msk_jumbo_rx_sparemap;
uint16_t msk_tso_mtu;
+ uint32_t msk_last_csum;
int msk_tx_prod;
int msk_tx_cons;
int msk_tx_cnt;
@@ -2405,6 +2406,8 @@ struct msk_ring_data {
#define MSK_PROC_MIN 30
#define MSK_PROC_MAX (MSK_RX_RING_CNT - 1)
+#define MSK_INT_HOLDOFF_DEFAULT 100
+
#define MSK_TX_TIMEOUT 5
#define MSK_PUT_WM 10
@@ -2467,14 +2470,16 @@ struct msk_hw_stats {
struct msk_softc {
struct resource *msk_res[1]; /* I/O resource */
struct resource_spec *msk_res_spec;
- struct resource *msk_irq[2]; /* IRQ resources */
+ struct resource *msk_irq[1]; /* IRQ resources */
struct resource_spec *msk_irq_spec;
- void *msk_intrhand[2]; /* irq handler handle */
+ void *msk_intrhand; /* irq handler handle */
device_t msk_dev;
uint8_t msk_hw_id;
uint8_t msk_hw_rev;
uint8_t msk_bustype;
uint8_t msk_num_port;
+ int msk_expcap;
+ int msk_pcixcap;
int msk_ramsize; /* amount of SRAM on NIC */
uint32_t msk_pmd; /* physical media type */
uint32_t msk_intrmask;
@@ -2493,10 +2498,9 @@ struct msk_softc {
bus_dmamap_t msk_stat_map;
struct msk_stat_desc *msk_stat_ring;
bus_addr_t msk_stat_ring_paddr;
+ int msk_int_holdoff;
int msk_process_limit;
int msk_stat_cons;
- struct taskqueue *msk_tq;
- struct task msk_int_task;
struct mtx msk_mtx;
};
@@ -2541,7 +2545,6 @@ struct msk_if_softc {
struct msk_ring_data msk_rdata;
struct msk_softc *msk_softc; /* parent controller */
struct msk_hw_stats msk_stats;
- struct task msk_tx_task;
int msk_if_flags;
uint16_t msk_vtag; /* VLAN tag id. */
};
diff --git a/sys/dev/mxge/if_mxge.c b/sys/dev/mxge/if_mxge.c
index 6dcba39..5b8bb99 100644
--- a/sys/dev/mxge/if_mxge.c
+++ b/sys/dev/mxge/if_mxge.c
@@ -4122,6 +4122,13 @@ mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
}
if (mask & IFCAP_VLAN_HWTAGGING)
ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
+ if (mask & IFCAP_VLAN_HWTSO)
+ ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
+
+ if (!(ifp->if_capabilities & IFCAP_VLAN_HWTSO) ||
+ !(ifp->if_capenable & IFCAP_VLAN_HWTAGGING))
+ ifp->if_capenable &= ~IFCAP_VLAN_HWTSO;
+
mtx_unlock(&sc->driver_mtx);
VLAN_CAPABILITIES(ifp);
@@ -4734,6 +4741,11 @@ mxge_attach(device_t dev)
#ifdef MXGE_NEW_VLAN_API
ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM;
+
+ /* Only FW 1.4.32 and newer can do TSO over vlans */
+ if (sc->fw_ver_major == 1 && sc->fw_ver_minor == 4 &&
+ sc->fw_ver_tiny >= 32)
+ ifp->if_capabilities |= IFCAP_VLAN_HWTSO;
#endif
sc->max_mtu = mxge_max_mtu(sc);
diff --git a/sys/dev/ofw/ofw_pci.h b/sys/dev/ofw/ofw_pci.h
index ef48ee9..eb60c5b 100644
--- a/sys/dev/ofw/ofw_pci.h
+++ b/sys/dev/ofw/ofw_pci.h
@@ -14,13 +14,6 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c
index a642925..9785801 100644
--- a/sys/dev/re/if_re.c
+++ b/sys/dev/re/if_re.c
@@ -1162,6 +1162,9 @@ re_attach(device_t dev)
msic = 0;
if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
sc->rl_flags |= RL_FLAG_PCIE;
+ /* Set PCIe maximum read request size to 2048. */
+ if (pci_get_max_read_req(dev) < 2048)
+ pci_set_max_read_req(dev, 2048);
msic = pci_msi_count(dev);
if (bootverbose)
device_printf(dev, "MSI count : %d\n", msic);
@@ -1426,7 +1429,7 @@ re_attach(device_t dev)
*/
if ((sc->rl_flags & RL_FLAG_DESCV2) == 0) {
ifp->if_hwassist |= CSUM_TSO;
- ifp->if_capabilities |= IFCAP_TSO4;
+ ifp->if_capabilities |= IFCAP_TSO4 | IFCAP_VLAN_HWTSO;
}
/*
@@ -1448,7 +1451,7 @@ re_attach(device_t dev)
* packets in TSO size.
*/
ifp->if_hwassist &= ~CSUM_TSO;
- ifp->if_capenable &= ~IFCAP_TSO4;
+ ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_VLAN_HWTSO);
#ifdef DEVICE_POLLING
ifp->if_capabilities |= IFCAP_POLLING;
#endif
@@ -2786,6 +2789,7 @@ re_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
(ifp->if_capenable & IFCAP_TSO4) != 0) {
ifp->if_capenable &= ~IFCAP_TSO4;
ifp->if_hwassist &= ~CSUM_TSO;
+ VLAN_CAPABILITIES(ifp);
}
RL_UNLOCK(sc);
break;
@@ -2852,14 +2856,10 @@ re_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
ifp->if_hwassist &= ~RE_CSUM_FEATURES;
reinit = 1;
}
- if (mask & IFCAP_VLAN_HWTAGGING) {
- ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
- reinit = 1;
- }
- if (mask & IFCAP_TSO4) {
+ if ((mask & IFCAP_TSO4) != 0 &&
+ (ifp->if_capabilities & IFCAP_TSO) != 0) {
ifp->if_capenable ^= IFCAP_TSO4;
- if ((IFCAP_TSO4 & ifp->if_capenable) &&
- (IFCAP_TSO4 & ifp->if_capabilities))
+ if ((IFCAP_TSO4 & ifp->if_capenable) != 0)
ifp->if_hwassist |= CSUM_TSO;
else
ifp->if_hwassist &= ~CSUM_TSO;
@@ -2869,6 +2869,17 @@ re_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
ifp->if_hwassist &= ~CSUM_TSO;
}
}
+ if ((mask & IFCAP_VLAN_HWTSO) != 0 &&
+ (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0)
+ ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
+ if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
+ (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) {
+ ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
+ /* TSO over VLAN requires VLAN hardware tagging. */
+ if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0)
+ ifp->if_capenable &= ~IFCAP_VLAN_HWTSO;
+ reinit = 1;
+ }
if ((mask & IFCAP_WOL) != 0 &&
(ifp->if_capabilities & IFCAP_WOL) != 0) {
if ((mask & IFCAP_WOL_UCAST) != 0)
diff --git a/sys/dev/sound/pci/hda/hdac.c b/sys/dev/sound/pci/hda/hdac.c
index 84fc322..0681568 100644
--- a/sys/dev/sound/pci/hda/hdac.c
+++ b/sys/dev/sound/pci/hda/hdac.c
@@ -86,7 +86,7 @@
#include "mixer_if.h"
-#define HDA_DRV_TEST_REV "20100122_0141"
+#define HDA_DRV_TEST_REV "20100226_0142"
SND_DECLARE_FILE("$FreeBSD$");
@@ -3503,7 +3503,7 @@ hdac_stream_setup(struct hdac_chan *ch)
/* If HP redirection is enabled, but failed to use same
DAC, make last DAC to duplicate first one. */
- if (as->hpredir >= 0 && i == as->pincnt) {
+ if (as->fakeredir && i == (as->pincnt - 1)) {
c = (ch->sid << 4);
} else {
if (map >= 0) /* Map known speaker setups. */
diff --git a/sys/dev/stge/if_stge.c b/sys/dev/stge/if_stge.c
index 271790d..e289814 100644
--- a/sys/dev/stge/if_stge.c
+++ b/sys/dev/stge/if_stge.c
@@ -15,13 +15,6 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/sys/dev/stge/if_stgereg.h b/sys/dev/stge/if_stgereg.h
index 9add8cb..6ecbdf9 100644
--- a/sys/dev/stge/if_stgereg.h
+++ b/sys/dev/stge/if_stgereg.h
@@ -15,13 +15,6 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/sys/dev/syscons/scvidctl.c b/sys/dev/syscons/scvidctl.c
index f973169..0f55499 100644
--- a/sys/dev/syscons/scvidctl.c
+++ b/sys/dev/syscons/scvidctl.c
@@ -369,34 +369,7 @@ sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize,
if ((info.vi_width < xsize*8) || (info.vi_height < ysize*fontsize))
return EINVAL;
- /*
- * We currently support the following graphic modes:
- *
- * - 4 bpp planar modes whose memory size does not exceed 64K
- * - 15, 16, 24 and 32 bpp linear modes
- */
-
- if (info.vi_mem_model == V_INFO_MM_PLANAR) {
- if (info.vi_planes != 4)
- return ENODEV;
-
- /*
- * A memory size >64K requires bank switching to access the entire
- * screen. XXX
- */
-
- if (info.vi_width * info.vi_height / 8 > info.vi_window_size)
- return ENODEV;
- } else if (info.vi_mem_model == V_INFO_MM_DIRECT) {
- if (!(info.vi_flags & V_INFO_LINEAR) &&
- (info.vi_depth != 15) && (info.vi_depth != 16) &&
- (info.vi_depth != 24) && (info.vi_depth != 32))
- return ENODEV;
- } else if (info.vi_mem_model == V_INFO_MM_PACKED) {
- if (!(info.vi_flags & V_INFO_LINEAR) &&
- (info.vi_depth != 8))
- return ENODEV;
- } else
+ if (!sc_support_pixel_mode(&info))
return ENODEV;
/* stop screen saver, etc */
@@ -472,6 +445,48 @@ sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize,
#endif /* SC_PIXEL_MODE */
}
+int
+sc_support_pixel_mode(void *arg)
+{
+#ifdef SC_PIXEL_MODE
+ video_info_t *info = arg;
+
+ if ((info->vi_flags & V_INFO_GRAPHICS) == 0)
+ return (0);
+
+ /*
+ * We currently support the following graphic modes:
+ *
+ * - 4 bpp planar modes whose memory size does not exceed 64K
+ * - 15, 16, 24 and 32 bpp linear modes
+ */
+ switch (info->vi_mem_model) {
+ case V_INFO_MM_PLANAR:
+ if (info->vi_planes != 4)
+ break;
+ /*
+ * A memory size >64K requires bank switching to access
+ * the entire screen. XXX
+ */
+ if (info->vi_width * info->vi_height / 8 > info->vi_window_size)
+ break;
+ return (1);
+ case V_INFO_MM_DIRECT:
+ if ((info->vi_flags & V_INFO_LINEAR) == 0 &&
+ info->vi_depth != 15 && info->vi_depth != 16 &&
+ info->vi_depth != 24 && info->vi_depth != 32)
+ break;
+ return (1);
+ case V_INFO_MM_PACKED:
+ if ((info->vi_flags & V_INFO_LINEAR) == 0 &&
+ info->vi_depth != 8)
+ break;
+ return (1);
+ }
+#endif
+ return (0);
+}
+
#define fb_ioctl(a, c, d) \
(((a) == NULL) ? ENODEV : \
vidd_ioctl((a), (c), (caddr_t)(d)))
@@ -725,6 +740,11 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
#endif
#ifndef SC_NO_PALETTE_LOADING
+#ifdef SC_PIXEL_MODE
+ if ((adp->va_flags & V_ADP_DAC8) != 0)
+ vidd_load_palette(adp, scp->sc->palette2);
+ else
+#endif
vidd_load_palette(adp, scp->sc->palette);
#endif
@@ -782,7 +802,10 @@ sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
if (scp == scp->sc->cur_scp) {
set_mode(scp);
#ifndef SC_NO_PALETTE_LOADING
- vidd_load_palette(adp, scp->sc->palette);
+ if ((adp->va_flags & V_ADP_DAC8) != 0)
+ vidd_load_palette(adp, scp->sc->palette2);
+ else
+ vidd_load_palette(adp, scp->sc->palette);
#endif
}
sc_clear_screen(scp);
diff --git a/sys/dev/syscons/snake/snake_saver.c b/sys/dev/syscons/snake/snake_saver.c
index bbdcda3..dbcc217 100644
--- a/sys/dev/syscons/snake/snake_saver.c
+++ b/sys/dev/syscons/snake/snake_saver.c
@@ -36,6 +36,8 @@
#include <sys/sysctl.h>
#include <sys/consio.h>
#include <sys/fbio.h>
+#include <sys/resourcevar.h>
+#include <sys/smp.h>
#include <machine/pc/display.h>
@@ -48,11 +50,22 @@ static int *messagep;
static int messagelen;
static int blanked;
+#define MSGBUF_LEN 70
+
+static int nofancy = 0;
+TUNABLE_INT("hw.syscons.saver_snake_nofancy", &nofancy);
+
+#define FANCY_SNAKE (!nofancy)
+#define LOAD_HIGH(ld) (((ld * 100 + FSCALE / 2) >> FSHIFT) / 100)
+#define LOAD_LOW(ld) (((ld * 100 + FSCALE / 2) >> FSHIFT) % 100)
+
+static inline void update_msg(void);
+
static int
snake_saver(video_adapter_t *adp, int blank)
{
static int dirx, diry;
- int f;
+ int f, color, load;
sc_softc_t *sc;
scr_stat *scp;
@@ -99,22 +112,52 @@ snake_saver(video_adapter_t *adp, int blank)
(random() % 20) == 0)
diry = -diry;
savs[0] += dirx + diry;
+ if (FANCY_SNAKE) {
+ update_msg();
+ load = ((averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT);
+ if (load == 0)
+ color = FG_LIGHTGREY | BG_BLACK;
+ else if (load / mp_ncpus <= 50)
+ color = FG_LIGHTGREEN | BG_BLACK;
+ else if (load / mp_ncpus <= 75)
+ color = FG_YELLOW | BG_BLACK;
+ else if (load / mp_ncpus <= 99)
+ color = FG_LIGHTRED | BG_BLACK;
+ else
+ color = FG_RED | FG_BLINK | BG_BLACK;
+ } else
+ color = FG_LIGHTGREY | BG_BLACK;
+
for (f=messagelen-1; f>=0; f--)
sc_vtb_putc(&scp->scr, savs[f], sc->scr_map[save[f]],
- (FG_LIGHTGREY | BG_BLACK) << 8);
+ color << 8);
} else
blanked = 0;
return 0;
}
+static inline void
+update_msg(void)
+{
+ if (!FANCY_SNAKE) {
+ messagelen = sprintf(message, "%s %s", ostype, osrelease);
+ return;
+ }
+ messagelen = snprintf(message, MSGBUF_LEN,
+ "%s %s (%d.%02d %d.%02d, %d.%02d)",
+ ostype, osrelease,
+ LOAD_HIGH(averunnable.ldavg[0]), LOAD_LOW(averunnable.ldavg[0]),
+ LOAD_HIGH(averunnable.ldavg[1]), LOAD_LOW(averunnable.ldavg[1]),
+ LOAD_HIGH(averunnable.ldavg[2]), LOAD_LOW(averunnable.ldavg[2]));
+}
+
static int
snake_init(video_adapter_t *adp)
{
- messagelen = strlen(ostype) + 1 + strlen(osrelease);
- message = malloc(messagelen + 1, M_DEVBUF, M_WAITOK);
- sprintf(message, "%s %s", ostype, osrelease);
- messagep = malloc(messagelen * sizeof *messagep, M_DEVBUF, M_WAITOK);
+ message = malloc(MSGBUF_LEN, M_DEVBUF, M_WAITOK);
+ messagep = malloc(MSGBUF_LEN * sizeof *messagep, M_DEVBUF, M_WAITOK);
+ update_msg();
return 0;
}
diff --git a/sys/dev/syscons/syscons.c b/sys/dev/syscons/syscons.c
index f50d686..719935d 100644
--- a/sys/dev/syscons/syscons.c
+++ b/sys/dev/syscons/syscons.c
@@ -344,35 +344,94 @@ sc_alloc_tty(int index, int devnum)
}
#ifdef SC_PIXEL_MODE
-static int
-sc_initial_mode(video_adapter_t *adp, int unit)
+static void
+sc_set_vesa_mode(scr_stat *scp, sc_softc_t *sc, int unit)
{
video_info_t info;
- int depth, vmode;
+ int depth;
int i;
+ int vmode;
vmode = 0;
(void)resource_int_value("sc", unit, "vesa_mode", &vmode);
- if (vmode < M_VESA_BASE || vmode > M_VESA_MODE_MAX)
- vmode = 0;
+ if (vmode < M_VESA_BASE || vmode > M_VESA_MODE_MAX ||
+ vidd_get_info(sc->adp, vmode, &info) != 0 ||
+ !sc_support_pixel_mode(&info))
+ vmode = 0;
/*
- * If the default mode is not supported, search for an available
+ * If the mode is unset or unsupported, search for an available
* 800x600 graphics mode with the highest color depth.
*/
- if (vmode == 0 || vidd_get_info(adp, vmode, &info) != 0) {
- depth = vmode = 0;
- for (i = M_VESA_BASE; i <= M_VESA_MODE_MAX; i++)
- if (vidd_get_info(adp, i, &info) == 0 &&
- (info.vi_flags & V_INFO_GRAPHICS) != 0 &&
- info.vi_width == 800 && info.vi_height == 600 &&
- info.vi_depth > depth) {
- vmode = i;
- depth = info.vi_depth;
- }
+ if (vmode == 0) {
+ for (depth = 0, i = M_VESA_BASE; i <= M_VESA_MODE_MAX; i++)
+ if (vidd_get_info(sc->adp, i, &info) == 0 &&
+ info.vi_width == 800 && info.vi_height == 600 &&
+ sc_support_pixel_mode(&info) &&
+ info.vi_depth > depth) {
+ vmode = i;
+ depth = info.vi_depth;
+ }
+ if (vmode == 0)
+ return;
+ vidd_get_info(sc->adp, vmode, &info);
}
- return (vmode);
+#ifndef SC_NO_FONT_LOADING
+ if ((sc->fonts_loaded & FONT_16) == 0)
+ return;
+#endif
+#ifdef DEV_SPLASH
+ if ((sc->flags & SC_SPLASH_SCRN) != 0)
+ splash_term(sc->adp);
+#endif
+#ifndef SC_NO_HISTORY
+ if (scp->history != NULL) {
+ sc_vtb_append(&scp->vtb, 0, scp->history,
+ scp->ypos * scp->xsize + scp->xpos);
+ scp->history_pos = sc_vtb_tail(scp->history);
+ }
+#endif
+ vidd_set_mode(sc->adp, vmode);
+ scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN);
+ scp->status &= ~(GRAPHICS_MODE | MOUSE_VISIBLE);
+ scp->xpixel = info.vi_width;
+ scp->ypixel = info.vi_height;
+ scp->xsize = scp->xpixel / 8;
+ scp->ysize = scp->ypixel / 16;
+ scp->xpos = 0;
+ scp->ypos = scp->ysize - 1;
+ scp->xoff = scp->yoff = 0;
+#ifndef SC_NO_FONT_LOADING
+ scp->font = sc->font_16;
+#else
+ scp->font = NULL;
+#endif
+ scp->font_size = 16;
+ scp->font_width = 8;
+ scp->start = scp->xsize * scp->ysize - 1;
+ scp->end = 0;
+ scp->cursor_pos = scp->cursor_oldpos = scp->xsize * scp->xsize;
+ scp->mode = sc->initial_mode = vmode;
+#ifndef __sparc64__
+ sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
+ (void *)sc->adp->va_window, FALSE);
+#endif
+ sc_alloc_scr_buffer(scp, FALSE, FALSE);
+ sc_init_emulator(scp, NULL);
+#ifndef SC_NO_CUTPASTE
+ sc_alloc_cut_buffer(scp, FALSE);
+#endif
+#ifndef SC_NO_HISTORY
+ sc_alloc_history_buffer(scp, 0, 0, FALSE);
+#endif
+ sc_set_border(scp, scp->border);
+ sc_set_cursor_image(scp);
+ scp->status &= ~UNKNOWN_MODE;
+#ifdef DEV_SPLASH
+ if ((sc->flags & SC_SPLASH_SCRN) != 0)
+ splash_init(sc->adp, scsplash_callback, sc);
+#endif
}
#endif
@@ -381,8 +440,8 @@ sc_attach_unit(int unit, int flags)
{
sc_softc_t *sc;
scr_stat *scp;
- int vc;
struct cdev *dev;
+ int vc;
flags &= ~SC_KERNEL_CONSOLE;
@@ -404,27 +463,8 @@ sc_attach_unit(int unit, int flags)
sc_console = scp;
#ifdef SC_PIXEL_MODE
- if ((sc->config & SC_VESAMODE) != 0) {
- int vmode;
- vmode = sc_initial_mode(sc->adp, unit);
- if (vmode >= M_VESA_BASE) {
-#ifdef DEV_SPLASH
- if (sc->flags & SC_SPLASH_SCRN)
- splash_term(sc->adp);
-#endif
- sc_set_graphics_mode(scp, NULL, vmode);
- sc_set_pixel_mode(scp, NULL, 0, 0, 16, 8);
-#ifndef SC_NO_PALETTE_LOADING
- vidd_save_palette(sc->adp, sc->palette);
-#endif
- sc->initial_mode = vmode;
-#ifdef DEV_SPLASH
- /* put up the splash again! */
- if (sc->flags & SC_SPLASH_SCRN)
- splash_init(sc->adp, scsplash_callback, sc);
-#endif
- }
- }
+ if ((sc->config & SC_VESAMODE) != 0)
+ sc_set_vesa_mode(scp, sc, unit);
#endif /* SC_PIXEL_MODE */
/* initialize cursor */
@@ -2090,6 +2130,11 @@ restore_scrn_saver_mode(scr_stat *scp, int changemode)
}
if (set_mode(scp) == 0) {
#ifndef SC_NO_PALETTE_LOADING
+#ifdef SC_PIXEL_MODE
+ if ((scp->sc->adp->va_flags & V_ADP_DAC8) != 0)
+ vidd_load_palette(scp->sc->adp, scp->sc->palette2);
+ else
+#endif
vidd_load_palette(scp->sc->adp, scp->sc->palette);
#endif
--scrn_blanked;
@@ -2493,8 +2538,14 @@ exchange_scr(sc_softc_t *sc)
if (!ISGRAPHSC(scp))
sc_set_cursor_image(scp);
#ifndef SC_NO_PALETTE_LOADING
- if (ISGRAPHSC(sc->old_scp))
+ if (ISGRAPHSC(sc->old_scp)) {
+#ifdef SC_PIXEL_MODE
+ if ((sc->adp->va_flags & V_ADP_DAC8) != 0)
+ vidd_load_palette(sc->adp, sc->palette2);
+ else
+#endif
vidd_load_palette(sc->adp, sc->palette);
+ }
#endif
sc_set_border(scp, scp->border);
@@ -2843,6 +2894,10 @@ scinit(int unit, int flags)
#ifndef SC_NO_PALETTE_LOADING
vidd_save_palette(sc->adp, sc->palette);
+#ifdef SC_PIXEL_MODE
+ for (i = 0; i < sizeof(sc->palette2); i++)
+ sc->palette2[i] = i / 3;
+#endif
#endif
#ifdef DEV_SPLASH
diff --git a/sys/dev/syscons/syscons.h b/sys/dev/syscons/syscons.h
index 2f05755..a23f884 100644
--- a/sys/dev/syscons/syscons.h
+++ b/sys/dev/syscons/syscons.h
@@ -245,7 +245,10 @@ typedef struct sc_softc {
#endif
#ifndef SC_NO_PALETTE_LOADING
- u_char palette[256*3];
+ u_char palette[256 * 3];
+#ifdef SC_PIXEL_MODE
+ u_char palette2[256 * 3];
+#endif
#endif
#ifndef SC_NO_FONT_LOADING
@@ -620,6 +623,7 @@ int sc_set_text_mode(scr_stat *scp, struct tty *tp, int mode,
int sc_set_graphics_mode(scr_stat *scp, struct tty *tp, int mode);
int sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize,
int ysize, int fontsize, int font_width);
+int sc_support_pixel_mode(void *arg);
int sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data,
struct thread *td);
diff --git a/sys/dev/uart/uart_bus_pci.c b/sys/dev/uart/uart_bus_pci.c
index 24c4573..48a134b 100644
--- a/sys/dev/uart/uart_bus_pci.c
+++ b/sys/dev/uart/uart_bus_pci.c
@@ -113,6 +113,8 @@ static struct pci_id pci_ns8250_ids[] = {
{ 0x9710, 0x9820, 0x1000, 1, "NetMos NM9820 Serial Port", 0x10 },
{ 0x9710, 0x9835, 0x1000, 1, "NetMos NM9835 Serial Port", 0x10 },
{ 0x9710, 0x9865, 0xa000, 0x1000, "NetMos NM9865 Serial Port", 0x10 },
+{ 0x9710, 0x9901, 0xa000, 0x1000,
+ "MosChip MCS9901 PCIe to Peripheral Controller", 0x10 },
{ 0xdeaf, 0x9051, 0xffff, 0, "Middle Digital PC Weasel Serial Port", 0x10 },
{ 0xffff, 0, 0xffff, 0, NULL, 0, 0}
};
diff --git a/sys/dev/xen/netfront/netfront.c b/sys/dev/xen/netfront/netfront.c
index 93beb8b..d67d354 100644
--- a/sys/dev/xen/netfront/netfront.c
+++ b/sys/dev/xen/netfront/netfront.c
@@ -81,7 +81,7 @@ __FBSDID("$FreeBSD$");
#include "xenbus_if.h"
-#define XN_CSUM_FEATURES (CSUM_TCP | CSUM_UDP | CSUM_TSO)
+#define XN_CSUM_FEATURES (CSUM_TCP | CSUM_UDP)
#define GRANT_INVALID_REF 0
@@ -233,7 +233,7 @@ struct netfront_info {
struct mtx tx_lock;
struct mtx rx_lock;
- struct sx sc_lock;
+ struct mtx sc_lock;
u_int handle;
u_int irq;
@@ -280,7 +280,7 @@ struct netfront_info {
#define XN_LOCK_INIT(_sc, _name) \
mtx_init(&(_sc)->tx_lock, #_name"_tx", "network transmit lock", MTX_DEF); \
mtx_init(&(_sc)->rx_lock, #_name"_rx", "network receive lock", MTX_DEF); \
- sx_init(&(_sc)->sc_lock, #_name"_rx")
+ mtx_init(&(_sc)->sc_lock, #_name"_sc", "netfront softc lock", MTX_DEF)
#define XN_RX_LOCK(_sc) mtx_lock(&(_sc)->rx_lock)
#define XN_RX_UNLOCK(_sc) mtx_unlock(&(_sc)->rx_lock)
@@ -288,15 +288,15 @@ struct netfront_info {
#define XN_TX_LOCK(_sc) mtx_lock(&(_sc)->tx_lock)
#define XN_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->tx_lock)
-#define XN_LOCK(_sc) sx_xlock(&(_sc)->sc_lock);
-#define XN_UNLOCK(_sc) sx_xunlock(&(_sc)->sc_lock);
+#define XN_LOCK(_sc) mtx_lock(&(_sc)->sc_lock);
+#define XN_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_lock);
-#define XN_LOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_lock, SX_LOCKED);
+#define XN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_lock, MA_OWNED);
#define XN_RX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->rx_lock, MA_OWNED);
#define XN_TX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->tx_lock, MA_OWNED);
#define XN_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->rx_lock); \
mtx_destroy(&(_sc)->tx_lock); \
- sx_destroy(&(_sc)->sc_lock);
+ mtx_destroy(&(_sc)->sc_lock);
struct netfront_rx_info {
struct netif_rx_response rx;
@@ -361,9 +361,13 @@ xennet_get_rx_ref(struct netfront_info *np, RING_IDX ri)
#define IPRINTK(fmt, args...) \
printf("[XEN] " fmt, ##args)
+#ifdef INVARIANTS
#define WPRINTK(fmt, args...) \
printf("[XEN] " fmt, ##args)
-#if 0
+#else
+#define WPRINTK(fmt, args...)
+#endif
+#ifdef DEBUG
#define DPRINTK(fmt, args...) \
printf("[XEN] %s: " fmt, __func__, ##args)
#else
@@ -1085,7 +1089,7 @@ xn_txeof(struct netfront_info *np)
ifp->if_opackets++;
if (unlikely(gnttab_query_foreign_access(
np->grant_tx_ref[id]) != 0)) {
- printf("network_tx_buf_gc: warning "
+ WPRINTK("network_tx_buf_gc: warning "
"-- grant still in use by backend "
"domain.\n");
goto out;
@@ -1260,7 +1264,7 @@ xennet_get_responses(struct netfront_info *np,
u_long mfn;
#if 0
- printf("rx->status=%hd rx->offset=%hu frags=%u\n",
+ DPRINTK("rx->status=%hd rx->offset=%hu frags=%u\n",
rx->status, rx->offset, frags);
#endif
if (unlikely(rx->status < 0 ||
@@ -1474,7 +1478,7 @@ xn_start_locked(struct ifnet *ifp)
* slot [0] free for the freelist head
*/
if (sc->xn_cdata.xn_tx_chain_cnt + nfrags >= NET_TX_RING_SIZE) {
- printf("xn_start_locked: xn_tx_chain_cnt (%d) + nfrags %d >= NET_TX_RING_SIZE (%d); must be full!\n",
+ WPRINTK("xn_start_locked: xn_tx_chain_cnt (%d) + nfrags %d >= NET_TX_RING_SIZE (%d); must be full!\n",
(int) sc->xn_cdata.xn_tx_chain_cnt,
(int) nfrags, (int) NET_TX_RING_SIZE);
IF_PREPEND(&ifp->if_snd, m_head);
@@ -1490,7 +1494,7 @@ xn_start_locked(struct ifnet *ifp)
* the required size.
*/
if (RING_FREE_REQUESTS(&sc->tx) < (nfrags + 1)) {
- printf("xn_start_locked: free ring slots (%d) < (nfrags + 1) (%d); must be full!\n",
+ WPRINTK("xn_start_locked: free ring slots (%d) < (nfrags + 1) (%d); must be full!\n",
(int) RING_FREE_REQUESTS(&sc->tx),
(int) (nfrags + 1));
IF_PREPEND(&ifp->if_snd, m_head);
@@ -1821,7 +1825,6 @@ network_connect(struct netfront_info *np)
np->copying_receiver = ((MODPARM_rx_copy && feature_rx_copy) ||
(MODPARM_rx_flip && !feature_rx_flip));
- XN_LOCK(np);
/* Recovery procedure: */
error = talk_to_backend(np->xbdev, np);
if (error)
@@ -1871,7 +1874,6 @@ network_connect(struct netfront_info *np)
xn_txeof(np);
XN_TX_UNLOCK(np);
network_alloc_rx_buffers(np);
- XN_UNLOCK(np);
return (0);
}
@@ -1932,14 +1934,14 @@ create_netdev(device_t dev)
/* A grant for every tx ring slot */
if (gnttab_alloc_grant_references(TX_MAX_TARGET,
&np->gref_tx_head) < 0) {
- printf("#### netfront can't alloc tx grant refs\n");
+ IPRINTK("#### netfront can't alloc tx grant refs\n");
err = ENOMEM;
goto exit;
}
/* A grant for every rx ring slot */
if (gnttab_alloc_grant_references(RX_MAX_TARGET,
&np->gref_rx_head) < 0) {
- printf("#### netfront can't alloc rx grant refs\n");
+ WPRINTK("#### netfront can't alloc rx grant refs\n");
gnttab_free_grant_references(np->gref_tx_head);
err = ENOMEM;
goto exit;
@@ -1960,6 +1962,9 @@ create_netdev(device_t dev)
ifp->if_ioctl = xn_ioctl;
ifp->if_output = ether_output;
ifp->if_start = xn_start;
+#ifdef notyet
+ ifp->if_watchdog = xn_watchdog;
+#endif
ifp->if_init = xn_ifinit;
ifp->if_mtu = ETHERMTU;
ifp->if_snd.ifq_maxlen = NET_TX_RING_SIZE - 1;
@@ -1967,7 +1972,6 @@ create_netdev(device_t dev)
ifp->if_hwassist = XN_CSUM_FEATURES;
ifp->if_capabilities = IFCAP_HWCSUM;
#if __FreeBSD_version >= 700000
- ifp->if_capabilities |= IFCAP_TSO4;
if (xn_enable_lro) {
int err = tcp_lro_init(&np->xn_lro);
if (err) {
diff --git a/sys/fs/ext2fs/ext2_vnops.c b/sys/fs/ext2fs/ext2_vnops.c
index 43a2302..2b2f8c5 100644
--- a/sys/fs/ext2fs/ext2_vnops.c
+++ b/sys/fs/ext2fs/ext2_vnops.c
@@ -894,7 +894,7 @@ abortit:
/*
* If ".." must be changed (ie the directory gets a new
* parent) then the source directory must not be in the
- * directory heirarchy above the target, as this would
+ * directory hierarchy above the target, as this would
* orphan everything below the source directory. Also
* the user must have write permission in the source so
* as to be able to change "..". We must repeat the call
diff --git a/sys/fs/msdosfs/msdosfs_denode.c b/sys/fs/msdosfs/msdosfs_denode.c
index b689b5d..279ee99 100644
--- a/sys/fs/msdosfs/msdosfs_denode.c
+++ b/sys/fs/msdosfs/msdosfs_denode.c
@@ -167,9 +167,8 @@ deget(pmp, dirclust, diroffset, depp)
ldep->de_dirclust = dirclust;
ldep->de_diroffset = diroffset;
ldep->de_inode = inode;
- fc_purge(ldep, 0); /* init the fat cache for this denode */
-
lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL);
+ fc_purge(ldep, 0); /* init the fat cache for this denode */
error = insmntque(nvp, mntp);
if (error != 0) {
free(ldep, M_MSDOSFSNODE);
@@ -183,9 +182,8 @@ deget(pmp, dirclust, diroffset, depp)
return (error);
}
if (xvp != NULL) {
- /* XXX: Not sure this is right */
- nvp = xvp;
- ldep->de_vnode = nvp;
+ *depp = xvp->v_data;
+ return (0);
}
ldep->de_pmp = pmp;
@@ -594,7 +592,7 @@ msdosfs_inactive(ap)
/*
* Ignore denodes related to stale file handles.
*/
- if (dep->de_Name[0] == SLOT_DELETED)
+ if (dep->de_Name[0] == SLOT_DELETED || dep->de_Name[0] == SLOT_EMPTY)
goto out;
/*
@@ -622,7 +620,7 @@ out:
printf("msdosfs_inactive(): v_usecount %d, de_Name[0] %x\n",
vrefcnt(vp), dep->de_Name[0]);
#endif
- if (dep->de_Name[0] == SLOT_DELETED)
+ if (dep->de_Name[0] == SLOT_DELETED || dep->de_Name[0] == SLOT_EMPTY)
vrecycle(vp, td);
return (error);
}
diff --git a/sys/fs/msdosfs/msdosfs_fat.c b/sys/fs/msdosfs/msdosfs_fat.c
index 76d1527..c857b34 100644
--- a/sys/fs/msdosfs/msdosfs_fat.c
+++ b/sys/fs/msdosfs/msdosfs_fat.c
@@ -60,19 +60,6 @@
#include <fs/msdosfs/fat.h>
#include <fs/msdosfs/msdosfsmount.h>
-/*
- * Fat cache stats.
- */
-static int fc_fileextends; /* # of file extends */
-static int fc_lfcempty; /* # of time last file cluster cache entry
- * was empty */
-static int fc_bmapcalls; /* # of times pcbmap was called */
-
-#define LMMAX 20
-static int fc_lmdistance[LMMAX];/* counters for how far off the last
- * cluster mapped entry was. */
-static int fc_largedistance; /* off by more than LMMAX */
-
static int chainalloc(struct msdosfsmount *pmp, u_long start,
u_long count, u_long fillwith, u_long *retcluster,
u_long *got);
@@ -90,6 +77,9 @@ static __inline void
usemap_alloc(struct msdosfsmount *pmp, u_long cn);
static __inline void
usemap_free(struct msdosfsmount *pmp, u_long cn);
+static int clusteralloc1(struct msdosfsmount *pmp, u_long start,
+ u_long count, u_long fillwith, u_long *retcluster,
+ u_long *got);
static void
fatblock(pmp, ofs, bnp, sizep, bop)
@@ -152,14 +142,9 @@ pcbmap(dep, findcn, bnp, cnp, sp)
struct msdosfsmount *pmp = dep->de_pmp;
u_long bsize;
- fc_bmapcalls++;
-
- /*
- * If they don't give us someplace to return a value then don't
- * bother doing anything.
- */
- if (bnp == NULL && cnp == NULL && sp == NULL)
- return (0);
+ KASSERT(bnp != NULL || cnp != NULL || sp != NULL,
+ ("pcbmap: extra call"));
+ ASSERT_VOP_ELOCKED(DETOV(dep), "pcbmap");
cn = dep->de_StartCluster;
/*
@@ -203,10 +188,6 @@ pcbmap(dep, findcn, bnp, cnp, sp)
*/
i = 0;
fc_lookup(dep, findcn, &i, &cn);
- if ((bn = findcn - i) >= LMMAX)
- fc_largedistance++;
- else
- fc_lmdistance[bn]++;
/*
* Handle all other files or directories the normal way.
@@ -289,6 +270,8 @@ fc_lookup(dep, findcn, frcnp, fsrcnp)
u_long cn;
struct fatcache *closest = 0;
+ ASSERT_VOP_LOCKED(DETOV(dep), "fc_lookup");
+
for (i = 0; i < FC_SIZE; i++) {
cn = dep->de_fc[i].fc_frcn;
if (cn != FCE_EMPTY && cn <= findcn) {
@@ -314,6 +297,8 @@ fc_purge(dep, frcn)
int i;
struct fatcache *fcp;
+ ASSERT_VOP_ELOCKED(DETOV(dep), "fc_purge");
+
fcp = dep->de_fc;
for (i = 0; i < FC_SIZE; i++, fcp++) {
if (fcp->fc_frcn >= frcn)
@@ -427,7 +412,13 @@ usemap_alloc(pmp, cn)
u_long cn;
{
+ MSDOSFS_ASSERT_MP_LOCKED(pmp);
+
+ KASSERT((pmp->pm_inusemap[cn / N_INUSEBITS] & (1 << (cn % N_INUSEBITS)))
+ == 0, ("Allocating used sector %ld %ld %x", cn, cn % N_INUSEBITS,
+ (unsigned)pmp->pm_inusemap[cn / N_INUSEBITS]));
pmp->pm_inusemap[cn / N_INUSEBITS] |= 1 << (cn % N_INUSEBITS);
+ KASSERT(pmp->pm_freeclustercount > 0, ("usemap_alloc: too little"));
pmp->pm_freeclustercount--;
}
@@ -437,7 +428,11 @@ usemap_free(pmp, cn)
u_long cn;
{
+ MSDOSFS_ASSERT_MP_LOCKED(pmp);
pmp->pm_freeclustercount++;
+ KASSERT((pmp->pm_inusemap[cn / N_INUSEBITS] & (1 << (cn % N_INUSEBITS)))
+ != 0, ("Freeing unused sector %ld %ld %x", cn, cn % N_INUSEBITS,
+ (unsigned)pmp->pm_inusemap[cn / N_INUSEBITS]));
pmp->pm_inusemap[cn / N_INUSEBITS] &= ~(1 << (cn % N_INUSEBITS));
}
@@ -450,17 +445,17 @@ clusterfree(pmp, cluster, oldcnp)
int error;
u_long oldcn;
- usemap_free(pmp, cluster);
error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, MSDOSFSFREE);
- if (error) {
- usemap_alloc(pmp, cluster);
+ if (error)
return (error);
- }
/*
* If the cluster was successfully marked free, then update
* the count of free clusters, and turn off the "allocated"
* bit in the "in use" cluster bit map.
*/
+ MSDOSFS_LOCK_MP(pmp);
+ usemap_free(pmp, cluster);
+ MSDOSFS_UNLOCK_MP(pmp);
if (oldcnp)
*oldcnp = oldcn;
return (0);
@@ -678,6 +673,8 @@ chainlength(pmp, start, count)
u_int map;
u_long len;
+ MSDOSFS_ASSERT_MP_LOCKED(pmp);
+
max_idx = pmp->pm_maxcluster / N_INUSEBITS;
idx = start / N_INUSEBITS;
start %= N_INUSEBITS;
@@ -726,6 +723,8 @@ chainalloc(pmp, start, count, fillwith, retcluster, got)
int error;
u_long cl, n;
+ MSDOSFS_ASSERT_MP_LOCKED(pmp);
+
for (cl = start, n = count; n-- > 0;)
usemap_alloc(pmp, cl++);
@@ -758,19 +757,28 @@ chainalloc(pmp, start, count, fillwith, retcluster, got)
* got - how many clusters were actually allocated.
*/
int
-clusteralloc(pmp, start, count, fillwith, retcluster, got)
- struct msdosfsmount *pmp;
- u_long start;
- u_long count;
- u_long fillwith;
- u_long *retcluster;
- u_long *got;
+clusteralloc(struct msdosfsmount *pmp, u_long start, u_long count,
+ u_long fillwith, u_long *retcluster, u_long *got)
+{
+ int error;
+
+ MSDOSFS_LOCK_MP(pmp);
+ error = clusteralloc1(pmp, start, count, fillwith, retcluster, got);
+ MSDOSFS_UNLOCK_MP(pmp);
+ return (error);
+}
+
+static int
+clusteralloc1(struct msdosfsmount *pmp, u_long start, u_long count,
+ u_long fillwith, u_long *retcluster, u_long *got)
{
u_long idx;
u_long len, newst, foundl, cn, l;
u_long foundcn = 0; /* XXX: foundcn could be used unititialized */
u_int map;
+ MSDOSFS_ASSERT_MP_LOCKED(pmp);
+
#ifdef MSDOSFS_DEBUG
printf("clusteralloc(): find %lu clusters\n", count);
#endif
@@ -846,6 +854,7 @@ freeclusterchain(pmp, cluster)
u_long bn, bo, bsize, byteoffset;
u_long readcn, lbn = -1;
+ MSDOSFS_LOCK_MP(pmp);
while (cluster >= CLUST_FIRST && cluster <= pmp->pm_maxcluster) {
byteoffset = FATOFS(pmp, cluster);
fatblock(pmp, byteoffset, &bn, &bsize, &bo);
@@ -855,6 +864,7 @@ freeclusterchain(pmp, cluster)
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
if (error) {
brelse(bp);
+ MSDOSFS_UNLOCK_MP(pmp);
return (error);
}
lbn = bn;
@@ -890,6 +900,7 @@ freeclusterchain(pmp, cluster)
}
if (bp)
updatefats(pmp, bp, bn);
+ MSDOSFS_UNLOCK_MP(pmp);
return (0);
}
@@ -906,6 +917,8 @@ fillinusemap(pmp)
int error;
u_long bn, bo, bsize, byteoffset;
+ MSDOSFS_ASSERT_MP_LOCKED(pmp);
+
/*
* Mark all clusters in use, we mark the free ones in the fat scan
* loop further down.
@@ -992,10 +1005,8 @@ extendfile(dep, count, bpp, ncp, flags)
* If the "file's last cluster" cache entry is empty, and the file
* is not empty, then fill the cache entry by calling pcbmap().
*/
- fc_fileextends++;
if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY &&
dep->de_StartCluster != 0) {
- fc_lfcempty++;
error = pcbmap(dep, 0xffff, 0, &cn, 0);
/* we expect it to return E2BIG */
if (error != E2BIG)
diff --git a/sys/fs/msdosfs/msdosfs_fileno.c b/sys/fs/msdosfs/msdosfs_fileno.c
index ff1f2b7..b56fb43 100644
--- a/sys/fs/msdosfs/msdosfs_fileno.c
+++ b/sys/fs/msdosfs/msdosfs_fileno.c
@@ -51,7 +51,6 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mount.h>
-#include <sys/mutex.h>
#include <fs/msdosfs/bpb.h>
#include <fs/msdosfs/direntry.h>
@@ -59,9 +58,6 @@ __FBSDID("$FreeBSD$");
static MALLOC_DEFINE(M_MSDOSFSFILENO, "msdosfs_fileno", "MSDOSFS fileno mapping node");
-static struct mtx fileno_mtx;
-MTX_SYSINIT(fileno, &fileno_mtx, "MSDOSFS fileno", MTX_DEF);
-
RB_PROTOTYPE(msdosfs_filenotree, msdosfs_fileno, mf_tree,
msdosfs_fileno_compare)
@@ -117,30 +113,30 @@ msdosfs_fileno_map(mp, fileno)
}
if (fileno < FILENO_FIRST_DYN)
return ((uint32_t)fileno);
- mtx_lock(&fileno_mtx);
+ MSDOSFS_LOCK_MP(pmp);
key.mf_fileno64 = fileno;
mf = RB_FIND(msdosfs_filenotree, &pmp->pm_filenos, &key);
if (mf != NULL) {
mapped = mf->mf_fileno32;
- mtx_unlock(&fileno_mtx);
+ MSDOSFS_UNLOCK_MP(pmp);
return (mapped);
}
if (pmp->pm_nfileno < FILENO_FIRST_DYN)
panic("msdosfs_fileno_map: wraparound");
- mtx_unlock(&fileno_mtx);
+ MSDOSFS_UNLOCK_MP(pmp);
mf = malloc(sizeof(*mf), M_MSDOSFSFILENO, M_WAITOK);
- mtx_lock(&fileno_mtx);
+ MSDOSFS_LOCK_MP(pmp);
tmf = RB_FIND(msdosfs_filenotree, &pmp->pm_filenos, &key);
if (tmf != NULL) {
mapped = tmf->mf_fileno32;
- mtx_unlock(&fileno_mtx);
+ MSDOSFS_UNLOCK_MP(pmp);
free(mf, M_MSDOSFSFILENO);
return (mapped);
}
mf->mf_fileno64 = fileno;
mapped = mf->mf_fileno32 = pmp->pm_nfileno++;
RB_INSERT(msdosfs_filenotree, &pmp->pm_filenos, mf);
- mtx_unlock(&fileno_mtx);
+ MSDOSFS_UNLOCK_MP(pmp);
return (mapped);
}
diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c
index 8e0c3d5..ce5048a 100644
--- a/sys/fs/msdosfs/msdosfs_lookup.c
+++ b/sys/fs/msdosfs/msdosfs_lookup.c
@@ -61,6 +61,18 @@
#include <fs/msdosfs/fat.h>
#include <fs/msdosfs/msdosfsmount.h>
+static int msdosfs_lookup_(struct vnode *vdp, struct vnode **vpp,
+ struct componentname *cnp, u_int64_t *inum);
+static int msdosfs_deget_dotdot(struct vnode *vp, u_long cluster, int blkoff,
+ struct vnode **rvp);
+
+int
+msdosfs_lookup(struct vop_cachedlookup_args *ap)
+{
+
+ return (msdosfs_lookup_(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL));
+}
+
/*
* When we search a directory the blocks containing directory entries are
* read and examined. The directory entries contain information that would
@@ -76,18 +88,11 @@
* out to disk. This way disk blocks containing directory entries and in
* memory denode's will be in synch.
*/
-int
-msdosfs_lookup(ap)
- struct vop_cachedlookup_args /* {
- struct vnode *a_dvp;
- struct vnode **a_vpp;
- struct componentname *a_cnp;
- } */ *ap;
+static int
+msdosfs_lookup_(struct vnode *vdp, struct vnode **vpp,
+ struct componentname *cnp, u_int64_t *dd_inum)
{
struct mbnambuf nb;
- struct vnode *vdp = ap->a_dvp;
- struct vnode **vpp = ap->a_vpp;
- struct componentname *cnp = ap->a_cnp;
daddr_t bn;
int error;
int slotcount;
@@ -109,6 +114,7 @@ msdosfs_lookup(ap)
int flags = cnp->cn_flags;
int nameiop = cnp->cn_nameiop;
int unlen;
+ u_int64_t inode1;
int wincnt = 1;
int chksum = -1, chksum_ok;
@@ -119,12 +125,14 @@ msdosfs_lookup(ap)
#endif
dp = VTODE(vdp);
pmp = dp->de_pmp;
- *vpp = NULL;
+ if (vpp != NULL)
+ *vpp = NULL;
#ifdef MSDOSFS_DEBUG
printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n",
vdp, dp, dp->de_Attributes);
#endif
+ restart:
/*
* If they are going after the . or .. entry in the root directory,
* they won't find it. DOS filesystems don't have them in the root
@@ -436,6 +444,11 @@ foundroot:
if (FAT32(pmp) && scn == MSDOSFSROOT)
scn = pmp->pm_rootdirblk;
+ if (dd_inum != NULL) {
+ *dd_inum = (uint64_t)pmp->pm_bpcluster * scn + blkoff;
+ return (0);
+ }
+
/*
* If deleting, and at end of pathname, return
* parameters which can be used to remove file.
@@ -508,23 +521,25 @@ foundroot:
* inodes from the root, moving down the directory tree. Thus
* when following backward pointers ".." we must unlock the
* parent directory before getting the requested directory.
- * There is a potential race condition here if both the current
- * and parent directories are removed before the VFS_VGET for the
- * inode associated with ".." returns. We hope that this occurs
- * infrequently since we cannot avoid this race condition without
- * implementing a sophisticated deadlock detection algorithm.
- * Note also that this simple deadlock detection scheme will not
- * work if the filesystem has any hard links other than ".."
- * that point backwards in the directory structure.
*/
pdp = vdp;
if (flags & ISDOTDOT) {
- VOP_UNLOCK(pdp, 0);
- error = deget(pmp, cluster, blkoff, &tdp);
- vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY);
+ error = msdosfs_deget_dotdot(pdp, cluster, blkoff, vpp);
if (error)
return (error);
- *vpp = DETOV(tdp);
+ /*
+ * Recheck that ".." still points to the inode we
+ * looked up before pdp lock was dropped.
+ */
+ error = msdosfs_lookup_(pdp, NULL, cnp, &inode1);
+ if (error) {
+ vput(*vpp);
+ return (error);
+ }
+ if (VTODE(*vpp)->de_inode != inode1) {
+ vput(*vpp);
+ goto restart;
+ }
} else if (dp->de_StartCluster == scn && isadir) {
VREF(vdp); /* we want ourself, ie "." */
*vpp = vdp;
@@ -542,6 +557,49 @@ foundroot:
return (0);
}
+static int
+msdosfs_deget_dotdot(struct vnode *vp, u_long cluster, int blkoff,
+ struct vnode **rvp)
+{
+ struct mount *mp;
+ struct msdosfsmount *pmp;
+ struct denode *rdp;
+ int ltype, error;
+
+ mp = vp->v_mount;
+ pmp = VFSTOMSDOSFS(mp);
+ ltype = VOP_ISLOCKED(vp);
+ KASSERT(ltype == LK_EXCLUSIVE || ltype == LK_SHARED,
+ ("msdosfs_deget_dotdot: vp not locked"));
+
+ error = vfs_busy(mp, MBF_NOWAIT);
+ if (error != 0) {
+ vfs_ref(mp);
+ VOP_UNLOCK(vp, 0);
+ error = vfs_busy(mp, 0);
+ vn_lock(vp, ltype | LK_RETRY);
+ vfs_rel(mp);
+ if (error != 0)
+ return (ENOENT);
+ if (vp->v_iflag & VI_DOOMED) {
+ vfs_unbusy(mp);
+ return (ENOENT);
+ }
+ }
+ VOP_UNLOCK(vp, 0);
+ error = deget(pmp, cluster, blkoff, &rdp);
+ vfs_unbusy(mp);
+ if (error == 0)
+ *rvp = DETOV(rdp);
+ vn_lock(vp, ltype | LK_RETRY);
+ if (vp->v_iflag & VI_DOOMED) {
+ if (error == 0)
+ vput(*rvp);
+ error = ENOENT;
+ }
+ return (error);
+}
+
/*
* dep - directory entry to copy into the directory
* ddep - directory to add to
diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c
index 8186763..77583ee 100644
--- a/sys/fs/msdosfs/msdosfs_vfsops.c
+++ b/sys/fs/msdosfs/msdosfs_vfsops.c
@@ -75,6 +75,8 @@
#include <fs/msdosfs/fat.h>
#include <fs/msdosfs/msdosfsmount.h>
+static const char msdosfs_lock_msg[] = "fatlk";
+
/* Mount options that we support. */
static const char *msdosfs_opts[] = {
"async", "noatime", "noclusterr", "noclusterw",
@@ -381,10 +383,9 @@ msdosfs_mount(struct mount *mp)
pmp = VFSTOMSDOSFS(mp);
#endif
} else {
+ vput(devvp);
if (devvp != pmp->pm_devvp)
- error = EINVAL; /* XXX needs translation */
- else
- vput(devvp);
+ return (EINVAL); /* XXX needs translation */
}
if (error) {
vrele(devvp);
@@ -466,6 +467,8 @@ mountmsdosfs(struct vnode *devvp, struct mount *mp)
pmp->pm_cp = cp;
pmp->pm_bo = bo;
+ lockinit(&pmp->pm_fatlock, 0, msdosfs_lock_msg, 0, 0);
+
/*
* Initialize ownerships and permissions, since nothing else will
* initialize them iff we are mounting root.
@@ -716,7 +719,10 @@ mountmsdosfs(struct vnode *devvp, struct mount *mp)
/*
* Have the inuse map filled in.
*/
- if ((error = fillinusemap(pmp)) != 0)
+ MSDOSFS_LOCK_MP(pmp);
+ error = fillinusemap(pmp);
+ MSDOSFS_UNLOCK_MP(pmp);
+ if (error != 0)
goto error_exit;
/*
@@ -745,6 +751,7 @@ mountmsdosfs(struct vnode *devvp, struct mount *mp)
mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
MNT_ILOCK(mp);
mp->mnt_flag |= MNT_LOCAL;
+ mp->mnt_kern_flag |= MNTK_MPSAFE;
MNT_IUNLOCK(mp);
if (pmp->pm_flags & MSDOSFS_LARGEFS)
@@ -763,6 +770,7 @@ error_exit:
PICKUP_GIANT();
}
if (pmp) {
+ lockdestroy(&pmp->pm_fatlock);
if (pmp->pm_inusemap)
free(pmp->pm_inusemap, M_MSDOSFSFAT);
free(pmp, M_MSDOSFSMNT);
@@ -837,6 +845,7 @@ msdosfs_unmount(struct mount *mp, int mntflags)
free(pmp->pm_inusemap, M_MSDOSFSFAT);
if (pmp->pm_flags & MSDOSFS_LARGEFS)
msdosfs_fileno_free(mp);
+ lockdestroy(&pmp->pm_fatlock);
free(pmp, M_MSDOSFSMNT);
mp->mnt_data = NULL;
MNT_ILOCK(mp);
diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c
index e232f49..e9c593b 100644
--- a/sys/fs/msdosfs/msdosfs_vnops.c
+++ b/sys/fs/msdosfs/msdosfs_vnops.c
@@ -1072,7 +1072,7 @@ abortit:
/*
* If ".." must be changed (ie the directory gets a new
* parent) then the source directory must not be in the
- * directory heirarchy above the target, as this would
+ * directory hierarchy above the target, as this would
* orphan everything below the source directory. Also
* the user must have write permission in the source so
* as to be able to change "..". We must repeat the call
@@ -1468,14 +1468,12 @@ msdosfs_rmdir(ap)
* the name cache.
*/
cache_purge(dvp);
- VOP_UNLOCK(dvp, 0);
/*
* Truncate the directory that is being deleted.
*/
error = detrunc(ip, (u_long)0, IO_SYNC, cnp->cn_cred, td);
cache_purge(vp);
- vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
out:
return (error);
}
diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h
index bfe3ec3..2951b2c 100644
--- a/sys/fs/msdosfs/msdosfsmount.h
+++ b/sys/fs/msdosfs/msdosfsmount.h
@@ -53,6 +53,9 @@
#ifdef _KERNEL
+#include <sys/types.h>
+#include <sys/lock.h>
+#include <sys/lockmgr.h>
#include <sys/tree.h>
#ifdef MALLOC_DECLARE
@@ -106,7 +109,9 @@ struct msdosfsmount {
void *pm_u2d; /* Unicode->DOS iconv handle */
void *pm_d2u; /* DOS->Local iconv handle */
u_int32_t pm_nfileno; /* next 32-bit fileno */
- RB_HEAD(msdosfs_filenotree, msdosfs_fileno) pm_filenos; /* 64<->32-bit fileno mapping */
+ RB_HEAD(msdosfs_filenotree, msdosfs_fileno)
+ pm_filenos; /* 64<->32-bit fileno mapping */
+ struct lock pm_fatlock; /* lockmgr protecting allocations and rb tree */
};
/*
@@ -215,6 +220,13 @@ void msdosfs_fileno_init(struct mount *);
void msdosfs_fileno_free(struct mount *);
uint32_t msdosfs_fileno_map(struct mount *, uint64_t);
+#define MSDOSFS_LOCK_MP(pmp) \
+ lockmgr(&(pmp)->pm_fatlock, LK_EXCLUSIVE, NULL)
+#define MSDOSFS_UNLOCK_MP(pmp) \
+ lockmgr(&(pmp)->pm_fatlock, LK_RELEASE, NULL)
+#define MSDOSFS_ASSERT_MP_LOCKED(pmp) \
+ lockmgr_assert(&(pmp)->pm_fatlock, KA_XLOCKED)
+
#endif /* _KERNEL */
/*
diff --git a/sys/geom/gate/g_gate.c b/sys/geom/gate/g_gate.c
index 26df0f4..952e856 100644
--- a/sys/geom/gate/g_gate.c
+++ b/sys/geom/gate/g_gate.c
@@ -1,7 +1,11 @@
/*-
* Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
* All rights reserved.
*
+ * Portions of this software were developed by Pawel Jakub Dawidek
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -53,9 +57,14 @@ static MALLOC_DEFINE(M_GATE, "gg_data", "GEOM Gate Data");
SYSCTL_DECL(_kern_geom);
SYSCTL_NODE(_kern_geom, OID_AUTO, gate, CTLFLAG_RW, 0, "GEOM_GATE stuff");
-static u_int g_gate_debug = 0;
-SYSCTL_UINT(_kern_geom_gate, OID_AUTO, debug, CTLFLAG_RW, &g_gate_debug, 0,
+static int g_gate_debug = 0;
+TUNABLE_INT("kern.geom.gate.debug", &g_gate_debug);
+SYSCTL_INT(_kern_geom_gate, OID_AUTO, debug, CTLFLAG_RW, &g_gate_debug, 0,
"Debug level");
+static u_int g_gate_maxunits = 256;
+TUNABLE_INT("kern.geom.gate.maxunits", &g_gate_maxunits);
+SYSCTL_UINT(_kern_geom_gate, OID_AUTO, maxunits, CTLFLAG_RDTUN,
+ &g_gate_maxunits, 0, "Maximum number of ggate devices");
struct g_class g_gate_class = {
.name = G_GATE_CLASS_NAME,
@@ -71,10 +80,9 @@ static struct cdevsw g_gate_cdevsw = {
};
-static LIST_HEAD(, g_gate_softc) g_gate_list =
- LIST_HEAD_INITIALIZER(g_gate_list);
-static struct mtx g_gate_list_mtx;
-
+static struct g_gate_softc **g_gate_units;
+static u_int g_gate_nunits;
+static struct mtx g_gate_units_lock;
static int
g_gate_destroy(struct g_gate_softc *sc, boolean_t force)
@@ -84,13 +92,13 @@ g_gate_destroy(struct g_gate_softc *sc, boolean_t force)
struct bio *bp;
g_topology_assert();
- mtx_assert(&g_gate_list_mtx, MA_OWNED);
+ mtx_assert(&g_gate_units_lock, MA_OWNED);
pp = sc->sc_provider;
if (!force && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
- mtx_unlock(&g_gate_list_mtx);
+ mtx_unlock(&g_gate_units_lock);
return (EBUSY);
}
- mtx_unlock(&g_gate_list_mtx);
+ mtx_unlock(&g_gate_units_lock);
mtx_lock(&sc->sc_queue_mtx);
if ((sc->sc_flags & G_GATE_FLAG_DESTROY) == 0)
sc->sc_flags |= G_GATE_FLAG_DESTROY;
@@ -125,14 +133,15 @@ g_gate_destroy(struct g_gate_softc *sc, boolean_t force)
}
mtx_unlock(&sc->sc_queue_mtx);
g_topology_unlock();
- mtx_lock(&g_gate_list_mtx);
+ mtx_lock(&g_gate_units_lock);
/* One reference is ours. */
sc->sc_ref--;
- while (sc->sc_ref > 0) {
- msleep(&sc->sc_ref, &g_gate_list_mtx, 0, "gg:destroy", 0);
- }
- LIST_REMOVE(sc, sc_next);
- mtx_unlock(&g_gate_list_mtx);
+ while (sc->sc_ref > 0)
+ msleep(&sc->sc_ref, &g_gate_units_lock, 0, "gg:destroy", 0);
+ g_gate_units[sc->sc_unit] = NULL;
+ KASSERT(g_gate_nunits > 0, ("negative g_gate_nunits?"));
+ g_gate_nunits--;
+ mtx_unlock(&g_gate_units_lock);
mtx_destroy(&sc->sc_queue_mtx);
g_topology_lock();
G_GATE_DEBUG(0, "Device %s destroyed.", gp->name);
@@ -196,7 +205,7 @@ g_gate_start(struct bio *bp)
if (sc->sc_queue_count > sc->sc_queue_size) {
mtx_unlock(&sc->sc_queue_mtx);
G_GATE_LOGREQ(1, bp, "Queue full, request canceled.");
- g_io_deliver(bp, EIO);
+ g_io_deliver(bp, ENOMEM);
return;
}
@@ -211,18 +220,29 @@ g_gate_start(struct bio *bp)
}
static struct g_gate_softc *
-g_gate_hold(u_int unit)
+g_gate_hold(u_int unit, const char *name)
{
- struct g_gate_softc *sc;
-
- mtx_lock(&g_gate_list_mtx);
- LIST_FOREACH(sc, &g_gate_list, sc_next) {
- if (sc->sc_unit == unit)
+ struct g_gate_softc *sc = NULL;
+
+ mtx_lock(&g_gate_units_lock);
+ if (unit >= 0 && unit < g_gate_maxunits)
+ sc = g_gate_units[unit];
+ else if (unit == G_GATE_NAME_GIVEN) {
+ KASSERT(name != NULL, ("name is NULL"));
+ for (unit = 0; unit < g_gate_maxunits; unit++) {
+ if (g_gate_units[unit] == NULL)
+ continue;
+ if (strcmp(name,
+ g_gate_units[unit]->sc_provider->name) != 0) {
+ continue;
+ }
+ sc = g_gate_units[unit];
break;
+ }
}
if (sc != NULL)
sc->sc_ref++;
- mtx_unlock(&g_gate_list_mtx);
+ mtx_unlock(&g_gate_units_lock);
return (sc);
}
@@ -231,40 +251,34 @@ g_gate_release(struct g_gate_softc *sc)
{
g_topology_assert_not();
- mtx_lock(&g_gate_list_mtx);
+ mtx_lock(&g_gate_units_lock);
sc->sc_ref--;
KASSERT(sc->sc_ref >= 0, ("Negative sc_ref for %s.", sc->sc_name));
- if (sc->sc_ref == 0 && (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) {
+ if (sc->sc_ref == 0 && (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0)
wakeup(&sc->sc_ref);
- mtx_unlock(&g_gate_list_mtx);
- } else {
- mtx_unlock(&g_gate_list_mtx);
- }
+ mtx_unlock(&g_gate_units_lock);
}
static int
-g_gate_getunit(int unit)
+g_gate_getunit(int unit, int *errorp)
{
- struct g_gate_softc *sc;
- mtx_assert(&g_gate_list_mtx, MA_OWNED);
+ mtx_assert(&g_gate_units_lock, MA_OWNED);
if (unit >= 0) {
- LIST_FOREACH(sc, &g_gate_list, sc_next) {
- if (sc->sc_unit == unit)
- return (-1);
- }
+ if (unit >= g_gate_maxunits)
+ *errorp = EINVAL;
+ else if (g_gate_units[unit] == NULL)
+ return (unit);
+ else
+ *errorp = EEXIST;
} else {
- unit = 0;
-once_again:
- LIST_FOREACH(sc, &g_gate_list, sc_next) {
- if (sc->sc_unit == unit) {
- if (++unit > 666)
- return (-1);
- goto once_again;
- }
+ for (unit = 0; unit < g_gate_maxunits; unit++) {
+ if (g_gate_units[unit] == NULL)
+ return (unit);
}
+ *errorp = ENFILE;
}
- return (unit);
+ return (-1);
}
static void
@@ -276,7 +290,7 @@ g_gate_guard(void *arg)
sc = arg;
binuptime(&curtime);
- g_gate_hold(sc->sc_unit);
+ g_gate_hold(sc->sc_unit, NULL);
mtx_lock(&sc->sc_queue_mtx);
TAILQ_FOREACH_SAFE(bp, &sc->sc_inqueue.queue, bio_queue, bp2) {
if (curtime.sec - bp->bio_t0.sec < 5)
@@ -311,7 +325,7 @@ g_gate_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
sc = gp->softc;
if (sc == NULL || pp != NULL || cp != NULL)
return;
- g_gate_hold(sc->sc_unit);
+ g_gate_hold(sc->sc_unit, NULL);
if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0) {
sbuf_printf(sb, "%s<access>%s</access>\n", indent, "read-only");
} else if ((sc->sc_flags & G_GATE_FLAG_WRITEONLY) != 0) {
@@ -328,6 +342,7 @@ g_gate_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
sbuf_printf(sb, "%s<queue_size>%u</queue_size>\n", indent,
sc->sc_queue_size);
sbuf_printf(sb, "%s<ref>%u</ref>\n", indent, sc->sc_ref);
+ sbuf_printf(sb, "%s<unit>%d</unit>\n", indent, sc->sc_unit);
g_topology_unlock();
g_gate_release(sc);
g_topology_lock();
@@ -339,6 +354,8 @@ g_gate_create(struct g_gate_ctl_create *ggio)
struct g_gate_softc *sc;
struct g_geom *gp;
struct g_provider *pp;
+ char name[NAME_MAX];
+ int error = 0, unit;
if (ggio->gctl_mediasize == 0) {
G_GATE_DEBUG(1, "Invalid media size.");
@@ -357,15 +374,22 @@ g_gate_create(struct g_gate_ctl_create *ggio)
G_GATE_DEBUG(1, "Invalid flags.");
return (EINVAL);
}
- if (ggio->gctl_unit < -1) {
+ if (ggio->gctl_unit != G_GATE_UNIT_AUTO &&
+ ggio->gctl_unit != G_GATE_NAME_GIVEN &&
+ ggio->gctl_unit < 0) {
G_GATE_DEBUG(1, "Invalid unit number.");
return (EINVAL);
}
+ if (ggio->gctl_unit == G_GATE_NAME_GIVEN &&
+ ggio->gctl_name[0] == '\0') {
+ G_GATE_DEBUG(1, "No device name.");
+ return (EINVAL);
+ }
sc = malloc(sizeof(*sc), M_GATE, M_WAITOK | M_ZERO);
sc->sc_flags = (ggio->gctl_flags & G_GATE_USERFLAGS);
strlcpy(sc->sc_info, ggio->gctl_info, sizeof(sc->sc_info));
- sc->sc_seq = 0;
+ sc->sc_seq = 1;
bioq_init(&sc->sc_inqueue);
bioq_init(&sc->sc_outqueue);
mtx_init(&sc->sc_queue_mtx, "gg:queue", NULL, MTX_DEF);
@@ -375,26 +399,44 @@ g_gate_create(struct g_gate_ctl_create *ggio)
sc->sc_queue_size = G_GATE_MAX_QUEUE_SIZE;
sc->sc_timeout = ggio->gctl_timeout;
callout_init(&sc->sc_callout, CALLOUT_MPSAFE);
- mtx_lock(&g_gate_list_mtx);
- ggio->gctl_unit = g_gate_getunit(ggio->gctl_unit);
- if (ggio->gctl_unit == -1) {
- mtx_unlock(&g_gate_list_mtx);
+ mtx_lock(&g_gate_units_lock);
+ sc->sc_unit = g_gate_getunit(ggio->gctl_unit, &error);
+ if (sc->sc_unit < 0) {
+ mtx_unlock(&g_gate_units_lock);
mtx_destroy(&sc->sc_queue_mtx);
free(sc, M_GATE);
- return (EBUSY);
+ return (error);
+ }
+ if (ggio->gctl_unit == G_GATE_NAME_GIVEN)
+ snprintf(name, sizeof(name), "%s", ggio->gctl_name);
+ else {
+ snprintf(name, sizeof(name), "%s%d", G_GATE_PROVIDER_NAME,
+ sc->sc_unit);
}
- sc->sc_unit = ggio->gctl_unit;
- LIST_INSERT_HEAD(&g_gate_list, sc, sc_next);
- mtx_unlock(&g_gate_list_mtx);
+ /* Check for name collision. */
+ for (unit = 0; unit < g_gate_maxunits; unit++) {
+ if (g_gate_units[unit] == NULL)
+ continue;
+ if (strcmp(name, g_gate_units[unit]->sc_provider->name) != 0)
+ continue;
+ mtx_unlock(&g_gate_units_lock);
+ mtx_destroy(&sc->sc_queue_mtx);
+ free(sc, M_GATE);
+ return (EEXIST);
+ }
+ g_gate_units[sc->sc_unit] = sc;
+ g_gate_nunits++;
+ mtx_unlock(&g_gate_units_lock);
+
+ ggio->gctl_unit = sc->sc_unit;
g_topology_lock();
- gp = g_new_geomf(&g_gate_class, "%s%d", G_GATE_PROVIDER_NAME,
- sc->sc_unit);
+ gp = g_new_geomf(&g_gate_class, "%s", name);
gp->start = g_gate_start;
gp->access = g_gate_access;
gp->dumpconf = g_gate_dumpconf;
gp->softc = sc;
- pp = g_new_providerf(gp, "%s%d", G_GATE_PROVIDER_NAME, sc->sc_unit);
+ pp = g_new_providerf(gp, "%s", name);
pp->mediasize = ggio->gctl_mediasize;
pp->sectorsize = ggio->gctl_sectorsize;
sc->sc_provider = pp;
@@ -446,11 +488,11 @@ g_gate_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct threa
struct g_gate_ctl_destroy *ggio = (void *)addr;
G_GATE_CHECK_VERSION(ggio);
- sc = g_gate_hold(ggio->gctl_unit);
+ sc = g_gate_hold(ggio->gctl_unit, ggio->gctl_name);
if (sc == NULL)
return (ENXIO);
g_topology_lock();
- mtx_lock(&g_gate_list_mtx);
+ mtx_lock(&g_gate_units_lock);
error = g_gate_destroy(sc, ggio->gctl_force);
g_topology_unlock();
if (error != 0)
@@ -463,7 +505,7 @@ g_gate_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct threa
struct bio *tbp, *lbp;
G_GATE_CHECK_VERSION(ggio);
- sc = g_gate_hold(ggio->gctl_unit);
+ sc = g_gate_hold(ggio->gctl_unit, ggio->gctl_name);
if (sc == NULL)
return (ENXIO);
lbp = NULL;
@@ -491,6 +533,8 @@ g_gate_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct threa
break;
}
}
+ if (ggio->gctl_unit == G_GATE_NAME_GIVEN)
+ ggio->gctl_unit = sc->sc_unit;
mtx_unlock(&sc->sc_queue_mtx);
g_gate_release(sc);
return (error);
@@ -500,7 +544,7 @@ g_gate_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct threa
struct g_gate_ctl_io *ggio = (void *)addr;
G_GATE_CHECK_VERSION(ggio);
- sc = g_gate_hold(ggio->gctl_unit);
+ sc = g_gate_hold(ggio->gctl_unit, NULL);
if (sc == NULL)
return (ENXIO);
error = 0;
@@ -561,7 +605,7 @@ start_end:
struct g_gate_ctl_io *ggio = (void *)addr;
G_GATE_CHECK_VERSION(ggio);
- sc = g_gate_hold(ggio->gctl_unit);
+ sc = g_gate_hold(ggio->gctl_unit, NULL);
if (sc == NULL)
return (ENOENT);
error = 0;
@@ -631,20 +675,24 @@ g_gate_modevent(module_t mod, int type, void *data)
switch (type) {
case MOD_LOAD:
- mtx_init(&g_gate_list_mtx, "gg_list_lock", NULL, MTX_DEF);
+ mtx_init(&g_gate_units_lock, "gg_units_lock", NULL, MTX_DEF);
+ g_gate_units = malloc(g_gate_maxunits * sizeof(g_gate_units[0]),
+ M_GATE, M_WAITOK | M_ZERO);
+ g_gate_nunits = 0;
g_gate_device();
break;
case MOD_UNLOAD:
- mtx_lock(&g_gate_list_mtx);
- if (!LIST_EMPTY(&g_gate_list)) {
- mtx_unlock(&g_gate_list_mtx);
+ mtx_lock(&g_gate_units_lock);
+ if (g_gate_nunits > 0) {
+ mtx_unlock(&g_gate_units_lock);
error = EBUSY;
break;
}
- mtx_unlock(&g_gate_list_mtx);
- mtx_destroy(&g_gate_list_mtx);
+ mtx_unlock(&g_gate_units_lock);
+ mtx_destroy(&g_gate_units_lock);
if (status_dev != 0)
destroy_dev(status_dev);
+ free(g_gate_units, M_GATE);
break;
default:
return (EOPNOTSUPP);
diff --git a/sys/geom/gate/g_gate.h b/sys/geom/gate/g_gate.h
index cd2564d..4f41348 100644
--- a/sys/geom/gate/g_gate.h
+++ b/sys/geom/gate/g_gate.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * Copyright (c) 2004-2009 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -41,7 +41,7 @@
#define G_GATE_MOD_NAME "ggate"
#define G_GATE_CTL_NAME "ggctl"
-#define G_GATE_VERSION 1
+#define G_GATE_VERSION 2
/*
* Maximum number of request that can be stored in
@@ -54,6 +54,15 @@
#define G_GATE_FLAG_DESTROY 0x1000
#define G_GATE_USERFLAGS (G_GATE_FLAG_READONLY | G_GATE_FLAG_WRITEONLY)
+/*
+ * Pick unit number automatically in /dev/ggate<unit>.
+ */
+#define G_GATE_UNIT_AUTO (-1)
+/*
+ * Full provider name is given, so don't use ggate<unit>.
+ */
+#define G_GATE_NAME_GIVEN (-2)
+
#define G_GATE_CMD_CREATE _IOWR('m', 0, struct g_gate_ctl_create)
#define G_GATE_CMD_DESTROY _IOWR('m', 1, struct g_gate_ctl_destroy)
#define G_GATE_CMD_CANCEL _IOWR('m', 2, struct g_gate_ctl_cancel)
@@ -120,20 +129,23 @@ struct g_gate_ctl_create {
u_int gctl_flags;
u_int gctl_maxcount;
u_int gctl_timeout;
+ char gctl_name[NAME_MAX];
char gctl_info[G_GATE_INFOSIZE];
- int gctl_unit; /* out */
+ int gctl_unit; /* in/out */
};
struct g_gate_ctl_destroy {
u_int gctl_version;
int gctl_unit;
int gctl_force;
+ char gctl_name[NAME_MAX];
};
struct g_gate_ctl_cancel {
u_int gctl_version;
int gctl_unit;
uintptr_t gctl_seq;
+ char gctl_name[NAME_MAX];
};
struct g_gate_ctl_io {
diff --git a/sys/geom/geom_subr.c b/sys/geom/geom_subr.c
index ae7ee30..9bef0e3 100644
--- a/sys/geom/geom_subr.c
+++ b/sys/geom/geom_subr.c
@@ -707,6 +707,7 @@ g_attach(struct g_consumer *cp, struct g_provider *pp)
g_topology_assert();
G_VALID_CONSUMER(cp);
G_VALID_PROVIDER(pp);
+ g_trace(G_T_TOPOLOGY, "g_attach(%p, %p)", cp, pp);
KASSERT(cp->provider == NULL, ("attach but attached"));
cp->provider = pp;
LIST_INSERT_HEAD(&pp->consumers, cp, consumers);
diff --git a/sys/geom/multipath/g_multipath.c b/sys/geom/multipath/g_multipath.c
index d24edb6..a2e61586 100644
--- a/sys/geom/multipath/g_multipath.c
+++ b/sys/geom/multipath/g_multipath.c
@@ -95,9 +95,8 @@ g_mpd(void *arg, int flags __unused)
g_topology_assert();
cp = arg;
- if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) {
+ if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
g_access(cp, -cp->acr, -cp->acw, -cp->ace);
- }
if (cp->provider) {
printf("GEOM_MULTIPATH: %s removed from %s\n",
cp->provider->name, cp->geom->name);
@@ -222,15 +221,16 @@ g_multipath_done_error(struct bio *bp)
static void
g_multipath_kt(void *arg)
{
+
g_multipath_kt_state = GKT_RUN;
mtx_lock(&gmtbq_mtx);
while (g_multipath_kt_state == GKT_RUN) {
for (;;) {
struct bio *bp;
+
bp = bioq_takefirst(&gmtbq);
- if (bp == NULL) {
+ if (bp == NULL)
break;
- }
mtx_unlock(&gmtbq_mtx);
g_multipath_done_error(bp);
mtx_lock(&gmtbq_mtx);
@@ -264,9 +264,8 @@ g_multipath_access(struct g_provider *pp, int dr, int dw, int de)
fail:
LIST_FOREACH(cp, &gp->consumer, consumer) {
- if (cp == badcp) {
+ if (cp == badcp)
break;
- }
(void) g_access(cp, -dr, -dw, -de);
}
return (error);
@@ -290,9 +289,8 @@ g_multipath_create(struct g_class *mp, struct g_multipath_metadata *md)
}
gp = g_new_geomf(mp, md->md_name);
- if (gp == NULL) {
+ if (gp == NULL)
goto fail;
- }
sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
gp->softc = sc;
@@ -303,9 +301,8 @@ g_multipath_create(struct g_class *mp, struct g_multipath_metadata *md)
memcpy(sc->sc_name, md->md_name, sizeof (sc->sc_name));
pp = g_new_providerf(gp, "multipath/%s", md->md_name);
- if (pp == NULL) {
+ if (pp == NULL)
goto fail;
- }
/* limit the provider to not have it stomp on metadata */
pp->mediasize = md->md_size - md->md_sectorsize;
pp->sectorsize = md->md_sectorsize;
@@ -314,9 +311,8 @@ g_multipath_create(struct g_class *mp, struct g_multipath_metadata *md)
return (gp);
fail:
if (gp != NULL) {
- if (gp->softc != NULL) {
+ if (gp->softc != NULL)
g_free(gp->softc);
- }
g_destroy_geom(gp);
}
return (NULL);
@@ -338,9 +334,8 @@ g_multipath_add_disk(struct g_geom *gp, struct g_provider *pp)
* Make sure that the passed provider isn't already attached
*/
LIST_FOREACH(cp, &gp->consumer, consumer) {
- if (cp->provider == pp) {
+ if (cp->provider == pp)
break;
- }
}
if (cp) {
printf("GEOM_MULTIPATH: provider %s already attached to %s\n",
@@ -349,9 +344,8 @@ g_multipath_add_disk(struct g_geom *gp, struct g_provider *pp)
}
nxtcp = LIST_FIRST(&gp->consumer);
cp = g_new_consumer(gp);
- if (cp == NULL) {
+ if (cp == NULL)
return (ENOMEM);
- }
error = g_attach(cp, pp);
if (error != 0) {
printf("GEOM_MULTIPATH: cannot attach %s to %s",
@@ -392,13 +386,11 @@ g_multipath_destroy(struct g_geom *gp)
struct g_provider *pp;
g_topology_assert();
- if (gp->softc == NULL) {
+ if (gp->softc == NULL)
return (ENXIO);
- }
pp = LIST_FIRST(&gp->provider);
- if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
+ if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0))
return (EBUSY);
- }
printf("GEOM_MULTIPATH: destroying %s\n", gp->name);
g_free(gp->softc);
gp->softc = NULL;
@@ -410,6 +402,7 @@ static int
g_multipath_destroy_geom(struct gctl_req *req, struct g_class *mp,
struct g_geom *gp)
{
+
return (g_multipath_destroy(gp));
}
@@ -418,9 +411,8 @@ g_multipath_init(struct g_class *mp)
{
bioq_init(&gmtbq);
mtx_init(&gmtbq_mtx, "gmtbq", NULL, MTX_DEF);
- if (kproc_create(g_multipath_kt, mp, NULL, 0, 0, "g_mp_kt") == 0) {
+ if (kproc_create(g_multipath_kt, mp, NULL, 0, 0, "g_mp_kt") == 0)
g_multipath_kt_state = GKT_RUN;
- }
}
static void
@@ -446,18 +438,16 @@ g_multipath_read_metadata(struct g_consumer *cp,
g_topology_assert();
error = g_access(cp, 1, 0, 0);
- if (error != 0) {
+ if (error != 0)
return (error);
- }
pp = cp->provider;
g_topology_unlock();
buf = g_read_data(cp, pp->mediasize - pp->sectorsize,
pp->sectorsize, &error);
g_topology_lock();
g_access(cp, -1, 0, 0);
- if (buf == NULL) {
+ if (buf == NULL)
return (error);
- }
multipath_metadata_decode(buf, md);
g_free(buf);
return (0);
@@ -484,15 +474,13 @@ g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
g_detach(cp);
g_destroy_consumer(cp);
g_destroy_geom(gp);
- if (error != 0) {
+ if (error != 0)
return (NULL);
- }
gp = NULL;
if (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) {
- if (g_multipath_debug) {
+ if (g_multipath_debug)
printf("%s is not MULTIPATH\n", pp->name);
- }
return (NULL);
}
if (md.md_version != G_MULTIPATH_VERSION) {
@@ -501,9 +489,8 @@ g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
G_MULTIPATH_VERSION);
return (NULL);
}
- if (g_multipath_debug) {
+ if (g_multipath_debug)
printf("MULTIPATH: %s/%s\n", md.md_name, md.md_uuid);
- }
/*
* Let's check if such a device already is present. We check against
@@ -519,25 +506,20 @@ g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
sc = NULL;
LIST_FOREACH(gp, &mp->geom, geom) {
sc = gp->softc;
- if (sc == NULL) {
+ if (sc == NULL)
continue;
- }
- if (strncmp(md.md_uuid, sc->sc_uuid, sizeof(md.md_uuid)) == 0) {
+ if (strncmp(md.md_uuid, sc->sc_uuid, sizeof(md.md_uuid)) == 0)
break;
- }
}
LIST_FOREACH(gp1, &mp->geom, geom) {
- if (gp1 == gp) {
+ if (gp1 == gp)
continue;
- }
sc = gp1->softc;
- if (sc == NULL) {
+ if (sc == NULL)
continue;
- }
- if (strncmp(md.md_name, sc->sc_name, sizeof(md.md_name)) == 0) {
+ if (strncmp(md.md_name, sc->sc_name, sizeof(md.md_name)) == 0)
break;
- }
}
/*
@@ -564,9 +546,9 @@ g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
sc->sc_name, sc->sc_uuid);
printf("GEOM_MULTIPATH: %s will be (temporarily) %s\n",
md.md_uuid, buf);
- strlcpy(md.md_name, buf, sizeof (md.md_name));
+ strlcpy(md.md_name, buf, sizeof(md.md_name));
} else {
- strlcpy(md.md_name, sc->sc_name, sizeof (md.md_name));
+ strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name));
}
}
@@ -586,9 +568,8 @@ g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
KASSERT(sc != NULL, ("sc is NULL"));
error = g_multipath_add_disk(gp, pp);
if (error != 0) {
- if (isnew) {
+ if (isnew)
g_multipath_destroy(gp);
- }
return (NULL);
}
return (gp);
@@ -627,9 +608,8 @@ g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp)
gctl_error(req, "No 'arg1' argument");
return;
}
- if (strncmp(name, devpf, 5) == 0) {
+ if (strncmp(name, devpf, 5) == 0)
name += 5;
- }
pp0 = g_provider_by_name(name);
if (pp0 == NULL) {
gctl_error(req, "Provider %s is invalid", name);
@@ -641,9 +621,8 @@ g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp)
gctl_error(req, "No 'arg2' argument");
return;
}
- if (strncmp(name, devpf, 5) == 0) {
+ if (strncmp(name, devpf, 5) == 0)
name += 5;
- }
pp1 = g_provider_by_name(name);
if (pp1 == NULL) {
gctl_error(req, "Provider %s is invalid", name);
@@ -687,13 +666,12 @@ g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp)
memset(&md, 0, sizeof(md));
md.md_size = pp0->mediasize;
md.md_sectorsize = pp0->sectorsize;
- strncpy(md.md_name, mpname, sizeof (md.md_name));
- strncpy(md.md_uuid, uuid, sizeof (md.md_uuid));
+ strlcpy(md.md_name, mpname, sizeof(md.md_name));
+ strlcpy(md.md_uuid, uuid, sizeof(md.md_uuid));
gp = g_multipath_create(mp, &md);
- if (gp == NULL) {
+ if (gp == NULL)
return;
- }
error = g_multipath_add_disk(gp, pp0);
if (error) {
g_multipath_destroy(gp);
diff --git a/sys/geom/stripe/g_stripe.c b/sys/geom/stripe/g_stripe.c
index a913357..a799284 100644
--- a/sys/geom/stripe/g_stripe.c
+++ b/sys/geom/stripe/g_stripe.c
@@ -633,7 +633,7 @@ g_stripe_start(struct bio *bp)
* Do use "economic" when:
* 1. "Economic" mode is ON.
* or
- * 2. "Fast" mode failed. It can only failed if there is no memory.
+ * 2. "Fast" mode failed. It can only fail if there is no memory.
*/
if (!fast || error != 0)
error = g_stripe_start_economic(bp, no, offset, length);
diff --git a/sys/i386/conf/XEN b/sys/i386/conf/XEN
index 8bddd8d..ed07b0d 100644
--- a/sys/i386/conf/XEN
+++ b/sys/i386/conf/XEN
@@ -67,12 +67,12 @@ options SMP # Symmetric MultiProcessor Kernel
device apic # I/O APIC
-device atkbdc # AT keyboard controller
-device atkbd # AT keyboard
+#device atkbdc # AT keyboard controller
+#device atkbd # AT keyboard
device psm # PS/2 mouse
device pci
-device kbdmux # keyboard multiplexer
+#device kbdmux # keyboard multiplexer
# Pseudo devices.
device loop # Network loopback
diff --git a/sys/i386/isa/atpic_vector.s b/sys/i386/i386/atpic_vector.s
index 0e4e1b6..0e4e1b6 100644
--- a/sys/i386/isa/atpic_vector.s
+++ b/sys/i386/i386/atpic_vector.s
diff --git a/sys/i386/i386/exception.s b/sys/i386/i386/exception.s
index 1451fa8..9db9532 100644
--- a/sys/i386/i386/exception.s
+++ b/sys/i386/i386/exception.s
@@ -294,7 +294,7 @@ ENTRY(fork_trampoline)
SUPERALIGN_TEXT
MCOUNT_LABEL(bintr)
-#include <i386/isa/atpic_vector.s>
+#include <i386/i386/atpic_vector.s>
#ifdef DEV_APIC
.data
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index 8313216..1ef94ea 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -132,7 +132,7 @@ __FBSDID("$FreeBSD$");
#endif
#ifdef DEV_ISA
-#include <i386/isa/icu.h>
+#include <x86/isa/icu.h>
#endif
#ifdef XBOX
diff --git a/sys/i386/i386/mca.c b/sys/i386/i386/mca.c
index eaa78b8..6148af7 100644
--- a/sys/i386/i386/mca.c
+++ b/sys/i386/i386/mca.c
@@ -288,6 +288,8 @@ mca_log(const struct mca_record *rec)
printf("\n");
if (rec->mr_status & MC_STATUS_ADDRV)
printf("MCA: Address 0x%llx\n", (long long)rec->mr_addr);
+ if (rec->mr_status & MC_STATUS_MISCV)
+ printf("MCA: Misc 0x%llx\n", (long long)rec->mr_misc);
}
static int __nonnull(2)
diff --git a/sys/i386/i386/nexus.c b/sys/i386/i386/nexus.c
index 8eacc6a..04dd464 100644
--- a/sys/i386/i386/nexus.c
+++ b/sys/i386/i386/nexus.c
@@ -72,7 +72,7 @@ __FBSDID("$FreeBSD$");
#ifdef PC98
#include <pc98/cbus/cbus.h>
#else
-#include <i386/isa/isa.h>
+#include <x86/isa/isa.h>
#endif
#endif
#include <sys/rtprio.h>
diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c
index 7291306..4b2e34f 100644
--- a/sys/i386/i386/pmap.c
+++ b/sys/i386/i386/pmap.c
@@ -692,6 +692,15 @@ pmap_init(void)
pv_entry_high_water = 9 * (pv_entry_max / 10);
/*
+ * Disable large page mappings by default if the kernel is running in
+ * a virtual machine on an AMD Family 10h processor. This is a work-
+ * around for Erratum 383.
+ */
+ if (vm_guest == VM_GUEST_VM && cpu_vendor_id == CPU_VENDOR_AMD &&
+ CPUID_TO_FAMILY(cpu_id) == 0x10)
+ pg_ps_enabled = 0;
+
+ /*
* Are large page mappings enabled?
*/
TUNABLE_INT_FETCH("vm.pmap.pg_ps_enabled", &pg_ps_enabled);
diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c
index 2948eb7..d2c13b8 100644
--- a/sys/i386/i386/vm_machdep.c
+++ b/sys/i386/i386/vm_machdep.c
@@ -95,7 +95,7 @@ __FBSDID("$FreeBSD$");
#ifdef PC98
#include <pc98/cbus/cbus.h>
#else
-#include <i386/isa/isa.h>
+#include <x86/isa/isa.h>
#endif
#ifdef XBOX
diff --git a/sys/i386/isa/elcr.c b/sys/i386/isa/elcr.c
deleted file mode 100644
index 266d783..0000000
--- a/sys/i386/isa/elcr.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*-
- * Copyright (c) 2004 John Baldwin <jhb@FreeBSD.org>
- * 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.
- * 3. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * 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$");
-
-/*
- * The ELCR is a register that controls the trigger mode and polarity of
- * EISA and ISA interrupts. In FreeBSD 3.x and 4.x, the ELCR was only
- * consulted for determining the appropriate trigger mode of EISA
- * interrupts when using an APIC. However, it seems that almost all
- * systems that include PCI also include an ELCR that manages the ISA
- * IRQs 0 through 15. Thus, we check for the presence of an ELCR on
- * every machine by checking to see if the values found at bootup are
- * sane. Note that the polarity of ISA and EISA IRQs are linked to the
- * trigger mode. All edge triggered IRQs use active-hi polarity, and
- * all level triggered interrupts use active-lo polarity.
- *
- * The format of the ELCR is simple: it is a 16-bit bitmap where bit 0
- * controls IRQ 0, bit 1 controls IRQ 1, etc. If the bit is zero, the
- * associated IRQ is edge triggered. If the bit is one, the IRQ is
- * level triggered.
- */
-
-#include <sys/param.h>
-#include <sys/bus.h>
-#include <sys/systm.h>
-#include <machine/intr_machdep.h>
-
-#define ELCR_PORT 0x4d0
-#define ELCR_MASK(irq) (1 << (irq))
-
-static int elcr_status;
-int elcr_found;
-
-/*
- * Check to see if we have what looks like a valid ELCR. We do this by
- * verifying that IRQs 0, 1, 2, and 13 are all edge triggered.
- */
-int
-elcr_probe(void)
-{
- int i;
-
- elcr_status = inb(ELCR_PORT) | inb(ELCR_PORT + 1) << 8;
- if ((elcr_status & (ELCR_MASK(0) | ELCR_MASK(1) | ELCR_MASK(2) |
- ELCR_MASK(8) | ELCR_MASK(13))) != 0)
- return (ENXIO);
- if (bootverbose) {
- printf("ELCR Found. ISA IRQs programmed as:\n");
- for (i = 0; i < 16; i++)
- printf(" %2d", i);
- printf("\n");
- for (i = 0; i < 16; i++)
- if (elcr_status & ELCR_MASK(i))
- printf(" L");
- else
- printf(" E");
- printf("\n");
- }
- if (resource_disabled("elcr", 0))
- return (ENXIO);
- elcr_found = 1;
- return (0);
-}
-
-/*
- * Returns 1 for level trigger, 0 for edge.
- */
-enum intr_trigger
-elcr_read_trigger(u_int irq)
-{
-
- KASSERT(elcr_found, ("%s: no ELCR was found!", __func__));
- KASSERT(irq <= 15, ("%s: invalid IRQ %u", __func__, irq));
- if (elcr_status & ELCR_MASK(irq))
- return (INTR_TRIGGER_LEVEL);
- else
- return (INTR_TRIGGER_EDGE);
-}
-
-/*
- * Set the trigger mode for a specified IRQ. Mode of 0 means edge triggered,
- * and a mode of 1 means level triggered.
- */
-void
-elcr_write_trigger(u_int irq, enum intr_trigger trigger)
-{
- int new_status;
-
- KASSERT(elcr_found, ("%s: no ELCR was found!", __func__));
- KASSERT(irq <= 15, ("%s: invalid IRQ %u", __func__, irq));
- if (trigger == INTR_TRIGGER_LEVEL)
- new_status = elcr_status | ELCR_MASK(irq);
- else
- new_status = elcr_status & ~ELCR_MASK(irq);
- if (new_status == elcr_status)
- return;
- elcr_status = new_status;
- if (irq >= 8)
- outb(ELCR_PORT + 1, elcr_status >> 8);
- else
- outb(ELCR_PORT, elcr_status & 0xff);
-}
-
-void
-elcr_resume(void)
-{
-
- KASSERT(elcr_found, ("%s: no ELCR was found!", __func__));
- outb(ELCR_PORT, elcr_status & 0xff);
- outb(ELCR_PORT + 1, elcr_status >> 8);
-}
diff --git a/sys/i386/isa/isa_dma.c b/sys/i386/isa/isa_dma.c
deleted file mode 100644
index 69d61c3..0000000
--- a/sys/i386/isa/isa_dma.c
+++ /dev/null
@@ -1,610 +0,0 @@
-/*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * William Jolitz.
- *
- * 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.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- * from: @(#)isa.c 7.2 (Berkeley) 5/13/91
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * code to manage AT bus
- *
- * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com):
- * Fixed uninitialized variable problem and added code to deal
- * with DMA page boundaries in isa_dmarangecheck(). Fixed word
- * mode DMA count compution and reorganized DMA setup code in
- * isa_dmastart()
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/lock.h>
-#include <sys/proc.h>
-#include <sys/mutex.h>
-#include <sys/module.h>
-#include <vm/vm.h>
-#include <vm/vm_param.h>
-#include <vm/pmap.h>
-#include <isa/isareg.h>
-#include <isa/isavar.h>
-#include <isa/isa_dmareg.h>
-
-static int isa_dmarangecheck(caddr_t va, u_int length, int chan);
-
-static caddr_t dma_bouncebuf[8];
-static u_int dma_bouncebufsize[8];
-static u_int8_t dma_bounced = 0;
-static u_int8_t dma_busy = 0; /* Used in isa_dmastart() */
-static u_int8_t dma_inuse = 0; /* User for acquire/release */
-static u_int8_t dma_auto_mode = 0;
-static struct mtx isa_dma_lock;
-MTX_SYSINIT(isa_dma_lock, &isa_dma_lock, "isa DMA lock", MTX_DEF);
-
-#define VALID_DMA_MASK (7)
-
-/* high byte of address is stored in this port for i-th dma channel */
-static int dmapageport[8] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
-
-/*
- * Setup a DMA channel's bounce buffer.
- */
-int
-isa_dma_init(int chan, u_int bouncebufsize, int flag)
-{
- void *buf;
- int contig;
-
-#ifdef DIAGNOSTIC
- if (chan & ~VALID_DMA_MASK)
- panic("isa_dma_init: channel out of range");
-#endif
-
-
- /* Try malloc() first. It works better if it works. */
- buf = malloc(bouncebufsize, M_DEVBUF, flag);
- if (buf != NULL) {
- if (isa_dmarangecheck(buf, bouncebufsize, chan) != 0) {
- free(buf, M_DEVBUF);
- buf = NULL;
- }
- contig = 0;
- }
-
- if (buf == NULL) {
- buf = contigmalloc(bouncebufsize, M_DEVBUF, flag, 0ul, 0xfffffful,
- 1ul, chan & 4 ? 0x20000ul : 0x10000ul);
- contig = 1;
- }
-
- if (buf == NULL)
- return (ENOMEM);
-
- mtx_lock(&isa_dma_lock);
- /*
- * If a DMA channel is shared, both drivers have to call isa_dma_init
- * since they don't know that the other driver will do it.
- * Just return if we're already set up good.
- * XXX: this only works if they agree on the bouncebuf size. This
- * XXX: is typically the case since they are multiple instances of
- * XXX: the same driver.
- */
- if (dma_bouncebuf[chan] != NULL) {
- if (contig)
- contigfree(buf, bouncebufsize, M_DEVBUF);
- else
- free(buf, M_DEVBUF);
- mtx_unlock(&isa_dma_lock);
- return (0);
- }
-
- dma_bouncebufsize[chan] = bouncebufsize;
- dma_bouncebuf[chan] = buf;
-
- mtx_unlock(&isa_dma_lock);
-
- return (0);
-}
-
-/*
- * Register a DMA channel's usage. Usually called from a device driver
- * in open() or during its initialization.
- */
-int
-isa_dma_acquire(chan)
- int chan;
-{
-#ifdef DIAGNOSTIC
- if (chan & ~VALID_DMA_MASK)
- panic("isa_dma_acquire: channel out of range");
-#endif
-
- mtx_lock(&isa_dma_lock);
- if (dma_inuse & (1 << chan)) {
- printf("isa_dma_acquire: channel %d already in use\n", chan);
- mtx_unlock(&isa_dma_lock);
- return (EBUSY);
- }
- dma_inuse |= (1 << chan);
- dma_auto_mode &= ~(1 << chan);
- mtx_unlock(&isa_dma_lock);
-
- return (0);
-}
-
-/*
- * Unregister a DMA channel's usage. Usually called from a device driver
- * during close() or during its shutdown.
- */
-void
-isa_dma_release(chan)
- int chan;
-{
-#ifdef DIAGNOSTIC
- if (chan & ~VALID_DMA_MASK)
- panic("isa_dma_release: channel out of range");
-
- mtx_lock(&isa_dma_lock);
- if ((dma_inuse & (1 << chan)) == 0)
- printf("isa_dma_release: channel %d not in use\n", chan);
-#else
- mtx_lock(&isa_dma_lock);
-#endif
-
- if (dma_busy & (1 << chan)) {
- dma_busy &= ~(1 << chan);
- /*
- * XXX We should also do "dma_bounced &= (1 << chan);"
- * because we are acting on behalf of isa_dmadone() which
- * was not called to end the last DMA operation. This does
- * not matter now, but it may in the future.
- */
- }
-
- dma_inuse &= ~(1 << chan);
- dma_auto_mode &= ~(1 << chan);
-
- mtx_unlock(&isa_dma_lock);
-}
-
-/*
- * isa_dmacascade(): program 8237 DMA controller channel to accept
- * external dma control by a board.
- */
-void
-isa_dmacascade(chan)
- int chan;
-{
-#ifdef DIAGNOSTIC
- if (chan & ~VALID_DMA_MASK)
- panic("isa_dmacascade: channel out of range");
-#endif
-
- mtx_lock(&isa_dma_lock);
- /* set dma channel mode, and set dma channel mode */
- if ((chan & 4) == 0) {
- outb(DMA1_MODE, DMA37MD_CASCADE | chan);
- outb(DMA1_SMSK, chan);
- } else {
- outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
- outb(DMA2_SMSK, chan & 3);
- }
- mtx_unlock(&isa_dma_lock);
-}
-
-/*
- * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
- * problems by using a bounce buffer.
- */
-void
-isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan)
-{
- vm_paddr_t phys;
- int waport;
- caddr_t newaddr;
- int dma_range_checked;
-
- /* translate to physical */
- phys = pmap_extract(kernel_pmap, (vm_offset_t)addr);
- dma_range_checked = isa_dmarangecheck(addr, nbytes, chan);
-
-#ifdef DIAGNOSTIC
- if (chan & ~VALID_DMA_MASK)
- panic("isa_dmastart: channel out of range");
-
- if ((chan < 4 && nbytes > (1<<16))
- || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
- panic("isa_dmastart: impossible request");
-
- mtx_lock(&isa_dma_lock);
- if ((dma_inuse & (1 << chan)) == 0)
- printf("isa_dmastart: channel %d not acquired\n", chan);
-#else
- mtx_lock(&isa_dma_lock);
-#endif
-
-#if 0
- /*
- * XXX This should be checked, but drivers like ad1848 only call
- * isa_dmastart() once because they use Auto DMA mode. If we
- * leave this in, drivers that do this will print this continuously.
- */
- if (dma_busy & (1 << chan))
- printf("isa_dmastart: channel %d busy\n", chan);
-#endif
-
- dma_busy |= (1 << chan);
-
- if (dma_range_checked) {
- if (dma_bouncebuf[chan] == NULL
- || dma_bouncebufsize[chan] < nbytes)
- panic("isa_dmastart: bad bounce buffer");
- dma_bounced |= (1 << chan);
- newaddr = dma_bouncebuf[chan];
-
- /* copy bounce buffer on write */
- if (!(flags & ISADMA_READ))
- bcopy(addr, newaddr, nbytes);
- addr = newaddr;
- }
-
- if (flags & ISADMA_RAW) {
- dma_auto_mode |= (1 << chan);
- } else {
- dma_auto_mode &= ~(1 << chan);
- }
-
- if ((chan & 4) == 0) {
- /*
- * Program one of DMA channels 0..3. These are
- * byte mode channels.
- */
- /* set dma channel mode, and reset address ff */
-
- /* If ISADMA_RAW flag is set, then use autoinitialise mode */
- if (flags & ISADMA_RAW) {
- if (flags & ISADMA_READ)
- outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan);
- else
- outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan);
- }
- else
- if (flags & ISADMA_READ)
- outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
- else
- outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
- outb(DMA1_FFC, 0);
-
- /* send start address */
- waport = DMA1_CHN(chan);
- outb(waport, phys);
- outb(waport, phys>>8);
- outb(dmapageport[chan], phys>>16);
-
- /* send count */
- outb(waport + 1, --nbytes);
- outb(waport + 1, nbytes>>8);
-
- /* unmask channel */
- outb(DMA1_SMSK, chan);
- } else {
- /*
- * Program one of DMA channels 4..7. These are
- * word mode channels.
- */
- /* set dma channel mode, and reset address ff */
-
- /* If ISADMA_RAW flag is set, then use autoinitialise mode */
- if (flags & ISADMA_RAW) {
- if (flags & ISADMA_READ)
- outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_WRITE|(chan&3));
- else
- outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_READ|(chan&3));
- }
- else
- if (flags & ISADMA_READ)
- outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
- else
- outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
- outb(DMA2_FFC, 0);
-
- /* send start address */
- waport = DMA2_CHN(chan - 4);
- outb(waport, phys>>1);
- outb(waport, phys>>9);
- outb(dmapageport[chan], phys>>16);
-
- /* send count */
- nbytes >>= 1;
- outb(waport + 2, --nbytes);
- outb(waport + 2, nbytes>>8);
-
- /* unmask channel */
- outb(DMA2_SMSK, chan & 3);
- }
- mtx_unlock(&isa_dma_lock);
-}
-
-void
-isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
-{
-#ifdef DIAGNOSTIC
- if (chan & ~VALID_DMA_MASK)
- panic("isa_dmadone: channel out of range");
-
- if ((dma_inuse & (1 << chan)) == 0)
- printf("isa_dmadone: channel %d not acquired\n", chan);
-#endif
-
- mtx_lock(&isa_dma_lock);
- if (((dma_busy & (1 << chan)) == 0) &&
- (dma_auto_mode & (1 << chan)) == 0 )
- printf("isa_dmadone: channel %d not busy\n", chan);
-
- if ((dma_auto_mode & (1 << chan)) == 0)
- outb(chan & 4 ? DMA2_SMSK : DMA1_SMSK, (chan & 3) | 4);
-
- if (dma_bounced & (1 << chan)) {
- /* copy bounce buffer on read */
- if (flags & ISADMA_READ)
- bcopy(dma_bouncebuf[chan], addr, nbytes);
-
- dma_bounced &= ~(1 << chan);
- }
- dma_busy &= ~(1 << chan);
- mtx_unlock(&isa_dma_lock);
-}
-
-/*
- * Check for problems with the address range of a DMA transfer
- * (non-contiguous physical pages, outside of bus address space,
- * crossing DMA page boundaries).
- * Return true if special handling needed.
- */
-
-static int
-isa_dmarangecheck(caddr_t va, u_int length, int chan)
-{
- vm_paddr_t phys, priorpage = 0;
- vm_offset_t endva;
- u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1);
-
- endva = (vm_offset_t)round_page((vm_offset_t)va + length);
- for (; va < (caddr_t) endva ; va += PAGE_SIZE) {
- phys = trunc_page(pmap_extract(kernel_pmap, (vm_offset_t)va));
-#define ISARAM_END RAM_END
- if (phys == 0)
- panic("isa_dmacheck: no physical page present");
- if (phys >= ISARAM_END)
- return (1);
- if (priorpage) {
- if (priorpage + PAGE_SIZE != phys)
- return (1);
- /* check if crossing a DMA page boundary */
- if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
- return (1);
- }
- priorpage = phys;
- }
- return (0);
-}
-
-/*
- * Query the progress of a transfer on a DMA channel.
- *
- * To avoid having to interrupt a transfer in progress, we sample
- * each of the high and low databytes twice, and apply the following
- * logic to determine the correct count.
- *
- * Reads are performed with interrupts disabled, thus it is to be
- * expected that the time between reads is very small. At most
- * one rollover in the low count byte can be expected within the
- * four reads that are performed.
- *
- * There are three gaps in which a rollover can occur :
- *
- * - read low1
- * gap1
- * - read high1
- * gap2
- * - read low2
- * gap3
- * - read high2
- *
- * If a rollover occurs in gap1 or gap2, the low2 value will be
- * greater than the low1 value. In this case, low2 and high2 are a
- * corresponding pair.
- *
- * In any other case, low1 and high1 can be considered to be correct.
- *
- * The function returns the number of bytes remaining in the transfer,
- * or -1 if the channel requested is not active.
- *
- */
-static int
-isa_dmastatus_locked(int chan)
-{
- u_long cnt = 0;
- int ffport, waport;
- u_long low1, high1, low2, high2;
-
- mtx_assert(&isa_dma_lock, MA_OWNED);
-
- /* channel active? */
- if ((dma_inuse & (1 << chan)) == 0) {
- printf("isa_dmastatus: channel %d not active\n", chan);
- return(-1);
- }
- /* channel busy? */
-
- if (((dma_busy & (1 << chan)) == 0) &&
- (dma_auto_mode & (1 << chan)) == 0 ) {
- printf("chan %d not busy\n", chan);
- return -2 ;
- }
- if (chan < 4) { /* low DMA controller */
- ffport = DMA1_FFC;
- waport = DMA1_CHN(chan) + 1;
- } else { /* high DMA controller */
- ffport = DMA2_FFC;
- waport = DMA2_CHN(chan - 4) + 2;
- }
-
- disable_intr(); /* no interrupts Mr Jones! */
- outb(ffport, 0); /* clear register LSB flipflop */
- low1 = inb(waport);
- high1 = inb(waport);
- outb(ffport, 0); /* clear again */
- low2 = inb(waport);
- high2 = inb(waport);
- enable_intr(); /* enable interrupts again */
-
- /*
- * Now decide if a wrap has tried to skew our results.
- * Note that after TC, the count will read 0xffff, while we want
- * to return zero, so we add and then mask to compensate.
- */
- if (low1 >= low2) {
- cnt = (low1 + (high1 << 8) + 1) & 0xffff;
- } else {
- cnt = (low2 + (high2 << 8) + 1) & 0xffff;
- }
-
- if (chan >= 4) /* high channels move words */
- cnt *= 2;
- return(cnt);
-}
-
-int
-isa_dmastatus(int chan)
-{
- int status;
-
- mtx_lock(&isa_dma_lock);
- status = isa_dmastatus_locked(chan);
- mtx_unlock(&isa_dma_lock);
-
- return (status);
-}
-
-/*
- * Reached terminal count yet ?
- */
-int
-isa_dmatc(int chan)
-{
-
- if (chan < 4)
- return(inb(DMA1_STATUS) & (1 << chan));
- else
- return(inb(DMA2_STATUS) & (1 << (chan & 3)));
-}
-
-/*
- * Stop a DMA transfer currently in progress.
- */
-int
-isa_dmastop(int chan)
-{
- int status;
-
- mtx_lock(&isa_dma_lock);
- if ((dma_inuse & (1 << chan)) == 0)
- printf("isa_dmastop: channel %d not acquired\n", chan);
-
- if (((dma_busy & (1 << chan)) == 0) &&
- ((dma_auto_mode & (1 << chan)) == 0)) {
- printf("chan %d not busy\n", chan);
- mtx_unlock(&isa_dma_lock);
- return -2 ;
- }
-
- if ((chan & 4) == 0) {
- outb(DMA1_SMSK, (chan & 3) | 4 /* disable mask */);
- } else {
- outb(DMA2_SMSK, (chan & 3) | 4 /* disable mask */);
- }
-
- status = isa_dmastatus_locked(chan);
-
- mtx_unlock(&isa_dma_lock);
-
- return (status);
-}
-
-/*
- * Attach to the ISA PnP descriptor for the AT DMA controller
- */
-static struct isa_pnp_id atdma_ids[] = {
- { 0x0002d041 /* PNP0200 */, "AT DMA controller" },
- { 0 }
-};
-
-static int
-atdma_probe(device_t dev)
-{
- int result;
-
- if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, atdma_ids)) <= 0)
- device_quiet(dev);
- return(result);
-}
-
-static int
-atdma_attach(device_t dev)
-{
- return(0);
-}
-
-static device_method_t atdma_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, atdma_probe),
- DEVMETHOD(device_attach, atdma_attach),
- DEVMETHOD(device_detach, bus_generic_detach),
- DEVMETHOD(device_shutdown, bus_generic_shutdown),
- DEVMETHOD(device_suspend, bus_generic_suspend),
- DEVMETHOD(device_resume, bus_generic_resume),
- { 0, 0 }
-};
-
-static driver_t atdma_driver = {
- "atdma",
- atdma_methods,
- 1, /* no softc */
-};
-
-static devclass_t atdma_devclass;
-
-DRIVER_MODULE(atdma, isa, atdma_driver, atdma_devclass, 0, 0);
-DRIVER_MODULE(atdma, acpi, atdma_driver, atdma_devclass, 0, 0);
diff --git a/sys/i386/xen/clock.c b/sys/i386/xen/clock.c
index d965022..09ed7c3 100644
--- a/sys/i386/xen/clock.c
+++ b/sys/i386/xen/clock.c
@@ -74,8 +74,8 @@ __FBSDID("$FreeBSD$");
#include <machine/specialreg.h>
#include <machine/timerreg.h>
-#include <i386/isa/icu.h>
-#include <i386/isa/isa.h>
+#include <x86/isa/icu.h>
+#include <x86/isa/isa.h>
#include <isa/rtc.h>
#include <xen/xen_intr.h>
diff --git a/sys/i386/xen/pmap.c b/sys/i386/xen/pmap.c
index cec1663..ae4d4aa 100644
--- a/sys/i386/xen/pmap.c
+++ b/sys/i386/xen/pmap.c
@@ -251,9 +251,8 @@ struct sysmaps {
caddr_t CADDR2;
};
static struct sysmaps sysmaps_pcpu[MAXCPU];
-pt_entry_t *CMAP1 = 0;
static pt_entry_t *CMAP3;
-caddr_t CADDR1 = 0, ptvmmap = 0;
+caddr_t ptvmmap = 0;
static caddr_t CADDR3;
struct msgbuf *msgbufp = 0;
@@ -454,8 +453,9 @@ pmap_bootstrap(vm_paddr_t firstaddr)
mtx_init(&sysmaps->lock, "SYSMAPS", NULL, MTX_DEF);
SYSMAP(caddr_t, sysmaps->CMAP1, sysmaps->CADDR1, 1)
SYSMAP(caddr_t, sysmaps->CMAP2, sysmaps->CADDR2, 1)
+ PT_SET_MA(sysmaps->CADDR1, 0);
+ PT_SET_MA(sysmaps->CADDR2, 0);
}
- SYSMAP(caddr_t, CMAP1, CADDR1, 1)
SYSMAP(caddr_t, CMAP3, CADDR3, 1)
PT_SET_MA(CADDR3, 0);
@@ -483,7 +483,6 @@ pmap_bootstrap(vm_paddr_t firstaddr)
mtx_init(&PMAP2mutex, "PMAP2", NULL, MTX_DEF);
virtual_avail = va;
- PT_SET_MA(CADDR1, 0);
/*
* Leave in place an identity mapping (virt == phys) for the low 1 MB
@@ -1061,7 +1060,9 @@ pmap_pte(pmap_t pmap, vm_offset_t va)
mtx_lock(&PMAP2mutex);
newpf = *pde & PG_FRAME;
if ((*PMAP2 & PG_FRAME) != newpf) {
+ vm_page_lock_queues();
PT_SET_MA(PADDR2, newpf | PG_V | PG_A | PG_M);
+ vm_page_unlock_queues();
CTR3(KTR_PMAP, "pmap_pte: pmap=%p va=0x%x newpte=0x%08x",
pmap, va, (*PMAP2 & 0xffffffff));
}
diff --git a/sys/i386/xen/xen_machdep.c b/sys/i386/xen/xen_machdep.c
index 4eccdfa..060fad5 100644
--- a/sys/i386/xen/xen_machdep.c
+++ b/sys/i386/xen/xen_machdep.c
@@ -869,23 +869,25 @@ extern unsigned long physfree;
int pdir, curoffset;
extern int nkpt;
+extern uint32_t kernbase;
+
void
initvalues(start_info_t *startinfo)
{
- int l3_pages, l2_pages, l1_pages, offset;
vm_offset_t cur_space, cur_space_pt;
struct physdev_set_iopl set_iopl;
- vm_paddr_t KPTphys, IdlePTDma;
+ int l3_pages, l2_pages, l1_pages, offset;
vm_paddr_t console_page_ma, xen_store_ma;
- vm_offset_t KPTphysoff, tmpva;
+ vm_offset_t tmpva;
vm_paddr_t shinfo;
#ifdef PAE
vm_paddr_t IdlePDPTma, IdlePDPTnewma;
vm_paddr_t IdlePTDnewma[4];
pd_entry_t *IdlePDPTnew, *IdlePTDnew;
+ vm_paddr_t IdlePTDma[4];
#else
- vm_paddr_t pdir_shadow_ma;
+ vm_paddr_t IdlePTDma[1];
#endif
unsigned long i;
int ncpus = MAXCPU;
@@ -921,11 +923,9 @@ initvalues(start_info_t *startinfo)
* Note that only one page directory has been allocated at this point.
* Thus, if KERNBASE
*/
-#if 0
for (i = 0; i < l2_pages; i++)
IdlePTDma[i] = xpmap_ptom(VTOP(IdlePTD + i*PAGE_SIZE));
-#endif
-
+
l2_pages = (l2_pages == 0) ? 1 : l2_pages;
#else
l3_pages = 0;
@@ -938,10 +938,11 @@ initvalues(start_info_t *startinfo)
break;
l1_pages++;
}
-
+
/* number of pages allocated after the pts + 1*/;
cur_space = xen_start_info->pt_base +
- ((xen_start_info->nr_pt_frames) + 3 )*PAGE_SIZE;
+ (l3_pages + l2_pages + l1_pages + 1)*PAGE_SIZE;
+
printk("initvalues(): wooh - availmem=%x,%x\n", avail_space, cur_space);
printk("KERNBASE=%x,pt_base=%x, VTOPFN(base)=%x, nr_pt_frames=%x\n",
@@ -949,72 +950,15 @@ initvalues(start_info_t *startinfo)
xen_start_info->nr_pt_frames);
xendebug_flags = 0; /* 0xffffffff; */
- /* allocate 4 pages for bootmem allocator */
- bootmem_start = bootmem_current = (char *)cur_space;
- cur_space += (4 * PAGE_SIZE);
- bootmem_end = (char *)cur_space;
-
- /* allocate page for gdt */
- gdt = (union descriptor *)cur_space;
- cur_space += PAGE_SIZE*ncpus;
-
- /* allocate page for ldt */
- ldt = (union descriptor *)cur_space; cur_space += PAGE_SIZE;
- cur_space += PAGE_SIZE;
-
- HYPERVISOR_shared_info = (shared_info_t *)cur_space;
- cur_space += PAGE_SIZE;
-
- xen_store = (struct ringbuf_head *)cur_space;
- cur_space += PAGE_SIZE;
-
- console_page = (char *)cur_space;
- cur_space += PAGE_SIZE;
-
#ifdef ADD_ISA_HOLE
shift_phys_machine(xen_phys_machine, xen_start_info->nr_pages);
#endif
- /*
- * pre-zero unused mapped pages - mapped on 4MB boundary
- */
-#ifdef PAE
- IdlePDPT = (pd_entry_t *)startinfo->pt_base;
- IdlePDPTma = xpmap_ptom(VTOP(startinfo->pt_base));
- /*
- * Note that only one page directory has been allocated at this point.
- * Thus, if KERNBASE
- */
- IdlePTD = (pd_entry_t *)((uint8_t *)startinfo->pt_base + PAGE_SIZE);
- IdlePTDma = xpmap_ptom(VTOP(IdlePTD));
- l3_pages = 1;
-#else
- IdlePTD = (pd_entry_t *)startinfo->pt_base;
- IdlePTDma = xpmap_ptom(VTOP(startinfo->pt_base));
- l3_pages = 0;
-#endif
- l2_pages = 1;
- l1_pages = xen_start_info->nr_pt_frames - l2_pages - l3_pages;
-
- KPTphysoff = (l2_pages + l3_pages)*PAGE_SIZE;
-
- KPTphys = xpmap_ptom(VTOP(startinfo->pt_base + KPTphysoff));
XENPRINTF("IdlePTD %p\n", IdlePTD);
XENPRINTF("nr_pages: %ld shared_info: 0x%lx flags: 0x%lx pt_base: 0x%lx "
"mod_start: 0x%lx mod_len: 0x%lx\n",
xen_start_info->nr_pages, xen_start_info->shared_info,
xen_start_info->flags, xen_start_info->pt_base,
xen_start_info->mod_start, xen_start_info->mod_len);
- /* Map proc0's KSTACK */
-
- proc0kstack = cur_space; cur_space += (KSTACK_PAGES * PAGE_SIZE);
- printk("proc0kstack=%u\n", proc0kstack);
-
- /* vm86/bios stack */
- cur_space += PAGE_SIZE;
-
- /* Map space for the vm86 region */
- vm86paddr = (vm_offset_t)cur_space;
- cur_space += (PAGE_SIZE * 3);
#ifdef PAE
IdlePDPTnew = (pd_entry_t *)cur_space; cur_space += PAGE_SIZE;
@@ -1047,26 +991,42 @@ initvalues(start_info_t *startinfo)
* Unpin the current PDPT
*/
xen_pt_unpin(IdlePDPTma);
-
- for (i = 0; i < 20; i++) {
- int startidx = ((KERNBASE >> 18) & PAGE_MASK) >> 3;
-
- if (IdlePTD[startidx + i] == 0) {
- l1_pages = i;
- break;
- }
- }
#endif /* PAE */
+
+ /* Map proc0's KSTACK */
+ proc0kstack = cur_space; cur_space += (KSTACK_PAGES * PAGE_SIZE);
+ printk("proc0kstack=%u\n", proc0kstack);
+
+ /* vm86/bios stack */
+ cur_space += PAGE_SIZE;
+
+ /* Map space for the vm86 region */
+ vm86paddr = (vm_offset_t)cur_space;
+ cur_space += (PAGE_SIZE * 3);
+
+ /* allocate 4 pages for bootmem allocator */
+ bootmem_start = bootmem_current = (char *)cur_space;
+ cur_space += (4 * PAGE_SIZE);
+ bootmem_end = (char *)cur_space;
+
+ /* allocate pages for gdt */
+ gdt = (union descriptor *)cur_space;
+ cur_space += PAGE_SIZE*ncpus;
+
+ /* allocate page for ldt */
+ ldt = (union descriptor *)cur_space; cur_space += PAGE_SIZE;
+ cur_space += PAGE_SIZE;
- /* unmap remaining pages from initial 4MB chunk
+ /* unmap remaining pages from initial chunk
*
*/
- for (tmpva = cur_space; (tmpva & ((1<<22)-1)) != 0; tmpva += PAGE_SIZE) {
+ for (tmpva = cur_space; tmpva < (((uint32_t)&kernbase) + (l1_pages<<PDRSHIFT));
+ tmpva += PAGE_SIZE) {
bzero((char *)tmpva, PAGE_SIZE);
PT_SET_MA(tmpva, (vm_paddr_t)0);
}
-
+
PT_UPDATES_FLUSH();
memcpy(((uint8_t *)IdlePTDnew) + ((unsigned int)(KERNBASE >> 18)),
@@ -1093,10 +1053,10 @@ initvalues(start_info_t *startinfo)
* make sure that all the initial page table pages
* have been zeroed
*/
- PT_SET_MA(cur_space_pt,
+ PT_SET_MA(cur_space,
xpmap_ptom(VTOP(cur_space)) | PG_V | PG_RW);
- bzero((char *)cur_space_pt, PAGE_SIZE);
- PT_SET_MA(cur_space_pt, (vm_paddr_t)0);
+ bzero((char *)cur_space, PAGE_SIZE);
+ PT_SET_MA(cur_space, (vm_paddr_t)0);
xen_pt_pin(xpmap_ptom(VTOP(cur_space)));
xen_queue_pt_update((vm_paddr_t)(IdlePTDnewma[pdir] +
curoffset*sizeof(vm_paddr_t)),
@@ -1119,6 +1079,15 @@ initvalues(start_info_t *startinfo)
IdlePDPT = IdlePDPTnew;
IdlePDPTma = IdlePDPTnewma;
+ HYPERVISOR_shared_info = (shared_info_t *)cur_space;
+ cur_space += PAGE_SIZE;
+
+ xen_store = (struct ringbuf_head *)cur_space;
+ cur_space += PAGE_SIZE;
+
+ console_page = (char *)cur_space;
+ cur_space += PAGE_SIZE;
+
/*
* shared_info is an unsigned long so this will randomly break if
* it is allocated above 4GB - I guess people are used to that
diff --git a/sys/ia64/ia64/context.S b/sys/ia64/ia64/context.S
index 77a1821..84d8fd1 100644
--- a/sys/ia64/ia64/context.S
+++ b/sys/ia64/ia64/context.S
@@ -86,18 +86,18 @@ ENTRY(restorectx, 1)
{ .mmi
ld8.fill r6=[r14],16 // r6
ld8.fill r7=[r15],16 // r7
- nop 1
+ nop 0
;;
}
{ .mmi
mov ar.unat=r16
mov ar.rsc=3
- nop 2
+ nop 0
}
{ .mmi
ld8 r17=[r14],16 // b1
ld8 r18=[r15],16 // b2
- nop 3
+ nop 0
;;
}
{ .mmi
@@ -286,7 +286,7 @@ ENTRY(swapctx, 2)
(p15) br.ret.sptk rp
;;
}
-{ .mfb
+{ .mib
mov r32=r33
nop 0
br.sptk restorectx
@@ -338,10 +338,10 @@ ENTRY(save_callee_saved, 1)
mov r17=b5
;;
}
-{ .mfi
+{ .mii
st8 [r14]=r17,16 // b5
- nop 0
mov r16=ar.lc
+ nop 0
;;
}
{ .mmb
@@ -363,13 +363,13 @@ ENTRY(restore_callee_saved, 1)
add r31=-8,r32
;;
}
-{ .mmb
+{ .mmi
ld8.fill r4=[r31],16 // r4
ld8.fill r5=[r32],16 // r5
nop 0
;;
}
-{ .mmb
+{ .mmi
ld8.fill r6=[r31],16 // r6
ld8.fill r7=[r32],16 // r7
nop 0
diff --git a/sys/ia64/ia64/exception.S b/sys/ia64/ia64/exception.S
index 1a5fa32..3a4ac03 100644
--- a/sys/ia64/ia64/exception.S
+++ b/sys/ia64/ia64/exception.S
@@ -89,10 +89,10 @@ xhead: data8 xtrace
addl r29=1024*5*8,r0 ;; \
(p15) sub r27=r28,r29 ;; \
} ; \
-{ .mib ; \
+{ .mmi ; \
st8 [r28]=r27 ; \
- mov pr=r25,0x1ffff ; \
- nop 0 ;; \
+ nop 0 ; \
+ mov pr=r25,0x1ffff ;; \
}
#else
@@ -148,10 +148,10 @@ ENTRY_NOPROFILE(exception_save, 0)
add r31=8,r30
;;
}
-{ .mib
+{ .mmi
mov r22=cr.iip
- addl r29=NTLBRT_SAVE,r0 // 22-bit restart token.
nop 0
+ addl r29=NTLBRT_SAVE,r0 // 22-bit restart token.
;;
}
@@ -235,7 +235,7 @@ exception_save_restart:
nop 0
;;
}
-{ .mmb
+{ .mmi
(p13) mov ar.rnat=r19
mov r18=ar.bsp
nop 0
@@ -248,7 +248,7 @@ exception_save_restart:
;;
}
// r19=ifs, r22=iip
-{ .mmb
+{ .mmi
st8 [r31]=r18,16 // ndirty
st8 [r30]=r19,16 // cfm
nop 0
@@ -260,7 +260,7 @@ exception_save_restart:
add r29=16,r30
;;
}
-{ .mmb
+{ .mmi
st8 [r30]=r17,24 // ifa
st8 [r31]=r18,24 // isr
nop 0
@@ -407,7 +407,7 @@ exception_save_restart:
movl gp=__gp
;;
}
-{ .mfb
+{ .mib
srlz.d
nop 0
br.sptk b7
@@ -567,7 +567,7 @@ ENTRY_NOPROFILE(exception_restore, 0)
cmp.le p14,p15=5,r28
;;
}
-{ .mmb
+{ .mmi
ld8 r25=[r30] // cfm
ld8 r19=[r31] // ip
nop 0
@@ -606,13 +606,13 @@ exception_restore_restart:
dep r31=0,r31,0,13 // 8KB aligned
;;
}
-{ .mmb
+{ .mmi
mov ar.k6=r31
mov ar.rnat=r21
nop 0
;;
}
-{ .mmb
+{ .mmi
mov ar.unat=r17
mov cr.iip=r19
nop 0
@@ -656,7 +656,7 @@ END(exception_restore)
add out1=16,sp ; \
br.call.sptk rp=_func_ ;; \
} ; \
-{ .mfb ; \
+{ .mib ; \
nop 0 ; \
nop 0 ; \
br.sptk exception_restore ;; \
@@ -1021,10 +1021,10 @@ IVT_ENTRY(Data_Nested_TLB, 0x1400)
movl r27=kstack
;;
}
-{ .mib
+{ .mmi
mov r28=sp
- addl r27=KSTACK_PAGES*PAGE_SIZE-16,r0
nop 0
+ addl r27=KSTACK_PAGES*PAGE_SIZE-16,r0
;;
}
{ .mmi
@@ -1287,13 +1287,13 @@ IVT_ENTRY(Break_Instruction, 0x2c00)
(p11) srlz.d
add out1=16,sp
}
-{ .mfb
+{ .mib
nop 0
nop 0
br.call.sptk rp=trap
;;
}
-{ .mfb
+{ .mib
nop 0
nop 0
br.sptk exception_restore
@@ -1308,19 +1308,19 @@ IVT_ENTRY(External_Interrupt, 0x3000)
br.sptk exception_save
;;
}
-{ .mfb
+{ .mmi
alloc r15=ar.pfs,0,0,1,0
nop 0
nop 0
;;
}
-{ .mfb
+{ .mib
add out0=16,sp
nop 0
br.call.sptk rp=interrupt
;;
}
-{ .mfb
+{ .mib
nop 0
nop 0
br.sptk exception_restore
diff --git a/sys/ia64/ia64/interrupt.c b/sys/ia64/ia64/interrupt.c
index a90e8e8..a9bee27 100644
--- a/sys/ia64/ia64/interrupt.c
+++ b/sys/ia64/ia64/interrupt.c
@@ -60,7 +60,6 @@
#include <machine/md_var.h>
#include <machine/pcb.h>
#include <machine/reg.h>
-#include <machine/sapicvar.h>
#include <machine/smp.h>
#ifdef EVCNT_COUNTERS
@@ -74,16 +73,6 @@ struct evcnt clock_intr_evcnt; /* event counter for clock intrs. */
#include <ddb/ddb.h>
#endif
-static void ia64_dispatch_intr(void *, u_int);
-
-static void
-dummy_perf(unsigned long vector, struct trapframe *tf)
-{
- printf("performance interrupt!\n");
-}
-
-void (*perf_irq)(unsigned long, struct trapframe *) = dummy_perf;
-
SYSCTL_NODE(_debug, OID_AUTO, clock, CTLFLAG_RW, 0, "clock statistics");
static int adjust_edges = 0;
@@ -102,6 +91,19 @@ static int adjust_ticks = 0;
SYSCTL_INT(_debug_clock, OID_AUTO, adjust_ticks, CTLFLAG_RD,
&adjust_ticks, 0, "Total number of ITC interrupts with adjustment");
+
+struct ia64_intr {
+ struct intr_event *event; /* interrupt event */
+ volatile long *cntp; /* interrupt counter */
+ struct sapic *sapic;
+ u_int irq;
+};
+
+static struct ia64_intr *ia64_intrs[256];
+
+
+static void ia64_dispatch_intr(void *, u_int);
+
void
interrupt(struct trapframe *tf)
{
@@ -247,19 +249,6 @@ stray:
}
}
-/*
- * Hardware irqs have vectors starting at this offset.
- */
-#define IA64_HARDWARE_IRQ_BASE 0x20
-
-struct ia64_intr {
- struct intr_event *event; /* interrupt event */
- volatile long *cntp; /* interrupt counter */
- struct sapic *sapic;
- u_int irq;
-};
-
-static struct ia64_intr *ia64_intrs[256];
static void
ia64_intr_eoi(void *arg)
@@ -303,57 +292,75 @@ ia64_setup_intr(const char *name, int irq, driver_filter_t filter,
struct ia64_intr *i;
struct sapic *sa;
char *intrname;
- u_int vector;
+ u_int prio, vector;
int error;
- /* Get the I/O SAPIC that corresponds to the IRQ. */
- sa = sapic_lookup(irq);
- if (sa == NULL)
+ prio = intr_priority(flags);
+ if (prio > PRI_MAX_ITHD)
return (EINVAL);
+ /* XXX lock */
+
+ /* Get the I/O SAPIC and vector that corresponds to the IRQ. */
+ sa = sapic_lookup(irq, &vector);
+ if (sa == NULL) {
+ /* XXX unlock */
+ return (EINVAL);
+ }
+
+ if (vector == 0) {
+ /* XXX unlock */
+ i = malloc(sizeof(struct ia64_intr), M_DEVBUF,
+ M_ZERO | M_WAITOK);
+ /* XXX lock */
+ sa = sapic_lookup(irq, &vector);
+ KASSERT(sa != NULL, ("sapic_lookup"));
+ if (vector != 0)
+ free(i, M_DEVBUF);
+ }
+
/*
- * XXX - There's a priority implied by the choice of vector.
- * We should therefore relate the vector to the interrupt type.
+ * If the IRQ has no vector assigned to it yet, assign one based
+ * on the priority.
*/
- vector = irq + IA64_HARDWARE_IRQ_BASE;
-
- i = ia64_intrs[vector];
- if (i == NULL) {
- i = malloc(sizeof(struct ia64_intr), M_DEVBUF, M_NOWAIT);
- if (i == NULL)
- return (ENOMEM);
+ if (vector == 0) {
+ vector = (256 - 64) - (prio << 1);
+ while (vector < 256 && ia64_intrs[vector] != NULL)
+ vector++;
error = intr_event_create(&i->event, (void *)(uintptr_t)vector,
0, irq, ia64_intr_mask, ia64_intr_unmask, ia64_intr_eoi,
NULL, "irq%u:", irq);
if (error) {
+ /* XXX unlock */
free(i, M_DEVBUF);
return (error);
}
- if (!atomic_cmpset_ptr(&ia64_intrs[vector], NULL, i)) {
- intr_event_destroy(i->event);
- free(i, M_DEVBUF);
- i = ia64_intrs[vector];
- } else {
- i->sapic = sa;
- i->irq = irq;
-
- i->cntp = intrcnt + irq + INTRCNT_ISA_IRQ;
- if (name != NULL && *name != '\0') {
- /* XXX needs abstraction. Too error prone. */
- intrname = intrnames +
- (irq + INTRCNT_ISA_IRQ) * INTRNAME_LEN;
- memset(intrname, ' ', INTRNAME_LEN - 1);
- bcopy(name, intrname, strlen(name));
- }
-
- sapic_enable(i->sapic, irq, vector);
+ i->sapic = sa;
+ i->irq = irq;
+ i->cntp = intrcnt + irq + INTRCNT_ISA_IRQ;
+ ia64_intrs[vector] = i;
+ sapic_enable(sa, irq, vector);
+
+ /* XXX unlock */
+
+ if (name != NULL && *name != '\0') {
+ /* XXX needs abstraction. Too error prone. */
+ intrname = intrnames +
+ (irq + INTRCNT_ISA_IRQ) * INTRNAME_LEN;
+ memset(intrname, ' ', INTRNAME_LEN - 1);
+ bcopy(name, intrname, strlen(name));
}
+ } else {
+ i = ia64_intrs[vector];
+ /* XXX unlock */
}
+ KASSERT(i != NULL, ("vector mapping bug"));
+
error = intr_event_add_handler(i->event, name, filter, handler, arg,
- intr_priority(flags), flags, cookiep);
+ prio, flags, cookiep);
return (error);
}
diff --git a/sys/ia64/ia64/locore.S b/sys/ia64/ia64/locore.S
index 6b1d8f1..afba834 100644
--- a/sys/ia64/ia64/locore.S
+++ b/sys/ia64/ia64/locore.S
@@ -98,13 +98,13 @@ ENTRY_NOPROFILE(__start, 1)
mov out0=r0 // we are linked at the right address
;; // we just need to process fptrs
}
-{ .bbb
+{ .mib
nop 0
nop 0
br.call.sptk.many rp=_reloc
;;
}
-{ .bbb
+{ .mib
nop 0
nop 0
br.call.sptk.many rp=ia64_init
@@ -112,21 +112,21 @@ ENTRY_NOPROFILE(__start, 1)
}
// We have the new bspstore in r8 and the new sp in r9.
// Switch onto the new stack and call mi_startup().
-{
+{ .mmi
mov ar.rsc = 0
;;
mov ar.bspstore = r8
mov sp = r9
;;
}
-{
+{ .mmi
loadrs
;;
mov ar.rsc = 3
nop 0
;;
}
-{
+{ .mib
nop 0
nop 0
br.call.sptk.many rp=mi_startup
@@ -163,7 +163,7 @@ ENTRY(fork_trampoline, 0)
ld8 out1=[r16]
nop 0
}
-{ .mfb
+{ .mib
add out2=16,sp
nop 0
br.call.sptk rp=fork_exit
@@ -174,7 +174,7 @@ ENTRY(fork_trampoline, 0)
.global enter_userland
.type enter_userland, @function
enter_userland:
-{ .mfb
+{ .mib
nop 0
nop 0
br.sptk epc_syscall_return
@@ -282,7 +282,7 @@ ENTRY_NOPROFILE(os_boot_rendez,0)
add sp = r18, r16
;;
}
-{ .mfb
+{ .mib
mov ar.rsc = 3
nop 0
br.call.sptk.few rp = ia64_ap_startup
@@ -290,7 +290,7 @@ ENTRY_NOPROFILE(os_boot_rendez,0)
}
/* NOT REACHED */
9:
-{ .mfb
+{ .mib
nop 0
nop 0
br.sptk 9b
diff --git a/sys/ia64/ia64/nexus.c b/sys/ia64/ia64/nexus.c
index 5ce4731..17c07d6 100644
--- a/sys/ia64/ia64/nexus.c
+++ b/sys/ia64/ia64/nexus.c
@@ -59,7 +59,6 @@
#include <machine/nexusvar.h>
#include <machine/pmap.h>
#include <machine/resource.h>
-#include <machine/sapicvar.h>
#include <machine/vmparam.h>
#include <contrib/dev/acpica/include/acpi.h>
diff --git a/sys/ia64/ia64/pmap.c b/sys/ia64/ia64/pmap.c
index a2af574..f829746 100644
--- a/sys/ia64/ia64/pmap.c
+++ b/sys/ia64/ia64/pmap.c
@@ -453,7 +453,6 @@ pmap_bootstrap()
PMAP_LOCK_INIT(kernel_pmap);
for (i = 0; i < 5; i++)
kernel_pmap->pm_rid[i] = 0;
- kernel_pmap->pm_active = 1;
TAILQ_INIT(&kernel_pmap->pm_pvlist);
PCPU_SET(md.current_pmap, kernel_pmap);
@@ -662,7 +661,6 @@ pmap_pinit(struct pmap *pmap)
PMAP_LOCK_INIT(pmap);
for (i = 0; i < 5; i++)
pmap->pm_rid[i] = pmap_allocate_rid();
- pmap->pm_active = 0;
TAILQ_INIT(&pmap->pm_pvlist);
bzero(&pmap->pm_stats, sizeof pmap->pm_stats);
return (1);
@@ -2246,8 +2244,6 @@ pmap_switch(pmap_t pm)
prevpm = PCPU_GET(md.current_pmap);
if (prevpm == pm)
goto out;
- if (prevpm != NULL)
- atomic_clear_32(&prevpm->pm_active, PCPU_GET(cpumask));
if (pm == NULL) {
for (i = 0; i < 5; i++) {
ia64_set_rr(IA64_RR_BASE(i),
@@ -2258,7 +2254,6 @@ pmap_switch(pmap_t pm)
ia64_set_rr(IA64_RR_BASE(i),
(pm->pm_rid[i] << 8)|(PAGE_SHIFT << 2)|1);
}
- atomic_set_32(&pm->pm_active, PCPU_GET(cpumask));
}
PCPU_SET(md.current_pmap, pm);
ia64_srlz_d();
diff --git a/sys/ia64/ia64/sapic.c b/sys/ia64/ia64/sapic.c
index 88bd013..cb8a1c3 100644
--- a/sys/ia64/ia64/sapic.c
+++ b/sys/ia64/ia64/sapic.c
@@ -39,77 +39,100 @@
#include <machine/intr.h>
#include <machine/pal.h>
-#include <machine/sapicreg.h>
-#include <machine/sapicvar.h>
#include <vm/vm.h>
#include <vm/pmap.h>
-static MALLOC_DEFINE(M_SAPIC, "sapic", "I/O SAPIC devices");
-
-static int sysctl_machdep_apic(SYSCTL_HANDLER_ARGS);
-
-SYSCTL_OID(_machdep, OID_AUTO, apic, CTLTYPE_STRING|CTLFLAG_RD,
- NULL, 0, sysctl_machdep_apic, "A", "(x)APIC redirection table entries");
+/*
+ * Offsets from the SAPIC base in memory. Most registers are accessed
+ * by indexing using the SAPIC_IO_SELECT register.
+ */
+#define SAPIC_IO_SELECT 0x00
+#define SAPIC_IO_WINDOW 0x10
+#define SAPIC_APIC_EOI 0x40
-struct sapic *ia64_sapics[16]; /* XXX make this resizable */
-int ia64_sapic_count;
+/*
+ * Indexed registers.
+ */
+#define SAPIC_ID 0x00
+#define SAPIC_VERSION 0x01
+#define SAPIC_ARBITRATION_ID 0x02
+#define SAPIC_RTE_BASE 0x10
+
+/* Interrupt polarity. */
+#define SAPIC_POLARITY_HIGH 0
+#define SAPIC_POLARITY_LOW 1
+
+/* Interrupt trigger. */
+#define SAPIC_TRIGGER_EDGE 0
+#define SAPIC_TRIGGER_LEVEL 1
+
+/* Interrupt delivery mode. */
+#define SAPIC_DELMODE_FIXED 0
+#define SAPIC_DELMODE_LOWPRI 1
+#define SAPIC_DELMODE_PMI 2
+#define SAPIC_DELMODE_NMI 4
+#define SAPIC_DELMODE_INIT 5
+#define SAPIC_DELMODE_EXTINT 7
+
+struct sapic {
+ struct mtx sa_mtx;
+ uint64_t sa_registers; /* virtual address of sapic */
+ u_int sa_id; /* I/O SAPIC Id */
+ u_int sa_base; /* ACPI vector base */
+ u_int sa_limit; /* last ACPI vector handled here */
+};
struct sapic_rte {
- u_int64_t rte_vector :8;
- u_int64_t rte_delivery_mode :3;
- u_int64_t rte_destination_mode :1;
- u_int64_t rte_delivery_status :1;
- u_int64_t rte_polarity :1;
- u_int64_t rte_rirr :1;
- u_int64_t rte_trigger_mode :1;
- u_int64_t rte_mask :1;
- u_int64_t rte_flushen :1;
- u_int64_t rte_reserved :30;
- u_int64_t rte_destination_eid :8;
- u_int64_t rte_destination_id :8;
+ uint64_t rte_vector :8;
+ uint64_t rte_delivery_mode :3;
+ uint64_t rte_destination_mode :1;
+ uint64_t rte_delivery_status :1;
+ uint64_t rte_polarity :1;
+ uint64_t rte_rirr :1;
+ uint64_t rte_trigger_mode :1;
+ uint64_t rte_mask :1;
+ uint64_t rte_flushen :1;
+ uint64_t rte_reserved :30;
+ uint64_t rte_destination_eid :8;
+ uint64_t rte_destination_id :8;
};
-struct sapic *
-sapic_lookup(u_int irq)
-{
- struct sapic *sa;
- int i;
+MALLOC_DEFINE(M_SAPIC, "sapic", "I/O SAPIC devices");
- for (i = 0; i < ia64_sapic_count; i++) {
- sa = ia64_sapics[i];
- if (irq >= sa->sa_base && irq <= sa->sa_limit)
- return (sa);
- }
+struct sapic *ia64_sapics[16]; /* XXX make this resizable */
+int ia64_sapic_count;
- return (NULL);
-}
+static int sysctl_machdep_apic(SYSCTL_HANDLER_ARGS);
-static __inline u_int32_t
+SYSCTL_OID(_machdep, OID_AUTO, apic, CTLTYPE_STRING|CTLFLAG_RD,
+ NULL, 0, sysctl_machdep_apic, "A", "(x)APIC redirection table entries");
+
+static __inline uint32_t
sapic_read(struct sapic *sa, int which)
{
- vm_offset_t reg = sa->sa_registers;
+ uint32_t value;
- *(volatile u_int32_t *) (reg + SAPIC_IO_SELECT) = which;
- ia64_mf();
- return *(volatile u_int32_t *) (reg + SAPIC_IO_WINDOW);
+ ia64_st4((void *)(sa->sa_registers + SAPIC_IO_SELECT), which);
+ ia64_mf_a();
+ value = ia64_ld4((void *)(sa->sa_registers + SAPIC_IO_WINDOW));
+ return (value);
}
static __inline void
-sapic_write(struct sapic *sa, int which, u_int32_t value)
+sapic_write(struct sapic *sa, int which, uint32_t value)
{
- vm_offset_t reg = sa->sa_registers;
- *(volatile u_int32_t *) (reg + SAPIC_IO_SELECT) = which;
- ia64_mf();
- *(volatile u_int32_t *) (reg + SAPIC_IO_WINDOW) = value;
- ia64_mf();
+ ia64_st4((void *)(sa->sa_registers + SAPIC_IO_SELECT), which);
+ ia64_mf_a();
+ ia64_st4((void *)(sa->sa_registers + SAPIC_IO_WINDOW), value);
+ ia64_mf_a();
}
static __inline void
sapic_read_rte(struct sapic *sa, int which, struct sapic_rte *rte)
{
- u_int32_t *p = (u_int32_t *) rte;
+ uint32_t *p = (uint32_t *) rte;
p[0] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which);
p[1] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which + 1);
@@ -118,19 +141,43 @@ sapic_read_rte(struct sapic *sa, int which, struct sapic_rte *rte)
static __inline void
sapic_write_rte(struct sapic *sa, int which, struct sapic_rte *rte)
{
- u_int32_t *p = (u_int32_t *) rte;
+ uint32_t *p = (uint32_t *) rte;
+
+ sapic_write(sa, SAPIC_RTE_BASE + 2 * which, p[0]);
+ sapic_write(sa, SAPIC_RTE_BASE + 2 * which + 1, p[1]);
+}
+
+struct sapic *
+sapic_lookup(u_int irq, u_int *vecp)
+{
+ struct sapic_rte rte;
+ struct sapic *sa;
+ int i;
+
+ for (i = 0; i < ia64_sapic_count; i++) {
+ sa = ia64_sapics[i];
+ if (irq >= sa->sa_base && irq <= sa->sa_limit) {
+ if (vecp != NULL) {
+ mtx_lock_spin(&sa->sa_mtx);
+ sapic_read_rte(sa, irq - sa->sa_base, &rte);
+ mtx_unlock_spin(&sa->sa_mtx);
+ *vecp = rte.rte_vector;
+ }
+ return (sa);
+ }
+ }
- sapic_write(sa, SAPIC_RTE_BASE + 2 *which, p[0]);
- sapic_write(sa, SAPIC_RTE_BASE + 2 *which + 1, p[1]);
+ return (NULL);
}
+
int
sapic_config_intr(u_int irq, enum intr_trigger trig, enum intr_polarity pol)
{
struct sapic_rte rte;
struct sapic *sa;
- sa = sapic_lookup(irq);
+ sa = sapic_lookup(irq, NULL);
if (sa == NULL)
return (EINVAL);
@@ -154,7 +201,7 @@ sapic_config_intr(u_int irq, enum intr_trigger trig, enum intr_polarity pol)
}
struct sapic *
-sapic_create(u_int id, u_int base, u_int64_t address)
+sapic_create(u_int id, u_int base, uint64_t address)
{
struct sapic_rte rte;
struct sapic *sa;
@@ -214,10 +261,9 @@ sapic_enable(struct sapic *sa, u_int irq, u_int vector)
void
sapic_eoi(struct sapic *sa, u_int vector)
{
- vm_offset_t reg = sa->sa_registers;
- *(volatile u_int32_t *)(reg + SAPIC_APIC_EOI) = vector;
- ia64_mf();
+ ia64_st4((void *)(sa->sa_registers + SAPIC_APIC_EOI), vector);
+ ia64_mf_a();
}
/* Expected to be called with interrupts disabled. */
diff --git a/sys/ia64/ia64/support.S b/sys/ia64/ia64/support.S
index ea04276..1a82dd6 100644
--- a/sys/ia64/ia64/support.S
+++ b/sys/ia64/ia64/support.S
@@ -227,14 +227,14 @@ ENTRY(casuword, 3)
nop 0
;;
}
-{ .mfb
+{ .mib
st8.rel [r15]=r0 // Clear onfault
nop 0
br.ret.sptk rp
;;
}
1:
-{ .mfb
+{ .mib
add ret0=-1,r0
nop 0
br.ret.sptk rp
@@ -277,14 +277,14 @@ ENTRY(casuword32, 3)
nop 0
;;
}
-{ .mfb
+{ .mib
st8.rel [r15]=r0 // Clear onfault
nop 0
br.ret.sptk rp
;;
}
1:
-{ .mfb
+{ .mib
add ret0=-1,r0
nop 0
br.ret.sptk rp
@@ -338,7 +338,7 @@ ENTRY(subyte, 2)
;;
}
1:
-{ .mfb
+{ .mib
add ret0=-1,r0
nop 0
br.ret.sptk rp
@@ -384,7 +384,7 @@ ENTRY(suword16, 2)
;;
}
1:
-{ .mfb
+{ .mib
add ret0=-1,r0
nop 0
br.ret.sptk rp
@@ -430,7 +430,7 @@ ENTRY(suword32, 2)
;;
}
1:
-{ .mfb
+{ .mib
add ret0=-1,r0
nop 0
br.ret.sptk rp
@@ -477,7 +477,7 @@ XENTRY(suword)
;;
}
1:
-{ .mfb
+{ .mib
add ret0=-1,r0
nop 0
br.ret.sptk rp
@@ -531,7 +531,7 @@ ENTRY(fubyte, 1)
;;
}
1:
-{ .mfb
+{ .mib
add ret0=-1,r0
nop 0
br.ret.sptk rp
@@ -577,7 +577,7 @@ ENTRY(fuword16, 2)
;;
}
1:
-{ .mfb
+{ .mib
add ret0=-1,r0
nop 0
br.ret.sptk rp
@@ -623,7 +623,7 @@ ENTRY(fuword32, 2)
;;
}
1:
-{ .mfb
+{ .mib
add ret0=-1,r0
nop 0
br.ret.sptk rp
@@ -670,7 +670,7 @@ XENTRY(fuword)
;;
}
1:
-{ .mfb
+{ .mib
add ret0=-1,r0
nop 0
br.ret.sptk rp
@@ -684,7 +684,7 @@ END(fuword64)
*/
ENTRY(fuswintr, 1)
-{ .mfb
+{ .mib
add ret0=-1,r0
nop 0
br.ret.sptk rp
@@ -693,7 +693,7 @@ ENTRY(fuswintr, 1)
END(fuswintr)
ENTRY(suswintr, 0)
-{ .mfb
+{ .mib
add ret0=-1,r0
nop 0
br.ret.sptk rp
diff --git a/sys/ia64/ia64/syscall.S b/sys/ia64/ia64/syscall.S
index 73f8da6..b35523a 100644
--- a/sys/ia64/ia64/syscall.S
+++ b/sys/ia64/ia64/syscall.S
@@ -102,13 +102,13 @@ gw_ret:
;;
}
gw_ret_ia32:
-{ .mfb
+{ .mmi
flushrs
nop 0
nop 0
;;
}
-{ .mfb
+{ .mib
nop 0
nop 0
br.ia.sptk b6
@@ -193,7 +193,7 @@ ENTRY_NOPROFILE(epc_sigtramp, 0)
mov b7=r16
;;
}
-{ .mmb
+{ .mmi
alloc r14=ar.pfs, 0, 0, 3, 0
mov ar.rsc=15
nop 0
@@ -204,7 +204,7 @@ ENTRY_NOPROFILE(epc_sigtramp, 0)
mov out0=r8
mov out1=r9
}
-{ .mfb
+{ .mib
add out2=16,sp
nop 0
br.call.sptk rp=b7
@@ -257,7 +257,7 @@ ENTRY_NOPROFILE(epc_syscall, 8)
add r31=8,r30
;;
}
-{ .mib
+{ .mii
mov r22=ar.fpsr
sub r29=r14,r30
nop 0
@@ -380,7 +380,7 @@ ENTRY_NOPROFILE(epc_syscall, 8)
}
.global epc_syscall_return
epc_syscall_return:
-{ .mfb
+{ .mib
add out0=16,sp
nop 0
br.call.sptk rp=do_ast
@@ -392,7 +392,7 @@ epc_syscall_return:
(p15) br.spnt 1b // restart syscall
;;
}
-{ .mfb
+{ .mmi
ld8 r14=[r14] // tf_flags
nop 0
nop 0
@@ -422,7 +422,7 @@ epc_syscall_return:
add r31=r31,sp
;;
}
-{ .mmb
+{ .mmi
ld8 r19=[r15],16 // pr
ld8 r20=[r14],16 // pfs (syscall caller)
nop 0
@@ -434,7 +434,7 @@ epc_syscall_return:
mov pr=r19,0x1fffe
;;
}
-{ .mmb
+{ .mmi
ld8 r23=[r15],16 // tp
ld8 r24=[r14],16 // rsc
nop 0
@@ -488,7 +488,7 @@ epc_syscall_return:
dep r30=0,r30,0,13 // 8KB aligned.
;;
}
-{ .mib
+{ .mii
mov ar.k6=r30
mov r13=r23
nop 0
diff --git a/sys/ia64/include/intr.h b/sys/ia64/include/intr.h
index 8651fda..0635e34 100644
--- a/sys/ia64/include/intr.h
+++ b/sys/ia64/include/intr.h
@@ -30,6 +30,8 @@
#ifndef _MACHINE_INTR_H_
#define _MACHINE_INTR_H_
+struct sapic;
+
/*
* Layout of the Processor Interrupt Block.
*/
@@ -46,8 +48,20 @@ struct ia64_pib
extern struct ia64_pib *ia64_pib;
-int ia64_setup_intr(const char *name, int irq, driver_filter_t filter,
- driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep);
-int ia64_teardown_intr(void *cookie);
+int ia64_setup_intr(const char *, int, driver_filter_t, driver_intr_t,
+ void *, enum intr_type, void **);
+int ia64_teardown_intr(void *);
+
+int sapic_config_intr(u_int, enum intr_trigger, enum intr_polarity);
+struct sapic *sapic_create(u_int, u_int, uint64_t);
+int sapic_enable(struct sapic *, u_int, u_int);
+void sapic_eoi(struct sapic *, u_int);
+struct sapic *sapic_lookup(u_int, u_int *);
+void sapic_mask(struct sapic *, u_int);
+void sapic_unmask(struct sapic *, u_int);
+
+#ifdef DDB
+void sapic_print(struct sapic *, u_int);
+#endif
#endif /* !_MACHINE_INTR_H_ */
diff --git a/sys/ia64/include/pmap.h b/sys/ia64/include/pmap.h
index e40d647..44079c8 100644
--- a/sys/ia64/include/pmap.h
+++ b/sys/ia64/include/pmap.h
@@ -76,7 +76,6 @@ struct pmap {
struct mtx pm_mtx;
TAILQ_HEAD(,pv_entry) pm_pvlist; /* list of mappings in pmap */
u_int32_t pm_rid[5]; /* base RID for pmap */
- int pm_active; /* active flag */
struct pmap_statistics pm_stats; /* pmap statistics */
};
diff --git a/sys/ia64/include/sapicvar.h b/sys/ia64/include/sapicvar.h
deleted file mode 100644
index 30a353c..0000000
--- a/sys/ia64/include/sapicvar.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*-
- * Copyright (c) 2001 Doug Rabson
- * 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_SAPICVAR_H_
-#define _MACHINE_SAPICVAR_H_
-
-struct sapic {
- struct mtx sa_mtx;
- vm_offset_t sa_registers; /* virtual address of sapic */
- u_int sa_id; /* I/O SAPIC Id */
- u_int sa_base; /* ACPI vector base */
- u_int sa_limit; /* last ACPI vector handled here */
-};
-
-#define SAPIC_TRIGGER_EDGE 0
-#define SAPIC_TRIGGER_LEVEL 1
-
-#define SAPIC_POLARITY_HIGH 0
-#define SAPIC_POLARITY_LOW 1
-
-#define SAPIC_DELMODE_FIXED 0
-#define SAPIC_DELMODE_LOWPRI 1
-#define SAPIC_DELMODE_PMI 2
-#define SAPIC_DELMODE_NMI 4
-#define SAPIC_DELMODE_INIT 5
-#define SAPIC_DELMODE_EXTINT 7
-
-int sapic_config_intr(u_int irq, enum intr_trigger, enum intr_polarity);
-struct sapic *sapic_create(u_int id, u_int base, uint64_t address);
-int sapic_enable(struct sapic *sa, u_int irq, u_int vector);
-void sapic_eoi(struct sapic *sa, u_int vector);
-struct sapic *sapic_lookup(u_int irq);
-void sapic_mask(struct sapic *sa, u_int irq);
-void sapic_unmask(struct sapic *sa, u_int irq);
-
-#ifdef DDB
-void sapic_print(struct sapic *sa, u_int irq);
-#endif
-
-#endif /* ! _MACHINE_SAPICVAR_H_ */
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index 56cd66f..fa6ddaf 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -32,6 +32,7 @@
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
+#include "opt_core.h"
#include <sys/param.h>
#include <sys/exec.h>
@@ -58,6 +59,10 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <sys/sysent.h>
#include <sys/vnode.h>
+#include <sys/syslog.h>
+#include <sys/eventhandler.h>
+
+#include <net/zlib.h>
#include <vm/vm.h>
#include <vm/vm_kern.h>
@@ -95,6 +100,12 @@ static boolean_t __elfN(check_note)(struct image_params *imgp,
SYSCTL_NODE(_kern, OID_AUTO, __CONCAT(elf, __ELF_WORD_SIZE), CTLFLAG_RW, 0,
"");
+#ifdef COMPRESS_USER_CORES
+static int compress_core(gzFile, char *, char *, unsigned int,
+ struct thread * td);
+#define CORE_BUF_SIZE (16 * 1024)
+#endif
+
int __elfN(fallback_brand) = -1;
SYSCTL_INT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO,
fallback_brand, CTLFLAG_RW, &__elfN(fallback_brand), 0,
@@ -1003,16 +1014,38 @@ static void cb_put_phdr(vm_map_entry_t, void *);
static void cb_size_segment(vm_map_entry_t, void *);
static void each_writable_segment(struct thread *, segment_callback, void *);
static int __elfN(corehdr)(struct thread *, struct vnode *, struct ucred *,
- int, void *, size_t);
+ int, void *, size_t, gzFile);
static void __elfN(puthdr)(struct thread *, void *, size_t *, int);
static void __elfN(putnote)(void *, size_t *, const char *, int,
const void *, size_t);
+#ifdef COMPRESS_USER_CORES
+extern int compress_user_cores;
+extern int compress_user_cores_gzlevel;
+#endif
+
+static int
+core_output(struct vnode *vp, void *base, size_t len, off_t offset,
+ struct ucred *active_cred, struct ucred *file_cred,
+ struct thread *td, char *core_buf, gzFile gzfile) {
+
+ int error;
+ if (gzfile) {
+#ifdef COMPRESS_USER_CORES
+ error = compress_core(gzfile, base, core_buf, len, td);
+#else
+ panic("shouldn't be here");
+#endif
+ } else {
+ error = vn_rdwr_inchunks(UIO_WRITE, vp, base, len, offset,
+ UIO_USERSPACE, IO_UNIT | IO_DIRECT, active_cred, file_cred,
+ NULL, td);
+ }
+ return (error);
+}
+
int
-__elfN(coredump)(td, vp, limit)
- struct thread *td;
- struct vnode *vp;
- off_t limit;
+__elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
{
struct ucred *cred = td->td_ucred;
int error = 0;
@@ -1020,6 +1053,37 @@ __elfN(coredump)(td, vp, limit)
void *hdr;
size_t hdrsize;
+ gzFile gzfile = Z_NULL;
+ char *core_buf = NULL;
+#ifdef COMPRESS_USER_CORES
+ char gzopen_flags[8];
+ char *p;
+ int doing_compress = flags & IMGACT_CORE_COMPRESS;
+#endif
+
+ hdr = NULL;
+
+#ifdef COMPRESS_USER_CORES
+ if (doing_compress) {
+ p = gzopen_flags;
+ *p++ = 'w';
+ if (compress_user_cores_gzlevel >= 0 &&
+ compress_user_cores_gzlevel <= 9)
+ *p++ = '0' + compress_user_cores_gzlevel;
+ *p = 0;
+ gzfile = gz_open("", gzopen_flags, vp);
+ if (gzfile == Z_NULL) {
+ error = EFAULT;
+ goto done;
+ }
+ core_buf = malloc(CORE_BUF_SIZE, M_TEMP, M_WAITOK | M_ZERO);
+ if (!core_buf) {
+ error = ENOMEM;
+ goto done;
+ }
+ }
+#endif
+
/* Size the program segments. */
seginfo.count = 0;
seginfo.size = 0;
@@ -1044,7 +1108,8 @@ __elfN(coredump)(td, vp, limit)
if (hdr == NULL) {
return (EINVAL);
}
- error = __elfN(corehdr)(td, vp, cred, seginfo.count, hdr, hdrsize);
+ error = __elfN(corehdr)(td, vp, cred, seginfo.count, hdr, hdrsize,
+ gzfile);
/* Write the contents of all of the writable segments. */
if (error == 0) {
@@ -1055,17 +1120,28 @@ __elfN(coredump)(td, vp, limit)
php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1;
offset = hdrsize;
for (i = 0; i < seginfo.count; i++) {
- error = vn_rdwr_inchunks(UIO_WRITE, vp,
- (caddr_t)(uintptr_t)php->p_vaddr,
- php->p_filesz, offset, UIO_USERSPACE,
- IO_UNIT | IO_DIRECT, cred, NOCRED, NULL,
- curthread);
+ error = core_output(vp, (caddr_t)(uintptr_t)php->p_vaddr,
+ php->p_filesz, offset, cred, NOCRED, curthread, core_buf, gzfile);
if (error != 0)
break;
offset += php->p_filesz;
php++;
}
}
+ if (error) {
+ log(LOG_WARNING,
+ "Failed to write core file for process %s (error %d)\n",
+ curproc->p_comm, error);
+ }
+
+#ifdef COMPRESS_USER_CORES
+done:
+#endif
+ if (core_buf)
+ free(core_buf, M_TEMP);
+ if (gzfile)
+ gzclose(gzfile);
+
free(hdr, M_TEMP);
return (error);
@@ -1189,13 +1265,14 @@ each_writable_segment(td, func, closure)
* the page boundary.
*/
static int
-__elfN(corehdr)(td, vp, cred, numsegs, hdr, hdrsize)
+__elfN(corehdr)(td, vp, cred, numsegs, hdr, hdrsize, gzfile)
struct thread *td;
struct vnode *vp;
struct ucred *cred;
int numsegs;
size_t hdrsize;
void *hdr;
+ gzFile gzfile;
{
size_t off;
@@ -1204,10 +1281,26 @@ __elfN(corehdr)(td, vp, cred, numsegs, hdr, hdrsize)
off = 0;
__elfN(puthdr)(td, hdr, &off, numsegs);
- /* Write it to the core file. */
- return (vn_rdwr_inchunks(UIO_WRITE, vp, hdr, hdrsize, (off_t)0,
- UIO_SYSSPACE, IO_UNIT | IO_DIRECT, cred, NOCRED, NULL,
- td));
+ if (!gzfile) {
+ /* Write it to the core file. */
+ return (vn_rdwr_inchunks(UIO_WRITE, vp, hdr, hdrsize, (off_t)0,
+ UIO_SYSSPACE, IO_UNIT | IO_DIRECT, cred, NOCRED, NULL,
+ td));
+ } else {
+#ifdef COMPRESS_USER_CORES
+ if (gzwrite(gzfile, hdr, hdrsize) != hdrsize) {
+ log(LOG_WARNING,
+ "Failed to compress core file header for process"
+ " %s.\n", curproc->p_comm);
+ return (EFAULT);
+ }
+ else {
+ return (0);
+ }
+#else
+ panic("shouldn't be here");
+#endif
+ }
}
#if defined(COMPAT_IA32) && __ELF_WORD_SIZE == 32
@@ -1476,3 +1569,50 @@ static struct execsw __elfN(execsw) = {
__XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE))
};
EXEC_SET(__CONCAT(elf, __ELF_WORD_SIZE), __elfN(execsw));
+
+#ifdef COMPRESS_USER_CORES
+/*
+ * Compress and write out a core segment for a user process.
+ *
+ * 'inbuf' is the starting address of a VM segment in the process' address
+ * space that is to be compressed and written out to the core file. 'dest_buf'
+ * is a buffer in the kernel's address space. The segment is copied from
+ * 'inbuf' to 'dest_buf' first before being processed by the compression
+ * routine gzwrite(). This copying is necessary because the content of the VM
+ * segment may change between the compression pass and the crc-computation pass
+ * in gzwrite(). This is because realtime threads may preempt the UNIX kernel.
+ */
+static int
+compress_core (gzFile file, char *inbuf, char *dest_buf, unsigned int len,
+ struct thread *td)
+{
+ int len_compressed;
+ int error = 0;
+ unsigned int chunk_len;
+
+ while (len) {
+ chunk_len = (len > CORE_BUF_SIZE) ? CORE_BUF_SIZE : len;
+ copyin(inbuf, dest_buf, chunk_len);
+ len_compressed = gzwrite(file, dest_buf, chunk_len);
+
+ EVENTHANDLER_INVOKE(app_coredump_progress, td, len_compressed);
+
+ if ((unsigned int)len_compressed != chunk_len) {
+ log(LOG_WARNING,
+ "compress_core: length mismatch (0x%x returned, "
+ "0x%x expected)\n", len_compressed, chunk_len);
+ EVENTHANDLER_INVOKE(app_coredump_error, td,
+ "compress_core: length mismatch %x -> %x",
+ chunk_len, len_compressed);
+ error = EFAULT;
+ break;
+ }
+ inbuf += chunk_len;
+ len -= chunk_len;
+ if (ticks - PCPU_GET(switchticks) >= hogticks)
+ uio_yield();
+ }
+
+ return (error);
+}
+#endif /* COMPRESS_USER_CORES */
diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c
index f4510ac..a2e292e 100644
--- a/sys/kern/kern_conf.c
+++ b/sys/kern/kern_conf.c
@@ -649,7 +649,7 @@ prep_cdevsw(struct cdevsw *devsw)
cdevsw_free_devlocked(dsw2);
}
-struct cdev *
+static struct cdev *
make_dev_credv(int flags, struct cdevsw *devsw, int unit,
struct ucred *cr, uid_t uid,
gid_t gid, int mode, const char *fmt, va_list ap)
@@ -947,7 +947,8 @@ clone_setup(struct clonedevs **cdp)
}
int
-clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, int extra)
+clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up,
+ struct cdev **dp, int extra)
{
struct clonedevs *cd;
struct cdev *dev, *ndev, *dl, *de;
@@ -1118,6 +1119,7 @@ destroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg)
int
destroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg)
{
+
dev_lock();
return (destroy_dev_sched_cbl(dev, cb, arg));
}
@@ -1125,6 +1127,7 @@ destroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg)
int
destroy_dev_sched(struct cdev *dev)
{
+
return (destroy_dev_sched_cb(dev, NULL, NULL));
}
diff --git a/sys/kern/kern_gzio.c b/sys/kern/kern_gzio.c
new file mode 100644
index 0000000..1f9c387
--- /dev/null
+++ b/sys/kern/kern_gzio.c
@@ -0,0 +1,406 @@
+/*
+ * $Id: kern_gzio.c,v 1.6 2008-10-18 22:54:45 lbazinet Exp $
+ *
+ * core_gzip.c -- gzip routines used in compressing user process cores
+ *
+ * This file is derived from src/lib/libz/gzio.c in FreeBSD.
+ */
+
+/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ */
+
+/* @(#) $FreeBSD$ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/syslog.h>
+#include <sys/endian.h>
+#include <net/zutil.h>
+#include <sys/libkern.h>
+
+#include <sys/vnode.h>
+#include <sys/mount.h>
+
+#define GZ_HEADER_LEN 10
+
+#ifndef Z_BUFSIZE
+# ifdef MAXSEG_64K
+# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
+# else
+# define Z_BUFSIZE 16384
+# endif
+#endif
+#ifndef Z_PRINTF_BUFSIZE
+# define Z_PRINTF_BUFSIZE 4096
+#endif
+
+#define ALLOC(size) malloc(size, M_TEMP, M_WAITOK | M_ZERO)
+#define TRYFREE(p) {if (p) free(p, M_TEMP);}
+
+static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+typedef struct gz_stream {
+ z_stream stream;
+ int z_err; /* error code for last stream operation */
+ int z_eof; /* set if end of input file */
+ struct vnode *file; /* vnode pointer of .gz file */
+ Byte *inbuf; /* input buffer */
+ Byte *outbuf; /* output buffer */
+ uLong crc; /* crc32 of uncompressed data */
+ char *msg; /* error message */
+ char *path; /* path name for debugging only */
+ int transparent; /* 1 if input file is not a .gz file */
+ char mode; /* 'w' or 'r' */
+ long startpos; /* start of compressed data in file (header skipped) */
+ off_t outoff; /* current offset in output file */
+ int flags;
+} gz_stream;
+
+
+local int do_flush OF((gzFile file, int flush));
+local int destroy OF((gz_stream *s));
+local void putU32 OF((gz_stream *file, uint32_t x));
+local void *gz_alloc OF((void *notused, u_int items, u_int size));
+local void gz_free OF((void *notused, void *ptr));
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb"). The file is given either by file descriptor
+ or path name (if fd == -1).
+ gz_open return NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR).
+*/
+gzFile gz_open (path, mode, vp)
+ const char *path;
+ const char *mode;
+ struct vnode *vp;
+{
+ int err;
+ int level = Z_DEFAULT_COMPRESSION; /* compression level */
+ int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
+ const char *p = mode;
+ gz_stream *s;
+ char fmode[80]; /* copy of mode, without the compression level */
+ char *m = fmode;
+ int resid;
+ int error;
+ char buf[GZ_HEADER_LEN + 1];
+
+ if (!path || !mode) return Z_NULL;
+
+ s = (gz_stream *)ALLOC(sizeof(gz_stream));
+ if (!s) return Z_NULL;
+
+ s->stream.zalloc = (alloc_func)gz_alloc;
+ s->stream.zfree = (free_func)gz_free;
+ s->stream.opaque = (voidpf)0;
+ s->stream.next_in = s->inbuf = Z_NULL;
+ s->stream.next_out = s->outbuf = Z_NULL;
+ s->stream.avail_in = s->stream.avail_out = 0;
+ s->file = NULL;
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->crc = 0;
+ s->msg = NULL;
+ s->transparent = 0;
+ s->outoff = 0;
+ s->flags = 0;
+
+ s->path = (char*)ALLOC(strlen(path)+1);
+ if (s->path == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ strcpy(s->path, path); /* do this early for debugging */
+
+ s->mode = '\0';
+ do {
+ if (*p == 'r') s->mode = 'r';
+ if (*p == 'w' || *p == 'a') s->mode = 'w';
+ if (*p >= '0' && *p <= '9') {
+ level = *p - '0';
+ } else if (*p == 'f') {
+ strategy = Z_FILTERED;
+ } else if (*p == 'h') {
+ strategy = Z_HUFFMAN_ONLY;
+ } else {
+ *m++ = *p; /* copy the mode */
+ }
+ } while (*p++ && m != fmode + sizeof(fmode));
+
+ if (s->mode != 'w') {
+ log(LOG_ERR, "gz_open: mode is not w (%c)\n", s->mode);
+ return destroy(s), (gzFile)Z_NULL;
+ }
+
+ err = deflateInit2(&(s->stream), level,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
+ /* windowBits is passed < 0 to suppress zlib header */
+
+ s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+ if (err != Z_OK || s->outbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+
+ s->stream.avail_out = Z_BUFSIZE;
+ s->file = vp;
+
+ /* Write a very simple .gz header:
+ */
+ snprintf(buf, sizeof(buf), "%c%c%c%c%c%c%c%c%c%c", gz_magic[0],
+ gz_magic[1], Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/,
+ 0 /*xflags*/, OS_CODE);
+
+ if ((error = vn_rdwr(UIO_WRITE, s->file, buf, GZ_HEADER_LEN, s->outoff,
+ UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, curproc->p_ucred,
+ NOCRED, &resid, curthread))) {
+ s->outoff += GZ_HEADER_LEN - resid;
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ s->outoff += GZ_HEADER_LEN;
+ s->startpos = 10L;
+
+ return (gzFile)s;
+}
+
+
+ /* ===========================================================================
+ * Cleanup then free the given gz_stream. Return a zlib error code.
+ Try freeing in the reverse order of allocations.
+ */
+local int destroy (s)
+ gz_stream *s;
+{
+ int err = Z_OK;
+
+ if (!s) return Z_STREAM_ERROR;
+
+ TRYFREE(s->msg);
+
+ if (s->stream.state != NULL) {
+ if (s->mode == 'w') {
+ err = deflateEnd(&(s->stream));
+ }
+ }
+ if (s->z_err < 0) err = s->z_err;
+
+ TRYFREE(s->inbuf);
+ TRYFREE(s->outbuf);
+ TRYFREE(s->path);
+ TRYFREE(s);
+ return err;
+}
+
+
+/* ===========================================================================
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of bytes actually written (0 in case of error).
+*/
+int ZEXPORT gzwrite (file, buf, len)
+ gzFile file;
+ const voidp buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+ off_t curoff;
+ size_t resid;
+ int error;
+ int vfslocked;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.next_in = (Bytef*)buf;
+ s->stream.avail_in = len;
+
+ curoff = s->outoff;
+ while (s->stream.avail_in != 0) {
+
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ vfslocked = VFS_LOCK_GIANT(s->file->v_mount);
+ error = vn_rdwr_inchunks(UIO_WRITE, s->file, s->outbuf, Z_BUFSIZE,
+ curoff, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT,
+ curproc->p_ucred, NOCRED, &resid, curthread);
+ VFS_UNLOCK_GIANT(vfslocked);
+ if (error) {
+ log(LOG_ERR, "gzwrite: vn_rdwr return %d\n", error);
+ curoff += Z_BUFSIZE - resid;
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ curoff += Z_BUFSIZE;
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
+ if (s->z_err != Z_OK) {
+ log(LOG_ERR,
+ "gzwrite: deflate returned error %d\n", s->z_err);
+ break;
+ }
+ }
+
+ s->crc = ~crc32_raw(buf, len, ~s->crc);
+ s->outoff = curoff;
+
+ return (int)(len - s->stream.avail_in);
+}
+
+
+/* ===========================================================================
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function.
+*/
+local int do_flush (file, flush)
+ gzFile file;
+ int flush;
+{
+ uInt len;
+ int done = 0;
+ gz_stream *s = (gz_stream*)file;
+ off_t curoff = s->outoff;
+ size_t resid;
+ int vfslocked = 0;
+ int error;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ if (s->stream.avail_in) {
+ log(LOG_WARNING, "do_flush: avail_in non-zero on entry\n");
+ }
+
+ s->stream.avail_in = 0; /* should be zero already anyway */
+
+ for (;;) {
+ len = Z_BUFSIZE - s->stream.avail_out;
+
+ if (len != 0) {
+ vfslocked = VFS_LOCK_GIANT(s->file->v_mount);
+ error = vn_rdwr_inchunks(UIO_WRITE, s->file, s->outbuf, len, curoff,
+ UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, curproc->p_ucred,
+ NOCRED, &resid, curthread);
+ VFS_UNLOCK_GIANT(vfslocked);
+ if (error) {
+ s->z_err = Z_ERRNO;
+ s->outoff = curoff + len - resid;
+ return Z_ERRNO;
+ }
+ s->stream.next_out = s->outbuf;
+ s->stream.avail_out = Z_BUFSIZE;
+ curoff += len;
+ }
+ if (done) break;
+ s->z_err = deflate(&(s->stream), flush);
+
+ /* Ignore the second of two consecutive flushes: */
+ if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
+
+ /* deflate has finished flushing only when it hasn't used up
+ * all the available space in the output buffer:
+ */
+ done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
+
+ if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
+ }
+ s->outoff = curoff;
+
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+int ZEXPORT gzflush (file, flush)
+ gzFile file;
+ int flush;
+{
+ gz_stream *s = (gz_stream*)file;
+ int err = do_flush (file, flush);
+
+ if (err) return err;
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+
+/* ===========================================================================
+ Outputs a long in LSB order to the given file
+*/
+local void putU32 (s, x)
+ gz_stream *s;
+ uint32_t x;
+{
+ uint32_t xx;
+ off_t curoff = s->outoff;
+ int resid;
+
+#if BYTE_ORDER == BIG_ENDIAN
+ xx = bswap32(x);
+#else
+ xx = x;
+#endif
+ vn_rdwr(UIO_WRITE, s->file, (caddr_t)&xx, sizeof(xx), curoff,
+ UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, curproc->p_ucred,
+ NOCRED, &resid, curthread);
+ s->outoff += sizeof(xx) - resid;
+}
+
+
+/* ===========================================================================
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state.
+*/
+int ZEXPORT gzclose (file)
+ gzFile file;
+{
+ int err;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return Z_STREAM_ERROR;
+
+ if (s->mode == 'w') {
+ err = do_flush (file, Z_FINISH);
+ if (err != Z_OK) {
+ log(LOG_ERR, "gzclose: do_flush failed (err %d)\n", err);
+ return destroy((gz_stream*)file);
+ }
+#if 0
+ printf("gzclose: putting crc: %lld total: %lld\n",
+ (long long)s->crc, (long long)s->stream.total_in);
+ printf("sizeof uLong = %d\n", (int)sizeof(uLong));
+#endif
+ putU32 (s, s->crc);
+ putU32 (s, (uint32_t) s->stream.total_in);
+ }
+ return destroy((gz_stream*)file);
+}
+
+/*
+ * Space allocation and freeing routines for use by zlib routines when called
+ * from gzip modules.
+ */
+static void *
+gz_alloc(void *notused __unused, u_int items, u_int size)
+{
+ void *ptr;
+
+ MALLOC(ptr, void *, items * size, M_TEMP, M_NOWAIT | M_ZERO);
+ return ptr;
+}
+
+static void
+gz_free(void *opaque __unused, void *ptr)
+{
+ FREE(ptr, M_TEMP);
+}
+
diff --git a/sys/kern/kern_kthread.c b/sys/kern/kern_kthread.c
index 5809d14..341707a 100644
--- a/sys/kern/kern_kthread.c
+++ b/sys/kern/kern_kthread.c
@@ -312,18 +312,17 @@ kthread_exit(void)
{
struct proc *p;
+ p = curthread->td_proc;
+
/* A module may be waiting for us to exit. */
wakeup(curthread);
-
- /*
- * We could rely on thread_exit to call exit1() but
- * there is extra work that needs to be done
- */
- if (curthread->td_proc->p_numthreads == 1)
- kproc_exit(0); /* never returns */
-
- p = curthread->td_proc;
PROC_LOCK(p);
+ if (p->p_numthreads == 1) {
+ PROC_UNLOCK(p);
+ kproc_exit(0);
+
+ /* NOTREACHED. */
+ }
PROC_SLOCK(p);
thread_exit();
}
@@ -340,9 +339,9 @@ kthread_suspend(struct thread *td, int timo)
p = td->td_proc;
/*
- * td_pflags should not be ready by any other thread different by
+ * td_pflags should not be read by any thread other than
* curthread, but as long as this flag is invariant during the
- * thread lifetime, it is ok to check for it now.
+ * thread's lifetime, it is OK to check its state.
*/
if ((td->td_pflags & TDP_KTHREAD) == 0)
return (EINVAL);
@@ -371,9 +370,9 @@ kthread_resume(struct thread *td)
p = td->td_proc;
/*
- * td_pflags should not be ready by any other thread different by
+ * td_pflags should not be read by any thread other than
* curthread, but as long as this flag is invariant during the
- * thread lifetime, it is ok to check for it now.
+ * thread's lifetime, it is OK to check its state.
*/
if ((td->td_pflags & TDP_KTHREAD) == 0)
return (EINVAL);
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c
index eaf13f2..c41909d 100644
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -676,11 +676,9 @@ fill_kinfo_aggregate(struct proc *p, struct kinfo_proc *kp)
kp->ki_estcpu = 0;
kp->ki_pctcpu = 0;
- kp->ki_runtime = 0;
FOREACH_THREAD_IN_PROC(p, td) {
thread_lock(td);
kp->ki_pctcpu += sched_pctcpu(td);
- kp->ki_runtime += cputick2usec(td->td_runtime);
kp->ki_estcpu += td->td_estcpu;
thread_unlock(td);
}
@@ -830,9 +828,10 @@ fill_kinfo_proc_only(struct proc *p, struct kinfo_proc *kp)
}
/*
- * Fill in information that is thread specific. Must be called with p_slock
- * locked. If 'preferthread' is set, overwrite certain process-related
- * fields that are maintained for both threads and processes.
+ * Fill in information that is thread specific. Must be called with
+ * target process locked. If 'preferthread' is set, overwrite certain
+ * process-related fields that are maintained for both threads and
+ * processes.
*/
static void
fill_kinfo_thread(struct thread *td, struct kinfo_proc *kp, int preferthread)
@@ -901,7 +900,8 @@ fill_kinfo_thread(struct thread *td, struct kinfo_proc *kp, int preferthread)
/* We can't get this anymore but ps etc never used it anyway. */
kp->ki_rqindex = 0;
- SIGSETOR(kp->ki_siglist, td->td_siglist);
+ if (preferthread)
+ kp->ki_siglist = td->td_siglist;
kp->ki_sigmask = td->td_sigmask;
thread_unlock(td);
}
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index c0ec56f..98a121b 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_kdtrace.h"
#include "opt_ktrace.h"
+#include "opt_core.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -49,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include <sys/condvar.h>
#include <sys/event.h>
#include <sys/fcntl.h>
+#include <sys/imgact.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/ktrace.h>
@@ -78,6 +80,8 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_extern.h>
#include <vm/uma.h>
+#include <sys/jail.h>
+
#include <machine/cpu.h>
#include <security/audit/audit.h>
@@ -98,7 +102,7 @@ SDT_PROBE_ARGTYPE(proc, kernel, , signal_discard, 1, "struct proc *");
SDT_PROBE_ARGTYPE(proc, kernel, , signal_discard, 2, "int");
static int coredump(struct thread *);
-static char *expand_name(const char *, uid_t, pid_t);
+static char *expand_name(const char *, uid_t, pid_t, struct thread *, int);
static int killpg1(struct thread *td, int sig, int pgid, int all,
ksiginfo_t *ksi);
static int issignal(struct thread *td, int stop_allowed);
@@ -2936,12 +2940,51 @@ childproc_exited(struct proc *p)
sigparent(p, reason, status);
}
+/*
+ * We only have 1 character for the core count in the format
+ * string, so the range will be 0-9
+ */
+#define MAX_NUM_CORES 10
+static int num_cores = 5;
+
+static int
+sysctl_debug_num_cores_check (SYSCTL_HANDLER_ARGS)
+{
+ int error;
+ int new_val;
+
+ error = sysctl_handle_int(oidp, &new_val, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ if (new_val > MAX_NUM_CORES)
+ new_val = MAX_NUM_CORES;
+ if (new_val < 0)
+ new_val = 0;
+ num_cores = new_val;
+ return (0);
+}
+SYSCTL_PROC(_debug, OID_AUTO, ncores, CTLTYPE_INT|CTLFLAG_RW,
+ 0, sizeof(int), sysctl_debug_num_cores_check, "I", "");
+
+#if defined(COMPRESS_USER_CORES)
+int compress_user_cores = 1;
+SYSCTL_INT(_kern, OID_AUTO, compress_user_cores, CTLFLAG_RW,
+ &compress_user_cores, 0, "");
+
+int compress_user_cores_gzlevel = -1; /* default level */
+SYSCTL_INT(_kern, OID_AUTO, compress_user_cores_gzlevel, CTLFLAG_RW,
+ &compress_user_cores_gzlevel, -1, "user core gz compression level");
+
+#define GZ_SUFFIX ".gz"
+#define GZ_SUFFIX_LEN 3
+#endif
+
static char corefilename[MAXPATHLEN] = {"%N.core"};
SYSCTL_STRING(_kern, OID_AUTO, corefile, CTLFLAG_RW, corefilename,
sizeof(corefilename), "process corefile name format string");
/*
- * expand_name(name, uid, pid)
+ * expand_name(name, uid, pid, td, compress)
* Expand the name described in corefilename, using name, uid, and pid.
* corefilename is a printf-like string, with three format specifiers:
* %N name of process ("name")
@@ -2952,20 +2995,21 @@ SYSCTL_STRING(_kern, OID_AUTO, corefile, CTLFLAG_RW, corefilename,
* This is controlled by the sysctl variable kern.corefile (see above).
*/
static char *
-expand_name(name, uid, pid)
- const char *name;
- uid_t uid;
- pid_t pid;
+expand_name(const char *name, uid_t uid, pid_t pid, struct thread *td,
+ int compress)
{
struct sbuf sb;
const char *format;
char *temp;
size_t i;
-
+ int indexpos;
+ char hostname[MAXHOSTNAMELEN];
+
format = corefilename;
temp = malloc(MAXPATHLEN, M_TEMP, M_NOWAIT | M_ZERO);
if (temp == NULL)
return (NULL);
+ indexpos = -1;
(void)sbuf_new(&sb, temp, MAXPATHLEN, SBUF_FIXEDLEN);
for (i = 0; format[i]; i++) {
switch (format[i]) {
@@ -2975,6 +3019,15 @@ expand_name(name, uid, pid)
case '%':
sbuf_putc(&sb, '%');
break;
+ case 'H': /* hostname */
+ getcredhostname(td->td_ucred, hostname,
+ sizeof(hostname));
+ sbuf_printf(&sb, "%s", hostname);
+ break;
+ case 'I': /* autoincrementing index */
+ sbuf_printf(&sb, "0");
+ indexpos = sbuf_len(&sb) - 1;
+ break;
case 'N': /* process name */
sbuf_printf(&sb, "%s", name);
break;
@@ -2994,6 +3047,11 @@ expand_name(name, uid, pid)
sbuf_putc(&sb, format[i]);
}
}
+#ifdef COMPRESS_USER_CORES
+ if (compress) {
+ sbuf_printf(&sb, GZ_SUFFIX);
+ }
+#endif
if (sbuf_overflowed(&sb)) {
sbuf_delete(&sb);
log(LOG_ERR, "pid %ld (%s), uid (%lu): corename is too "
@@ -3003,6 +3061,53 @@ expand_name(name, uid, pid)
}
sbuf_finish(&sb);
sbuf_delete(&sb);
+
+ /*
+ * If the core format has a %I in it, then we need to check
+ * for existing corefiles before returning a name.
+ * To do this we iterate over 0..num_cores to find a
+ * non-existing core file name to use.
+ */
+ if (indexpos != -1) {
+ struct nameidata nd;
+ int error, n;
+ int flags = O_CREAT | O_EXCL | FWRITE | O_NOFOLLOW;
+ int cmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
+ int vfslocked;
+
+ for (n = 0; n < num_cores; n++) {
+ temp[indexpos] = '0' + n;
+ NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE,
+ temp, td);
+ error = vn_open(&nd, &flags, cmode, NULL);
+ if (error) {
+ if (error == EEXIST) {
+ continue;
+ }
+ log(LOG_ERR,
+ "pid %d (%s), uid (%u): Path `%s' failed "
+ "on initial open test, error = %d\n",
+ pid, name, uid, temp, error);
+ free(temp, M_TEMP);
+ return (NULL);
+ }
+ vfslocked = NDHASGIANT(&nd);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ VOP_UNLOCK(nd.ni_vp, 0);
+ error = vn_close(nd.ni_vp, FWRITE, td->td_ucred, td);
+ VFS_UNLOCK_GIANT(vfslocked);
+ if (error) {
+ log(LOG_ERR,
+ "pid %d (%s), uid (%u): Path `%s' failed "
+ "on close after initial open test, "
+ "error = %d\n",
+ pid, name, uid, temp, error);
+ free(temp, M_TEMP);
+ return (NULL);
+ }
+ break;
+ }
+ }
return (temp);
}
@@ -3028,12 +3133,19 @@ coredump(struct thread *td)
char *name; /* name of corefile */
off_t limit;
int vfslocked;
+ int compress;
+#ifdef COMPRESS_USER_CORES
+ compress = compress_user_cores;
+#else
+ compress = 0;
+#endif
PROC_LOCK_ASSERT(p, MA_OWNED);
MPASS((p->p_flag & P_HADTHREADS) == 0 || p->p_singlethread == td);
_STOPEVENT(p, S_CORE, 0);
- name = expand_name(p->p_comm, td->td_ucred->cr_uid, p->p_pid);
+ name = expand_name(p->p_comm, td->td_ucred->cr_uid, p->p_pid, td,
+ compress);
if (name == NULL) {
PROC_UNLOCK(p);
#ifdef AUDIT
@@ -3124,7 +3236,7 @@ restart:
PROC_UNLOCK(p);
error = p->p_sysent->sv_coredump ?
- p->p_sysent->sv_coredump(td, vp, limit) :
+ p->p_sysent->sv_coredump(td, vp, limit, compress ? IMGACT_CORE_COMPRESS : 0) :
ENOSYS;
if (locked) {
diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c
index 3159a91..116e79b 100644
--- a/sys/kern/kern_thr.c
+++ b/sys/kern/kern_thr.c
@@ -303,12 +303,18 @@ int
thr_kill(struct thread *td, struct thr_kill_args *uap)
/* long id, int sig */
{
+ ksiginfo_t ksi;
struct thread *ttd;
struct proc *p;
int error;
p = td->td_proc;
error = 0;
+ ksiginfo_init(&ksi);
+ ksi.ksi_signo = uap->sig;
+ ksi.ksi_code = SI_USER;
+ ksi.ksi_pid = p->p_pid;
+ ksi.ksi_uid = td->td_ucred->cr_ruid;
PROC_LOCK(p);
if (uap->id == -1) {
if (uap->sig != 0 && !_SIG_VALID(uap->sig)) {
@@ -320,7 +326,7 @@ thr_kill(struct thread *td, struct thr_kill_args *uap)
error = 0;
if (uap->sig == 0)
break;
- tdsignal(p, ttd, uap->sig, NULL);
+ tdsignal(p, ttd, uap->sig, &ksi);
}
}
}
@@ -336,7 +342,7 @@ thr_kill(struct thread *td, struct thr_kill_args *uap)
else if (!_SIG_VALID(uap->sig))
error = EINVAL;
else
- tdsignal(p, ttd, uap->sig, NULL);
+ tdsignal(p, ttd, uap->sig, &ksi);
}
PROC_UNLOCK(p);
return (error);
@@ -346,6 +352,7 @@ int
thr_kill2(struct thread *td, struct thr_kill2_args *uap)
/* pid_t pid, long id, int sig */
{
+ ksiginfo_t ksi;
struct thread *ttd;
struct proc *p;
int error;
@@ -362,6 +369,11 @@ thr_kill2(struct thread *td, struct thr_kill2_args *uap)
error = p_cansignal(td, p, uap->sig);
if (error == 0) {
+ ksiginfo_init(&ksi);
+ ksi.ksi_signo = uap->sig;
+ ksi.ksi_code = SI_USER;
+ ksi.ksi_pid = td->td_proc->p_pid;
+ ksi.ksi_uid = td->td_ucred->cr_ruid;
if (uap->id == -1) {
if (uap->sig != 0 && !_SIG_VALID(uap->sig)) {
error = EINVAL;
@@ -372,7 +384,8 @@ thr_kill2(struct thread *td, struct thr_kill2_args *uap)
error = 0;
if (uap->sig == 0)
break;
- tdsignal(p, ttd, uap->sig, NULL);
+ tdsignal(p, ttd, uap->sig,
+ &ksi);
}
}
}
@@ -388,7 +401,7 @@ thr_kill2(struct thread *td, struct thr_kill2_args *uap)
else if (!_SIG_VALID(uap->sig))
error = EINVAL;
else
- tdsignal(p, ttd, uap->sig, NULL);
+ tdsignal(p, ttd, uap->sig, &ksi);
}
}
PROC_UNLOCK(p);
diff --git a/sys/kern/subr_hash.c b/sys/kern/subr_hash.c
new file mode 100644
index 0000000..8ffbc9c
--- /dev/null
+++ b/sys/kern/subr_hash.c
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 1982, 1986, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+/*
+ * General routine to allocate a hash table with control of memory flags.
+ */
+void *
+hashinit_flags(int elements, struct malloc_type *type, u_long *hashmask,
+ int flags)
+{
+ long hashsize;
+ LIST_HEAD(generic, generic) *hashtbl;
+ int i;
+
+ if (elements <= 0)
+ panic("hashinit: bad elements");
+
+ /* Exactly one of HASH_WAITOK and HASH_NOWAIT must be set. */
+ KASSERT((flags & HASH_WAITOK) ^ (flags & HASH_NOWAIT),
+ ("Bad flags (0x%x) passed to hashinit_flags", flags));
+
+ for (hashsize = 1; hashsize <= elements; hashsize <<= 1)
+ continue;
+ hashsize >>= 1;
+
+ if (flags & HASH_NOWAIT)
+ hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl),
+ type, M_NOWAIT);
+ else
+ hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl),
+ type, M_WAITOK);
+
+ if (hashtbl != NULL) {
+ for (i = 0; i < hashsize; i++)
+ LIST_INIT(&hashtbl[i]);
+ *hashmask = hashsize - 1;
+ }
+ return (hashtbl);
+}
+
+/*
+ * Allocate and initialize a hash table with default flag: may sleep.
+ */
+void *
+hashinit(int elements, struct malloc_type *type, u_long *hashmask)
+{
+
+ return (hashinit_flags(elements, type, hashmask, HASH_WAITOK));
+}
+
+void
+hashdestroy(void *vhashtbl, struct malloc_type *type, u_long hashmask)
+{
+ LIST_HEAD(generic, generic) *hashtbl, *hp;
+
+ hashtbl = vhashtbl;
+ for (hp = hashtbl; hp <= &hashtbl[hashmask]; hp++)
+ if (!LIST_EMPTY(hp))
+ panic("hashdestroy: hash not empty");
+ free(hashtbl, type);
+}
+
+static const int primes[] = { 1, 13, 31, 61, 127, 251, 509, 761, 1021, 1531,
+ 2039, 2557, 3067, 3583, 4093, 4603, 5119, 5623, 6143,
+ 6653, 7159, 7673, 8191, 12281, 16381, 24571, 32749 };
+#define NPRIMES (sizeof(primes) / sizeof(primes[0]))
+
+/*
+ * General routine to allocate a prime number sized hash table.
+ */
+void *
+phashinit(int elements, struct malloc_type *type, u_long *nentries)
+{
+ long hashsize;
+ LIST_HEAD(generic, generic) *hashtbl;
+ int i;
+
+ if (elements <= 0)
+ panic("phashinit: bad elements");
+ for (i = 1, hashsize = primes[1]; hashsize <= elements;) {
+ i++;
+ if (i == NPRIMES)
+ break;
+ hashsize = primes[i];
+ }
+ hashsize = primes[i - 1];
+ hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK);
+ for (i = 0; i < hashsize; i++)
+ LIST_INIT(&hashtbl[i]);
+ *nentries = hashsize;
+ return (hashtbl);
+}
diff --git a/sys/kern/subr_param.c b/sys/kern/subr_param.c
index fcd8131..a4d4ff8 100644
--- a/sys/kern/subr_param.c
+++ b/sys/kern/subr_param.c
@@ -74,10 +74,6 @@ __FBSDID("$FreeBSD$");
#define MAXFILES (maxproc * 2)
#endif
-/* Values of enum VM_GUEST members are used as indices in
- * vm_guest_sysctl_names */
-enum VM_GUEST { VM_GUEST_NO = 0, VM_GUEST_VM, VM_GUEST_XEN };
-
static int sysctl_kern_vm_guest(SYSCTL_HANDLER_ARGS);
int hz;
@@ -137,6 +133,10 @@ SYSCTL_PROC(_kern, OID_AUTO, vm_guest, CTLFLAG_RD | CTLTYPE_STRING,
*/
struct buf *swbuf;
+/*
+ * The elements of this array are ordered based upon the values of the
+ * corresponding enum VM_GUEST members.
+ */
static const char *const vm_guest_sysctl_names[] = {
"none",
"generic",
@@ -240,8 +240,6 @@ init_param1(void)
TUNABLE_INT_FETCH("kern.ngroups", &ngroups_max);
if (ngroups_max < NGROUPS_MAX)
ngroups_max = NGROUPS_MAX;
- if (ngroups_max > INT_MAX - 1)
- ngroups_max = INT_MAX - 1;
}
/*
diff --git a/sys/kern/kern_subr.c b/sys/kern/subr_uio.c
index 95ce586..725b1a8 100644
--- a/sys/kern/kern_subr.c
+++ b/sys/kern/subr_uio.c
@@ -42,13 +42,10 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/ktr.h>
#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/proc.h>
-#include <sys/malloc.h>
-#include <sys/resourcevar.h>
#include <sys/sched.h>
#include <sys/sysctl.h>
#include <sys/vnode.h>
@@ -360,96 +357,6 @@ again:
return (0);
}
-/*
- * General routine to allocate a hash table with control of memory flags.
- */
-void *
-hashinit_flags(int elements, struct malloc_type *type, u_long *hashmask,
- int flags)
-{
- long hashsize;
- LIST_HEAD(generic, generic) *hashtbl;
- int i;
-
- if (elements <= 0)
- panic("hashinit: bad elements");
-
- /* Exactly one of HASH_WAITOK and HASH_NOWAIT must be set. */
- KASSERT((flags & HASH_WAITOK) ^ (flags & HASH_NOWAIT),
- ("Bad flags (0x%x) passed to hashinit_flags", flags));
-
- for (hashsize = 1; hashsize <= elements; hashsize <<= 1)
- continue;
- hashsize >>= 1;
-
- if (flags & HASH_NOWAIT)
- hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl),
- type, M_NOWAIT);
- else
- hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl),
- type, M_WAITOK);
-
- if (hashtbl != NULL) {
- for (i = 0; i < hashsize; i++)
- LIST_INIT(&hashtbl[i]);
- *hashmask = hashsize - 1;
- }
- return (hashtbl);
-}
-
-/*
- * Allocate and initialize a hash table with default flag: may sleep.
- */
-void *
-hashinit(int elements, struct malloc_type *type, u_long *hashmask)
-{
-
- return (hashinit_flags(elements, type, hashmask, HASH_WAITOK));
-}
-
-void
-hashdestroy(void *vhashtbl, struct malloc_type *type, u_long hashmask)
-{
- LIST_HEAD(generic, generic) *hashtbl, *hp;
-
- hashtbl = vhashtbl;
- for (hp = hashtbl; hp <= &hashtbl[hashmask]; hp++)
- if (!LIST_EMPTY(hp))
- panic("hashdestroy: hash not empty");
- free(hashtbl, type);
-}
-
-static const int primes[] = { 1, 13, 31, 61, 127, 251, 509, 761, 1021, 1531,
- 2039, 2557, 3067, 3583, 4093, 4603, 5119, 5623, 6143,
- 6653, 7159, 7673, 8191, 12281, 16381, 24571, 32749 };
-#define NPRIMES (sizeof(primes) / sizeof(primes[0]))
-
-/*
- * General routine to allocate a prime number sized hash table.
- */
-void *
-phashinit(int elements, struct malloc_type *type, u_long *nentries)
-{
- long hashsize;
- LIST_HEAD(generic, generic) *hashtbl;
- int i;
-
- if (elements <= 0)
- panic("phashinit: bad elements");
- for (i = 1, hashsize = primes[1]; hashsize <= elements;) {
- i++;
- if (i == NPRIMES)
- break;
- hashsize = primes[i];
- }
- hashsize = primes[i - 1];
- hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK);
- for (i = 0; i < hashsize; i++)
- LIST_INIT(&hashtbl[i]);
- *nentries = hashsize;
- return (hashtbl);
-}
-
void
uio_yield(void)
{
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index cc16c49..5cbdc40 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -773,6 +773,8 @@ soconnect(struct socket *so, struct sockaddr *nam, struct thread *td)
if (so->so_options & SO_ACCEPTCONN)
return (EOPNOTSUPP);
+
+ CURVNET_SET(so->so_vnet);
/*
* If protocol is connection-based, can only connect once.
* Otherwise, if connected, try to disconnect first. This allows
@@ -788,10 +790,9 @@ soconnect(struct socket *so, struct sockaddr *nam, struct thread *td)
* biting us.
*/
so->so_error = 0;
- CURVNET_SET(so->so_vnet);
error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam, td);
- CURVNET_RESTORE();
}
+ CURVNET_RESTORE();
return (error);
}
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index a9001d9..c3e755b 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -941,8 +941,8 @@ kern_recvit(td, s, mp, fromseg, controlp)
struct uio *ktruio = NULL;
#endif
- if(controlp != NULL)
- *controlp = 0;
+ if (controlp != NULL)
+ *controlp = NULL;
AUDIT_ARG_FD(s);
error = getsock(td->td_proc->p_fd, s, &fp, NULL);
diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c
index b80d03d..50bf0d2 100644
--- a/sys/kern/vfs_default.c
+++ b/sys/kern/vfs_default.c
@@ -894,10 +894,7 @@ loop:
error = VOP_FSYNC(vp, waitfor, td);
if (error)
allerror = error;
-
- /* Do not turn this into vput. td is not always curthread. */
- VOP_UNLOCK(vp, 0);
- vrele(vp);
+ vput(vp);
MNT_ILOCK(mp);
}
MNT_IUNLOCK(mp);
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
index b443152..088d939 100644
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -959,12 +959,12 @@ vfs_domount(
}
vp->v_iflag |= VI_MOUNT;
VI_UNLOCK(vp);
+ VOP_UNLOCK(vp, 0);
/*
* Allocate and initialize the filesystem.
*/
mp = vfs_mount_alloc(vp, vfsp, fspath, td->td_ucred);
- VOP_UNLOCK(vp, 0);
/* XXXMAC: pass to vfs_mount_alloc? */
mp->mnt_optnew = fsdata;
@@ -1060,12 +1060,12 @@ vfs_domount(
* Put the new filesystem on the mount list after root.
*/
cache_purge(vp);
+ VI_LOCK(vp);
+ vp->v_iflag &= ~VI_MOUNT;
+ VI_UNLOCK(vp);
if (!error) {
struct vnode *newdp;
- VI_LOCK(vp);
- vp->v_iflag &= ~VI_MOUNT;
- VI_UNLOCK(vp);
vp->v_mountedhere = mp;
mtx_lock(&mountlist_mtx);
TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
@@ -1083,9 +1083,6 @@ vfs_domount(
if (error)
vrele(vp);
} else {
- VI_LOCK(vp);
- vp->v_iflag &= ~VI_MOUNT;
- VI_UNLOCK(vp);
vfs_unbusy(mp);
vfs_mount_destroy(mp);
vput(vp);
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index aa072ff..f1e6ca8 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -2122,8 +2122,7 @@ kern_accessat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
/*
* Create and modify a temporary credential instead of one that
- * is potentially shared. This could also mess up socket
- * buffer accounting which can run in an interrupt context.
+ * is potentially shared.
*/
if (!(flags & AT_EACCESS)) {
cred = td->td_ucred;
diff --git a/sys/mips/alchemy/obio.c b/sys/mips/alchemy/obio.c
index 8d83928..fb55813 100644
--- a/sys/mips/alchemy/obio.c
+++ b/sys/mips/alchemy/obio.c
@@ -120,6 +120,40 @@ static int obio_setup_intr(device_t, device_t, struct resource *, int,
static int obio_teardown_intr(device_t, device_t, struct resource *,
void *);
+static void
+obio_mask_irq(void *arg)
+{
+ /* XXX need to write */
+#if 0
+ unsigned int irq = (unsigned int)arg;
+ int ip_bit, mask, mask_register;
+
+ /* mask IRQ */
+ mask_register = ICU_IRQ_MASK_REG(irq);
+ ip_bit = ICU_IP_BIT(irq);
+
+ mask = ICU_REG_READ(mask_register);
+ ICU_REG_WRITE(mask_register, mask | ip_bit);
+#endif
+}
+
+static void
+obio_unmask_irq(void *arg)
+{
+ /* XXX need to write */
+#if 0
+ unsigned int irq = (unsigned int)arg;
+ int ip_bit, mask, mask_register;
+
+ /* unmask IRQ */
+ mask_register = ICU_IRQ_MASK_REG(irq);
+ ip_bit = ICU_IP_BIT(irq);
+
+ mask = ICU_REG_READ(mask_register);
+ ICU_REG_WRITE(mask_register, mask & ~ip_bit);
+#endif
+}
+
static int
obio_probe(device_t dev)
{
@@ -320,9 +354,10 @@ obio_setup_intr(device_t dev, device_t child, struct resource *ires,
event = sc->sc_eventstab[irq];
if (event == NULL) {
- error = intr_event_create(&event, (void *)irq, 0, irq,
- (mask_fn)mips_mask_irq, (mask_fn)mips_unmask_irq,
- NULL, NULL, "obio intr%d:", irq);
+ error = intr_event_create(&event, (void *)irq, 0, irq,
+ obio_mask_irq, obio_unmask_irq,
+ NULL, NULL,
+ "obio intr%d:", irq);
sc->sc_eventstab[irq] = event;
}
diff --git a/sys/mips/atheros/ar71xxreg.h b/sys/mips/atheros/ar71xxreg.h
index 0983966..1908d68 100644
--- a/sys/mips/atheros/ar71xxreg.h
+++ b/sys/mips/atheros/ar71xxreg.h
@@ -403,9 +403,9 @@
#define AR71XX_DMA_RX_STATUS 0x194
#define DMA_RX_STATUS_PCOUNT_MASK 0xff
#define DMA_RX_STATUS_PCOUNT_SHIFT 16
-#define DMA_RX_STATUS_BUS_ERROR (1 << 3)
-#define DMA_RX_STATUS_OVERFLOW (1 << 1)
-#define DMA_RX_STATUS_PKT_RECVD (1 << 0)
+#define DMA_RX_STATUS_BUS_ERROR (1 << 3)
+#define DMA_RX_STATUS_OVERFLOW (1 << 2)
+#define DMA_RX_STATUS_PKT_RECVD (1 << 0)
#define AR71XX_DMA_INTR 0x198
#define AR71XX_DMA_INTR_STATUS 0x19C
#define DMA_INTR_ALL ((1 << 8) - 1)
diff --git a/sys/mips/cavium/dev/rgmii/octeon_fpa.c b/sys/mips/cavium/dev/rgmii/octeon_fpa.c
index f247d2b..3e43a88 100644
--- a/sys/mips/cavium/dev/rgmii/octeon_fpa.c
+++ b/sys/mips/cavium/dev/rgmii/octeon_fpa.c
@@ -209,8 +209,9 @@ void octeon_fpa_fill_pool_mem (u_int pool, u_int elem_size_words, u_int elem_num
memory = (void *) OCTEON_ALIGN(memory);
#ifdef FPA_DEBUG_TERSE
- printf("FPA fill: %u Count: %u SizeBytes: %u SizeBytesAligned: %u 1st: %p = 0x%X\n",
- pool, elem_num, elem_size_bytes, block_size, memory, (void *)OCTEON_PTR2PHYS(memory));
+ printf("FPA fill: %u Count: %u SizeBytes: %u SizeBytesAligned: %u 1st: %p = %p\n",
+ pool, elem_num, elem_size_bytes, block_size, memory,
+ (void *)(intptr_t)OCTEON_PTR2PHYS(memory));
#endif
// memory = (void *) ((((u_int) memory / OCTEON_FPA_POOL_ALIGNMENT) + 1) * OCTEON_FPA_POOL_ALIGNMENT);
@@ -218,7 +219,8 @@ void octeon_fpa_fill_pool_mem (u_int pool, u_int elem_size_words, u_int elem_num
while (elem_num--) {
#ifdef FPA_DEBUG
if (((elems - elem_num) < 4) || (elem_num < 4))
- printf(" %% Block %d: %p Phys 0x%X Bytes %u\n", block, memory, OCTEON_PTR2PHYS(memory), elem_size_bytes);
+ printf(" %% Block %d: %p Phys %p Bytes %u\n", block, memory,
+ (void *)(intptr_t)OCTEON_PTR2PHYS(memory), elem_size_bytes);
block++;
#endif
octeon_fpa_free(memory, pool, 0);
diff --git a/sys/mips/cavium/octeon_machdep.c b/sys/mips/cavium/octeon_machdep.c
index e4d77f3..e3f2fbd 100644
--- a/sys/mips/cavium/octeon_machdep.c
+++ b/sys/mips/cavium/octeon_machdep.c
@@ -659,8 +659,8 @@ octeon_memory_init(void)
uint32_t realmem_bytes;
if (octeon_board_real()) {
- printf("octeon_dram == %llx\n", octeon_dram);
- printf("reduced to ram: %u MB", (uint32_t) octeon_dram >> 20);
+ printf("octeon_dram == %jx\n", (intmax_t)octeon_dram);
+ printf("reduced to ram: %u MB", (uint32_t)octeon_dram >> 20);
realmem_bytes = (octeon_dram - PAGE_SIZE);
realmem_bytes &= ~(PAGE_SIZE - 1);
@@ -678,8 +678,8 @@ octeon_memory_init(void)
phys_avail[1] = realmem_bytes;
realmem_bytes -= OCTEON_DRAM_FIRST_256_END;
realmem_bytes &= ~(PAGE_SIZE - 1);
- printf("phys_avail[0] = %x phys_avail[1] = %x\n",
- phys_avail[0], phys_avail[1]);
+ printf("phys_avail[0] = %#lx phys_avail[1] = %#lx\n",
+ (long)phys_avail[0], (long)phys_avail[1]);
} else {
/* Simulator gets 96Meg period. */
phys_avail[1] = (96 << 20);
@@ -707,8 +707,8 @@ octeon_memory_init(void)
phys_avail[2] = 0x20000000;
printf("realmem_bytes is now at %x\n", realmem_bytes);
phys_avail[3] = ((uint32_t) 0x20000000 + realmem_bytes);
- printf("Next block of memory goes from %x to %x\n",
- phys_avail[2], phys_avail[3]);
+ printf("Next block of memory goes from %#lx to %#lx\n",
+ (long)phys_avail[2], (long)phys_avail[3]);
physmem += btoc(phys_avail[3] - phys_avail[2]);
} else {
printf("realmem_bytes is %d\n", realmem_bytes);
@@ -716,8 +716,8 @@ octeon_memory_init(void)
realmem = physmem;
printf("Total DRAM Size %#X\n", (uint32_t) octeon_dram);
- printf("Bank 0 = %#08X -> %#08X\n", phys_avail[0], phys_avail[1]);
- printf("Bank 1 = %#08X -> %#08X\n", phys_avail[2], phys_avail[3]);
+ printf("Bank 0 = %#08lX -> %#08lX\n", (long)phys_avail[0], (long)phys_avail[1]);
+ printf("Bank 1 = %#08lX -> %#08lX\n", (long)phys_avail[2], (long)phys_avail[3]);
printf("physmem: %#lx\n", physmem);
Maxmem = physmem;
diff --git a/sys/mips/cavium/octeon_pcmap_regs.h b/sys/mips/cavium/octeon_pcmap_regs.h
index ab19d77..a80c3d4 100644
--- a/sys/mips/cavium/octeon_pcmap_regs.h
+++ b/sys/mips/cavium/octeon_pcmap_regs.h
@@ -601,10 +601,9 @@ typedef enum {
#define octeon_ptr_to_phys(ptr) \
- ((((mipsx_addr_size) ptr) >> MIPSX_ADDR_SIZE_KSEGX_BIT_SHIFT) == 2) ? \
+ (((((mipsx_addr_size) ptr) >> MIPSX_ADDR_SIZE_KSEGX_BIT_SHIFT) == 2) ? \
((mipsx_addr_size) ptr & MIPSX_ADDR_SIZE_KSEGX_MASK_REMOVED) : \
- (vtophys(ptr))
-
+ (vtophys(ptr)))
#ifdef CODE_FOR_64_BIT_NEEDED
static inline mipsx_addr_size octeon_ptr_to_phys (void *ptr)
diff --git a/sys/mips/conf/ADM5120 b/sys/mips/conf/ADM5120
index 4e3057a..a834c16 100644
--- a/sys/mips/conf/ADM5120
+++ b/sys/mips/conf/ADM5120
@@ -25,7 +25,6 @@ makeoptions MIPS_LITTLE_ENDIAN=defined
# Don't build any modules yet.
makeoptions MODULES_OVERRIDE=""
-options KERNVIRTADDR=0x80100000
include "../adm5120/std.adm5120"
hints "ADM5120.hints" #Default places to look for devices.
diff --git a/sys/mips/conf/MALTA b/sys/mips/conf/MALTA
index 91684f1..77e072c 100644
--- a/sys/mips/conf/MALTA
+++ b/sys/mips/conf/MALTA
@@ -28,7 +28,6 @@ options YAMON
# Don't build any modules yet.
makeoptions MODULES_OVERRIDE=""
-options KERNVIRTADDR=0x80100000
options TICK_USE_YAMON_FREQ=defined
#options TICK_USE_MALTA_RTC=defined
diff --git a/sys/mips/conf/MALTA64 b/sys/mips/conf/MALTA64
index 3dc5d1b..e7f01c7 100644
--- a/sys/mips/conf/MALTA64
+++ b/sys/mips/conf/MALTA64
@@ -29,7 +29,6 @@ options YAMON
# Don't build any modules yet.
makeoptions MODULES_OVERRIDE=""
-options KERNVIRTADDR=0x80100000
options TICK_USE_YAMON_FREQ=defined
#options TICK_USE_MALTA_RTC=defined
diff --git a/sys/mips/conf/OCTEON1 b/sys/mips/conf/OCTEON1
index 4542bd8..b326823 100644
--- a/sys/mips/conf/OCTEON1
+++ b/sys/mips/conf/OCTEON1
@@ -37,7 +37,6 @@ makeoptions TARGET_BIG_ENDIAN=defined
makeoptions TARGET_64BIT=defined
makeoptions KERNLOADADDR=0xffffffff80100000
-options KERNVIRTADDR=0xffffffff80100000
include "../cavium/std.octeon1"
hints "OCTEON1.hints" #Default places to look for devices.
diff --git a/sys/mips/conf/OCTEON1-32 b/sys/mips/conf/OCTEON1-32
index 0196ad3..7962a06 100644
--- a/sys/mips/conf/OCTEON1-32
+++ b/sys/mips/conf/OCTEON1-32
@@ -26,7 +26,6 @@ makeoptions MODULES_OVERRIDE=""
makeoptions TARGET_BIG_ENDIAN=defined
makeoptions LDSCRIPT_NAME=ldscript.mips.octeon1.32
-options KERNVIRTADDR=0x81000000
makeoptions KERNLOADADDR=0x81000000
include "../cavium/std.octeon1"
diff --git a/sys/mips/conf/QEMU b/sys/mips/conf/QEMU
index 8f830b7..ebb09f8 100644
--- a/sys/mips/conf/QEMU
+++ b/sys/mips/conf/QEMU
@@ -27,7 +27,6 @@ makeoptions ARCH_FLAGS=-march=mips32
# Don't build any modules yet.
makeoptions MODULES_OVERRIDE=""
-options KERNVIRTADDR=0x80100000
include "../adm5120/std.adm5120"
makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
diff --git a/sys/mips/conf/SWARM b/sys/mips/conf/SWARM
index 5679e69..3189bcb 100644
--- a/sys/mips/conf/SWARM
+++ b/sys/mips/conf/SWARM
@@ -19,11 +19,6 @@ options CFE_CONSOLE
options CFE_ENV
options ALT_BREAK_TO_DEBUGGER
-# cfe loader expects kernel at 0x80001000 for mips32 w/o backwards
-# offsets in the linked elf image (see ldscript hack)
-# XXX can we conditionalize the linker stuff on options CFE?
-options KERNVIRTADDR=0x80001000
-
makeoptions LDSCRIPT_NAME= ldscript.mips.cfe
#cpu CPU_MIPS64
diff --git a/sys/mips/conf/XLR b/sys/mips/conf/XLR
index 9818388..d743c1b 100644
--- a/sys/mips/conf/XLR
+++ b/sys/mips/conf/XLR
@@ -53,7 +53,6 @@ makeoptions MODULES_OVERRIDE=""
makeoptions TARGET_BIG_ENDIAN
#
-options KERNVIRTADDR=0x80100000
include "../rmi/std.xlr"
@@ -87,7 +86,6 @@ options ROOTDEVNAME=\"nfs:10.1.1.8:/usr/extra/nfsroot\"
#options ROOTDEVNAME=\"ufs:md0\"
options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions
options HZ=1000
-options PHYS_ADDR_64BIT
options NO_SWAPPING
#Debugging options
diff --git a/sys/mips/include/asm.h b/sys/mips/include/asm.h
index 3dd9aa4..0a9c518 100644
--- a/sys/mips/include/asm.h
+++ b/sys/mips/include/asm.h
@@ -340,17 +340,47 @@ _C_LABEL(x):
#define NON_LEAF(x, fsize, retpc) NESTED(x, fsize, retpc)
#define NNON_LEAF(x, fsize, retpc) NESTED_NOPROFILE(x, fsize, retpc)
+#if defined(__mips_o32)
+#define SZREG 4
+#else
+#define SZREG 8
+#endif
+
+#if defined(__mips_o32) || defined(__mips_o64)
+#define ALSK 7 /* stack alignment */
+#define ALMASK -7 /* stack alignment */
+#define SZFPREG 4
+#define FP_L lwc1
+#define FP_S swc1
+#else
+#define ALSK 15 /* stack alignment */
+#define ALMASK -15 /* stack alignment */
+#define SZFPREG 8
+#define FP_L ldc1
+#define FP_S sdc1
+#endif
+
/*
* standard callframe {
- * register_t cf_args[4]; arg0 - arg3
+ * register_t cf_pad[N]; o32/64 (N=0), n32 (N=1) n64 (N=1)
+ * register_t cf_args[4]; arg0 - arg3 (only on o32 and o64)
+ * register_t cf_gp; global pointer (only on n32 and n64)
* register_t cf_sp; frame pointer
* register_t cf_ra; return address
* };
*/
-#define CALLFRAME_SIZ (4 * (4 + 2))
-#define CALLFRAME_SP (4 * 4)
-#define CALLFRAME_RA (4 * 5)
-#define START_FRAME CALLFRAME_SIZ
+#if defined(__mips_o32) || defined(__mips_o64)
+#define CALLFRAME_SIZ (SZREG * (4 + 2))
+#define CALLFRAME_S0 0
+#elif defined(__mips_n32) || defined(__mips_n64)
+#define CALLFRAME_SIZ (SZREG * 4)
+#define CALLFRAME_S0 (CALLFRAME_SIZ - 4 * SZREG)
+#endif
+#ifndef _KERNEL
+#define CALLFRAME_GP (CALLFRAME_SIZ - 3 * SZREG)
+#endif
+#define CALLFRAME_SP (CALLFRAME_SIZ - 2 * SZREG)
+#define CALLFRAME_RA (CALLFRAME_SIZ - 1 * SZREG)
/*
* While it would be nice to be compatible with the SGI
@@ -361,27 +391,264 @@ _C_LABEL(x):
* assembler to prevent the assembler from generating 64-bit style
* ABI calls.
*/
+#if _MIPS_SZPTR == 32
+#define PTR_ADD add
+#define PTR_ADDI addi
+#define PTR_ADDU addu
+#define PTR_ADDIU addiu
+#define PTR_SUB add
+#define PTR_SUBI subi
+#define PTR_SUBU subu
+#define PTR_SUBIU subu
+#define PTR_L lw
+#define PTR_LA la
+#define PTR_S sw
+#define PTR_SLL sll
+#define PTR_SLLV sllv
+#define PTR_SRL srl
+#define PTR_SRLV srlv
+#define PTR_SRA sra
+#define PTR_SRAV srav
+#define PTR_LL ll
+#define PTR_SC sc
+#define PTR_WORD .word
+#define PTR_SCALESHIFT 2
+#else /* _MIPS_SZPTR == 64 */
+#define PTR_ADD dadd
+#define PTR_ADDI daddi
+#define PTR_ADDU daddu
+#define PTR_ADDIU daddiu
+#define PTR_SUB dadd
+#define PTR_SUBI dsubi
+#define PTR_SUBU dsubu
+#define PTR_SUBIU dsubu
+#define PTR_L ld
+#define PTR_LA dla
+#define PTR_S sd
+#define PTR_SLL dsll
+#define PTR_SLLV dsllv
+#define PTR_SRL dsrl
+#define PTR_SRLV dsrlv
+#define PTR_SRA dsra
+#define PTR_SRAV dsrav
+#define PTR_LL lld
+#define PTR_SC scd
+#define PTR_WORD .dword
+#define PTR_SCALESHIFT 3
+#endif /* _MIPS_SZPTR == 64 */
+
+#if _MIPS_SZINT == 32
+#define INT_ADD add
+#define INT_ADDI addi
+#define INT_ADDU addu
+#define INT_ADDIU addiu
+#define INT_SUB add
+#define INT_SUBI subi
+#define INT_SUBU subu
+#define INT_SUBIU subu
+#define INT_L lw
+#define INT_LA la
+#define INT_S sw
+#define INT_SLL sll
+#define INT_SLLV sllv
+#define INT_SRL srl
+#define INT_SRLV srlv
+#define INT_SRA sra
+#define INT_SRAV srav
+#define INT_LL ll
+#define INT_SC sc
+#define INT_WORD .word
+#define INT_SCALESHIFT 2
+#else
+#define INT_ADD dadd
+#define INT_ADDI daddi
+#define INT_ADDU daddu
+#define INT_ADDIU daddiu
+#define INT_SUB dadd
+#define INT_SUBI dsubi
+#define INT_SUBU dsubu
+#define INT_SUBIU dsubu
+#define INT_L ld
+#define INT_LA dla
+#define INT_S sd
+#define INT_SLL dsll
+#define INT_SLLV dsllv
+#define INT_SRL dsrl
+#define INT_SRLV dsrlv
+#define INT_SRA dsra
+#define INT_SRAV dsrav
+#define INT_LL lld
+#define INT_SC scd
+#define INT_WORD .dword
+#define INT_SCALESHIFT 3
+#endif
+
+#if _MIPS_SZLONG == 32
+#define LONG_ADD add
+#define LONG_ADDI addi
+#define LONG_ADDU addu
+#define LONG_ADDIU addiu
+#define LONG_SUB add
+#define LONG_SUBI subi
+#define LONG_SUBU subu
+#define LONG_SUBIU subu
+#define LONG_L lw
+#define LONG_LA la
+#define LONG_S sw
+#define LONG_SLL sll
+#define LONG_SLLV sllv
+#define LONG_SRL srl
+#define LONG_SRLV srlv
+#define LONG_SRA sra
+#define LONG_SRAV srav
+#define LONG_LL ll
+#define LONG_SC sc
+#define LONG_WORD .word
+#define LONG_SCALESHIFT 2
+#else
+#define LONG_ADD dadd
+#define LONG_ADDI daddi
+#define LONG_ADDU daddu
+#define LONG_ADDIU daddiu
+#define LONG_SUB dadd
+#define LONG_SUBI dsubi
+#define LONG_SUBU dsubu
+#define LONG_SUBIU dsubu
+#define LONG_L ld
+#define LONG_LA dla
+#define LONG_S sd
+#define LONG_SLL dsll
+#define LONG_SLLV dsllv
+#define LONG_SRL dsrl
+#define LONG_SRLV dsrlv
+#define LONG_SRA dsra
+#define LONG_SRAV dsrav
+#define LONG_LL lld
+#define LONG_SC scd
+#define LONG_WORD .dword
+#define LONG_SCALESHIFT 3
+#endif
-#if !defined(_MIPS_BSD_API) || _MIPS_BSD_API == _MIPS_BSD_API_LP32
-/* #if !defined(__mips_n64) */
+#if SZREG == 4
#define REG_L lw
#define REG_S sw
#define REG_LI li
-#define REG_PROLOGUE .set push
-#define REG_EPILOGUE .set pop
-#define SZREG 4
-#define PTR_LA la
-#define PTR_ADDU addu
+#define REG_ADDU addu
+#define REG_SLL sll
+#define REG_SLLV sllv
+#define REG_SRL srl
+#define REG_SRLV srlv
+#define REG_SRA sra
+#define REG_SRAV srav
+#define REG_LL ll
+#define REG_SC sc
+#define REG_SCALESHIFT 2
#else
#define REG_L ld
#define REG_S sd
#define REG_LI dli
+#define REG_ADDU daddu
+#define REG_SLL dsll
+#define REG_SLLV dsllv
+#define REG_SRL dsrl
+#define REG_SRLV dsrlv
+#define REG_SRA dsra
+#define REG_SRAV dsrav
+#define REG_LL lld
+#define REG_SC scd
+#define REG_SCALESHIFT 3
+#endif
+
+#if _MIPS_ISA == _MIPS_ISA_MIPS1 || _MIPS_ISA == _MIPS_ISA_MIPS2 || \
+ _MIPS_ISA == _MIPS_ISA_MIPS32
+#define MFC0 mfc0
+#define MTC0 mtc0
+#endif
+#if _MIPS_ISA == _MIPS_ISA_MIPS3 || _MIPS_ISA == _MIPS_ISA_MIPS4 || \
+ _MIPS_ISA == _MIPS_ISA_MIPS64
+#define MFC0 dmfc0
+#define MTC0 dmtc0
+#endif
+
+#if defined(__mips_o32) || defined(__mips_o64)
+
+#ifdef __ABICALLS__
+#define CPRESTORE(r) .cprestore r
+#define CPLOAD(r) .cpload r
+#else
+#define CPRESTORE(r) /* not needed */
+#define CPLOAD(r) /* not needed */
+#endif
+
+#define SETUP_GP \
+ .set push; \
+ .set noreorder; \
+ .cpload t9; \
+ .set pop
+#define SETUP_GPX(r) \
+ .set push; \
+ .set noreorder; \
+ move r,ra; /* save old ra */ \
+ bal 7f; \
+ nop; \
+ 7: .cpload ra; \
+ move ra,r; \
+ .set pop
+#define SETUP_GPX_L(r,lbl) \
+ .set push; \
+ .set noreorder; \
+ move r,ra; /* save old ra */ \
+ bal lbl; \
+ nop; \
+ lbl: .cpload ra; \
+ move ra,r; \
+ .set pop
+#define SAVE_GP(x) .cprestore x
+
+#define SETUP_GP64(a,b) /* n32/n64 specific */
+#define SETUP_GP64_R(a,b) /* n32/n64 specific */
+#define SETUP_GPX64(a,b) /* n32/n64 specific */
+#define SETUP_GPX64_L(a,b,c) /* n32/n64 specific */
+#define RESTORE_GP64 /* n32/n64 specific */
+#define USE_ALT_CP(a) /* n32/n64 specific */
+#endif /* __mips_o32 || __mips_o64 */
+
+#if defined(__mips_o32) || defined(__mips_o64)
+#define REG_PROLOGUE .set push
+#define REG_EPILOGUE .set pop
+#endif
+#if defined(__mips_n32) || defined(__mips_n64)
#define REG_PROLOGUE .set push ; .set mips3
#define REG_EPILOGUE .set pop
-#define SZREG 8
-#define PTR_LA dla
-#define PTR_ADDU daddu
-#endif /* _MIPS_BSD_API */
+#endif
+
+#if defined(__mips_n32) || defined(__mips_n64)
+#define SETUP_GP /* o32 specific */
+#define SETUP_GPX(r) /* o32 specific */
+#define SETUP_GPX_L(r,lbl) /* o32 specific */
+#define SAVE_GP(x) /* o32 specific */
+#define SETUP_GP64(a,b) .cpsetup $25, a, b
+#define SETUP_GPX64(a,b) \
+ .set push; \
+ move b,ra; \
+ .set noreorder; \
+ bal 7f; \
+ nop; \
+ 7: .set pop; \
+ .cpsetup ra, a, 7b; \
+ move ra,b
+#define SETUP_GPX64_L(a,b,c) \
+ .set push; \
+ move b,ra; \
+ .set noreorder; \
+ bal c; \
+ nop; \
+ c: .set pop; \
+ .cpsetup ra, a, c; \
+ move ra,b
+#define RESTORE_GP64 .cpreturn
+#define USE_ALT_CP(a) .cplocal a
+#endif /* __mips_n32 || __mips_n64 */
#define mfc0_macro(data, spr) \
__asm __volatile ("mfc0 %0, $%1" \
diff --git a/sys/mips/include/bus.h b/sys/mips/include/bus.h
index 94f876e..ccaeb34 100644
--- a/sys/mips/include/bus.h
+++ b/sys/mips/include/bus.h
@@ -721,6 +721,7 @@ extern bus_space_tag_t mips_bus_space_generic;
/* Special bus space for RMI processors */
#ifdef TARGET_XLR_XLS
extern bus_space_tag_t rmi_bus_space;
+extern bus_space_tag_t rmi_pci_bus_space;
#endif
#include <machine/bus_dma.h>
diff --git a/sys/mips/include/cdefs.h b/sys/mips/include/cdefs.h
index c45cefd..181d6ee 100644
--- a/sys/mips/include/cdefs.h
+++ b/sys/mips/include/cdefs.h
@@ -25,11 +25,16 @@
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
+ *
+ * $FreeBSD$
*/
#ifndef _MIPS_CDEFS_H_
#define _MIPS_CDEFS_H_
+/*
+ * These are depreciated. Use __mips_{o32,o64,n32,n64} instead.
+ */
/* MIPS Subprogram Interface Model */
#define _MIPS_SIM_ABIX32 4 /* 64 bit safe, ILP32 o32 model */
#define _MIPS_SIM_ABI64 3
@@ -38,17 +43,34 @@
#define _MIPS_BSD_API_LP32 _MIPS_SIM_ABI32
#define _MIPS_BSD_API_LP32_64CLEAN _MIPS_SIM_ABIX32
-#define _MIPS_BSD_API_N32 _MIPS_SIM_NABI32
#define _MIPS_BSD_API_LP64 _MIPS_SIM_ABI64
+#define _MIPS_BSD_API_O32 _MIPS_SIM_ABI32
+#define _MIPS_BSD_API_O64 _MIPS_SIM_ABIX32
+#define _MIPS_BSD_API_N32 _MIPS_SIM_NABI32
+#define _MIPS_BSD_API_N64 _MIPS_SIM_ABI64
+
+#define _MIPS_SIM_NEWABI_P(abi) ((abi) == _MIPS_SIM_NABI32 || \
+ (abi) == _MIPS_SIM_ABI64)
+
+#define _MIPS_SIM_LP64_P(abi) ((abi) == _MIPS_SIM_ABIX32 || \
+ (abi) == _MIPS_SIM_ABI64)
+
#if defined(__mips_n64)
-#define _MIPS_BSD_API _MIPS_BSD_API_LP64
+#define _MIPS_BSD_API _MIPS_BSD_API_N64
#elif defined(__mips_n32)
#define _MIPS_BSD_API _MIPS_BSD_API_N32
#elif defined(__mips_o64)
-#define _MIPS_BSD_API _MIPS_BSD_API_LP32_64CLEAN
+#define _MIPS_BSD_API _MIPS_BSD_API_O64
#else
-#define _MIPS_BSD_API _MIPS_BSD_API_LP32
+#define _MIPS_BSD_API _MIPS_BSD_API_O32
#endif
+#define _MIPS_ISA_MIPS1 1
+#define _MIPS_ISA_MIPS2 2
+#define _MIPS_ISA_MIPS3 3
+#define _MIPS_ISA_MIPS4 4
+#define _MIPS_ISA_MIPS32 5
+#define _MIPS_ISA_MIPS64 6
+
#endif /* !_MIPS_CDEFS_H_ */
diff --git a/sys/mips/include/intr_machdep.h b/sys/mips/include/intr_machdep.h
index 60e969d..575bba4 100644
--- a/sys/mips/include/intr_machdep.h
+++ b/sys/mips/include/intr_machdep.h
@@ -30,21 +30,7 @@
#define _MACHINE_INTR_MACHDEP_H_
#ifdef TARGET_XLR_XLS
-/*
- * XLR/XLS uses its own intr_machdep.c and has
- * a different number of interupts. This probably
- * should be placed somewhere else.
- */
-
-struct mips_intrhand {
- struct intr_event *mih_event;
- driver_intr_t *mih_disable;
- volatile long *cntp; /* interrupt counter */
-};
-
-extern struct mips_intrhand mips_intr_handlers[];
#define XLR_MAX_INTR 64
-
#else
#define NHARD_IRQS 6
#define NSOFT_IRQS 2
diff --git a/sys/mips/include/ucontext.h b/sys/mips/include/ucontext.h
index c360a65..7d4c2e4 100644
--- a/sys/mips/include/ucontext.h
+++ b/sys/mips/include/ucontext.h
@@ -58,10 +58,12 @@ typedef struct __mcontext {
} mcontext_t;
#endif
-#if defined(__mips_n64) || defined(__mips_n32)
-#define SZREG 8
+#ifndef SZREG
+#if defined(__mips_o32)
+#define SZREG 4
#else
-#define SZREG 4
+#define SZREG 8
+#endif
#endif
/* offsets into mcontext_t */
diff --git a/sys/mips/mips/elf_trampoline.c b/sys/mips/mips/elf_trampoline.c
index 5bd100c..4b38761 100644
--- a/sys/mips/mips/elf_trampoline.c
+++ b/sys/mips/mips/elf_trampoline.c
@@ -96,7 +96,7 @@ load_kernel(void * kstart)
#ifdef __mips_n64
Elf64_Ehdr *eh;
Elf64_Phdr phdr[64] /* XXX */;
- Elf64_Phdr shdr[64] /* XXX */;
+ Elf64_Shdr shdr[64] /* XXX */;
#else
Elf32_Ehdr *eh;
Elf32_Phdr phdr[64] /* XXX */;
diff --git a/sys/mips/mips/exception.S b/sys/mips/mips/exception.S
index 262701e..eff484a 100644
--- a/sys/mips/mips/exception.S
+++ b/sys/mips/mips/exception.S
@@ -275,6 +275,15 @@ SlowFault:
mtc0 a0, COP_0_STATUS_REG
#endif
+/*
+ * Save CPU and CP0 register state.
+ *
+ * This is straightforward except for saving the exception program
+ * counter. The ddb backtrace code looks for the first instruction
+ * matching the form "sw ra, (off)sp" to figure out the address of the
+ * calling function. So we must make sure that we save the exception
+ * PC by staging it through 'ra' as opposed to any other register.
+ */
#define SAVE_CPU \
SAVE_REG(AT, AST, sp) ;\
.set at ; \
@@ -314,9 +323,12 @@ SlowFault:
SAVE_REG(v1, MULHI, sp) ;\
SAVE_REG(a0, SR, sp) ;\
SAVE_REG(a1, CAUSE, sp) ;\
- SAVE_REG(ra, RA, sp) ;\
SAVE_REG(a2, BADVADDR, sp) ;\
- SAVE_REG(a3, PC, sp) ;\
+ move t0, ra ;\
+ move ra, a3 ;\
+ SAVE_REG(ra, PC, sp) ;\
+ move ra, t0 ;\
+ SAVE_REG(ra, RA, sp) ;\
PTR_ADDU v0, sp, KERN_EXC_FRAME_SIZE ;\
SAVE_REG(v0, SP, sp) ;\
CLEAR_STATUS ;\
diff --git a/sys/mips/rmi/board.c b/sys/mips/rmi/board.c
index 932fee2..ae7b43f 100644
--- a/sys/mips/rmi/board.c
+++ b/sys/mips/rmi/board.c
@@ -27,6 +27,8 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*
* *****************************RMI_2**********************************/
+#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
+__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -93,6 +95,7 @@ struct xlr_board_info xlr_board_info;
int
xlr_board_info_setup()
{
+
if (xlr_is_xls()) {
xlr_board_info.is_xls = 1;
xlr_board_info.nr_cpus = 8;
@@ -122,6 +125,18 @@ xlr_board_info_setup()
/* network block 1 */
xlr_board_info.gmac_block[1].type = XLR_GMAC;
xlr_board_info.gmac_block[1].enabled = 0xf;
+ if (xlr_is_xls4xx()) {
+ xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_GPIO_OFFSET);
+ uint32_t tmp;
+
+ /* some ports are not enabled on 4xx, figure this out
+ from the GPIO fuse bank */
+ tmp = xlr_read_reg(mmio, 35);
+ if (tmp & (1<<28))
+ xlr_board_info.gmac_block[1].enabled &= ~0x8;
+ if (tmp & (1<<29))
+ xlr_board_info.gmac_block[1].enabled &= ~0x4;
+ }
xlr_board_info.gmac_block[1].credit_config = &xls_cc_table_gmac1;
xlr_board_info.gmac_block[1].station_txbase = MSGRNG_STNID_GMAC1_TX0;
xlr_board_info.gmac_block[1].station_rfr = MSGRNG_STNID_GMAC1_FR_0;
diff --git a/sys/mips/rmi/bus_space_rmi.c b/sys/mips/rmi/bus_space_rmi.c
index 568eaca..b2daeb4 100644
--- a/sys/mips/rmi/bus_space_rmi.c
+++ b/sys/mips/rmi/bus_space_rmi.c
@@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
+#include <sys/endian.h>
#include <sys/malloc.h>
#include <sys/ktr.h>
@@ -42,14 +43,12 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/cache.h>
-void xlr_print_int(uint32_t);
static int
rmi_bus_space_map(void *t, bus_addr_t addr,
bus_size_t size, int flags,
bus_space_handle_t * bshp);
-
static void
rmi_bus_space_unmap(void *t, bus_space_handle_t bsh,
bus_size_t size);
@@ -132,6 +131,7 @@ rmi_bus_space_write_multi_1(void *t,
bus_size_t offset,
const u_int8_t * addr,
size_t count);
+
static void
rmi_bus_space_write_multi_2(void *t,
bus_space_handle_t handle,
@@ -176,7 +176,6 @@ static void
rmi_bus_space_barrier(void *tag __unused, bus_space_handle_t bsh __unused,
bus_size_t offset __unused, bus_size_t len __unused, int flags);
-
static void
rmi_bus_space_copy_region_2(void *t,
bus_space_handle_t bsh1,
@@ -244,7 +243,8 @@ rmi_bus_space_write_multi_stream_4(void *t,
const u_int32_t * addr,
size_t count);
-
+#define TODO() printf("XLR memory bus space function '%s' unimplemented\n", __func__)
+
static struct bus_space local_rmi_bus_space = {
/* cookie */
(void *)0,
@@ -355,27 +355,9 @@ static struct bus_space local_rmi_bus_space = {
/* generic bus_space tag */
bus_space_tag_t rmi_bus_space = &local_rmi_bus_space;
-#define MIPS_BUS_SPACE_IO 0 /* space is i/o space */
-#define MIPS_BUS_SPACE_MEM 1 /* space is mem space */
-#define MIPS_BUS_SPACE_PCI 10 /* avoid conflict with other spaces */
-
-#define BUS_SPACE_UNRESTRICTED (~0)
-
-#define SWAP32(x)\
- (((x) & 0xff000000) >> 24) | \
- (((x) & 0x000000ff) << 24) | \
- (((x) & 0x0000ff00) << 8) | \
- (((x) & 0x00ff0000) >> 8)
-
-#define SWAP16(x)\
- (((x) & 0xff00) >> 8) | \
- (((x) & 0x00ff) << 8)
-
/*
* Map a region of device bus space into CPU virtual address space.
*/
-
-
static int
rmi_bus_space_map(void *t __unused, bus_addr_t addr,
bus_size_t size __unused, int flags __unused,
@@ -417,34 +399,24 @@ static u_int8_t
rmi_bus_space_read_1(void *tag, bus_space_handle_t handle,
bus_size_t offset)
{
- if ((int)tag == MIPS_BUS_SPACE_PCI)
- return (u_int8_t) (*(volatile u_int8_t *)(handle + offset));
- else
- return (u_int8_t) (*(volatile u_int32_t *)(handle + offset));
+ return (u_int8_t) (*(volatile u_int32_t *)(handle + offset));
}
static u_int16_t
rmi_bus_space_read_2(void *tag, bus_space_handle_t handle,
bus_size_t offset)
{
- if ((int)tag == MIPS_BUS_SPACE_PCI)
- return SWAP16((u_int16_t) (*(volatile u_int16_t *)(handle + offset)));
- else
- return *(volatile u_int16_t *)(handle + offset);
+ return (u_int16_t)(*(volatile u_int32_t *)(handle + offset));
}
static u_int32_t
rmi_bus_space_read_4(void *tag, bus_space_handle_t handle,
bus_size_t offset)
{
- if ((int)tag == MIPS_BUS_SPACE_PCI)
- return SWAP32((*(volatile u_int32_t *)(handle + offset)));
- else
- return (*(volatile u_int32_t *)(handle + offset));
+ return (*(volatile u_int32_t *)(handle + offset));
}
-
/*
* Read `count' 1, 2, 4, or 8 byte quantities from bus space
* described by tag/handle/offset and copy into buffer provided.
@@ -453,41 +425,21 @@ static void
rmi_bus_space_read_multi_1(void *tag, bus_space_handle_t handle,
bus_size_t offset, u_int8_t * addr, size_t count)
{
-
- if ((int)tag != MIPS_BUS_SPACE_PCI)
- return;
- while (count--) {
- *addr = (*(volatile u_int8_t *)(handle + offset));
- addr++;
- }
+ TODO();
}
static void
rmi_bus_space_read_multi_2(void *tag, bus_space_handle_t handle,
bus_size_t offset, u_int16_t * addr, size_t count)
{
-
- if ((int)tag != MIPS_BUS_SPACE_PCI)
- return;
- while (count--) {
- *addr = *(volatile u_int16_t *)(handle + offset);
- *addr = SWAP16(*addr);
- addr++;
- }
+ TODO();
}
static void
rmi_bus_space_read_multi_4(void *tag, bus_space_handle_t handle,
bus_size_t offset, u_int32_t * addr, size_t count)
{
-
- if ((int)tag != MIPS_BUS_SPACE_PCI)
- return;
- while (count--) {
- *addr = *(volatile u_int32_t *)(handle + offset);
- *addr = SWAP32(*addr);
- addr++;
- }
+ TODO();
}
/*
@@ -495,43 +447,28 @@ rmi_bus_space_read_multi_4(void *tag, bus_space_handle_t handle,
* described by tag/handle/offset.
*/
-
static void
rmi_bus_space_write_1(void *tag, bus_space_handle_t handle,
bus_size_t offset, u_int8_t value)
{
- mips_sync();
- if ((int)tag == MIPS_BUS_SPACE_PCI)
- *(volatile u_int8_t *)(handle + offset) = value;
- else
- *(volatile u_int32_t *)(handle + offset) = (u_int32_t) value;
+ *(volatile u_int32_t *)(handle + offset) = (u_int32_t)value;
}
static void
rmi_bus_space_write_2(void *tag, bus_space_handle_t handle,
bus_size_t offset, u_int16_t value)
{
- mips_sync();
- if ((int)tag == MIPS_BUS_SPACE_PCI) {
- *(volatile u_int16_t *)(handle + offset) = SWAP16(value);
- } else
- *(volatile u_int16_t *)(handle + offset) = value;
+ *(volatile u_int32_t *)(handle + offset) = (u_int32_t)value;
}
-
static void
rmi_bus_space_write_4(void *tag, bus_space_handle_t handle,
bus_size_t offset, u_int32_t value)
{
- mips_sync();
- if ((int)tag == MIPS_BUS_SPACE_PCI) {
- *(volatile u_int32_t *)(handle + offset) = SWAP32(value);
- } else
- *(volatile u_int32_t *)(handle + offset) = value;
+ *(volatile u_int32_t *)(handle + offset) = value;
}
-
/*
* Write `count' 1, 2, 4, or 8 byte quantities from the buffer
* provided to bus space described by tag/handle/offset.
@@ -542,39 +479,21 @@ static void
rmi_bus_space_write_multi_1(void *tag, bus_space_handle_t handle,
bus_size_t offset, const u_int8_t * addr, size_t count)
{
- mips_sync();
- if ((int)tag != MIPS_BUS_SPACE_PCI)
- return;
- while (count--) {
- (*(volatile u_int8_t *)(handle + offset)) = *addr;
- addr++;
- }
+ TODO();
}
static void
rmi_bus_space_write_multi_2(void *tag, bus_space_handle_t handle,
bus_size_t offset, const u_int16_t * addr, size_t count)
{
- mips_sync();
- if ((int)tag != MIPS_BUS_SPACE_PCI)
- return;
- while (count--) {
- (*(volatile u_int16_t *)(handle + offset)) = SWAP16(*addr);
- addr++;
- }
+ TODO();
}
static void
rmi_bus_space_write_multi_4(void *tag, bus_space_handle_t handle,
bus_size_t offset, const u_int32_t * addr, size_t count)
{
- mips_sync();
- if ((int)tag != MIPS_BUS_SPACE_PCI)
- return;
- while (count--) {
- (*(volatile u_int32_t *)(handle + offset)) = SWAP32(*addr);
- addr++;
- }
+ TODO();
}
/*
@@ -589,7 +508,7 @@ rmi_bus_space_set_region_2(void *t, bus_space_handle_t bsh,
bus_addr_t addr = bsh + offset;
for (; count != 0; count--, addr += 2)
- (*(volatile u_int16_t *)(addr)) = value;
+ (*(volatile u_int32_t *)(addr)) = value;
}
static void
@@ -649,43 +568,24 @@ static void
rmi_bus_space_read_multi_stream_1(void *tag, bus_space_handle_t handle,
bus_size_t offset, u_int8_t * addr, size_t count)
{
-
- if ((int)tag != MIPS_BUS_SPACE_PCI)
- return;
- while (count--) {
- *addr = (*(volatile u_int8_t *)(handle + offset));
- addr++;
- }
+ TODO();
}
static void
rmi_bus_space_read_multi_stream_2(void *tag, bus_space_handle_t handle,
bus_size_t offset, u_int16_t * addr, size_t count)
{
-
- if ((int)tag != MIPS_BUS_SPACE_PCI)
- return;
- while (count--) {
- *addr = (*(volatile u_int16_t *)(handle + offset));
- addr++;
- }
+ TODO();
}
static void
rmi_bus_space_read_multi_stream_4(void *tag, bus_space_handle_t handle,
bus_size_t offset, u_int32_t * addr, size_t count)
{
-
- if ((int)tag != MIPS_BUS_SPACE_PCI)
- return;
- while (count--) {
- *addr = (*(volatile u_int32_t *)(handle + offset));
- addr++;
- }
+ TODO();
}
-
/*
* Read `count' 1, 2, 4, or 8 byte quantities from bus space
* described by tag/handle and starting at `offset' and copy into
@@ -695,24 +595,14 @@ void
rmi_bus_space_read_region_1(void *t, bus_space_handle_t bsh,
bus_size_t offset, u_int8_t * addr, size_t count)
{
- bus_addr_t baddr = bsh + offset;
-
- while (count--) {
- *addr++ = (*(volatile u_int8_t *)(baddr));
- baddr += 1;
- }
+ TODO();
}
void
rmi_bus_space_read_region_2(void *t, bus_space_handle_t bsh,
bus_size_t offset, u_int16_t * addr, size_t count)
{
- bus_addr_t baddr = bsh + offset;
-
- while (count--) {
- *addr++ = (*(volatile u_int16_t *)(baddr));
- baddr += 2;
- }
+ TODO();
}
void
@@ -727,13 +617,11 @@ rmi_bus_space_read_region_4(void *t, bus_space_handle_t bsh,
}
}
-
void
rmi_bus_space_write_stream_1(void *t, bus_space_handle_t handle,
bus_size_t offset, u_int8_t value)
{
- mips_sync();
- *(volatile u_int8_t *)(handle + offset) = value;
+ TODO();
}
@@ -741,8 +629,7 @@ static void
rmi_bus_space_write_stream_2(void *t, bus_space_handle_t handle,
bus_size_t offset, u_int16_t value)
{
- mips_sync();
- *(volatile u_int16_t *)(handle + offset) = value;
+ TODO();
}
@@ -750,8 +637,7 @@ static void
rmi_bus_space_write_stream_4(void *t, bus_space_handle_t handle,
bus_size_t offset, u_int32_t value)
{
- mips_sync();
- *(volatile u_int32_t *)(handle + offset) = value;
+ TODO();
}
@@ -759,39 +645,21 @@ static void
rmi_bus_space_write_multi_stream_1(void *tag, bus_space_handle_t handle,
bus_size_t offset, const u_int8_t * addr, size_t count)
{
- mips_sync();
- if ((int)tag != MIPS_BUS_SPACE_PCI)
- return;
- while (count--) {
- (*(volatile u_int8_t *)(handle + offset)) = *addr;
- addr++;
- }
+ TODO();
}
static void
rmi_bus_space_write_multi_stream_2(void *tag, bus_space_handle_t handle,
bus_size_t offset, const u_int16_t * addr, size_t count)
{
- mips_sync();
- if ((int)tag != MIPS_BUS_SPACE_PCI)
- return;
- while (count--) {
- (*(volatile u_int16_t *)(handle + offset)) = *addr;
- addr++;
- }
+ TODO();
}
static void
rmi_bus_space_write_multi_stream_4(void *tag, bus_space_handle_t handle,
bus_size_t offset, const u_int32_t * addr, size_t count)
{
- mips_sync();
- if ((int)tag != MIPS_BUS_SPACE_PCI)
- return;
- while (count--) {
- (*(volatile u_int32_t *)(handle + offset)) = *addr;
- addr++;
- }
+ TODO();
}
void
@@ -801,31 +669,18 @@ rmi_bus_space_write_region_2(void *t,
const u_int16_t * addr,
size_t count)
{
- bus_addr_t baddr = (bus_addr_t) bsh + offset;
-
- while (count--) {
- (*(volatile u_int16_t *)(baddr)) = *addr;
- addr++;
- baddr += 2;
- }
+ TODO();
}
void
rmi_bus_space_write_region_4(void *t, bus_space_handle_t bsh,
bus_size_t offset, const u_int32_t * addr, size_t count)
{
- bus_addr_t baddr = bsh + offset;
-
- while (count--) {
- (*(volatile u_int32_t *)(baddr)) = *addr;
- addr++;
- baddr += 4;
- }
+ TODO();
}
static void
rmi_bus_space_barrier(void *tag __unused, bus_space_handle_t bsh __unused,
bus_size_t offset __unused, bus_size_t len __unused, int flags)
{
-
}
diff --git a/sys/mips/rmi/bus_space_rmi_pci.c b/sys/mips/rmi/bus_space_rmi_pci.c
new file mode 100644
index 0000000..ebd70c1
--- /dev/null
+++ b/sys/mips/rmi/bus_space_rmi_pci.c
@@ -0,0 +1,761 @@
+/*-
+ * Copyright (c) 2009 RMI Corporation
+ * 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$
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/endian.h>
+#include <sys/malloc.h>
+#include <sys/ktr.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_extern.h>
+
+#include <machine/bus.h>
+#include <machine/cache.h>
+
+static int
+rmi_pci_bus_space_map(void *t, bus_addr_t addr,
+ bus_size_t size, int flags,
+ bus_space_handle_t * bshp);
+
+static void
+rmi_pci_bus_space_unmap(void *t, bus_space_handle_t bsh,
+ bus_size_t size);
+
+static int
+rmi_pci_bus_space_subregion(void *t,
+ bus_space_handle_t bsh,
+ bus_size_t offset, bus_size_t size,
+ bus_space_handle_t * nbshp);
+
+static u_int8_t
+rmi_pci_bus_space_read_1(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset);
+
+static u_int16_t
+rmi_pci_bus_space_read_2(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset);
+
+static u_int32_t
+rmi_pci_bus_space_read_4(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset);
+
+static void
+rmi_pci_bus_space_read_multi_1(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset, u_int8_t * addr,
+ size_t count);
+
+static void
+rmi_pci_bus_space_read_multi_2(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset, u_int16_t * addr,
+ size_t count);
+
+static void
+rmi_pci_bus_space_read_multi_4(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset, u_int32_t * addr,
+ size_t count);
+
+static void
+rmi_pci_bus_space_read_region_1(void *t,
+ bus_space_handle_t bsh,
+ bus_size_t offset, u_int8_t * addr,
+ size_t count);
+
+static void
+rmi_pci_bus_space_read_region_2(void *t,
+ bus_space_handle_t bsh,
+ bus_size_t offset, u_int16_t * addr,
+ size_t count);
+
+static void
+rmi_pci_bus_space_read_region_4(void *t,
+ bus_space_handle_t bsh,
+ bus_size_t offset, u_int32_t * addr,
+ size_t count);
+
+static void
+rmi_pci_bus_space_write_1(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset, u_int8_t value);
+
+static void
+rmi_pci_bus_space_write_2(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset, u_int16_t value);
+
+static void
+rmi_pci_bus_space_write_4(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset, u_int32_t value);
+
+static void
+rmi_pci_bus_space_write_multi_1(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset,
+ const u_int8_t * addr,
+ size_t count);
+
+static void
+rmi_pci_bus_space_write_multi_2(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset,
+ const u_int16_t * addr,
+ size_t count);
+
+static void
+rmi_pci_bus_space_write_multi_4(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset,
+ const u_int32_t * addr,
+ size_t count);
+
+static void
+rmi_pci_bus_space_write_region_2(void *t,
+ bus_space_handle_t bsh,
+ bus_size_t offset,
+ const u_int16_t * addr,
+ size_t count);
+
+static void
+rmi_pci_bus_space_write_region_4(void *t,
+ bus_space_handle_t bsh,
+ bus_size_t offset,
+ const u_int32_t * addr,
+ size_t count);
+
+
+static void
+rmi_pci_bus_space_set_region_2(void *t,
+ bus_space_handle_t bsh,
+ bus_size_t offset, u_int16_t value,
+ size_t count);
+static void
+rmi_pci_bus_space_set_region_4(void *t,
+ bus_space_handle_t bsh,
+ bus_size_t offset, u_int32_t value,
+ size_t count);
+
+static void
+rmi_pci_bus_space_barrier(void *tag __unused, bus_space_handle_t bsh __unused,
+ bus_size_t offset __unused, bus_size_t len __unused, int flags);
+
+static void
+rmi_pci_bus_space_copy_region_2(void *t,
+ bus_space_handle_t bsh1,
+ bus_size_t off1,
+ bus_space_handle_t bsh2,
+ bus_size_t off2, size_t count);
+
+u_int8_t
+rmi_pci_bus_space_read_stream_1(void *t, bus_space_handle_t handle,
+ bus_size_t offset);
+
+static u_int16_t
+rmi_pci_bus_space_read_stream_2(void *t, bus_space_handle_t handle,
+ bus_size_t offset);
+
+static u_int32_t
+rmi_pci_bus_space_read_stream_4(void *t, bus_space_handle_t handle,
+ bus_size_t offset);
+static void
+rmi_pci_bus_space_read_multi_stream_1(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset, u_int8_t * addr,
+ size_t count);
+
+static void
+rmi_pci_bus_space_read_multi_stream_2(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset, u_int16_t * addr,
+ size_t count);
+
+static void
+rmi_pci_bus_space_read_multi_stream_4(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset, u_int32_t * addr,
+ size_t count);
+
+void
+rmi_pci_bus_space_write_stream_1(void *t, bus_space_handle_t bsh,
+ bus_size_t offset, u_int8_t value);
+static void
+rmi_pci_bus_space_write_stream_2(void *t, bus_space_handle_t handle,
+ bus_size_t offset, u_int16_t value);
+
+static void
+rmi_pci_bus_space_write_stream_4(void *t, bus_space_handle_t handle,
+ bus_size_t offset, u_int32_t value);
+
+static void
+rmi_pci_bus_space_write_multi_stream_1(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset,
+ const u_int8_t * addr,
+ size_t count);
+static void
+rmi_pci_bus_space_write_multi_stream_2(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset,
+ const u_int16_t * addr,
+ size_t count);
+
+static void
+rmi_pci_bus_space_write_multi_stream_4(void *t,
+ bus_space_handle_t handle,
+ bus_size_t offset,
+ const u_int32_t * addr,
+ size_t count);
+
+#define TODO() printf("XLR memory bus space function '%s' unimplemented\n", __func__)
+
+static struct bus_space local_rmi_pci_bus_space = {
+ /* cookie */
+ (void *)0,
+
+ /* mapping/unmapping */
+ rmi_pci_bus_space_map,
+ rmi_pci_bus_space_unmap,
+ rmi_pci_bus_space_subregion,
+
+ /* allocation/deallocation */
+ NULL,
+ NULL,
+
+ /* barrier */
+ rmi_pci_bus_space_barrier,
+
+ /* read (single) */
+ rmi_pci_bus_space_read_1,
+ rmi_pci_bus_space_read_2,
+ rmi_pci_bus_space_read_4,
+ NULL,
+
+ /* read multiple */
+ rmi_pci_bus_space_read_multi_1,
+ rmi_pci_bus_space_read_multi_2,
+ rmi_pci_bus_space_read_multi_4,
+ NULL,
+
+ /* read region */
+ rmi_pci_bus_space_read_region_1,
+ rmi_pci_bus_space_read_region_2,
+ rmi_pci_bus_space_read_region_4,
+ NULL,
+
+ /* write (single) */
+ rmi_pci_bus_space_write_1,
+ rmi_pci_bus_space_write_2,
+ rmi_pci_bus_space_write_4,
+ NULL,
+
+ /* write multiple */
+ rmi_pci_bus_space_write_multi_1,
+ rmi_pci_bus_space_write_multi_2,
+ rmi_pci_bus_space_write_multi_4,
+ NULL,
+
+ /* write region */
+ NULL,
+ rmi_pci_bus_space_write_region_2,
+ rmi_pci_bus_space_write_region_4,
+ NULL,
+
+ /* set multiple */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ /* set region */
+ NULL,
+ rmi_pci_bus_space_set_region_2,
+ rmi_pci_bus_space_set_region_4,
+ NULL,
+
+ /* copy */
+ NULL,
+ rmi_pci_bus_space_copy_region_2,
+ NULL,
+ NULL,
+
+ /* read (single) stream */
+ rmi_pci_bus_space_read_stream_1,
+ rmi_pci_bus_space_read_stream_2,
+ rmi_pci_bus_space_read_stream_4,
+ NULL,
+
+ /* read multiple stream */
+ rmi_pci_bus_space_read_multi_stream_1,
+ rmi_pci_bus_space_read_multi_stream_2,
+ rmi_pci_bus_space_read_multi_stream_4,
+ NULL,
+
+ /* read region stream */
+ rmi_pci_bus_space_read_region_1,
+ rmi_pci_bus_space_read_region_2,
+ rmi_pci_bus_space_read_region_4,
+ NULL,
+
+ /* write (single) stream */
+ rmi_pci_bus_space_write_stream_1,
+ rmi_pci_bus_space_write_stream_2,
+ rmi_pci_bus_space_write_stream_4,
+ NULL,
+
+ /* write multiple stream */
+ rmi_pci_bus_space_write_multi_stream_1,
+ rmi_pci_bus_space_write_multi_stream_2,
+ rmi_pci_bus_space_write_multi_stream_4,
+ NULL,
+
+ /* write region stream */
+ NULL,
+ rmi_pci_bus_space_write_region_2,
+ rmi_pci_bus_space_write_region_4,
+ NULL,
+};
+
+/* generic bus_space tag */
+bus_space_tag_t rmi_pci_bus_space = &local_rmi_pci_bus_space;
+
+/*
+ * Map a region of device bus space into CPU virtual address space.
+ */
+static int
+rmi_pci_bus_space_map(void *t __unused, bus_addr_t addr,
+ bus_size_t size __unused, int flags __unused,
+ bus_space_handle_t * bshp)
+{
+ *bshp = addr;
+ return (0);
+}
+
+/*
+ * Unmap a region of device bus space.
+ */
+static void
+rmi_pci_bus_space_unmap(void *t __unused, bus_space_handle_t bsh __unused,
+ bus_size_t size __unused)
+{
+}
+
+/*
+ * Get a new handle for a subregion of an already-mapped area of bus space.
+ */
+
+static int
+rmi_pci_bus_space_subregion(void *t __unused, bus_space_handle_t bsh,
+ bus_size_t offset, bus_size_t size __unused,
+ bus_space_handle_t * nbshp)
+{
+ *nbshp = bsh + offset;
+ return (0);
+}
+
+/*
+ * Read a 1, 2, 4, or 8 byte quantity from bus space
+ * described by tag/handle/offset.
+ */
+
+static u_int8_t
+rmi_pci_bus_space_read_1(void *tag, bus_space_handle_t handle,
+ bus_size_t offset)
+{
+ return (u_int8_t) (*(volatile u_int8_t *)(handle + offset));
+}
+
+static u_int16_t
+rmi_pci_bus_space_read_2(void *tag, bus_space_handle_t handle,
+ bus_size_t offset)
+{
+ return bswap16((u_int16_t) (*(volatile u_int16_t *)(handle + offset)));
+}
+
+static u_int32_t
+rmi_pci_bus_space_read_4(void *tag, bus_space_handle_t handle,
+ bus_size_t offset)
+{
+ return bswap32((*(volatile u_int32_t *)(handle + offset)));
+}
+
+
+/*
+ * Read `count' 1, 2, 4, or 8 byte quantities from bus space
+ * described by tag/handle/offset and copy into buffer provided.
+ */
+static void
+rmi_pci_bus_space_read_multi_1(void *tag, bus_space_handle_t handle,
+ bus_size_t offset, u_int8_t * addr, size_t count)
+{
+ while (count--) {
+ *addr = (*(volatile u_int8_t *)(handle + offset));
+ addr++;
+ }
+}
+
+static void
+rmi_pci_bus_space_read_multi_2(void *tag, bus_space_handle_t handle,
+ bus_size_t offset, u_int16_t * addr, size_t count)
+{
+
+ while (count--) {
+ *addr = *(volatile u_int16_t *)(handle + offset);
+ *addr = bswap16(*addr);
+ addr++;
+ }
+}
+
+static void
+rmi_pci_bus_space_read_multi_4(void *tag, bus_space_handle_t handle,
+ bus_size_t offset, u_int32_t * addr, size_t count)
+{
+
+ while (count--) {
+ *addr = *(volatile u_int32_t *)(handle + offset);
+ *addr = bswap32(*addr);
+ addr++;
+ }
+}
+
+/*
+ * Write the 1, 2, 4, or 8 byte value `value' to bus space
+ * described by tag/handle/offset.
+ */
+
+static void
+rmi_pci_bus_space_write_1(void *tag, bus_space_handle_t handle,
+ bus_size_t offset, u_int8_t value)
+{
+ mips_sync();
+ *(volatile u_int8_t *)(handle + offset) = value;
+}
+
+static void
+rmi_pci_bus_space_write_2(void *tag, bus_space_handle_t handle,
+ bus_size_t offset, u_int16_t value)
+{
+ mips_sync();
+ *(volatile u_int16_t *)(handle + offset) = bswap16(value);
+}
+
+
+static void
+rmi_pci_bus_space_write_4(void *tag, bus_space_handle_t handle,
+ bus_size_t offset, u_int32_t value)
+{
+ mips_sync();
+ *(volatile u_int32_t *)(handle + offset) = bswap32(value);
+}
+
+/*
+ * Write `count' 1, 2, 4, or 8 byte quantities from the buffer
+ * provided to bus space described by tag/handle/offset.
+ */
+
+
+static void
+rmi_pci_bus_space_write_multi_1(void *tag, bus_space_handle_t handle,
+ bus_size_t offset, const u_int8_t * addr, size_t count)
+{
+ mips_sync();
+ while (count--) {
+ (*(volatile u_int8_t *)(handle + offset)) = *addr;
+ addr++;
+ }
+}
+
+static void
+rmi_pci_bus_space_write_multi_2(void *tag, bus_space_handle_t handle,
+ bus_size_t offset, const u_int16_t * addr, size_t count)
+{
+ mips_sync();
+ while (count--) {
+ (*(volatile u_int16_t *)(handle + offset)) = bswap16(*addr);
+ addr++;
+ }
+}
+
+static void
+rmi_pci_bus_space_write_multi_4(void *tag, bus_space_handle_t handle,
+ bus_size_t offset, const u_int32_t * addr, size_t count)
+{
+ mips_sync();
+ while (count--) {
+ (*(volatile u_int32_t *)(handle + offset)) = bswap32(*addr);
+ addr++;
+ }
+}
+
+/*
+ * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described
+ * by tag/handle starting at `offset'.
+ */
+
+static void
+rmi_pci_bus_space_set_region_2(void *t, bus_space_handle_t bsh,
+ bus_size_t offset, u_int16_t value, size_t count)
+{
+ bus_addr_t addr = bsh + offset;
+
+ for (; count != 0; count--, addr += 2)
+ (*(volatile u_int16_t *)(addr)) = value;
+}
+
+static void
+rmi_pci_bus_space_set_region_4(void *t, bus_space_handle_t bsh,
+ bus_size_t offset, u_int32_t value, size_t count)
+{
+ bus_addr_t addr = bsh + offset;
+
+ for (; count != 0; count--, addr += 4)
+ (*(volatile u_int32_t *)(addr)) = value;
+}
+
+
+/*
+ * Copy `count' 1, 2, 4, or 8 byte values from bus space starting
+ * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2.
+ */
+static void
+rmi_pci_bus_space_copy_region_2(void *t, bus_space_handle_t bsh1,
+ bus_size_t off1, bus_space_handle_t bsh2,
+ bus_size_t off2, size_t count)
+{
+ TODO();
+}
+
+/*
+ * Read `count' 1, 2, 4, or 8 byte quantities from bus space
+ * described by tag/handle/offset and copy into buffer provided.
+ */
+
+u_int8_t
+rmi_pci_bus_space_read_stream_1(void *t, bus_space_handle_t handle,
+ bus_size_t offset)
+{
+
+ return *((volatile u_int8_t *)(handle + offset));
+}
+
+
+static u_int16_t
+rmi_pci_bus_space_read_stream_2(void *t, bus_space_handle_t handle,
+ bus_size_t offset)
+{
+ return *(volatile u_int16_t *)(handle + offset);
+}
+
+
+static u_int32_t
+rmi_pci_bus_space_read_stream_4(void *t, bus_space_handle_t handle,
+ bus_size_t offset)
+{
+ return (*(volatile u_int32_t *)(handle + offset));
+}
+
+
+static void
+rmi_pci_bus_space_read_multi_stream_1(void *tag, bus_space_handle_t handle,
+ bus_size_t offset, u_int8_t * addr, size_t count)
+{
+ while (count--) {
+ *addr = (*(volatile u_int8_t *)(handle + offset));
+ addr++;
+ }
+}
+
+static void
+rmi_pci_bus_space_read_multi_stream_2(void *tag, bus_space_handle_t handle,
+ bus_size_t offset, u_int16_t * addr, size_t count)
+{
+ while (count--) {
+ *addr = (*(volatile u_int16_t *)(handle + offset));
+ addr++;
+ }
+}
+
+static void
+rmi_pci_bus_space_read_multi_stream_4(void *tag, bus_space_handle_t handle,
+ bus_size_t offset, u_int32_t * addr, size_t count)
+{
+ while (count--) {
+ *addr = (*(volatile u_int32_t *)(handle + offset));
+ addr++;
+ }
+}
+
+
+
+/*
+ * Read `count' 1, 2, 4, or 8 byte quantities from bus space
+ * described by tag/handle and starting at `offset' and copy into
+ * buffer provided.
+ */
+void
+rmi_pci_bus_space_read_region_1(void *t, bus_space_handle_t bsh,
+ bus_size_t offset, u_int8_t * addr, size_t count)
+{
+ bus_addr_t baddr = bsh + offset;
+
+ while (count--) {
+ *addr++ = (*(volatile u_int8_t *)(baddr));
+ baddr += 1;
+ }
+}
+
+void
+rmi_pci_bus_space_read_region_2(void *t, bus_space_handle_t bsh,
+ bus_size_t offset, u_int16_t * addr, size_t count)
+{
+ bus_addr_t baddr = bsh + offset;
+
+ while (count--) {
+ *addr++ = (*(volatile u_int16_t *)(baddr));
+ baddr += 2;
+ }
+}
+
+void
+rmi_pci_bus_space_read_region_4(void *t, bus_space_handle_t bsh,
+ bus_size_t offset, u_int32_t * addr, size_t count)
+{
+ bus_addr_t baddr = bsh + offset;
+
+ while (count--) {
+ *addr++ = (*(volatile u_int32_t *)(baddr));
+ baddr += 4;
+ }
+}
+
+
+void
+rmi_pci_bus_space_write_stream_1(void *t, bus_space_handle_t handle,
+ bus_size_t offset, u_int8_t value)
+{
+ mips_sync();
+ *(volatile u_int8_t *)(handle + offset) = value;
+}
+
+static void
+rmi_pci_bus_space_write_stream_2(void *t, bus_space_handle_t handle,
+ bus_size_t offset, u_int16_t value)
+{
+ mips_sync();
+ *(volatile u_int16_t *)(handle + offset) = value;
+}
+
+
+static void
+rmi_pci_bus_space_write_stream_4(void *t, bus_space_handle_t handle,
+ bus_size_t offset, u_int32_t value)
+{
+ mips_sync();
+ *(volatile u_int32_t *)(handle + offset) = value;
+}
+
+
+static void
+rmi_pci_bus_space_write_multi_stream_1(void *tag, bus_space_handle_t handle,
+ bus_size_t offset, const u_int8_t * addr, size_t count)
+{
+ mips_sync();
+ while (count--) {
+ (*(volatile u_int8_t *)(handle + offset)) = *addr;
+ addr++;
+ }
+}
+
+static void
+rmi_pci_bus_space_write_multi_stream_2(void *tag, bus_space_handle_t handle,
+ bus_size_t offset, const u_int16_t * addr, size_t count)
+{
+ mips_sync();
+ while (count--) {
+ (*(volatile u_int16_t *)(handle + offset)) = *addr;
+ addr++;
+ }
+}
+
+static void
+rmi_pci_bus_space_write_multi_stream_4(void *tag, bus_space_handle_t handle,
+ bus_size_t offset, const u_int32_t * addr, size_t count)
+{
+ mips_sync();
+ while (count--) {
+ (*(volatile u_int32_t *)(handle + offset)) = *addr;
+ addr++;
+ }
+}
+
+void
+rmi_pci_bus_space_write_region_2(void *t,
+ bus_space_handle_t bsh,
+ bus_size_t offset,
+ const u_int16_t * addr,
+ size_t count)
+{
+ bus_addr_t baddr = (bus_addr_t) bsh + offset;
+
+ while (count--) {
+ (*(volatile u_int16_t *)(baddr)) = *addr;
+ addr++;
+ baddr += 2;
+ }
+}
+
+void
+rmi_pci_bus_space_write_region_4(void *t, bus_space_handle_t bsh,
+ bus_size_t offset, const u_int32_t * addr, size_t count)
+{
+ bus_addr_t baddr = bsh + offset;
+
+ while (count--) {
+ (*(volatile u_int32_t *)(baddr)) = *addr;
+ addr++;
+ baddr += 4;
+ }
+}
+
+static void
+rmi_pci_bus_space_barrier(void *tag __unused, bus_space_handle_t bsh __unused,
+ bus_size_t offset __unused, bus_size_t len __unused, int flags)
+{
+
+}
diff --git a/sys/mips/rmi/files.xlr b/sys/mips/rmi/files.xlr
index 22cd521..fdf5b27 100644
--- a/sys/mips/rmi/files.xlr
+++ b/sys/mips/rmi/files.xlr
@@ -14,10 +14,10 @@ mips/rmi/uart_bus_xlr_iodi.c optional uart
mips/rmi/uart_cpu_mips_xlr.c optional uart
mips/rmi/perfmon_kern.c optional xlr_perfmon
mips/rmi/perfmon_percpu.c optional xlr_perfmon
-#mips/rmi/pcibus.c optional pci
-#mips/rmi/xlr_pci.c optional pci
-#mips/rmi/xls_ehci.c optional usb ehci
+mips/rmi/xlr_pci.c optional pci
+mips/rmi/xls_ehci.c optional usb ehci
mips/rmi/bus_space_rmi.c standard
+mips/rmi/bus_space_rmi_pci.c optional pci
mips/rmi/dev/sec/rmisec.c optional rmisec
mips/rmi/dev/sec/rmilib.c optional rmisec
mips/rmi/dev/xlr/rge.c optional rge
diff --git a/sys/mips/rmi/interrupt.h b/sys/mips/rmi/interrupt.h
index 013a8e9..247dc9f 100644
--- a/sys/mips/rmi/interrupt.h
+++ b/sys/mips/rmi/interrupt.h
@@ -25,7 +25,7 @@
* 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.
- *
+ *__FBSDID("$FreeBSD$")
* RMI_BSD */
#ifndef _RMI_INTERRUPT_H_
#define _RMI_INTERRUPT_H_
@@ -39,4 +39,14 @@
#define IRQ_MSGRING 6
#define IRQ_TIMER 7
+/*
+ * XLR needs custom pre and post handlers for PCI/PCI-e interrupts
+ * XXX: maybe follow i386 intsrc model
+ */
+void xlr_cpu_establish_hardintr(const char *, driver_filter_t *,
+ driver_intr_t *, void *, int, int, void **, void (*)(void *),
+ void (*)(void *), void (*)(void *), int (*)(void *, u_char));
+void xlr_mask_hard_irq(void *);
+void xlr_unmask_hard_irq(void *);
+
#endif /* _RMI_INTERRUPT_H_ */
diff --git a/sys/mips/rmi/intr_machdep.c b/sys/mips/rmi/intr_machdep.c
index c1bbe95..8785ac7 100644
--- a/sys/mips/rmi/intr_machdep.c
+++ b/sys/mips/rmi/intr_machdep.c
@@ -51,19 +51,19 @@ __FBSDID("$FreeBSD$");
/*#include <machine/intrcnt.h>*/
static mips_intrcnt_t mips_intr_counters[XLR_MAX_INTR];
-struct mips_intrhand mips_intr_handlers[XLR_MAX_INTR];
+static struct intr_event *mips_intr_events[XLR_MAX_INTR];
static int intrcnt_index;
-static void
-mips_mask_hard_irq(void *source)
+void
+xlr_mask_hard_irq(void *source)
{
uintptr_t irq = (uintptr_t) source;
write_c0_eimr64(read_c0_eimr64() & ~(1ULL << irq));
}
-static void
-mips_unmask_hard_irq(void *source)
+void
+xlr_unmask_hard_irq(void *source)
{
uintptr_t irq = (uintptr_t) source;
@@ -71,10 +71,11 @@ mips_unmask_hard_irq(void *source)
}
void
-cpu_establish_hardintr(const char *name, driver_filter_t * filt,
- void (*handler) (void *), void *arg, int irq, int flags, void **cookiep)
+xlr_cpu_establish_hardintr(const char *name, driver_filter_t * filt,
+ void (*handler) (void *), void *arg, int irq, int flags, void **cookiep,
+ void (*pre_ithread)(void *), void (*post_ithread)(void *),
+ void (*post_filter)(void *), int (*assign_cpu)(void *, u_char))
{
- struct mips_intrhand *mih; /* descriptor for the IRQ */
struct intr_event *ie; /* descriptor for the IRQ */
int errcode;
@@ -85,25 +86,33 @@ cpu_establish_hardintr(const char *name, driver_filter_t * filt,
* FIXME locking - not needed now, because we do this only on
* startup from CPU0
*/
- mih = &mips_intr_handlers[irq];
+ ie = mips_intr_events[irq];
/* mih->cntp = &intrcnt[irq]; */
- ie = mih->mih_event;
if (ie == NULL) {
errcode = intr_event_create(&ie, (void *)(uintptr_t) irq, 0,
- irq, mips_mask_hard_irq, mips_unmask_hard_irq,
- NULL, NULL, "hard intr%d:", irq);
+ irq, pre_ithread, post_ithread, post_filter, assign_cpu,
+ "hard intr%d:", irq);
if (errcode) {
printf("Could not create event for intr %d\n", irq);
return;
}
+ mips_intr_events[irq] = ie;
}
+
intr_event_add_handler(ie, name, filt, handler, arg,
intr_priority(flags), flags, cookiep);
- mih->mih_event = ie;
- mips_unmask_hard_irq((void *)(uintptr_t) irq);
+ xlr_unmask_hard_irq((void *)(uintptr_t) irq);
}
+void
+cpu_establish_hardintr(const char *name, driver_filter_t * filt,
+ void (*handler) (void *), void *arg, int irq, int flags, void **cookiep)
+{
+ xlr_cpu_establish_hardintr(name, filt, handler, arg, irq,
+ flags, cookiep, xlr_mask_hard_irq, xlr_unmask_hard_irq,
+ NULL, NULL);
+}
void
cpu_establish_softintr(const char *name, driver_filter_t * filt,
@@ -111,20 +120,26 @@ cpu_establish_softintr(const char *name, driver_filter_t * filt,
void **cookiep)
{
/* we don't separate them into soft/hard like other mips */
- cpu_establish_hardintr(name, filt, handler, arg, irq, flags, cookiep);
+ xlr_cpu_establish_hardintr(name, filt, handler, arg, irq,
+ flags, cookiep, xlr_mask_hard_irq, xlr_unmask_hard_irq,
+ NULL, NULL);
}
void
cpu_intr(struct trapframe *tf)
{
- struct mips_intrhand *mih;
struct intr_event *ie;
- register_t eirr;
+ uint64_t eirr, eimr;
int i;
critical_enter();
+
+ /* find a list of enabled interrupts */
eirr = read_c0_eirr64();
- if (eirr == 0) {
+ eimr = read_c0_eimr64();
+ eirr &= eimr;
+
+ if (eirr == 0) {
critical_exit();
return;
}
@@ -162,9 +177,8 @@ cpu_intr(struct trapframe *tf)
}
#endif
#endif
- mih = &mips_intr_handlers[i];
+ ie = mips_intr_events[i];
/* atomic_add_long(mih->cntp, 1); */
- ie = mih->mih_event;
write_c0_eirr64(1ULL << i);
pic_ack(i, 0);
diff --git a/sys/mips/rmi/iodi.c b/sys/mips/rmi/iodi.c
index 76796ad..134de9b 100644
--- a/sys/mips/rmi/iodi.c
+++ b/sys/mips/rmi/iodi.c
@@ -74,8 +74,6 @@ __FBSDID("$FreeBSD$");
#include <mips/rmi/dev/xlr/atx_cpld.h>
#include <mips/rmi/dev/xlr/xgmac_mdio.h>
-extern void iodi_activateirqs(void);
-
extern bus_space_tag_t uart_bus_space_mem;
static struct resource *
@@ -91,19 +89,6 @@ iodi_setup_intr(device_t, device_t, struct resource *, int,
struct iodi_softc *iodi_softc; /* There can be only one. */
-/*
-static void pic_usb_ack(void *arg)
-{
- xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
- int irq = PIC_USB_IRQ ;
-
- mtx_lock_spin(&xlr_pic_lock);
- xlr_write_reg(mmio, PIC_INT_ACK, (1 << (irq - PIC_IRQ_BASE)));
- mtx_unlock_spin(&xlr_pic_lock);
-}
-*/
-
-
static int
iodi_setup_intr(device_t dev, device_t child,
struct resource *ires, int flags, driver_filter_t * filt, driver_intr_t * intr, void *arg,
@@ -157,11 +142,6 @@ iodi_setup_intr(device_t dev, device_t child,
return (0);
}
-/* Strange hook found in mips/include/bus.h */
-#ifndef MIPS_BUS_SPACE_PCI
-#define MIPS_BUS_SPACE_PCI 10
-#endif
-
static struct resource *
iodi_alloc_resource(device_t bus, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
@@ -199,7 +179,7 @@ iodi_alloc_resource(device_t bus, device_t child, int type, int *rid,
res->r_bustag = uart_bus_space_mem;
} else if (strcmp(device_get_name(child), "ehci") == 0) {
res->r_bushandle = 0xbef24000;
- res->r_bustag = (bus_space_tag_t) MIPS_BUS_SPACE_PCI;
+ res->r_bustag = rmi_pci_bus_space;
} else if (strcmp(device_get_name(child), "cfi") == 0) {
res->r_bushandle = 0xbc000000;
res->r_bustag = 0;
@@ -271,11 +251,15 @@ iodi_attach(device_t dev)
tmpd = device_add_child(dev, "rge", 5);
device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
- tmpd = device_add_child(dev, "rge", 6);
- device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
+ if (xlr_board_info.gmac_block[1].enabled & 0x4) {
+ tmpd = device_add_child(dev, "rge", 6);
+ device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
+ }
- tmpd = device_add_child(dev, "rge", 7);
- device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
+ if (xlr_board_info.gmac_block[1].enabled & 0x8) {
+ tmpd = device_add_child(dev, "rge", 7);
+ device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]);
+ }
} else if (xlr_board_info.gmac_block[1].type == XLR_XGMAC) {
#if 0 /* XGMAC not yet */
tmpd = device_add_child(dev, "rge", 4);
diff --git a/sys/mips/rmi/pcibus.h b/sys/mips/rmi/pcibus.h
index 45070ad..7d1e923 100644
--- a/sys/mips/rmi/pcibus.h
+++ b/sys/mips/rmi/pcibus.h
@@ -25,38 +25,11 @@
*
* $FreeBSD$
*/
-#define DEFAULT_PCI_CONFIG_BASE 0x18000000
+#define DEFAULT_PCI_CONFIG_BASE 0x18000000
+#define MSI_MIPS_ADDR_BASE 0xfee00000
-#define MSI_MIPS_ADDR_BASE 0xfee00000
+#define PCIE_LINK0_MSI_STATUS 0x90
+#define PCIE_LINK1_MSI_STATUS 0x94
+#define PCIE_LINK2_MSI_STATUS 0x190
+#define PCIE_LINK3_MSI_STATUS 0x194
-
-#define PCIE_LINK0_MSI_STATUS 0x90
-#define PCIE_LINK1_MSI_STATUS 0x94
-#define PCIE_LINK2_MSI_STATUS 0x190
-#define PCIE_LINK3_MSI_STATUS 0x194
-
-void pci_init_resources(void);
-struct resource *
-xlr_pci_alloc_resource(device_t bus, device_t child,
- int type, int *rid,
- u_long start, u_long end, u_long count,
- u_int flags);
-int
-pci_activate_resource(device_t bus, device_t child, int type, int rid,
- struct resource *r);
-int
-pci_deactivate_resource(device_t bus, device_t child, int type, int rid,
- struct resource *r);
-int
-pci_release_resource(device_t bus, device_t child, int type, int rid,
- struct resource *r);
-struct rman *pci_get_rman(device_t dev, int type);
-
-int
-mips_platform_pci_setup_intr(device_t dev, device_t child,
- struct resource *irq, int flags,
- driver_filter_t * filt,
- driver_intr_t * intr, void *arg,
- void **cookiep);
-int
- mips_pci_route_interrupt(device_t bus, device_t dev, int pin);
diff --git a/sys/mips/rmi/xlr_pci.c b/sys/mips/rmi/xlr_pci.c
index 1ed6a7c..5f52e9e 100644
--- a/sys/mips/rmi/xlr_pci.c
+++ b/sys/mips/rmi/xlr_pci.c
@@ -28,17 +28,21 @@
*
* RMI_BSD */
#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include <sys/param.h>
-#include <sys/types.h>
#include <sys/systm.h>
+#include <sys/types.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/bus.h>
+#include <sys/endian.h>
#include <machine/bus.h>
#include <machine/md_var.h>
+#include <machine/intr_machdep.h>
#include <mips/rmi/rmi_mips_exts.h>
+#include <mips/rmi/interrupt.h>
#include <machine/cpuregs.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@@ -47,50 +51,46 @@
#include <sys/rman.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
-#include <dev/pci/pcib_private.h>
#include <mips/rmi/iomap.h>
#include <mips/rmi/pic.h>
#include <mips/rmi/shared_structs.h>
#include <mips/rmi/board.h>
#include <mips/rmi/pcibus.h>
+
#include "pcib_if.h"
+#define pci_cfg_offset(bus,slot,devfn,where) (((bus)<<16) + ((slot) << 11)+((devfn)<<8)+(where))
+#define PCIE_LINK_STATE 0x4000
+
#define LSU_CFG0_REGID 0
#define LSU_CERRLOG_REGID 9
#define LSU_CERROVF_REGID 10
#define LSU_CERRINT_REGID 11
-#define SWAP32(x)\
- (((x) & 0xff000000) >> 24) | \
- (((x) & 0x000000ff) << 24) | \
- (((x) & 0x0000ff00) << 8) | \
- (((x) & 0x00ff0000) >> 8)
-
/* MSI support */
-
-#define MSI_MIPS_ADDR_DEST 0x000ff000
-#define MSI_MIPS_ADDR_RH 0x00000008
-#define MSI_MIPS_ADDR_RH_OFF 0x00000000
-#define MSI_MIPS_ADDR_RH_ON 0x00000008
-#define MSI_MIPS_ADDR_DM 0x00000004
-#define MSI_MIPS_ADDR_DM_PHYSICAL 0x00000000
-#define MSI_MIPS_ADDR_DM_LOGICAL 0x00000004
+#define MSI_MIPS_ADDR_DEST 0x000ff000
+#define MSI_MIPS_ADDR_RH 0x00000008
+#define MSI_MIPS_ADDR_RH_OFF 0x00000000
+#define MSI_MIPS_ADDR_RH_ON 0x00000008
+#define MSI_MIPS_ADDR_DM 0x00000004
+#define MSI_MIPS_ADDR_DM_PHYSICAL 0x00000000
+#define MSI_MIPS_ADDR_DM_LOGICAL 0x00000004
/* Fields in data for Intel MSI messages. */
-#define MSI_MIPS_DATA_TRGRMOD 0x00008000 /* Trigger mode */
-#define MSI_MIPS_DATA_TRGREDG 0x00000000 /* edge */
-#define MSI_MIPS_DATA_TRGRLVL 0x00008000 /* level */
+#define MSI_MIPS_DATA_TRGRMOD 0x00008000 /* Trigger mode */
+#define MSI_MIPS_DATA_TRGREDG 0x00000000 /* edge */
+#define MSI_MIPS_DATA_TRGRLVL 0x00008000 /* level */
-#define MSI_MIPS_DATA_LEVEL 0x00004000 /* Polarity. */
-#define MSI_MIPS_DATA_DEASSERT 0x00000000
-#define MSI_MIPS_DATA_ASSERT 0x00004000
+#define MSI_MIPS_DATA_LEVEL 0x00004000 /* Polarity. */
+#define MSI_MIPS_DATA_DEASSERT 0x00000000
+#define MSI_MIPS_DATA_ASSERT 0x00004000
-#define MSI_MIPS_DATA_DELMOD 0x00000700 /* Delivery Mode */
-#define MSI_MIPS_DATA_DELFIXED 0x00000000 /* fixed */
-#define MSI_MIPS_DATA_DELLOPRI 0x00000100 /* lowest priority */
+#define MSI_MIPS_DATA_DELMOD 0x00000700 /* Delivery Mode */
+#define MSI_MIPS_DATA_DELFIXED 0x00000000 /* fixed */
+#define MSI_MIPS_DATA_DELLOPRI 0x00000100 /* lowest priority */
-#define MSI_MIPS_DATA_INTVEC 0x000000ff
+#define MSI_MIPS_DATA_INTVEC 0x000000ff
/*
* Build Intel MSI message and data values from a source. AMD64 systems
@@ -104,52 +104,94 @@
(MSI_MIPS_DATA_TRGRLVL | MSI_MIPS_DATA_DELFIXED | \
MSI_MIPS_DATA_ASSERT | (irq))
-struct xlr_hose_softc {
+#define DEBUG
+#ifdef DEBUG
+#define dbg_devprintf device_printf
+#else
+#define dbg_devprintf(dev, fmt, ...)
+#endif
+
+struct xlr_pcib_softc {
int junk; /* no softc */
};
+
static devclass_t pcib_devclass;
-static int pci_bus_status = 0;
-static void *pci_config_base;
+static void *xlr_pci_config_base;
+static struct rman irq_rman, port_rman, mem_rman;
-static uint32_t pci_cfg_read_32bit(uint32_t addr);
-static void pci_cfg_write_32bit(uint32_t addr, uint32_t data);
+static void
+xlr_pci_init_resources(void)
+{
+ irq_rman.rm_start = 0;
+ irq_rman.rm_end = 255;
+ irq_rman.rm_type = RMAN_ARRAY;
+ irq_rman.rm_descr = "PCI Mapped Interrupts";
+ if (rman_init(&irq_rman)
+ || rman_manage_region(&irq_rman, 0, 255))
+ panic("pci_init_resources irq_rman");
+
+ port_rman.rm_start = 0;
+ port_rman.rm_end = ~0u;
+ port_rman.rm_type = RMAN_ARRAY;
+ port_rman.rm_descr = "I/O ports";
+ if (rman_init(&port_rman)
+ || rman_manage_region(&port_rman, 0x10000000, 0x1fffffff))
+ panic("pci_init_resources port_rman");
+
+ mem_rman.rm_start = 0;
+ mem_rman.rm_end = ~0u;
+ mem_rman.rm_type = RMAN_ARRAY;
+ mem_rman.rm_descr = "I/O memory";
+ if (rman_init(&mem_rman)
+ || rman_manage_region(&mem_rman, 0xd0000000, 0xdfffffff))
+ panic("pci_init_resources mem_rman");
+}
static int
xlr_pcib_probe(device_t dev)
{
- device_set_desc(dev, "xlr system bridge controller");
+ if (xlr_board_info.is_xls)
+ device_set_desc(dev, "XLS PCIe bus");
+ else
+ device_set_desc(dev, "XLR PCI bus");
- pci_init_resources();
- pci_config_base = (void *)MIPS_PHYS_TO_KSEG1(DEFAULT_PCI_CONFIG_BASE);
- pci_bus_status = 1;
+ xlr_pci_init_resources();
+ xlr_pci_config_base = (void *)MIPS_PHYS_TO_KSEG1(DEFAULT_PCI_CONFIG_BASE);
return 0;
}
static int
-xlr_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t * result)
+xlr_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
{
-#if 0
- device_printf(dev, "xlr_pcib_read_ivar : read ivar %d for child %s\n", which, device_get_nameunit(child));
-#endif
switch (which) {
+ case PCIB_IVAR_DOMAIN:
+ *result = 0;
+ return (0);
case PCIB_IVAR_BUS:
*result = 0;
- return 0;
+ return (0);
}
- return ENOENT;
+ return (ENOENT);
}
static int
-xlr_pcib_maxslots(device_t dev)
+xlr_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t result)
{
- if (xlr_board_info.is_xls)
- return 4;
- else
- return 32;
+ switch (which) {
+ case PCIB_IVAR_DOMAIN:
+ return (EINVAL);
+ case PCIB_IVAR_BUS:
+ return (EINVAL);
+ }
+ return (ENOENT);
}
-#define pci_cfg_offset(bus,slot,devfn,where) (((bus)<<16) + ((slot) << 11)+((devfn)<<8)+(where))
+static int
+xlr_pcib_maxslots(device_t dev)
+{
+ return (PCI_SLOTMAX);
+}
static __inline__ void
disable_and_clear_cache_error(void)
@@ -178,8 +220,29 @@ clear_and_enable_cache_error(void)
}
static uint32_t
-phoenix_pciread(u_int b, u_int s, u_int f,
- u_int reg, int width)
+pci_cfg_read_32bit(uint32_t addr)
+{
+ uint32_t temp = 0;
+ uint32_t *p = (uint32_t *) ((uint32_t) xlr_pci_config_base + (addr & ~3));
+ uint64_t cerr_cpu_log = 0;
+
+ disable_and_clear_cache_error();
+
+ temp = bswap32(*p);
+
+ /* Read cache err log */
+ cerr_cpu_log = read_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CERRLOG_REGID);
+ if (cerr_cpu_log) {
+ /* Device don't exist. */
+ temp = ~0x0;
+ }
+ clear_and_enable_cache_error();
+ return temp;
+}
+
+static u_int32_t
+xlr_pcib_read_config(device_t dev, u_int b, u_int s, u_int f,
+ u_int reg, int width)
{
uint32_t data = 0;
@@ -188,10 +251,7 @@ phoenix_pciread(u_int b, u_int s, u_int f,
else if ((width == 4) && (reg & 3))
return 0xFFFFFFFF;
- if (pci_bus_status)
- data = pci_cfg_read_32bit(pci_cfg_offset(b, s, f, reg));
- else
- data = 0xFFFFFFFF;
+ data = pci_cfg_read_32bit(pci_cfg_offset(b, s, f, reg));
if (width == 1)
return ((data >> ((reg & 3) << 3)) & 0xff);
@@ -201,21 +261,18 @@ phoenix_pciread(u_int b, u_int s, u_int f,
return data;
}
-static void
-phoenix_pciwrite(u_int b, u_int s, u_int f,
- u_int reg, u_int val, int width)
+static void
+xlr_pcib_write_config(device_t dev, u_int b, u_int s, u_int f,
+ u_int reg, u_int32_t val, int width)
{
uint32_t cfgaddr = pci_cfg_offset(b, s, f, reg);
- uint32_t data = 0;
+ uint32_t data = 0, *p;
if ((width == 2) && (reg & 1))
return;
else if ((width == 4) && (reg & 3))
return;
- if (!pci_bus_status)
- return;
-
if (width == 1) {
data = pci_cfg_read_32bit(cfgaddr);
data = (data & ~(0xff << ((reg & 3) << 3))) |
@@ -228,56 +285,12 @@ phoenix_pciwrite(u_int b, u_int s, u_int f,
data = val;
}
- pci_cfg_write_32bit(cfgaddr, data);
+ p = (uint32_t *)((uint32_t) xlr_pci_config_base + (cfgaddr & ~3));
+ *p = bswap32(data);
return;
}
-static uint32_t
-pci_cfg_read_32bit(uint32_t addr)
-{
- uint32_t temp = 0;
- uint32_t *p = (uint32_t *) ((uint32_t) pci_config_base + (addr & ~3));
- uint64_t cerr_cpu_log = 0;
-
- disable_and_clear_cache_error();
-
- temp = SWAP32(*p);
-
- /* Read cache err log */
- cerr_cpu_log = read_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CERRLOG_REGID);
-
- if (cerr_cpu_log) {
- /* Device don't exist. */
- temp = ~0x0;
- }
- clear_and_enable_cache_error();
- return temp;
-}
-
-
-static void
-pci_cfg_write_32bit(uint32_t addr, uint32_t data)
-{
- unsigned int *p = (unsigned int *)((uint32_t) pci_config_base + (addr & ~3));
-
- *p = SWAP32(data);
-}
-
-static u_int32_t
-xlr_pcib_read_config(device_t dev, u_int b, u_int s, u_int f,
- u_int reg, int width)
-{
- return phoenix_pciread(b, s, f, reg, width);
-}
-
-static void
-xlr_pcib_write_config(device_t dev, u_int b, u_int s, u_int f,
- u_int reg, u_int32_t val, int width)
-{
- phoenix_pciwrite(b, s, f, reg, val, width);
-}
-
static int
xlr_pcib_attach(device_t dev)
{
@@ -286,28 +299,24 @@ xlr_pcib_attach(device_t dev)
return 0;
}
-#define PCIE_LINK_STATE 0x4000
-
static void
xlr_pcib_identify(driver_t * driver, device_t parent)
{
- xlr_reg_t *pcie_mmio_le = xlr_io_mmio(XLR_IO_PCIE_1_OFFSET);
- xlr_reg_t reg_link0 = xlr_read_reg(pcie_mmio_le, (0x80 >> 2));
- xlr_reg_t reg_link1 = xlr_read_reg(pcie_mmio_le, (0x84 >> 2));
+ if (xlr_board_info.is_xls) {
+ xlr_reg_t *pcie_mmio_le = xlr_io_mmio(XLR_IO_PCIE_1_OFFSET);
+ xlr_reg_t reg_link0 = xlr_read_reg(pcie_mmio_le, (0x80 >> 2));
+ xlr_reg_t reg_link1 = xlr_read_reg(pcie_mmio_le, (0x84 >> 2));
- if ((uint16_t) reg_link0 & PCIE_LINK_STATE) {
- device_printf(parent, "Link 0 up\n");
- }
- if ((uint16_t) reg_link1 & PCIE_LINK_STATE) {
- device_printf(parent, "Link 1 up\n");
+ if ((uint16_t) reg_link0 & PCIE_LINK_STATE) {
+ device_printf(parent, "Link 0 up\n");
+ }
+ if ((uint16_t) reg_link1 & PCIE_LINK_STATE) {
+ device_printf(parent, "Link 1 up\n");
+ }
}
- BUS_ADD_CHILD(parent, 0, "pcib", 0);
+ BUS_ADD_CHILD(parent, 0, "pcib", 0);
}
-static int
- xlr_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs);
-static int
- xlr_release_msi(device_t pcib, device_t dev, int count, int *irqs);
static int
xlr_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs)
@@ -364,8 +373,6 @@ xlr_release_msi(device_t pcib, device_t dev, int count, int *irqs)
device_printf(dev, "%s: msi release %d\n", device_get_nameunit(pcib), count);
return 0;
}
-static int
- xlr_map_msi(device_t pcib, device_t dev, int irq, uint64_t * addr, uint32_t * data);
static int
xlr_map_msi(device_t pcib, device_t dev, int irq, uint64_t * addr, uint32_t * data)
@@ -387,6 +394,212 @@ xlr_map_msi(device_t pcib, device_t dev, int irq, uint64_t * addr, uint32_t * da
}
+static void
+bridge_pcix_ack(void *arg)
+{
+ xlr_read_reg(xlr_io_mmio(XLR_IO_PCIX_OFFSET), 0x140 >> 2);
+}
+
+static void
+bridge_pcix_mask_ack(void *arg)
+{
+ xlr_mask_hard_irq(arg);
+ bridge_pcix_ack(arg);
+}
+
+static void
+bridge_pcie_ack(void *arg)
+{
+ int irq = (int)arg;
+ uint32_t reg;
+ xlr_reg_t *pcie_mmio_le = xlr_io_mmio(XLR_IO_PCIE_1_OFFSET);
+
+ switch (irq) {
+ case PIC_PCIE_LINK0_IRQ : reg = PCIE_LINK0_MSI_STATUS; break;
+ case PIC_PCIE_LINK1_IRQ : reg = PCIE_LINK1_MSI_STATUS; break;
+ case PIC_PCIE_LINK2_IRQ : reg = PCIE_LINK2_MSI_STATUS; break;
+ case PIC_PCIE_LINK3_IRQ : reg = PCIE_LINK3_MSI_STATUS; break;
+ default:
+ return;
+ }
+
+ xlr_write_reg(pcie_mmio_le, reg>>2, 0xffffffff);
+}
+
+static void
+bridge_pcie_mask_ack(void *arg)
+{
+ xlr_mask_hard_irq(arg);
+ bridge_pcie_ack(arg);
+}
+
+static int
+mips_platform_pci_setup_intr(device_t dev, device_t child,
+ struct resource *irq, int flags,
+ driver_filter_t * filt,
+ driver_intr_t * intr, void *arg,
+ void **cookiep)
+{
+ int level;
+ xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
+ int error = 0;
+ int xlrirq;
+
+ error = rman_activate_resource(irq);
+ if (error)
+ return error;
+ if (rman_get_start(irq) != rman_get_end(irq)) {
+ device_printf(dev, "Interrupt allocation %lu != %lu\n",
+ rman_get_start(irq), rman_get_end(irq));
+ return EINVAL;
+ }
+ xlrirq = rman_get_start(irq);
+
+ if (strcmp(device_get_name(dev), "pcib") != 0)
+ return 0;
+
+ if (xlr_board_info.is_xls == 0) {
+ if (rmi_spin_mutex_safe)
+ mtx_lock_spin(&xlr_pic_lock);
+ level = PIC_IRQ_IS_EDGE_TRIGGERED(PIC_IRT_PCIX_INDEX);
+ xlr_write_reg(mmio, PIC_IRT_0_PCIX, 0x01);
+ xlr_write_reg(mmio, PIC_IRT_1_PCIX, ((1 << 31) | (level << 30) |
+ (1 << 6) | (PIC_PCIX_IRQ)));
+ if (rmi_spin_mutex_safe)
+ mtx_unlock_spin(&xlr_pic_lock);
+ xlr_cpu_establish_hardintr(device_get_name(child), filt,
+ intr, arg, PIC_PCIX_IRQ, flags, cookiep,
+ bridge_pcix_mask_ack, xlr_unmask_hard_irq,
+ bridge_pcix_ack, NULL);
+ } else {
+ if (rmi_spin_mutex_safe)
+ mtx_lock_spin(&xlr_pic_lock);
+ xlr_write_reg(mmio, PIC_IRT_0_BASE + xlrirq - PIC_IRQ_BASE, 0x01);
+ xlr_write_reg(mmio, PIC_IRT_1_BASE + xlrirq - PIC_IRQ_BASE,
+ ((1 << 31) | (1 << 30) | (1 << 6) | xlrirq));
+ if (rmi_spin_mutex_safe)
+ mtx_unlock_spin(&xlr_pic_lock);
+
+ xlr_cpu_establish_hardintr(device_get_name(child), filt,
+ intr, arg, xlrirq, flags, cookiep,
+ bridge_pcie_mask_ack, xlr_unmask_hard_irq,
+ bridge_pcie_ack, NULL);
+ }
+
+ return bus_generic_setup_intr(dev, child, irq, flags, filt, intr,
+ arg, cookiep);
+}
+
+static int
+mips_platform_pci_teardown_intr(device_t dev, device_t child,
+ struct resource *irq, void *cookie)
+{
+ if (strcmp(device_get_name(child), "pci") == 0) {
+ /* if needed reprogram the pic to clear pcix related entry */
+ device_printf(dev, "teardown intr\n");
+ }
+ return bus_generic_teardown_intr(dev, child, irq, cookie);
+}
+
+static struct resource *
+xlr_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct rman *rm;
+ struct resource *rv;
+ vm_offset_t va;
+ int needactivate = flags & RF_ACTIVE;
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ rm = &irq_rman;
+ break;
+
+ case SYS_RES_IOPORT:
+ rm = &port_rman;
+ break;
+
+ case SYS_RES_MEMORY:
+ rm = &mem_rman;
+ break;
+
+ default:
+ return 0;
+ }
+
+ rv = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (rv == 0)
+ return 0;
+
+ rman_set_rid(rv, *rid);
+
+ if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
+ va = (vm_offset_t)pmap_mapdev(start, count);
+ rman_set_bushandle(rv, va);
+ /* bushandle is same as virtual addr */
+ rman_set_virtual(rv, (void *)va);
+ rman_set_bustag(rv, rmi_pci_bus_space);
+ }
+
+ if (needactivate) {
+ if (bus_activate_resource(child, type, *rid, rv)) {
+ rman_release_resource(rv);
+ return (NULL);
+ }
+ }
+ return rv;
+}
+
+static int
+xlr_pci_release_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+ return (rman_release_resource(r));
+}
+
+static int
+xlr_pci_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+ return (rman_activate_resource(r));
+}
+
+static int
+xlr_pci_deactivate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+ return (rman_deactivate_resource(r));
+}
+
+static int
+mips_pci_route_interrupt(device_t bus, device_t dev, int pin)
+{
+ /*
+ * Validate requested pin number.
+ */
+ if ((pin < 1) || (pin > 4))
+ return (255);
+
+ if (xlr_board_info.is_xls) {
+ switch (pin) {
+ case 1:
+ return PIC_PCIE_LINK0_IRQ;
+ case 2:
+ return PIC_PCIE_LINK1_IRQ;
+ case 3:
+ return PIC_PCIE_LINK2_IRQ;
+ case 4:
+ return PIC_PCIE_LINK3_IRQ;
+ }
+ } else {
+ if (pin == 1) {
+ return (16);
+ }
+ }
+
+ return (255);
+}
+
static device_method_t xlr_pcib_methods[] = {
/* Device interface */
DEVMETHOD(device_identify, xlr_pcib_identify),
@@ -396,18 +609,18 @@ static device_method_t xlr_pcib_methods[] = {
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(bus_read_ivar, xlr_pcib_read_ivar),
+ DEVMETHOD(bus_write_ivar, xlr_pcib_write_ivar),
DEVMETHOD(bus_alloc_resource, xlr_pci_alloc_resource),
- DEVMETHOD(bus_release_resource, pci_release_resource),
- DEVMETHOD(bus_activate_resource, pci_activate_resource),
- DEVMETHOD(bus_deactivate_resource, pci_deactivate_resource),
+ DEVMETHOD(bus_release_resource, xlr_pci_release_resource),
+ DEVMETHOD(bus_activate_resource, xlr_pci_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, xlr_pci_deactivate_resource),
DEVMETHOD(bus_setup_intr, mips_platform_pci_setup_intr),
- DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_teardown_intr, mips_platform_pci_teardown_intr),
/* pcib interface */
DEVMETHOD(pcib_maxslots, xlr_pcib_maxslots),
DEVMETHOD(pcib_read_config, xlr_pcib_read_config),
DEVMETHOD(pcib_write_config, xlr_pcib_write_config),
-
DEVMETHOD(pcib_route_interrupt, mips_pci_route_interrupt),
DEVMETHOD(pcib_alloc_msi, xlr_alloc_msi),
@@ -420,7 +633,7 @@ static device_method_t xlr_pcib_methods[] = {
static driver_t xlr_pcib_driver = {
"pcib",
xlr_pcib_methods,
- sizeof(struct xlr_hose_softc),
+ sizeof(struct xlr_pcib_softc),
};
DRIVER_MODULE(pcib, nexus, xlr_pcib_driver, pcib_devclass, 0, 0);
diff --git a/sys/mips/rmi/xls_ehci.c b/sys/mips/rmi/xls_ehci.c
index 1d696b5..b90f317 100644
--- a/sys/mips/rmi/xls_ehci.c
+++ b/sys/mips/rmi/xls_ehci.c
@@ -38,58 +38,50 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-/*
- * USB Enhanced Host Controller Driver, a.k.a. USB 2.0 controller.
- *
- * The EHCI 1.0 spec can be found at
- * http://developer.intel.com/technology/usb/download/ehci-r10.pdf
- * and the USB 2.0 spec at
- * http://www.usb.org/developers/docs/usb_20.zip
- */
-
-/* The low level controller code for EHCI has been split into
- * PCI probes and EHCI specific code. This was done to facilitate the
- * sharing of code between *BSD's
- */
-
#include "opt_bus.h"
+#include <sys/stdint.h>
+#include <sys/stddef.h>
#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/module.h>
#include <sys/bus.h>
-#include <sys/queue.h>
+#include <sys/linker_set.h>
+#include <sys/module.h>
#include <sys/lock.h>
-#include <sys/lockmgr.h>
-#include <machine/bus.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
-/*#include <dev/usb/usbdivar.h> */
-/*#include <dev/usb/usb_mem.h> */
-#include <mips/rmi/ehcireg.h>
-#include <mips/rmi/ehcivar.h>
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_util.h>
-#ifdef USB_DEBUG
-#define EHCI_DEBUG USB_DEBUG
-#define DPRINTF(x) do { if (ehcidebug) logprintf x; } while (0)
-extern int ehcidebug;
-
-#else
-#define DPRINTF(x)
-#endif
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#include <dev/usb/controller/ehci.h>
+#include <dev/usb/controller/ehcireg.h>
+#include <mips/rmi/pic.h>
static int ehci_xls_attach(device_t self);
static int ehci_xls_detach(device_t self);
static int ehci_xls_shutdown(device_t self);
static int ehci_xls_suspend(device_t self);
static int ehci_xls_resume(device_t self);
-static void ehci_xls_givecontroller(device_t self);
-static void ehci_xls_takecontroller(device_t self);
static int
ehci_xls_suspend(device_t self)
@@ -100,9 +92,8 @@ ehci_xls_suspend(device_t self)
err = bus_generic_suspend(self);
if (err)
return (err);
- ehci_power(PWR_SUSPEND, sc);
-
- return 0;
+ ehci_suspend(sc);
+ return (0);
}
static int
@@ -110,11 +101,11 @@ ehci_xls_resume(device_t self)
{
ehci_softc_t *sc = device_get_softc(self);
- ehci_xls_takecontroller(self);
- ehci_power(PWR_RESUME, sc);
+ ehci_resume(sc);
+
bus_generic_resume(self);
- return 0;
+ return (0);
}
static int
@@ -127,18 +118,16 @@ ehci_xls_shutdown(device_t self)
if (err)
return (err);
ehci_shutdown(sc);
- ehci_xls_givecontroller(self);
- return 0;
+ return (0);
}
-
static const char *xlr_usb_dev_desc = "RMI XLR USB 2.0 controller";
static const char *xlr_vendor_desc = "RMI Corp";
+
static int
ehci_xls_probe(device_t self)
{
-
/* TODO see if usb is enabled on the board */
device_set_desc(self, xlr_usb_dev_desc);
return BUS_PROBE_DEFAULT;
@@ -148,132 +137,125 @@ static int
ehci_xls_attach(device_t self)
{
ehci_softc_t *sc = device_get_softc(self);
- device_t parent;
- device_t *neighbors;
int err;
int rid;
- int count;
- int res;
+ sc->sc_bus.parent = self;
+ sc->sc_bus.devices = sc->sc_devices;
+ sc->sc_bus.devices_max = EHCI_MAX_DEVICES;
- sc->sc_bus.usbrev = USBREV_2_0;
+ /* get all DMA memory */
+ if (usb_bus_mem_alloc_all(&sc->sc_bus,
+ USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) {
+ return (ENOMEM);
+ }
rid = 0;
- sc->io_res = bus_alloc_resource(self, SYS_RES_MEMORY, &rid,
- 0ul, ~0ul, 0x400, RF_ACTIVE);
- if (!sc->io_res) {
+ sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (!sc->sc_io_res) {
device_printf(self, "Could not map memory\n");
- return ENXIO;
+ goto error;
}
- sc->iot = rman_get_bustag(sc->io_res);
- sc->ioh = rman_get_bushandle(sc->io_res);
+ sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
+ sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
+ printf("IO Resource tag %lx, hdl %lx, size %lx\n",
+ (u_long)sc->sc_io_tag, (u_long)sc->sc_io_hdl,
+ (u_long)sc->sc_io_size);
rid = 0;
- sc->irq_res = bus_alloc_resource(self, SYS_RES_IRQ, &rid,
- 39, 39, 1, RF_SHAREABLE | RF_ACTIVE);
- if (sc->irq_res == NULL) {
+ sc->sc_irq_res = bus_alloc_resource(self, SYS_RES_IRQ, &rid,
+ PIC_USB_IRQ, PIC_USB_IRQ, 1, RF_SHAREABLE | RF_ACTIVE);
+ if (sc->sc_irq_res == NULL) {
device_printf(self, "Could not allocate irq\n");
- ehci_xls_detach(self);
- return ENXIO;
+ goto error;
}
- sc->sc_bus.bdev = device_add_child(self, "usb", -1);
+
+ sc->sc_bus.bdev = device_add_child(self, "usbus", -1);
if (!sc->sc_bus.bdev) {
device_printf(self, "Could not add USB device\n");
- ehci_xls_detach(self);
- return ENOMEM;
+ goto error;
}
device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
-
- /* ehci_pci_match will never return NULL if ehci_pci_probe succeeded */
device_set_desc(sc->sc_bus.bdev, xlr_usb_dev_desc);
+
sprintf(sc->sc_vendor, xlr_vendor_desc);
- err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_BIO,
- (driver_intr_t *) ehci_intr, sc, &sc->ih);
+ err = bus_setup_intr(self, sc->sc_irq_res,
+ INTR_TYPE_BIO | INTR_MPSAFE, NULL,
+ (driver_intr_t *) ehci_interrupt, sc, &sc->sc_intr_hdl);
if (err) {
device_printf(self, "Could not setup irq, %d\n", err);
- sc->ih = NULL;
- ehci_xls_detach(self);
- return ENXIO;
+ sc->sc_intr_hdl = NULL;
+ goto error;
}
- /*
- * Find companion controllers. According to the spec they always
- * have lower function numbers so they should be enumerated already.
- */
- parent = device_get_parent(self);
- res = device_get_children(parent, &neighbors, &count);
- if (res != 0) {
- device_printf(self, "Error finding companion busses\n");
- ehci_xls_detach(self);
- return ENXIO;
- }
- sc->sc_ncomp = 0;
- ehci_xls_takecontroller(self);
err = ehci_init(sc);
- if (!err) {
- sc->sc_flags |= EHCI_SCFLG_DONEINIT;
- err = device_probe_and_attach(sc->sc_bus.bdev);
- }
if (err) {
device_printf(self, "USB init failed err=%d\n", err);
- ehci_xls_detach(self);
- return EIO;
+ goto error;
}
- return 0;
+
+ err = device_probe_and_attach(sc->sc_bus.bdev);
+ if (err) {
+ device_printf(self, "USB probe and attach failed err=%d\n", err);
+ goto error;
+ }
+
+ return (0);
+
+error:
+ ehci_xls_detach(self);
+ return (ENXIO);
}
static int
ehci_xls_detach(device_t self)
{
ehci_softc_t *sc = device_get_softc(self);
+ device_t bdev;
+ int err;
- if (sc->sc_flags & EHCI_SCFLG_DONEINIT) {
- ehci_detach(sc, 0);
- sc->sc_flags &= ~EHCI_SCFLG_DONEINIT;
+ if (sc->sc_bus.bdev) {
+ bdev = sc->sc_bus.bdev;
+ device_detach(bdev);
+ device_delete_child(self, bdev);
}
+ /* during module unload there are lots of children leftover */
+ device_delete_all_children(self);
+
/*
* disable interrupts that might have been switched on in ehci_init
*/
- if (sc->iot && sc->ioh)
- bus_space_write_4(sc->iot, sc->ioh, EHCI_USBINTR, 0);
+ if (sc->sc_io_res) {
+ EWRITE4(sc, EHCI_USBINTR, 0);
+ }
- if (sc->irq_res && sc->ih) {
- int err = bus_teardown_intr(self, sc->irq_res, sc->ih);
+ if (sc->sc_irq_res && sc->sc_intr_hdl) {
+ ehci_detach(sc);
+ err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl);
if (err)
- /* XXX or should we panic? */
device_printf(self, "Could not tear down irq, %d\n",
err);
- sc->ih = NULL;
+ sc->sc_intr_hdl = 0;
}
- if (sc->sc_bus.bdev) {
- device_delete_child(self, sc->sc_bus.bdev);
- sc->sc_bus.bdev = NULL;
- }
- if (sc->irq_res) {
- bus_release_resource(self, SYS_RES_IRQ, 0, sc->irq_res);
- sc->irq_res = NULL;
+
+ if (sc->sc_irq_res) {
+ bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res);
+ sc->sc_irq_res = NULL;
}
- if (sc->io_res) {
- bus_release_resource(self, SYS_RES_MEMORY, PCI_CBMEM, sc->io_res);
- sc->io_res = NULL;
- sc->iot = 0;
- sc->ioh = 0;
+ if (sc->sc_io_res) {
+ bus_release_resource(self, SYS_RES_MEMORY, 0,
+ sc->sc_io_res);
+ sc->sc_io_res = NULL;
+ sc->sc_io_tag = 0;
+ sc->sc_io_hdl = 0;
}
- return 0;
-}
-static void
-ehci_xls_takecontroller(device_t self)
-{
- //device_printf(self, "In func %s\n", __func__);
-}
+ usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
-static void
-ehci_xls_givecontroller(device_t self)
-{
- //device_printf(self, "In func %s\n", __func__);
+ return (0);
}
static device_method_t ehci_methods[] = {
@@ -294,10 +276,10 @@ static device_method_t ehci_methods[] = {
static driver_t ehci_driver = {
"ehci",
ehci_methods,
- sizeof(ehci_softc_t),
+ sizeof(struct ehci_softc),
};
static devclass_t ehci_devclass;
DRIVER_MODULE(ehci, iodi, ehci_driver, ehci_devclass, 0, 0);
-/* DRIVER_MODULE(ehci, cardbus, ehci_driver, ehci_devclass, 0, 0); */
+MODULE_DEPEND(ehci, usb, 1, 1, 1);
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 5b9a891..afb1286 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -42,6 +42,7 @@ SUBDIR= ${_3dfx} \
${_bm} \
bridgestp \
bwi \
+ bwn \
cam \
${_canbepm} \
${_canbus} \
@@ -194,6 +195,7 @@ SUBDIR= ${_3dfx} \
${_ndis} \
${_netgraph} \
${_nfe} \
+ nfs_common \
nfscl \
nfsclient \
nfscommon \
diff --git a/sys/modules/ath/Makefile b/sys/modules/ath/Makefile
index 7770cc7..a8bb5ea 100644
--- a/sys/modules/ath/Makefile
+++ b/sys/modules/ath/Makefile
@@ -92,6 +92,7 @@ SRCS+= ar9160_attach.c
SRCS+= ar9280.c ar9280_attach.c
# RF backend for 5416 and 9160
SRCS+= ar2133.c
+SRCS+= ar9285.c ar9285_attach.c
# NB: rate control is bound to the driver by symbol names so only pick one
.if ${ATH_RATE} == "sample"
diff --git a/sys/modules/bios/smbios/Makefile b/sys/modules/bios/smbios/Makefile
index 40df8e8..b7bdf48 100644
--- a/sys/modules/bios/smbios/Makefile
+++ b/sys/modules/bios/smbios/Makefile
@@ -1,7 +1,7 @@
# $FreeBSD$
#
-.PATH: ${.CURDIR}/../../../i386/bios
+.PATH: ${.CURDIR}/../../../x86/bios
KMOD= smbios
SRCS= smbios.c \
diff --git a/sys/modules/bios/vpd/Makefile b/sys/modules/bios/vpd/Makefile
index d1dd8f1..093ac81 100644
--- a/sys/modules/bios/vpd/Makefile
+++ b/sys/modules/bios/vpd/Makefile
@@ -1,7 +1,7 @@
# $FreeBSD$
#
-.PATH: ${.CURDIR}/../../../i386/bios
+.PATH: ${.CURDIR}/../../../x86/bios
KMOD= vpd
SRCS= vpd.c \
diff --git a/sys/modules/cpufreq/Makefile b/sys/modules/cpufreq/Makefile
index 69854f4..26fea83 100644
--- a/sys/modules/cpufreq/Makefile
+++ b/sys/modules/cpufreq/Makefile
@@ -8,7 +8,7 @@ SRCS= ichss.c
SRCS+= bus_if.h cpufreq_if.h device_if.h pci_if.h
.if ${MACHINE} == "i386" || ${MACHINE} == "amd64"
-.PATH: ${.CURDIR}/../../i386/cpufreq
+.PATH: ${.CURDIR}/../../x86/cpufreq
SRCS+= acpi_if.h opt_acpi.h
SRCS+= est.c hwpstate.c p4tcc.c powernow.c
diff --git a/sys/modules/cxgb/cxgb/Makefile b/sys/modules/cxgb/cxgb/Makefile
index 65b2f6f..9a433b2 100644
--- a/sys/modules/cxgb/cxgb/Makefile
+++ b/sys/modules/cxgb/cxgb/Makefile
@@ -12,13 +12,5 @@ SRCS+= opt_inet.h opt_zero.h opt_sched.h
SRCS+= uipc_mvec.c
CFLAGS+= -g -DDEFAULT_JUMBO -I${CXGB}
-CFLAGS+= -DDISABLE_MBUF_IOVEC
-#CFLAGS+= -DIFNET_MULTIQUEUE
-#CFLAGS+= -DDISABLE_MBUF_IOVEC
-#CFLAGS+= -DDEBUG -DDEBUG_PRINT
-#CFLAGS+= -DINVARIANT_SUPPORT -DINVARIANTS
-#CFLAGS+= -DWITNESS
-#CFLAGS += -DLOCK_PROFILING
-#CFLAGS+= -DWITNESS
.include <bsd.kmod.mk>
diff --git a/sys/net/bpf.c b/sys/net/bpf.c
index f6260c0..65e3f2b 100644
--- a/sys/net/bpf.c
+++ b/sys/net/bpf.c
@@ -664,8 +664,9 @@ static int
bpfread(struct cdev *dev, struct uio *uio, int ioflag)
{
struct bpf_d *d;
- int timed_out;
int error;
+ int non_block;
+ int timed_out;
error = devfs_get_cdevpriv((void **)&d);
if (error != 0)
@@ -678,6 +679,8 @@ bpfread(struct cdev *dev, struct uio *uio, int ioflag)
if (uio->uio_resid != d->bd_bufsize)
return (EINVAL);
+ non_block = ((ioflag & O_NONBLOCK) != 0);
+
BPFD_LOCK(d);
d->bd_pid = curthread->td_proc->p_pid;
if (d->bd_bufmode != BPF_BUFMODE_BUFFER) {
@@ -694,14 +697,20 @@ bpfread(struct cdev *dev, struct uio *uio, int ioflag)
* have arrived to fill the store buffer.
*/
while (d->bd_hbuf == NULL) {
- if ((d->bd_immediate || timed_out) && d->bd_slen != 0) {
+ if (d->bd_slen != 0) {
/*
* A packet(s) either arrived since the previous
* read or arrived while we were asleep.
- * Rotate the buffers and return what's here.
*/
- ROTATE_BUFFERS(d);
- break;
+ if (d->bd_immediate || non_block || timed_out) {
+ /*
+ * Rotate the buffers and return what's here
+ * if we are in immediate mode, non-blocking
+ * flag is set, or this descriptor timed out.
+ */
+ ROTATE_BUFFERS(d);
+ break;
+ }
}
/*
@@ -715,7 +724,7 @@ bpfread(struct cdev *dev, struct uio *uio, int ioflag)
return (ENXIO);
}
- if (ioflag & O_NONBLOCK) {
+ if (non_block) {
BPFD_UNLOCK(d);
return (EWOULDBLOCK);
}
diff --git a/sys/net/if.c b/sys/net/if.c
index ba5b73f..38b1d50 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -34,6 +34,7 @@
#include "opt_inet6.h"
#include "opt_inet.h"
#include "opt_carp.h"
+#include "opt_ddb.h"
#include <sys/param.h>
#include <sys/types.h>
@@ -62,6 +63,10 @@
#include <machine/stdarg.h>
#include <vm/uma.h>
+#ifdef DDB
+#include <ddb/ddb.h>
+#endif
+
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_clone.h>
@@ -809,7 +814,8 @@ if_detach_internal(struct ifnet *ifp, int vmove)
IFNET_WUNLOCK();
if (!found) {
if (vmove)
- panic("interface not in it's own ifnet list");
+ panic("%s: ifp=%p not on the ifnet tailq %p",
+ __func__, ifp, &V_ifnet);
else
return; /* XXX this should panic as well? */
}
@@ -3330,3 +3336,79 @@ if_deregister_com_alloc(u_char type)
if_com_alloc[type] = NULL;
if_com_free[type] = NULL;
}
+
+#ifdef DDB
+static void
+if_show_ifnet(struct ifnet *ifp)
+{
+
+ if (ifp == NULL)
+ return;
+ db_printf("%s:\n", ifp->if_xname);
+#define IF_DB_PRINTF(f, e) db_printf(" %s = " f "\n", #e, ifp->e);
+ IF_DB_PRINTF("%s", if_dname);
+ IF_DB_PRINTF("%d", if_dunit);
+ IF_DB_PRINTF("%s", if_description);
+ IF_DB_PRINTF("%u", if_index);
+ IF_DB_PRINTF("%u", if_refcount);
+ IF_DB_PRINTF("%d", if_index_reserved);
+ IF_DB_PRINTF("%p", if_softc);
+ IF_DB_PRINTF("%p", if_l2com);
+ IF_DB_PRINTF("%p", if_vnet);
+ IF_DB_PRINTF("%p", if_home_vnet);
+ IF_DB_PRINTF("%p", if_addr);
+ IF_DB_PRINTF("%p", if_llsoftc);
+ IF_DB_PRINTF("%p", if_label);
+ IF_DB_PRINTF("%u", if_pcount);
+ IF_DB_PRINTF("0x%08x", if_flags);
+ IF_DB_PRINTF("0x%08x", if_drv_flags);
+ IF_DB_PRINTF("0x%08x", if_capabilities);
+ IF_DB_PRINTF("0x%08x", if_capenable);
+ IF_DB_PRINTF("%p", if_snd.ifq_head);
+ IF_DB_PRINTF("%p", if_snd.ifq_tail);
+ IF_DB_PRINTF("%d", if_snd.ifq_len);
+ IF_DB_PRINTF("%d", if_snd.ifq_maxlen);
+ IF_DB_PRINTF("%d", if_snd.ifq_drops);
+ IF_DB_PRINTF("%p", if_snd.ifq_drv_head);
+ IF_DB_PRINTF("%p", if_snd.ifq_drv_tail);
+ IF_DB_PRINTF("%d", if_snd.ifq_drv_len);
+ IF_DB_PRINTF("%d", if_snd.ifq_drv_maxlen);
+ IF_DB_PRINTF("%d", if_snd.altq_type);
+ IF_DB_PRINTF("%x", if_snd.altq_flags);
+#undef IF_DB_PRINTF
+}
+
+DB_SHOW_COMMAND(ifnet, db_show_ifnet)
+{
+
+ if (!have_addr) {
+ db_printf("usage: show ifnet <struct ifnet *>\n");
+ return;
+ }
+
+ if_show_ifnet((struct ifnet *)addr);
+}
+
+DB_SHOW_ALL_COMMAND(ifnets, db_show_all_ifnets)
+{
+ VNET_ITERATOR_DECL(vnet_iter);
+ struct ifnet *ifp;
+ u_short idx;
+
+ VNET_FOREACH(vnet_iter) {
+ CURVNET_SET_QUIET(vnet_iter);
+#ifdef VIMAGE
+ db_printf("vnet=%p\n", curvnet);
+#endif
+ for (idx = 1; idx <= V_if_index; idx++) {
+ ifp = V_ifindex_table[idx].ife_ifnet;
+ if (ifp == NULL)
+ continue;
+ db_printf( "%20s ifp=%p\n", ifp->if_xname, ifp);
+ if (db_pager_quit)
+ break;
+ }
+ CURVNET_RESTORE();
+ }
+}
+#endif
diff --git a/sys/net/if.h b/sys/net/if.h
index aff0d76..e226654 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -218,6 +218,7 @@ struct if_data {
#define IFCAP_TOE6 0x08000 /* interface can offload TCP6 */
#define IFCAP_VLAN_HWFILTER 0x10000 /* interface hw can filter vlan tag */
#define IFCAP_POLLING_NOCOUNT 0x20000 /* polling ticks cannot be fragmented */
+#define IFCAP_VLAN_HWTSO 0x40000 /* can do IFCAP_TSO on VLANs */
#define IFCAP_HWCSUM (IFCAP_RXCSUM | IFCAP_TXCSUM)
#define IFCAP_TSO (IFCAP_TSO4 | IFCAP_TSO6)
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index d985e98..5f33dd5 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -135,7 +135,6 @@ __FBSDID("$FreeBSD$");
#include <net/route.h>
#include <netinet/ip_fw.h>
#include <netinet/ipfw/ip_fw_private.h>
-#include <netinet/ip_dummynet.h>
/*
* Size of the route hash table. Must be a power of two.
@@ -3073,15 +3072,15 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
if (mtag == NULL) {
args.rule.slot = 0;
} else {
- struct dn_pkt_tag *dn_tag;
+ struct ipfw_rule_ref *r;
/* XXX can we free the tag after use ? */
mtag->m_tag_id = PACKET_TAG_NONE;
- dn_tag = (struct dn_pkt_tag *)(mtag + 1);
+ r = (struct ipfw_rule_ref *)(mtag + 1);
/* packet already partially processed ? */
- if (dn_tag->rule.slot != 0 && V_fw_one_pass)
+ if (r->info & IPFW_ONEPASS)
goto ipfwpass;
- args.rule = dn_tag->rule;
+ args.rule = *r;
}
args.m = *mp;
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index ac2ab05..bbf9753 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -73,7 +73,6 @@
#include <netinet/ip_var.h>
#include <netinet/ip_fw.h>
#include <netinet/ipfw/ip_fw_private.h>
-#include <netinet/ip_dummynet.h>
#endif
#ifdef INET6
#include <netinet6/nd6.h>
@@ -474,15 +473,15 @@ ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, int shared)
if (mtag == NULL) {
args.rule.slot = 0;
} else {
- struct dn_pkt_tag *dn_tag;
+ /* dummynet packet, already partially processed */
+ struct ipfw_rule_ref *r;
/* XXX can we free it after use ? */
mtag->m_tag_id = PACKET_TAG_NONE;
- dn_tag = (struct dn_pkt_tag *)(mtag + 1);
- if (dn_tag->rule.slot != 0 && V_fw_one_pass)
- /* dummynet packet, already partially processed */
+ r = (struct ipfw_rule_ref *)(mtag + 1);
+ if (r->info & IPFW_ONEPASS)
return (1);
- args.rule = dn_tag->rule;
+ args.rule = *r;
}
/*
diff --git a/sys/net/if_gre.c b/sys/net/if_gre.c
index 2b283d6..bac3d795 100644
--- a/sys/net/if_gre.c
+++ b/sys/net/if_gre.c
@@ -18,13 +18,6 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/sys/net/if_gre.h b/sys/net/if_gre.h
index 186d4cc..e23daef 100644
--- a/sys/net/if_gre.h
+++ b/sys/net/if_gre.h
@@ -16,13 +16,6 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c
index 056b2f9..78d2de2 100644
--- a/sys/net/if_loop.c
+++ b/sys/net/if_loop.c
@@ -200,12 +200,12 @@ loop_modevent(module_t mod, int type, void *data)
}
static moduledata_t loop_mod = {
- "loop",
+ "if_lo",
loop_modevent,
0
};
-DECLARE_MODULE(loop, loop_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
+DECLARE_MODULE(if_lo, loop_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
int
looutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
diff --git a/sys/net/if_tap.c b/sys/net/if_tap.c
index 950e96c..93801f1 100644
--- a/sys/net/if_tap.c
+++ b/sys/net/if_tap.c
@@ -192,10 +192,6 @@ tap_clone_create(struct if_clone *ifc, int unit, caddr_t params)
if (i) {
dev = make_dev(&tap_cdevsw, unit | extra,
UID_ROOT, GID_WHEEL, 0600, "%s%d", ifc->ifc_name, unit);
- if (dev != NULL) {
- dev_ref(dev);
- dev->si_flags |= SI_CHEAPCLONE;
- }
}
tapcreate(dev);
@@ -300,6 +296,7 @@ tapmodevent(module_t mod, int type, void *data)
EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
if_clone_detach(&tap_cloner);
if_clone_detach(&vmnet_cloner);
+ drain_dev_clone_events();
mtx_lock(&tapmtx);
while ((tp = SLIST_FIRST(&taphead)) != NULL) {
@@ -381,12 +378,8 @@ tapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **d
name = devname;
}
- *dev = make_dev(&tap_cdevsw, unit | extra,
- UID_ROOT, GID_WHEEL, 0600, "%s", name);
- if (*dev != NULL) {
- dev_ref(*dev);
- (*dev)->si_flags |= SI_CHEAPCLONE;
- }
+ *dev = make_dev_credf(MAKEDEV_REF, &tap_cdevsw, unit | extra,
+ cred, UID_ROOT, GID_WHEEL, 0600, "%s", name);
}
if_clone_create(name, namelen, NULL);
diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c
index 37b5e70..1fa02ac 100644
--- a/sys/net/if_tun.c
+++ b/sys/net/if_tun.c
@@ -188,10 +188,6 @@ tun_clone_create(struct if_clone *ifc, int unit, caddr_t params)
/* No preexisting struct cdev *, create one */
dev = make_dev(&tun_cdevsw, unit,
UID_UUCP, GID_DIALER, 0600, "%s%d", ifc->ifc_name, unit);
- if (dev != NULL) {
- dev_ref(dev);
- dev->si_flags |= SI_CHEAPCLONE;
- }
}
tuncreate(ifc->ifc_name, dev);
@@ -237,12 +233,8 @@ tunclone(void *arg, struct ucred *cred, char *name, int namelen,
name = devname;
}
/* No preexisting struct cdev *, create one */
- *dev = make_dev(&tun_cdevsw, u,
+ *dev = make_dev_credf(MAKEDEV_REF, &tun_cdevsw, u, cred,
UID_UUCP, GID_DIALER, 0600, "%s", name);
- if (*dev != NULL) {
- dev_ref(*dev);
- (*dev)->si_flags |= SI_CHEAPCLONE;
- }
}
if_clone_create(name, namelen, NULL);
@@ -303,6 +295,7 @@ tunmodevent(module_t mod, int type, void *data)
case MOD_UNLOAD:
if_clone_detach(&tun_cloner);
EVENTHANDLER_DEREGISTER(dev_clone, tag);
+ drain_dev_clone_events();
mtx_lock(&tunmtx);
while ((tp = TAILQ_FIRST(&tunhead)) != NULL) {
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index 4b16a9c..f665047 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -25,8 +25,6 @@
* 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$
*/
/*
@@ -41,6 +39,9 @@
* and ask it to send them.
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include "opt_vlan.h"
#include <sys/param.h>
@@ -1322,11 +1323,26 @@ vlan_capabilities(struct ifvlan *ifv)
if (p->if_capenable & IFCAP_VLAN_HWCSUM &&
p->if_capenable & IFCAP_VLAN_HWTAGGING) {
ifp->if_capenable = p->if_capenable & IFCAP_HWCSUM;
- ifp->if_hwassist = p->if_hwassist;
+ ifp->if_hwassist = p->if_hwassist & (CSUM_IP | CSUM_TCP |
+ CSUM_UDP | CSUM_SCTP | CSUM_IP_FRAGS | CSUM_FRAGMENT);
} else {
ifp->if_capenable = 0;
ifp->if_hwassist = 0;
}
+ /*
+ * If the parent interface can do TSO on VLANs then
+ * propagate the hardware-assisted flag. TSO on VLANs
+ * does not necessarily require hardware VLAN tagging.
+ */
+ if (p->if_capabilities & IFCAP_VLAN_HWTSO)
+ ifp->if_capabilities |= p->if_capabilities & IFCAP_TSO;
+ if (p->if_capenable & IFCAP_VLAN_HWTSO) {
+ ifp->if_capenable |= p->if_capenable & IFCAP_TSO;
+ ifp->if_hwassist |= p->if_hwassist & CSUM_TSO;
+ } else {
+ ifp->if_capenable &= ~(p->if_capenable & IFCAP_TSO);
+ ifp->if_hwassist &= ~(p->if_hwassist & CSUM_TSO);
+ }
}
static void
diff --git a/sys/net/netisr.c b/sys/net/netisr.c
index 3574718..4ac1fae 100644
--- a/sys/net/netisr.c
+++ b/sys/net/netisr.c
@@ -1,7 +1,11 @@
/*-
* Copyright (c) 2007-2009 Robert N. M. Watson
+ * Copyright (c) 2010 Juniper Networks, Inc.
* All rights reserved.
*
+ * This software was developed by Robert N. M. Watson under contract
+ * to Juniper Networks, Inc.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -83,9 +87,11 @@ __FBSDID("$FreeBSD$");
#include <ddb/ddb.h>
#endif
+#define _WANT_NETISR_INTERNAL /* Enable definitions from netisr_internal.h */
#include <net/if.h>
#include <net/if_var.h>
#include <net/netisr.h>
+#include <net/netisr_internal.h>
#include <net/vnet.h>
/*-
@@ -95,7 +101,7 @@ __FBSDID("$FreeBSD$");
*
* The following data structures and fields are protected by this lock:
*
- * - The np array, including all fields of struct netisr_proto.
+ * - The netisr_proto array, including all fields of struct netisr_proto.
* - The nws array, including all fields of struct netisr_worker.
* - The nws_array array.
*
@@ -190,79 +196,23 @@ SYSCTL_INT(_net_isr, OID_AUTO, defaultqlimit, CTLFLAG_RDTUN,
"Default netisr per-protocol, per-CPU queue limit if not set by protocol");
/*
- * Each protocol is described by a struct netisr_proto, which holds all
- * global per-protocol information. This data structure is set up by
- * netisr_register(), and derived from the public struct netisr_handler.
- */
-struct netisr_proto {
- const char *np_name; /* Character string protocol name. */
- netisr_handler_t *np_handler; /* Protocol handler. */
- netisr_m2flow_t *np_m2flow; /* Query flow for untagged packet. */
- netisr_m2cpuid_t *np_m2cpuid; /* Query CPU to process packet on. */
- netisr_drainedcpu_t *np_drainedcpu; /* Callback when drained a queue. */
- u_int np_qlimit; /* Maximum per-CPU queue depth. */
- u_int np_policy; /* Work placement policy. */
-};
-
-#define NETISR_MAXPROT 16 /* Compile-time limit. */
-
-/*
- * The np array describes all registered protocols, indexed by protocol
- * number.
+ * Store and export the compile-time constant NETISR_MAXPROT limit on the
+ * number of protocols that can register with netisr at a time. This is
+ * required for crashdump analysis, as it sizes netisr_proto[].
*/
-static struct netisr_proto np[NETISR_MAXPROT];
-
-/*
- * Protocol-specific work for each workstream is described by struct
- * netisr_work. Each work descriptor consists of an mbuf queue and
- * statistics.
- */
-struct netisr_work {
- /*
- * Packet queue, linked by m_nextpkt.
- */
- struct mbuf *nw_head;
- struct mbuf *nw_tail;
- u_int nw_len;
- u_int nw_qlimit;
- u_int nw_watermark;
-
- /*
- * Statistics -- written unlocked, but mostly from curcpu.
- */
- u_int64_t nw_dispatched; /* Number of direct dispatches. */
- u_int64_t nw_hybrid_dispatched; /* "" hybrid dispatches. */
- u_int64_t nw_qdrops; /* "" drops. */
- u_int64_t nw_queued; /* "" enqueues. */
- u_int64_t nw_handled; /* "" handled in worker. */
-};
+static u_int netisr_maxprot = NETISR_MAXPROT;
+SYSCTL_INT(_net_isr, OID_AUTO, maxprot, CTLFLAG_RD,
+ &netisr_maxprot, 0,
+ "Compile-time limit on the number of protocols supported by netisr.");
/*
- * Workstreams hold a queue of ordered work across each protocol, and are
- * described by netisr_workstream. Each workstream is associated with a
- * worker thread, which in turn is pinned to a CPU. Work associated with a
- * workstream can be processd in other threads during direct dispatch;
- * concurrent processing is prevented by the NWS_RUNNING flag, which
- * indicates that a thread is already processing the work queue. It is
- * important to prevent a directly dispatched packet from "skipping ahead" of
- * work already in the workstream queue.
+ * The netisr_proto array describes all registered protocols, indexed by
+ * protocol number. See netisr_internal.h for more details.
*/
-struct netisr_workstream {
- struct intr_event *nws_intr_event; /* Handler for stream. */
- void *nws_swi_cookie; /* swi(9) cookie for stream. */
- struct mtx nws_mtx; /* Synchronize work. */
- u_int nws_cpu; /* CPU pinning. */
- u_int nws_flags; /* Wakeup flags. */
- u_int nws_pendingbits; /* Scheduled protocols. */
-
- /*
- * Each protocol has per-workstream data.
- */
- struct netisr_work nws_work[NETISR_MAXPROT];
-} __aligned(CACHE_LINE_SIZE);
+static struct netisr_proto netisr_proto[NETISR_MAXPROT];
/*
- * Per-CPU workstream data.
+ * Per-CPU workstream data. See netisr_internal.h for more details.
*/
DPCPU_DEFINE(struct netisr_workstream, nws);
@@ -282,13 +232,6 @@ SYSCTL_INT(_net_isr, OID_AUTO, numthreads, CTLFLAG_RD,
&nws_count, 0, "Number of extant netisr threads.");
/*
- * Per-workstream flags.
- */
-#define NWS_RUNNING 0x00000001 /* Currently running in a thread. */
-#define NWS_DISPATCHING 0x00000002 /* Currently being direct-dispatched. */
-#define NWS_SCHEDULED 0x00000004 /* Signal issued. */
-
-/*
* Synchronization for each workstream: a mutex protects all mutable fields
* in each stream, including per-protocol state (mbuf queues). The SWI is
* woken up if asynchronous dispatch is required.
@@ -376,32 +319,32 @@ netisr_register(const struct netisr_handler *nhp)
* Test that no existing registration exists for this protocol.
*/
NETISR_WLOCK();
- KASSERT(np[proto].np_name == NULL,
+ KASSERT(netisr_proto[proto].np_name == NULL,
("%s(%u, %s): name present", __func__, proto, name));
- KASSERT(np[proto].np_handler == NULL,
+ KASSERT(netisr_proto[proto].np_handler == NULL,
("%s(%u, %s): handler present", __func__, proto, name));
- np[proto].np_name = name;
- np[proto].np_handler = nhp->nh_handler;
- np[proto].np_m2flow = nhp->nh_m2flow;
- np[proto].np_m2cpuid = nhp->nh_m2cpuid;
- np[proto].np_drainedcpu = nhp->nh_drainedcpu;
+ netisr_proto[proto].np_name = name;
+ netisr_proto[proto].np_handler = nhp->nh_handler;
+ netisr_proto[proto].np_m2flow = nhp->nh_m2flow;
+ netisr_proto[proto].np_m2cpuid = nhp->nh_m2cpuid;
+ netisr_proto[proto].np_drainedcpu = nhp->nh_drainedcpu;
if (nhp->nh_qlimit == 0)
- np[proto].np_qlimit = netisr_defaultqlimit;
+ netisr_proto[proto].np_qlimit = netisr_defaultqlimit;
else if (nhp->nh_qlimit > netisr_maxqlimit) {
printf("%s: %s requested queue limit %u capped to "
"net.isr.maxqlimit %u\n", __func__, name, nhp->nh_qlimit,
netisr_maxqlimit);
- np[proto].np_qlimit = netisr_maxqlimit;
+ netisr_proto[proto].np_qlimit = netisr_maxqlimit;
} else
- np[proto].np_qlimit = nhp->nh_qlimit;
- np[proto].np_policy = nhp->nh_policy;
+ netisr_proto[proto].np_qlimit = nhp->nh_qlimit;
+ netisr_proto[proto].np_policy = nhp->nh_policy;
for (i = 0; i <= mp_maxid; i++) {
if (CPU_ABSENT(i))
continue;
npwp = &(DPCPU_ID_PTR(i, nws))->nws_work[proto];
bzero(npwp, sizeof(*npwp));
- npwp->nw_qlimit = np[proto].np_qlimit;
+ npwp->nw_qlimit = netisr_proto[proto].np_qlimit;
}
NETISR_WUNLOCK();
}
@@ -426,7 +369,7 @@ netisr_clearqdrops(const struct netisr_handler *nhp)
("%s(%u): protocol too big for %s", __func__, proto, name));
NETISR_WLOCK();
- KASSERT(np[proto].np_handler != NULL,
+ KASSERT(netisr_proto[proto].np_handler != NULL,
("%s(%u): protocol not registered for %s", __func__, proto,
name));
@@ -461,7 +404,7 @@ netisr_getqdrops(const struct netisr_handler *nhp, u_int64_t *qdropp)
("%s(%u): protocol too big for %s", __func__, proto, name));
NETISR_RLOCK(&tracker);
- KASSERT(np[proto].np_handler != NULL,
+ KASSERT(netisr_proto[proto].np_handler != NULL,
("%s(%u): protocol not registered for %s", __func__, proto,
name));
@@ -494,10 +437,10 @@ netisr_getqlimit(const struct netisr_handler *nhp, u_int *qlimitp)
("%s(%u): protocol too big for %s", __func__, proto, name));
NETISR_RLOCK(&tracker);
- KASSERT(np[proto].np_handler != NULL,
+ KASSERT(netisr_proto[proto].np_handler != NULL,
("%s(%u): protocol not registered for %s", __func__, proto,
name));
- *qlimitp = np[proto].np_qlimit;
+ *qlimitp = netisr_proto[proto].np_qlimit;
NETISR_RUNLOCK(&tracker);
}
@@ -526,11 +469,11 @@ netisr_setqlimit(const struct netisr_handler *nhp, u_int qlimit)
("%s(%u): protocol too big for %s", __func__, proto, name));
NETISR_WLOCK();
- KASSERT(np[proto].np_handler != NULL,
+ KASSERT(netisr_proto[proto].np_handler != NULL,
("%s(%u): protocol not registered for %s", __func__, proto,
name));
- np[proto].np_qlimit = qlimit;
+ netisr_proto[proto].np_qlimit = qlimit;
for (i = 0; i <= mp_maxid; i++) {
if (CPU_ABSENT(i))
continue;
@@ -587,16 +530,16 @@ netisr_unregister(const struct netisr_handler *nhp)
("%s(%u): protocol too big for %s", __func__, proto, name));
NETISR_WLOCK();
- KASSERT(np[proto].np_handler != NULL,
+ KASSERT(netisr_proto[proto].np_handler != NULL,
("%s(%u): protocol not registered for %s", __func__, proto,
name));
- np[proto].np_name = NULL;
- np[proto].np_handler = NULL;
- np[proto].np_m2flow = NULL;
- np[proto].np_m2cpuid = NULL;
- np[proto].np_qlimit = 0;
- np[proto].np_policy = 0;
+ netisr_proto[proto].np_name = NULL;
+ netisr_proto[proto].np_handler = NULL;
+ netisr_proto[proto].np_m2flow = NULL;
+ netisr_proto[proto].np_m2cpuid = NULL;
+ netisr_proto[proto].np_qlimit = 0;
+ netisr_proto[proto].np_policy = 0;
for (i = 0; i <= mp_maxid; i++) {
if (CPU_ABSENT(i))
continue;
@@ -716,13 +659,13 @@ netisr_process_workstream_proto(struct netisr_workstream *nwsp, u_int proto)
local_npw.nw_len--;
VNET_ASSERT(m->m_pkthdr.rcvif != NULL);
CURVNET_SET(m->m_pkthdr.rcvif->if_vnet);
- np[proto].np_handler(m);
+ netisr_proto[proto].np_handler(m);
CURVNET_RESTORE();
}
KASSERT(local_npw.nw_len == 0,
("%s(%u): len %u", __func__, proto, local_npw.nw_len));
- if (np[proto].np_drainedcpu)
- np[proto].np_drainedcpu(nwsp->nws_cpu);
+ if (netisr_proto[proto].np_drainedcpu)
+ netisr_proto[proto].np_drainedcpu(nwsp->nws_cpu);
NWS_LOCK(nwsp);
npwp->nw_handled += handled;
return (handled);
@@ -858,10 +801,10 @@ netisr_queue_src(u_int proto, uintptr_t source, struct mbuf *m)
#ifdef NETISR_LOCKING
NETISR_RLOCK(&tracker);
#endif
- KASSERT(np[proto].np_handler != NULL,
+ KASSERT(netisr_proto[proto].np_handler != NULL,
("%s: invalid proto %u", __func__, proto));
- m = netisr_select_cpuid(&np[proto], source, m, &cpuid);
+ m = netisr_select_cpuid(&netisr_proto[proto], source, m, &cpuid);
if (m != NULL) {
KASSERT(!CPU_ABSENT(cpuid), ("%s: CPU %u absent", __func__,
cpuid));
@@ -907,7 +850,7 @@ netisr_dispatch_src(u_int proto, uintptr_t source, struct mbuf *m)
#ifdef NETISR_LOCKING
NETISR_RLOCK(&tracker);
#endif
- KASSERT(np[proto].np_handler != NULL,
+ KASSERT(netisr_proto[proto].np_handler != NULL,
("%s: invalid proto %u", __func__, proto));
/*
@@ -922,7 +865,7 @@ netisr_dispatch_src(u_int proto, uintptr_t source, struct mbuf *m)
npwp = &nwsp->nws_work[proto];
npwp->nw_dispatched++;
npwp->nw_handled++;
- np[proto].np_handler(m);
+ netisr_proto[proto].np_handler(m);
error = 0;
goto out_unlock;
}
@@ -932,7 +875,7 @@ netisr_dispatch_src(u_int proto, uintptr_t source, struct mbuf *m)
* dispatch if we're on the right CPU and the netisr worker isn't
* already running.
*/
- m = netisr_select_cpuid(&np[proto], source, m, &cpuid);
+ m = netisr_select_cpuid(&netisr_proto[proto], source, m, &cpuid);
if (m == NULL) {
error = ENOBUFS;
goto out_unlock;
@@ -969,7 +912,7 @@ netisr_dispatch_src(u_int proto, uintptr_t source, struct mbuf *m)
*/
nwsp->nws_flags |= NWS_DISPATCHING;
NWS_UNLOCK(nwsp);
- np[proto].np_handler(m);
+ netisr_proto[proto].np_handler(m);
NWS_LOCK(nwsp);
nwsp->nws_flags &= ~NWS_DISPATCHING;
npwp->nw_handled++;
@@ -1126,6 +1069,170 @@ netisr_start(void *arg)
}
SYSINIT(netisr_start, SI_SUB_SMP, SI_ORDER_MIDDLE, netisr_start, NULL);
+/*
+ * Sysctl monitoring for netisr: query a list of registered protocols.
+ */
+static int
+sysctl_netisr_proto(SYSCTL_HANDLER_ARGS)
+{
+ struct rm_priotracker tracker;
+ struct sysctl_netisr_proto *snpp, *snp_array;
+ struct netisr_proto *npp;
+ u_int counter, proto;
+ int error;
+
+ if (req->newptr != NULL)
+ return (EINVAL);
+ snp_array = malloc(sizeof(*snp_array) * NETISR_MAXPROT, M_TEMP,
+ M_ZERO | M_WAITOK);
+ counter = 0;
+ NETISR_RLOCK(&tracker);
+ for (proto = 0; proto < NETISR_MAXPROT; proto++) {
+ npp = &netisr_proto[proto];
+ if (npp->np_name == NULL)
+ continue;
+ snpp = &snp_array[counter];
+ snpp->snp_version = sizeof(*snpp);
+ strlcpy(snpp->snp_name, npp->np_name, NETISR_NAMEMAXLEN);
+ snpp->snp_proto = proto;
+ snpp->snp_qlimit = npp->np_qlimit;
+ snpp->snp_policy = npp->np_policy;
+ if (npp->np_m2flow != NULL)
+ snpp->snp_flags |= NETISR_SNP_FLAGS_M2FLOW;
+ if (npp->np_m2cpuid != NULL)
+ snpp->snp_flags |= NETISR_SNP_FLAGS_M2CPUID;
+ if (npp->np_drainedcpu != NULL)
+ snpp->snp_flags |= NETISR_SNP_FLAGS_DRAINEDCPU;
+ counter++;
+ }
+ NETISR_RUNLOCK(&tracker);
+ KASSERT(counter <= NETISR_MAXPROT,
+ ("sysctl_netisr_proto: counter too big (%d)", counter));
+ error = SYSCTL_OUT(req, snp_array, sizeof(*snp_array) * counter);
+ free(snp_array, M_TEMP);
+ return (error);
+}
+
+SYSCTL_PROC(_net_isr, OID_AUTO, proto,
+ CTLFLAG_RD|CTLTYPE_STRUCT|CTLFLAG_MPSAFE, 0, 0, sysctl_netisr_proto,
+ "S,sysctl_netisr_proto",
+ "Return list of protocols registered with netisr");
+
+/*
+ * Sysctl monitoring for netisr: query a list of workstreams.
+ */
+static int
+sysctl_netisr_workstream(SYSCTL_HANDLER_ARGS)
+{
+ struct rm_priotracker tracker;
+ struct sysctl_netisr_workstream *snwsp, *snws_array;
+ struct netisr_workstream *nwsp;
+ u_int counter, cpuid;
+ int error;
+
+ if (req->newptr != NULL)
+ return (EINVAL);
+ snws_array = malloc(sizeof(*snws_array) * MAXCPU, M_TEMP,
+ M_ZERO | M_WAITOK);
+ counter = 0;
+ NETISR_RLOCK(&tracker);
+ for (cpuid = 0; cpuid < MAXCPU; cpuid++) {
+ if (CPU_ABSENT(cpuid))
+ continue;
+ nwsp = DPCPU_ID_PTR(cpuid, nws);
+ if (nwsp->nws_intr_event == NULL)
+ continue;
+ NWS_LOCK(nwsp);
+ snwsp = &snws_array[counter];
+ snwsp->snws_version = sizeof(*snwsp);
+
+ /*
+ * For now, we equate workstream IDs and CPU IDs in the
+ * kernel, but expose them independently to userspace in case
+ * that assumption changes in the future.
+ */
+ snwsp->snws_wsid = cpuid;
+ snwsp->snws_cpu = cpuid;
+ if (nwsp->nws_intr_event != NULL)
+ snwsp->snws_flags |= NETISR_SNWS_FLAGS_INTR;
+ NWS_UNLOCK(nwsp);
+ counter++;
+ }
+ NETISR_RUNLOCK(&tracker);
+ KASSERT(counter <= MAXCPU,
+ ("sysctl_netisr_workstream: counter too big (%d)", counter));
+ error = SYSCTL_OUT(req, snws_array, sizeof(*snws_array) * counter);
+ free(snws_array, M_TEMP);
+ return (error);
+}
+
+SYSCTL_PROC(_net_isr, OID_AUTO, workstream,
+ CTLFLAG_RD|CTLTYPE_STRUCT|CTLFLAG_MPSAFE, 0, 0, sysctl_netisr_workstream,
+ "S,sysctl_netisr_workstream",
+ "Return list of workstreams implemented by netisr");
+
+/*
+ * Sysctl monitoring for netisr: query per-protocol data across all
+ * workstreams.
+ */
+static int
+sysctl_netisr_work(SYSCTL_HANDLER_ARGS)
+{
+ struct rm_priotracker tracker;
+ struct sysctl_netisr_work *snwp, *snw_array;
+ struct netisr_workstream *nwsp;
+ struct netisr_proto *npp;
+ struct netisr_work *nwp;
+ u_int counter, cpuid, proto;
+ int error;
+
+ if (req->newptr != NULL)
+ return (EINVAL);
+ snw_array = malloc(sizeof(*snw_array) * MAXCPU * NETISR_MAXPROT,
+ M_TEMP, M_ZERO | M_WAITOK);
+ counter = 0;
+ NETISR_RLOCK(&tracker);
+ for (cpuid = 0; cpuid < MAXCPU; cpuid++) {
+ if (CPU_ABSENT(cpuid))
+ continue;
+ nwsp = DPCPU_ID_PTR(cpuid, nws);
+ if (nwsp->nws_intr_event == NULL)
+ continue;
+ NWS_LOCK(nwsp);
+ for (proto = 0; proto < NETISR_MAXPROT; proto++) {
+ npp = &netisr_proto[proto];
+ if (npp->np_name == NULL)
+ continue;
+ nwp = &nwsp->nws_work[proto];
+ snwp = &snw_array[counter];
+ snwp->snw_version = sizeof(*snwp);
+ snwp->snw_wsid = cpuid; /* See comment above. */
+ snwp->snw_proto = proto;
+ snwp->snw_len = nwp->nw_len;
+ snwp->snw_watermark = nwp->nw_watermark;
+ snwp->snw_dispatched = nwp->nw_dispatched;
+ snwp->snw_hybrid_dispatched =
+ nwp->nw_hybrid_dispatched;
+ snwp->snw_qdrops = nwp->nw_qdrops;
+ snwp->snw_queued = nwp->nw_queued;
+ snwp->snw_handled = nwp->nw_handled;
+ counter++;
+ }
+ NWS_UNLOCK(nwsp);
+ }
+ KASSERT(counter <= MAXCPU * NETISR_MAXPROT,
+ ("sysctl_netisr_work: counter too big (%d)", counter));
+ NETISR_RUNLOCK(&tracker);
+ error = SYSCTL_OUT(req, snw_array, sizeof(*snw_array) * counter);
+ free(snw_array, M_TEMP);
+ return (error);
+}
+
+SYSCTL_PROC(_net_isr, OID_AUTO, work,
+ CTLFLAG_RD|CTLTYPE_STRUCT|CTLFLAG_MPSAFE, 0, 0, sysctl_netisr_work,
+ "S,sysctl_netisr_work",
+ "Return list of per-workstream, per-protocol work in netisr");
+
#ifdef DDB
DB_SHOW_COMMAND(netisr, db_show_netisr)
{
@@ -1144,7 +1251,7 @@ DB_SHOW_COMMAND(netisr, db_show_netisr)
continue;
first = 1;
for (proto = 0; proto < NETISR_MAXPROT; proto++) {
- if (np[proto].np_handler == NULL)
+ if (netisr_proto[proto].np_handler == NULL)
continue;
nwp = &nwsp->nws_work[proto];
if (first) {
@@ -1154,7 +1261,7 @@ DB_SHOW_COMMAND(netisr, db_show_netisr)
db_printf("%3s ", "");
db_printf(
"%6s %5d %5d %5d %8ju %8ju %8ju %8ju\n",
- np[proto].np_name, nwp->nw_len,
+ netisr_proto[proto].np_name, nwp->nw_len,
nwp->nw_watermark, nwp->nw_qlimit,
nwp->nw_dispatched, nwp->nw_hybrid_dispatched,
nwp->nw_qdrops, nwp->nw_queued);
diff --git a/sys/net/netisr.h b/sys/net/netisr.h
index 0ab424f..cd692f6 100644
--- a/sys/net/netisr.h
+++ b/sys/net/netisr.h
@@ -1,7 +1,11 @@
/*-
* Copyright (c) 2007-2009 Robert N. M. Watson
+ * Copyright (c) 2010 Juniper Networks, Inc.
* All rights reserved.
*
+ * This software was developed by Robert N. M. Watson under contract
+ * to Juniper Networks, Inc.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -28,7 +32,6 @@
#ifndef _NET_NETISR_H_
#define _NET_NETISR_H_
-#ifdef _KERNEL
/*
* The netisr (network interrupt service routine) provides a deferred
@@ -39,6 +42,13 @@
* Historically, this was implemented by the BSD software ISR facility; it is
* now implemented via a software ithread (SWI).
*/
+
+/*
+ * Protocol numbers, which are encoded in monitoring applications and kernel
+ * modules. Internally, these are used in bit shift operations so must have
+ * a value 0 < proto < 32; we currently further limit at compile-time to 16
+ * for array-sizing purposes.
+ */
#define NETISR_IP 1
#define NETISR_IGMP 2 /* IGMPv3 output queue */
#define NETISR_ROUTE 3 /* routing socket */
@@ -52,6 +62,78 @@
#define NETISR_NATM 11
#define NETISR_EPAIR 12 /* if_epair(4) */
+/*
+ * Protocol ordering and affinity policy constants. See the detailed
+ * discussion of policies later in the file.
+ */
+#define NETISR_POLICY_SOURCE 1 /* Maintain source ordering. */
+#define NETISR_POLICY_FLOW 2 /* Maintain flow ordering. */
+#define NETISR_POLICY_CPU 3 /* Protocol determines CPU placement. */
+
+/*
+ * Monitoring data structures, exported by sysctl(2).
+ *
+ * Three sysctls are defined. First, a per-protocol structure exported by
+ * net.isr.proto.
+ */
+#define NETISR_NAMEMAXLEN 32
+struct sysctl_netisr_proto {
+ u_int snp_version; /* Length of struct. */
+ char snp_name[NETISR_NAMEMAXLEN]; /* nh_name */
+ u_int snp_proto; /* nh_proto */
+ u_int snp_qlimit; /* nh_qlimit */
+ u_int snp_policy; /* nh_policy */
+ u_int snp_flags; /* Various flags. */
+ u_int _snp_ispare[7];
+};
+
+/*
+ * Flags for sysctl_netisr_proto.snp_flags.
+ */
+#define NETISR_SNP_FLAGS_M2FLOW 0x00000001 /* nh_m2flow */
+#define NETISR_SNP_FLAGS_M2CPUID 0x00000002 /* nh_m2cpuid */
+#define NETISR_SNP_FLAGS_DRAINEDCPU 0x00000004 /* nh_drainedcpu */
+
+/*
+ * Next, a structure per-workstream, with per-protocol data, exported as
+ * net.isr.workstream.
+ */
+struct sysctl_netisr_workstream {
+ u_int snws_version; /* Length of struct. */
+ u_int snws_flags; /* Various flags. */
+ u_int snws_wsid; /* Workstream ID. */
+ u_int snws_cpu; /* nws_cpu */
+ u_int _snws_ispare[12];
+};
+
+/*
+ * Flags for sysctl_netisr_workstream.snws_flags
+ */
+#define NETISR_SNWS_FLAGS_INTR 0x00000001 /* nws_intr_event */
+
+/*
+ * Finally, a per-workstream-per-protocol structure, exported as
+ * net.isr.work.
+ */
+struct sysctl_netisr_work {
+ u_int snw_version; /* Length of struct. */
+ u_int snw_wsid; /* Workstream ID. */
+ u_int snw_proto; /* Protocol number. */
+ u_int snw_len; /* nw_len */
+ u_int snw_watermark; /* nw_watermark */
+ u_int _snw_ispare[3];
+
+ uint64_t snw_dispatched; /* nw_dispatched */
+ uint64_t snw_hybrid_dispatched; /* nw_hybrid_dispatched */
+ uint64_t snw_qdrops; /* nw_qdrops */
+ uint64_t snw_queued; /* nw_queued */
+ uint64_t snw_handled; /* nw_handled */
+
+ uint64_t _snw_llspare[7];
+};
+
+#ifdef _KERNEL
+
/*-
* Protocols express ordering constraints and affinity preferences by
* implementing one or neither of nh_m2flow and nh_m2cpuid, which are used by
@@ -85,16 +167,12 @@
* can rebalance work.
*/
struct mbuf;
-typedef void netisr_handler_t (struct mbuf *m);
+typedef void netisr_handler_t(struct mbuf *m);
typedef struct mbuf *netisr_m2cpuid_t(struct mbuf *m, uintptr_t source,
u_int *cpuid);
typedef struct mbuf *netisr_m2flow_t(struct mbuf *m, uintptr_t source);
typedef void netisr_drainedcpu_t(u_int cpuid);
-#define NETISR_POLICY_SOURCE 1 /* Maintain source ordering. */
-#define NETISR_POLICY_FLOW 2 /* Maintain flow ordering. */
-#define NETISR_POLICY_CPU 3 /* Protocol determines CPU placement. */
-
/*
* Data structure describing a protocol handler.
*/
diff --git a/sys/net/netisr_internal.h b/sys/net/netisr_internal.h
new file mode 100644
index 0000000..40afaf1
--- /dev/null
+++ b/sys/net/netisr_internal.h
@@ -0,0 +1,127 @@
+/*-
+ * Copyright (c) 2007-2009 Robert N. M. Watson
+ * Copyright (c) 2010 Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert N. M. Watson under contract
+ * to Juniper Networks, Inc.
+ *
+ * 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 _NET_NETISR_INTERNAL_H_
+#define _NET_NETISR_INTERNAL_H_
+
+#ifndef _WANT_NETISR_INTERNAL
+#error "no user-serviceable parts inside"
+#endif
+
+/*
+ * These definitions are private to the netisr implementation, but provided
+ * here for use by post-mortem crashdump analysis tools. They should not be
+ * used in any other context as they can and will change. Public definitions
+ * may be found in netisr.h.
+ */
+
+#ifndef _KERNEL
+typedef void *netisr_handler_t;
+typedef void *netisr_m2flow_t;
+typedef void *netisr_m2cpuid_t;
+typedef void *netisr_drainedcpu_t;
+#endif
+
+/*
+ * Each protocol is described by a struct netisr_proto, which holds all
+ * global per-protocol information. This data structure is set up by
+ * netisr_register(), and derived from the public struct netisr_handler.
+ */
+struct netisr_proto {
+ const char *np_name; /* Character string protocol name. */
+ netisr_handler_t *np_handler; /* Protocol handler. */
+ netisr_m2flow_t *np_m2flow; /* Query flow for untagged packet. */
+ netisr_m2cpuid_t *np_m2cpuid; /* Query CPU to process packet on. */
+ netisr_drainedcpu_t *np_drainedcpu; /* Callback when drained a queue. */
+ u_int np_qlimit; /* Maximum per-CPU queue depth. */
+ u_int np_policy; /* Work placement policy. */
+};
+
+#define NETISR_MAXPROT 16 /* Compile-time limit. */
+
+/*
+ * Protocol-specific work for each workstream is described by struct
+ * netisr_work. Each work descriptor consists of an mbuf queue and
+ * statistics.
+ */
+struct netisr_work {
+ /*
+ * Packet queue, linked by m_nextpkt.
+ */
+ struct mbuf *nw_head;
+ struct mbuf *nw_tail;
+ u_int nw_len;
+ u_int nw_qlimit;
+ u_int nw_watermark;
+
+ /*
+ * Statistics -- written unlocked, but mostly from curcpu.
+ */
+ u_int64_t nw_dispatched; /* Number of direct dispatches. */
+ u_int64_t nw_hybrid_dispatched; /* "" hybrid dispatches. */
+ u_int64_t nw_qdrops; /* "" drops. */
+ u_int64_t nw_queued; /* "" enqueues. */
+ u_int64_t nw_handled; /* "" handled in worker. */
+};
+
+/*
+ * Workstreams hold a queue of ordered work across each protocol, and are
+ * described by netisr_workstream. Each workstream is associated with a
+ * worker thread, which in turn is pinned to a CPU. Work associated with a
+ * workstream can be processd in other threads during direct dispatch;
+ * concurrent processing is prevented by the NWS_RUNNING flag, which
+ * indicates that a thread is already processing the work queue. It is
+ * important to prevent a directly dispatched packet from "skipping ahead" of
+ * work already in the workstream queue.
+ */
+struct netisr_workstream {
+ struct intr_event *nws_intr_event; /* Handler for stream. */
+ void *nws_swi_cookie; /* swi(9) cookie for stream. */
+ struct mtx nws_mtx; /* Synchronize work. */
+ u_int nws_cpu; /* CPU pinning. */
+ u_int nws_flags; /* Wakeup flags. */
+ u_int nws_pendingbits; /* Scheduled protocols. */
+
+ /*
+ * Each protocol has per-workstream data.
+ */
+ struct netisr_work nws_work[NETISR_MAXPROT];
+} __aligned(CACHE_LINE_SIZE);
+
+/*
+ * Per-workstream flags.
+ */
+#define NWS_RUNNING 0x00000001 /* Currently running in a thread. */
+#define NWS_DISPATCHING 0x00000002 /* Currently being direct-dispatched. */
+#define NWS_SCHEDULED 0x00000004 /* Signal issued. */
+
+#endif /* !_NET_NETISR_INTERNAL_H_ */
diff --git a/sys/net/radix.c b/sys/net/radix.c
index f092aa1..db1a46c 100644
--- a/sys/net/radix.c
+++ b/sys/net/radix.c
@@ -936,7 +936,7 @@ on1:
if (m)
log(LOG_ERR,
"rn_delete: Orphaned Mask %p at %p\n",
- (void *)m, (void *)x);
+ m, x);
}
}
/*
diff --git a/sys/net/zlib.h b/sys/net/zlib.h
index 9529e43..85db8d4 100644
--- a/sys/net/zlib.h
+++ b/sys/net/zlib.h
@@ -1010,6 +1010,13 @@ extern int EXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
uLongf *get_crc_table OF((void)); /* can be used by asm versions of crc32() */
+#ifdef _KERNEL
+struct vnode;
+extern gzFile gz_open OF((const char *path, const char *mode,
+ struct vnode *vp));
+#endif
+
+
#ifdef __cplusplus
}
#endif
diff --git a/sys/net/zutil.h b/sys/net/zutil.h
new file mode 100644
index 0000000..74f0221
--- /dev/null
+++ b/sys/net/zutil.h
@@ -0,0 +1,231 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */
+/* $FreeBSD$ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#define ZEXPORT
+
+#ifdef _KERNEL
+#include <net/zlib.h>
+#else
+#include "zlib.h"
+#endif
+
+#ifdef _KERNEL
+/* Assume this is a *BSD or SVR4 kernel */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/errno.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+# define HAVE_MEMCPY
+# define memcpy(d, s, n) bcopy((s), (d), (n))
+# define memset(d, v, n) bzero((d), (n))
+# define memcmp bcmp
+
+#else
+#if defined(__KERNEL__)
+/* Assume this is a Linux kernel */
+#include <linux/string.h>
+#define HAVE_MEMCPY
+
+#else /* not kernel */
+
+#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS)
+# include <stddef.h>
+# include <errno.h>
+#else
+ extern int errno;
+#endif
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+#endif
+#endif /* __KERNEL__ */
+#endif /* _KERNEL */
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = (const char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#ifdef MSDOS
+# define OS_CODE 0x00
+# ifdef __TURBOC__
+# include <alloc.h>
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+#endif
+
+#ifdef WIN32 /* Window 95 & Windows NT */
+# define OS_CODE 0x0b
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define FOPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#ifdef MACOS
+# define OS_CODE 0x07
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0F
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+ /* Common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef FOPEN
+# define FOPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#ifdef HAVE_STRERROR
+ extern char *strerror OF((int));
+# define zstrerror(errnum) strerror(errnum)
+#else
+# define zstrerror(errnum) ""
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ extern void zmemcpy OF((Bytef* dest, Bytef* source, uInt len));
+ extern int zmemcmp OF((Bytef* s1, Bytef* s2, uInt len));
+ extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG_ZLIB
+# include <stdio.h>
+# ifndef verbose
+# define verbose 0
+# endif
+ extern void z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len));
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* _Z_UTIL_H */
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index 2bc6ca9..d9cab84 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -114,6 +114,9 @@ struct protosw inetsw[] = {
.pr_domain = &inetdomain,
.pr_protocol = IPPROTO_IP,
.pr_init = ip_init,
+#ifdef VIMAGE
+ .pr_destroy = ip_destroy,
+#endif
.pr_slowtimo = ip_slowtimo,
.pr_drain = ip_drain,
.pr_usrreqs = &nousrreqs
diff --git a/sys/netinet/ip_dummynet.h b/sys/netinet/ip_dummynet.h
index 3a193e9..0bbc326 100644
--- a/sys/netinet/ip_dummynet.h
+++ b/sys/netinet/ip_dummynet.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1998-2002 Luigi Rizzo, Universita` di Pisa
+ * Copyright (c) 1998-2010 Luigi Rizzo, Universita` di Pisa
* Portions Copyright (c) 2000 Akamba Corp.
* All rights reserved
*
@@ -31,257 +31,124 @@
#define _IP_DUMMYNET_H
/*
- * Definition of dummynet data structures. In the structures, I decided
- * not to use the macros in <sys/queue.h> in the hope of making the code
- * easier to port to other architectures. The type of lists and queue we
- * use here is pretty simple anyways.
- */
-
-/*
- * We start with a heap, which is used in the scheduler to decide when
- * to transmit packets etc.
- *
- * The key for the heap is used for two different values:
+ * Definition of the kernel-userland API for dummynet.
*
- * 1. timer ticks- max 10K/second, so 32 bits are enough;
+ * Setsockopt() and getsockopt() pass a batch of objects, each
+ * of them starting with a "struct dn_id" which should fully identify
+ * the object and its relation with others in the sequence.
+ * The first object in each request should have
+ * type= DN_CMD_*, id = DN_API_VERSION.
+ * For other objects, type and subtype specify the object, len indicates
+ * the total length including the header, and 'id' identifies the specific
+ * object.
*
- * 2. virtual times. These increase in steps of len/x, where len is the
- * packet length, and x is either the weight of the flow, or the
- * sum of all weights.
- * If we limit to max 1000 flows and a max weight of 100, then
- * x needs 17 bits. The packet size is 16 bits, so we can easily
- * overflow if we do not allow errors.
- * So we use a key "dn_key" which is 64 bits. Some macros are used to
- * compare key values and handle wraparounds.
- * MAX64 returns the largest of two key values.
- * MY_M is used as a shift count when doing fixed point arithmetic
- * (a better name would be useful...).
+ * Most objects are numbered with an identifier in the range 1..65535.
+ * DN_MAX_ID indicates the first value outside the range.
*/
-typedef u_int64_t dn_key ; /* sorting key */
-#define DN_KEY_LT(a,b) ((int64_t)((a)-(b)) < 0)
-#define DN_KEY_LEQ(a,b) ((int64_t)((a)-(b)) <= 0)
-#define DN_KEY_GT(a,b) ((int64_t)((a)-(b)) > 0)
-#define DN_KEY_GEQ(a,b) ((int64_t)((a)-(b)) >= 0)
-#define MAX64(x,y) (( (int64_t) ( (y)-(x) )) > 0 ) ? (y) : (x)
-#define MY_M 16 /* number of left shift to obtain a larger precision */
-/*
- * XXX With this scaling, max 1000 flows, max weight 100, 1Gbit/s, the
- * virtual time wraps every 15 days.
- */
+#define DN_API_VERSION 12500000
+#define DN_MAX_ID 0x10000
+struct dn_id {
+ uint16_t len; /* total obj len including this header */
+ uint8_t type;
+ uint8_t subtype;
+ uint32_t id; /* generic id */
+};
/*
- * The maximum hash table size for queues. This value must be a power
- * of 2.
- */
-#define DN_MAX_HASH_SIZE 65536
-
-/*
- * A heap entry is made of a key and a pointer to the actual
- * object stored in the heap.
- * The heap is an array of dn_heap_entry entries, dynamically allocated.
- * Current size is "size", with "elements" actually in use.
- * The heap normally supports only ordered insert and extract from the top.
- * If we want to extract an object from the middle of the heap, we
- * have to know where the object itself is located in the heap (or we
- * need to scan the whole array). To this purpose, an object has a
- * field (int) which contains the index of the object itself into the
- * heap. When the object is moved, the field must also be updated.
- * The offset of the index in the object is stored in the 'offset'
- * field in the heap descriptor. The assumption is that this offset
- * is non-zero if we want to support extract from the middle.
+ * These values are in the type field of struct dn_id.
+ * To preserve the ABI, never rearrange the list or delete
+ * entries with the exception of DN_LAST
*/
-struct dn_heap_entry {
- dn_key key ; /* sorting key. Topmost element is smallest one */
- void *object ; /* object pointer */
+enum {
+ DN_NONE = 0,
+ DN_LINK = 1,
+ DN_FS,
+ DN_SCH,
+ DN_SCH_I,
+ DN_QUEUE,
+ DN_DELAY_LINE,
+ DN_PROFILE,
+ DN_FLOW, /* struct dn_flow */
+ DN_TEXT, /* opaque text is the object */
+
+ DN_CMD_CONFIG = 0x80, /* objects follow */
+ DN_CMD_DELETE, /* subtype + list of entries */
+ DN_CMD_GET, /* subtype + list of entries */
+ DN_CMD_FLUSH,
+ /* for compatibility with FreeBSD 7.2/8 */
+ DN_COMPAT_PIPE,
+ DN_COMPAT_QUEUE,
+ DN_GET_COMPAT,
+
+ /* special commands for emulation of sysctl variables */
+ DN_SYSCTL_GET,
+ DN_SYSCTL_SET,
+
+ DN_LAST,
} ;
-struct dn_heap {
- int size ;
- int elements ;
- int offset ; /* XXX if > 0 this is the offset of direct ptr to obj */
- struct dn_heap_entry *p ; /* really an array of "size" entries */
+enum { /* subtype for schedulers, flowset and the like */
+ DN_SCHED_UNKNOWN = 0,
+ DN_SCHED_FIFO = 1,
+ DN_SCHED_WF2QP = 2,
+ /* others are in individual modules */
} ;
-#ifdef _KERNEL
-/*
- * Packets processed by dummynet have an mbuf tag associated with
- * them that carries their dummynet state. This is used within
- * the dummynet code as well as outside when checking for special
- * processing requirements.
- * Note that the first part is the reinject info and is common to
- * other forms of packet reinjection.
- */
-struct dn_pkt_tag {
- struct ipfw_rule_ref rule; /* matching rule */
-
- /* second part, dummynet specific */
- int dn_dir; /* action when packet comes out. */
- /* see ip_fw_private.h */
-
- dn_key output_time; /* when the pkt is due for delivery */
- struct ifnet *ifp; /* interface, for ip_output */
- struct _ip6dn_args ip6opt; /* XXX ipv6 options */
+enum { /* user flags */
+ DN_HAVE_MASK = 0x0001, /* fs or sched has a mask */
+ DN_NOERROR = 0x0002, /* do not report errors */
+ DN_QHT_HASH = 0x0004, /* qht is a hash table */
+ DN_QSIZE_BYTES = 0x0008, /* queue size is in bytes */
+ DN_HAS_PROFILE = 0x0010, /* a link has a profile */
+ DN_IS_RED = 0x0020,
+ DN_IS_GENTLE_RED= 0x0040,
+ DN_PIPE_CMD = 0x1000, /* pipe config... */
};
-#endif /* _KERNEL */
/*
- * Overall structure of dummynet (with WF2Q+):
-
-In dummynet, packets are selected with the firewall rules, and passed
-to two different objects: PIPE or QUEUE.
-
-A QUEUE is just a queue with configurable size and queue management
-policy. It is also associated with a mask (to discriminate among
-different flows), a weight (used to give different shares of the
-bandwidth to different flows) and a "pipe", which essentially
-supplies the transmit clock for all queues associated with that
-pipe.
-
-A PIPE emulates a fixed-bandwidth link, whose bandwidth is
-configurable. The "clock" for a pipe can come from either an
-internal timer, or from the transmit interrupt of an interface.
-A pipe is also associated with one (or more, if masks are used)
-queue, where all packets for that pipe are stored.
-
-The bandwidth available on the pipe is shared by the queues
-associated with that pipe (only one in case the packet is sent
-to a PIPE) according to the WF2Q+ scheduling algorithm and the
-configured weights.
-
-In general, incoming packets are stored in the appropriate queue,
-which is then placed into one of a few heaps managed by a scheduler
-to decide when the packet should be extracted.
-The scheduler (a function called dummynet()) is run at every timer
-tick, and grabs queues from the head of the heaps when they are
-ready for processing.
-
-There are three data structures definining a pipe and associated queues:
-
- + dn_pipe, which contains the main configuration parameters related
- to delay and bandwidth;
- + dn_flow_set, which contains WF2Q+ configuration, flow
- masks, plr and RED configuration;
- + dn_flow_queue, which is the per-flow queue (containing the packets)
-
-Multiple dn_flow_set can be linked to the same pipe, and multiple
-dn_flow_queue can be linked to the same dn_flow_set.
-All data structures are linked in a linear list which is used for
-housekeeping purposes.
-
-During configuration, we create and initialize the dn_flow_set
-and dn_pipe structures (a dn_pipe also contains a dn_flow_set).
-
-At runtime: packets are sent to the appropriate dn_flow_set (either
-WFQ ones, or the one embedded in the dn_pipe for fixed-rate flows),
-which in turn dispatches them to the appropriate dn_flow_queue
-(created dynamically according to the masks).
-
-The transmit clock for fixed rate flows (ready_event()) selects the
-dn_flow_queue to be used to transmit the next packet. For WF2Q,
-wfq_ready_event() extract a pipe which in turn selects the right
-flow using a number of heaps defined into the pipe itself.
-
- *
+ * link template.
*/
+struct dn_link {
+ struct dn_id oid;
-/*
- * per flow queue. This contains the flow identifier, the queue
- * of packets, counters, and parameters used to support both RED and
- * WF2Q+.
- *
- * A dn_flow_queue is created and initialized whenever a packet for
- * a new flow arrives.
- */
-struct dn_flow_queue {
- struct dn_flow_queue *next ;
- struct ipfw_flow_id id ;
-
- struct mbuf *head, *tail ; /* queue of packets */
- u_int len ;
- u_int len_bytes ;
-
- /*
- * When we emulate MAC overheads, or channel unavailability due
- * to other traffic on a shared medium, we augment the packet at
- * the head of the queue with an 'extra_bits' field representsing
- * the additional delay the packet will be subject to:
- * extra_bits = bw*unavailable_time.
- * With large bandwidth and large delays, extra_bits (and also numbytes)
- * can become very large, so better play safe and use 64 bit
- */
- uint64_t numbytes ; /* credit for transmission (dynamic queues) */
- int64_t extra_bits; /* extra bits simulating unavailable channel */
-
- u_int64_t tot_pkts ; /* statistics counters */
- u_int64_t tot_bytes ;
- u_int32_t drops ;
-
- int hash_slot ; /* debugging/diagnostic */
-
- /* RED parameters */
- int avg ; /* average queue length est. (scaled) */
- int count ; /* arrivals since last RED drop */
- int random ; /* random value (scaled) */
- dn_key idle_time; /* start of queue idle time */
-
- /* WF2Q+ support */
- struct dn_flow_set *fs ; /* parent flow set */
- int heap_pos ; /* position (index) of struct in heap */
- dn_key sched_time ; /* current time when queue enters ready_heap */
-
- dn_key S,F ; /* start time, finish time */
/*
- * Setting F < S means the timestamp is invalid. We only need
- * to test this when the queue is empty.
+ * Userland sets bw and delay in bits/s and milliseconds.
+ * The kernel converts this back and forth to bits/tick and ticks.
+ * XXX what about burst ?
*/
+ int32_t link_nr;
+ int bandwidth; /* bit/s or bits/tick. */
+ int delay; /* ms and ticks */
+ uint64_t burst; /* scaled. bits*Hz XXX */
} ;
/*
- * flow_set descriptor. Contains the "template" parameters for the
- * queue configuration, and pointers to the hash table of dn_flow_queue's.
- *
- * The hash table is an array of lists -- we identify the slot by
- * hashing the flow-id, then scan the list looking for a match.
- * The size of the hash table (buckets) is configurable on a per-queue
- * basis.
- *
- * A dn_flow_set is created whenever a new queue or pipe is created (in the
- * latter case, the structure is located inside the struct dn_pipe).
+ * A flowset, which is a template for flows. Contains parameters
+ * from the command line: id, target scheduler, queue sizes, plr,
+ * flow masks, buckets for the flow hash, and possibly scheduler-
+ * specific parameters (weight, quantum and so on).
*/
-struct dn_flow_set {
- SLIST_ENTRY(dn_flow_set) next; /* linked list in a hash slot */
-
- u_short fs_nr ; /* flow_set number */
- u_short flags_fs;
-#define DN_HAVE_FLOW_MASK 0x0001
-#define DN_IS_RED 0x0002
-#define DN_IS_GENTLE_RED 0x0004
-#define DN_QSIZE_IS_BYTES 0x0008 /* queue size is measured in bytes */
-#define DN_NOERROR 0x0010 /* do not report ENOBUFS on drops */
-#define DN_HAS_PROFILE 0x0020 /* the pipe has a delay profile. */
-#define DN_IS_PIPE 0x4000
-#define DN_IS_QUEUE 0x8000
-
- struct dn_pipe *pipe ; /* pointer to parent pipe */
- u_short parent_nr ; /* parent pipe#, 0 if local to a pipe */
-
- int weight ; /* WFQ queue weight */
+struct dn_fs {
+ struct dn_id oid;
+ uint32_t fs_nr; /* the flowset number */
+ uint32_t flags; /* userland flags */
int qsize ; /* queue size in slots or bytes */
- int plr ; /* pkt loss rate (2^31-1 means 100%) */
+ int32_t plr; /* PLR, pkt loss rate (2^31-1 means 100%) */
+ uint32_t buckets; /* buckets used for the queue hash table */
struct ipfw_flow_id flow_mask ;
-
- /* hash table of queues onto this flow_set */
- int rq_size ; /* number of slots */
- int rq_elements ; /* active elements */
- struct dn_flow_queue **rq; /* array of rq_size entries */
-
- u_int32_t last_expired ; /* do not expire too frequently */
- int backlogged ; /* #active queues for this flowset */
-
- /* RED parameters */
+ uint32_t sched_nr; /* the scheduler we attach to */
+ /* generic scheduler parameters. Leave them at -1 if unset.
+ * Now we use 0: weight, 1: lmax, 2: priority
+ */
+ int par[4];
+
+ /* RED/GRED parameters.
+ * weight and probabilities are in the range 0..1 represented
+ * in fixed point arithmetic with SCALE_RED decimal bits.
+ */
#define SCALE_RED 16
#define SCALE(x) ( (x) << SCALE_RED )
#define SCALE_VAL(x) ( (x) >> SCALE_RED )
@@ -290,85 +157,107 @@ struct dn_flow_set {
int max_th ; /* maximum threshold for queue (scaled) */
int min_th ; /* minimum threshold for queue (scaled) */
int max_p ; /* maximum value for p_b (scaled) */
- u_int c_1 ; /* max_p/(max_th-min_th) (scaled) */
- u_int c_2 ; /* max_p*min_th/(max_th-min_th) (scaled) */
- u_int c_3 ; /* for GRED, (1-max_p)/max_th (scaled) */
- u_int c_4 ; /* for GRED, 1 - 2*max_p (scaled) */
- u_int * w_q_lookup ; /* lookup table for computing (1-w_q)^t */
- u_int lookup_depth ; /* depth of lookup table */
- int lookup_step ; /* granularity inside the lookup table */
- int lookup_weight ; /* equal to (1-w_q)^t / (1-w_q)^(t+1) */
- int avg_pkt_size ; /* medium packet size */
- int max_pkt_size ; /* max packet size */
+
};
-SLIST_HEAD(dn_flow_set_head, dn_flow_set);
/*
- * Pipe descriptor. Contains global parameters, delay-line queue,
- * and the flow_set used for fixed-rate queues.
- *
- * For WF2Q+ support it also has 3 heaps holding dn_flow_queue:
- * not_eligible_heap, for queues whose start time is higher
- * than the virtual time. Sorted by start time.
- * scheduler_heap, for queues eligible for scheduling. Sorted by
- * finish time.
- * idle_heap, all flows that are idle and can be removed. We
- * do that on each tick so we do not slow down too much
- * operations during forwarding.
- *
+ * dn_flow collects flow_id and stats for queues and scheduler
+ * instances, and is used to pass these info to userland.
+ * oid.type/oid.subtype describe the object, oid.id is number
+ * of the parent object.
*/
-struct dn_pipe { /* a pipe */
- SLIST_ENTRY(dn_pipe) next; /* linked list in a hash slot */
-
- int pipe_nr ; /* number */
- int bandwidth; /* really, bytes/tick. */
- int delay ; /* really, ticks */
-
- struct mbuf *head, *tail ; /* packets in delay line */
-
- /* WF2Q+ */
- struct dn_heap scheduler_heap ; /* top extract - key Finish time*/
- struct dn_heap not_eligible_heap; /* top extract- key Start time */
- struct dn_heap idle_heap ; /* random extract - key Start=Finish time */
-
- dn_key V ; /* virtual time */
- int sum; /* sum of weights of all active sessions */
-
- /* Same as in dn_flow_queue, numbytes can become large */
- int64_t numbytes; /* bits I can transmit (more or less). */
- uint64_t burst; /* burst size, scaled: bits * hz */
+struct dn_flow {
+ struct dn_id oid;
+ struct ipfw_flow_id fid;
+ uint64_t tot_pkts; /* statistics counters */
+ uint64_t tot_bytes;
+ uint32_t length; /* Queue lenght, in packets */
+ uint32_t len_bytes; /* Queue lenght, in bytes */
+ uint32_t drops;
+};
- dn_key sched_time ; /* time pipe was scheduled in ready_heap */
- dn_key idle_time; /* start of pipe idle time */
/*
- * When the tx clock come from an interface (if_name[0] != '\0'), its name
- * is stored below, whereas the ifp is filled when the rule is configured.
+ * Scheduler template, mostly indicating the name, number,
+ * sched_mask and buckets.
*/
- char if_name[IFNAMSIZ];
- struct ifnet *ifp ;
- int ready ; /* set if ifp != NULL and we got a signal from it */
+struct dn_sch {
+ struct dn_id oid;
+ uint32_t sched_nr; /* N, scheduler number */
+ uint32_t buckets; /* number of buckets for the instances */
+ uint32_t flags; /* have_mask, ... */
+
+ char name[16]; /* null terminated */
+ /* mask to select the appropriate scheduler instance */
+ struct ipfw_flow_id sched_mask; /* M */
+};
- struct dn_flow_set fs ; /* used with fixed-rate flows */
+/* A delay profile is attached to a link.
+ * Note that a profile, as any other object, cannot be longer than 2^16
+ */
+#define ED_MAX_SAMPLES_NO 1024
+struct dn_profile {
+ struct dn_id oid;
/* fields to simulate a delay profile */
-
#define ED_MAX_NAME_LEN 32
char name[ED_MAX_NAME_LEN];
+ int link_nr;
int loss_level;
- int samples_no;
- int *samples;
+ int bandwidth; // XXX use link bandwidth?
+ int samples_no; /* actual length of samples[] */
+ int samples[ED_MAX_SAMPLES_NO]; /* may be shorter */
};
-/* dn_pipe_max is used to pass pipe configuration from userland onto
- * kernel space and back
- */
-#define ED_MAX_SAMPLES_NO 1024
-struct dn_pipe_max {
- struct dn_pipe pipe;
- int samples[ED_MAX_SAMPLES_NO];
-};
-SLIST_HEAD(dn_pipe_head, dn_pipe);
+
+/*
+ * Overall structure of dummynet
+
+In dummynet, packets are selected with the firewall rules, and passed
+to two different objects: PIPE or QUEUE (bad name).
+
+A QUEUE defines a classifier, which groups packets into flows
+according to a 'mask', puts them into independent queues (one
+per flow) with configurable size and queue management policy,
+and passes flows to a scheduler:
+
+ (flow_mask|sched_mask) sched_mask
+ +---------+ weight Wx +-------------+
+ | |->-[flow]-->--| |-+
+ -->--| QUEUE x | ... | | |
+ | |->-[flow]-->--| SCHEDuler N | |
+ +---------+ | | |
+ ... | +--[LINK N]-->--
+ +---------+ weight Wy | | +--[LINK N]-->--
+ | |->-[flow]-->--| | |
+ -->--| QUEUE y | ... | | |
+ | |->-[flow]-->--| | |
+ +---------+ +-------------+ |
+ +-------------+
+
+Many QUEUE objects can connect to the same scheduler, each
+QUEUE object can have its own set of parameters.
+
+In turn, the SCHEDuler 'forks' multiple instances according
+to a 'sched_mask', each instance manages its own set of queues
+and transmits on a private instance of a configurable LINK.
+
+A PIPE is a simplified version of the above, where there
+is no flow_mask, and each scheduler instance handles a single queue.
+
+The following data structures (visible from userland) describe
+the objects used by dummynet:
+
+ + dn_link, contains the main configuration parameters related
+ to delay and bandwidth;
+ + dn_profile describes a delay profile;
+ + dn_flow describes the flow status (flow id, statistics)
+
+ + dn_sch describes a scheduler
+ + dn_fs describes a flowset (msk, weight, queue parameters)
+
+ *
+ */
#endif /* _IP_DUMMYNET_H */
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index 21a79ec..d357f18 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -487,24 +487,26 @@ struct ip_fw {
#define RULESIZE(rule) (sizeof(struct ip_fw) + \
((struct ip_fw *)(rule))->cmd_len * 4 - 4)
+#if 1 // moved to in.h
/*
* This structure is used as a flow mask and a flow id for various
* parts of the code.
*/
struct ipfw_flow_id {
- u_int32_t dst_ip;
- u_int32_t src_ip;
- u_int16_t dst_port;
- u_int16_t src_port;
- u_int8_t fib;
- u_int8_t proto;
- u_int8_t flags; /* protocol-specific flags */
+ uint32_t dst_ip;
+ uint32_t src_ip;
+ uint16_t dst_port;
+ uint16_t src_port;
+ uint8_t fib;
+ uint8_t proto;
+ uint8_t flags; /* protocol-specific flags */
uint8_t addr_type; /* 4 = ipv4, 6 = ipv6, 1=ether ? */
- struct in6_addr dst_ip6; /* could also store MAC addr! */
+ struct in6_addr dst_ip6;
struct in6_addr src_ip6;
- u_int32_t flow_id6;
- u_int32_t frag_id6;
+ uint32_t flow_id6;
+ uint32_t frag_id6;
};
+#endif
#define IS_IP6_FLOW_ID(id) ((id)->addr_type == 6)
diff --git a/sys/netinet/ip_gre.c b/sys/netinet/ip_gre.c
index 218cc6e..ae85e9f 100644
--- a/sys/netinet/ip_gre.c
+++ b/sys/netinet/ip_gre.c
@@ -17,13 +17,6 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/sys/netinet/ip_gre.h b/sys/netinet/ip_gre.h
index 1fb67d9..d2f3866 100644
--- a/sys/netinet/ip_gre.h
+++ b/sys/netinet/ip_gre.h
@@ -16,13 +16,6 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 8ffa01a..084bac0 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -199,6 +199,7 @@ static struct mtx ipqlock;
static void maxnipq_update(void);
static void ipq_zone_change(void *);
+static void ip_drain_locked(void);
SYSCTL_VNET_INT(_net_inet_ip, OID_AUTO, fragpackets, CTLFLAG_RD,
&VNET_NAME(nipq), 0,
@@ -368,6 +369,22 @@ ip_init(void)
netisr_register(&ip_nh);
}
+#ifdef VIMAGE
+void
+ip_destroy(void)
+{
+
+ /* Cleanup in_ifaddr hash table; should be empty. */
+ hashdestroy(V_in_ifaddrhashtbl, M_IFADDR, V_in_ifaddrhmask);
+
+ IPQ_LOCK();
+ ip_drain_locked();
+ IPQ_UNLOCK();
+
+ uma_zdestroy(V_ipq_zone);
+}
+#endif
+
void
ip_fini(void *xtp)
{
@@ -1237,23 +1254,32 @@ ip_slowtimo(void)
/*
* Drain off all datagram fragments.
*/
+static void
+ip_drain_locked(void)
+{
+ int i;
+
+ IPQ_LOCK_ASSERT();
+
+ for (i = 0; i < IPREASS_NHASH; i++) {
+ while(!TAILQ_EMPTY(&V_ipq[i])) {
+ IPSTAT_ADD(ips_fragdropped,
+ TAILQ_FIRST(&V_ipq[i])->ipq_nfrags);
+ ip_freef(&V_ipq[i], TAILQ_FIRST(&V_ipq[i]));
+ }
+ }
+}
+
void
ip_drain(void)
{
VNET_ITERATOR_DECL(vnet_iter);
- int i;
VNET_LIST_RLOCK_NOSLEEP();
IPQ_LOCK();
VNET_FOREACH(vnet_iter) {
CURVNET_SET(vnet_iter);
- for (i = 0; i < IPREASS_NHASH; i++) {
- while(!TAILQ_EMPTY(&V_ipq[i])) {
- IPSTAT_ADD(ips_fragdropped,
- TAILQ_FIRST(&V_ipq[i])->ipq_nfrags);
- ip_freef(&V_ipq[i], TAILQ_FIRST(&V_ipq[i]));
- }
- }
+ ip_drain_locked();
CURVNET_RESTORE();
}
IPQ_UNLOCK();
diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c
index debde7d..19035d2 100644
--- a/sys/netinet/ip_mroute.c
+++ b/sys/netinet/ip_mroute.c
@@ -114,8 +114,6 @@ __FBSDID("$FreeBSD$");
#include <machine/in_cksum.h>
-#include <security/mac/mac_framework.h>
-
#ifndef KTR_IPMF
#define KTR_IPMF KTR_INET
#endif
diff --git a/sys/netinet/ip_options.c b/sys/netinet/ip_options.c
index f95b3a0..50dcff6 100644
--- a/sys/netinet/ip_options.c
+++ b/sys/netinet/ip_options.c
@@ -65,8 +65,6 @@ __FBSDID("$FreeBSD$");
#include <sys/socketvar.h>
-#include <security/mac/mac_framework.h>
-
static int ip_dosourceroute = 0;
SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW,
&ip_dosourceroute, 0, "Enable forwarding source routed IP packets");
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index d041dd3..389ad6e 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -212,6 +212,9 @@ int ip_fragment(struct ip *ip, struct mbuf **m_frag, int mtu,
u_long if_hwassist_flags, int sw_csum);
void ip_forward(struct mbuf *m, int srcrt);
void ip_init(void);
+#ifdef VIMAGE
+void ip_destroy(void);
+#endif
extern int
(*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *,
struct ip_moptions *);
diff --git a/sys/netinet/ipfw/dn_heap.c b/sys/netinet/ipfw/dn_heap.c
new file mode 100644
index 0000000..ec9cb6c
--- /dev/null
+++ b/sys/netinet/ipfw/dn_heap.c
@@ -0,0 +1,550 @@
+/*-
+ * Copyright (c) 1998-2002,2010 Luigi Rizzo, Universita` di Pisa
+ * 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.
+ */
+
+/*
+ * Binary heap and hash tables, used in dummynet
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#ifdef _KERNEL
+__FBSDID("$FreeBSD$");
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <netinet/ipfw/dn_heap.h>
+#ifndef log
+#define log(x, arg...)
+#endif
+
+#else /* !_KERNEL */
+
+#include <stdio.h>
+#include <dn_test.h>
+#include <strings.h>
+#include <stdlib.h>
+
+#include "dn_heap.h"
+#define log(x, arg...) fprintf(stderr, ## arg)
+#define panic(x...) fprintf(stderr, ## x), exit(1)
+#define MALLOC_DEFINE(a, b, c)
+static void *my_malloc(int s) { return malloc(s); }
+static void my_free(void *p) { free(p); }
+#define malloc(s, t, w) my_malloc(s)
+#define free(p, t) my_free(p)
+#endif /* !_KERNEL */
+
+MALLOC_DEFINE(M_DN_HEAP, "dummynet", "dummynet heap");
+
+/*
+ * Heap management functions.
+ *
+ * In the heap, first node is element 0. Children of i are 2i+1 and 2i+2.
+ * Some macros help finding parent/children so we can optimize them.
+ *
+ * heap_init() is called to expand the heap when needed.
+ * Increment size in blocks of 16 entries.
+ * Returns 1 on error, 0 on success
+ */
+#define HEAP_FATHER(x) ( ( (x) - 1 ) / 2 )
+#define HEAP_LEFT(x) ( (x)+(x) + 1 )
+#define HEAP_SWAP(a, b, buffer) { buffer = a ; a = b ; b = buffer ; }
+#define HEAP_INCREMENT 15
+
+static int
+heap_resize(struct dn_heap *h, unsigned int new_size)
+{
+ struct dn_heap_entry *p;
+
+ if (h->size >= new_size ) /* have enough room */
+ return 0;
+#if 1 /* round to the next power of 2 */
+ new_size |= new_size >> 1;
+ new_size |= new_size >> 2;
+ new_size |= new_size >> 4;
+ new_size |= new_size >> 8;
+ new_size |= new_size >> 16;
+#else
+ new_size = (new_size + HEAP_INCREMENT ) & ~HEAP_INCREMENT;
+#endif
+ p = malloc(new_size * sizeof(*p), M_DN_HEAP, M_NOWAIT);
+ if (p == NULL) {
+ printf("--- %s, resize %d failed\n", __func__, new_size );
+ return 1; /* error */
+ }
+ if (h->size > 0) {
+ bcopy(h->p, p, h->size * sizeof(*p) );
+ free(h->p, M_DN_HEAP);
+ }
+ h->p = p;
+ h->size = new_size;
+ return 0;
+}
+
+int
+heap_init(struct dn_heap *h, int size, int ofs)
+{
+ if (heap_resize(h, size))
+ return 1;
+ h->elements = 0;
+ h->ofs = ofs;
+ return 0;
+}
+
+/*
+ * Insert element in heap. Normally, p != NULL, we insert p in
+ * a new position and bubble up. If p == NULL, then the element is
+ * already in place, and key is the position where to start the
+ * bubble-up.
+ * Returns 1 on failure (cannot allocate new heap entry)
+ *
+ * If ofs > 0 the position (index, int) of the element in the heap is
+ * also stored in the element itself at the given offset in bytes.
+ */
+#define SET_OFFSET(h, i) do { \
+ if (h->ofs > 0) \
+ *((int32_t *)((char *)(h->p[i].object) + h->ofs)) = i; \
+ } while (0)
+/*
+ * RESET_OFFSET is used for sanity checks. It sets ofs
+ * to an invalid value.
+ */
+#define RESET_OFFSET(h, i) do { \
+ if (h->ofs > 0) \
+ *((int32_t *)((char *)(h->p[i].object) + h->ofs)) = -16; \
+ } while (0)
+
+int
+heap_insert(struct dn_heap *h, uint64_t key1, void *p)
+{
+ int son = h->elements;
+
+ //log("%s key %llu p %p\n", __FUNCTION__, key1, p);
+ if (p == NULL) { /* data already there, set starting point */
+ son = key1;
+ } else { /* insert new element at the end, possibly resize */
+ son = h->elements;
+ if (son == h->size) /* need resize... */
+ // XXX expand by 16 or so
+ if (heap_resize(h, h->elements+16) )
+ return 1; /* failure... */
+ h->p[son].object = p;
+ h->p[son].key = key1;
+ h->elements++;
+ }
+ /* make sure that son >= father along the path */
+ while (son > 0) {
+ int father = HEAP_FATHER(son);
+ struct dn_heap_entry tmp;
+
+ if (DN_KEY_LT( h->p[father].key, h->p[son].key ) )
+ break; /* found right position */
+ /* son smaller than father, swap and repeat */
+ HEAP_SWAP(h->p[son], h->p[father], tmp);
+ SET_OFFSET(h, son);
+ son = father;
+ }
+ SET_OFFSET(h, son);
+ return 0;
+}
+
+/*
+ * remove top element from heap, or obj if obj != NULL
+ */
+void
+heap_extract(struct dn_heap *h, void *obj)
+{
+ int child, father, max = h->elements - 1;
+
+ if (max < 0) {
+ printf("--- %s: empty heap 0x%p\n", __FUNCTION__, h);
+ return;
+ }
+ if (obj == NULL)
+ father = 0; /* default: move up smallest child */
+ else { /* extract specific element, index is at offset */
+ if (h->ofs <= 0)
+ panic("%s: extract from middle not set on %p\n",
+ __FUNCTION__, h);
+ father = *((int *)((char *)obj + h->ofs));
+ if (father < 0 || father >= h->elements) {
+ panic("%s: father %d out of bound 0..%d\n",
+ __FUNCTION__, father, h->elements);
+ }
+ }
+ /*
+ * below, father is the index of the empty element, which
+ * we replace at each step with the smallest child until we
+ * reach the bottom level.
+ */
+ // XXX why removing RESET_OFFSET increases runtime by 10% ?
+ RESET_OFFSET(h, father);
+ while ( (child = HEAP_LEFT(father)) <= max ) {
+ if (child != max &&
+ DN_KEY_LT(h->p[child+1].key, h->p[child].key) )
+ child++; /* take right child, otherwise left */
+ h->p[father] = h->p[child];
+ SET_OFFSET(h, father);
+ father = child;
+ }
+ h->elements--;
+ if (father != max) {
+ /*
+ * Fill hole with last entry and bubble up,
+ * reusing the insert code
+ */
+ h->p[father] = h->p[max];
+ heap_insert(h, father, NULL);
+ }
+}
+
+#if 0
+/*
+ * change object position and update references
+ * XXX this one is never used!
+ */
+static void
+heap_move(struct dn_heap *h, uint64_t new_key, void *object)
+{
+ int temp, i, max = h->elements-1;
+ struct dn_heap_entry *p, buf;
+
+ if (h->ofs <= 0)
+ panic("cannot move items on this heap");
+ p = h->p; /* shortcut */
+
+ i = *((int *)((char *)object + h->ofs));
+ if (DN_KEY_LT(new_key, p[i].key) ) { /* must move up */
+ p[i].key = new_key;
+ for (; i>0 &&
+ DN_KEY_LT(new_key, p[(temp = HEAP_FATHER(i))].key);
+ i = temp ) { /* bubble up */
+ HEAP_SWAP(p[i], p[temp], buf);
+ SET_OFFSET(h, i);
+ }
+ } else { /* must move down */
+ p[i].key = new_key;
+ while ( (temp = HEAP_LEFT(i)) <= max ) {
+ /* found left child */
+ if (temp != max &&
+ DN_KEY_LT(p[temp+1].key, p[temp].key))
+ temp++; /* select child with min key */
+ if (DN_KEY_LT(>p[temp].key, new_key)) {
+ /* go down */
+ HEAP_SWAP(p[i], p[temp], buf);
+ SET_OFFSET(h, i);
+ } else
+ break;
+ i = temp;
+ }
+ }
+ SET_OFFSET(h, i);
+}
+#endif /* heap_move, unused */
+
+/*
+ * heapify() will reorganize data inside an array to maintain the
+ * heap property. It is needed when we delete a bunch of entries.
+ */
+static void
+heapify(struct dn_heap *h)
+{
+ int i;
+
+ for (i = 0; i < h->elements; i++ )
+ heap_insert(h, i , NULL);
+}
+
+int
+heap_scan(struct dn_heap *h, int (*fn)(void *, uintptr_t),
+ uintptr_t arg)
+{
+ int i, ret, found;
+
+ for (i = found = 0 ; i < h->elements ;) {
+ ret = fn(h->p[i].object, arg);
+ if (ret & HEAP_SCAN_DEL) {
+ h->elements-- ;
+ h->p[i] = h->p[h->elements] ;
+ found++ ;
+ } else
+ i++ ;
+ if (ret & HEAP_SCAN_END)
+ break;
+ }
+ if (found)
+ heapify(h);
+ return found;
+}
+
+/*
+ * cleanup the heap and free data structure
+ */
+void
+heap_free(struct dn_heap *h)
+{
+ if (h->size >0 )
+ free(h->p, M_DN_HEAP);
+ bzero(h, sizeof(*h) );
+}
+
+/*
+ * hash table support.
+ */
+
+struct dn_ht {
+ int buckets; /* how many buckets, really buckets - 1*/
+ int entries; /* how many entries */
+ int ofs; /* offset of link field */
+ uint32_t (*hash)(uintptr_t, int, void *arg);
+ int (*match)(void *_el, uintptr_t key, int, void *);
+ void *(*new)(uintptr_t, int, void *);
+ void **ht; /* bucket heads */
+};
+/*
+ * Initialize, allocating bucket pointers inline.
+ * Recycle previous record if possible.
+ * If the 'new' function is not supplied, we assume that the
+ * key passed to ht_find is the same object to be stored in.
+ */
+struct dn_ht *
+dn_ht_init(struct dn_ht *ht, int buckets, int ofs,
+ uint32_t (*h)(uintptr_t, int, void *),
+ int (*match)(void *, uintptr_t, int, void *),
+ void *(*new)(uintptr_t, int, void *))
+{
+ int l;
+
+ /*
+ * Notes about rounding bucket size to a power of two.
+ * Given the original bucket size, we compute the nearest lower and
+ * higher power of two, minus 1 (respectively b_min and b_max) because
+ * this value will be used to do an AND with the index returned
+ * by hash function.
+ * To choice between these two values, the original bucket size is
+ * compared with b_min. If the original size is greater than 4/3 b_min,
+ * we round the bucket size to b_max, else to b_min.
+ * This ratio try to round to the nearest power of two, advantaging
+ * the greater size if the different between two power is relatively
+ * big.
+ * Rounding the bucket size to a power of two avoid the use of
+ * module when calculating the correct bucket.
+ * The ht->buckets variable store the bucket size - 1 to simply
+ * do an AND between the index returned by hash function and ht->bucket
+ * instead of a module.
+ */
+ int b_min; /* min buckets */
+ int b_max; /* max buckets */
+ int b_ori; /* original buckets */
+
+ if (h == NULL || match == NULL) {
+ printf("--- missing hash or match function");
+ return NULL;
+ }
+ if (buckets < 1 || buckets > 65536)
+ return NULL;
+
+ b_ori = buckets;
+ /* calculate next power of 2, - 1*/
+ buckets |= buckets >> 1;
+ buckets |= buckets >> 2;
+ buckets |= buckets >> 4;
+ buckets |= buckets >> 8;
+ buckets |= buckets >> 16;
+
+ b_max = buckets; /* Next power */
+ b_min = buckets >> 1; /* Previous power */
+
+ /* Calculate the 'nearest' bucket size */
+ if (b_min * 4000 / 3000 < b_ori)
+ buckets = b_max;
+ else
+ buckets = b_min;
+
+ if (ht) { /* see if we can reuse */
+ if (buckets <= ht->buckets) {
+ ht->buckets = buckets;
+ } else {
+ /* free pointers if not allocated inline */
+ if (ht->ht != (void *)(ht + 1))
+ free(ht->ht, M_DN_HEAP);
+ free(ht, M_DN_HEAP);
+ ht = NULL;
+ }
+ }
+ if (ht == NULL) {
+ /* Allocate buckets + 1 entries because buckets is use to
+ * do the AND with the index returned by hash function
+ */
+ l = sizeof(*ht) + (buckets + 1) * sizeof(void **);
+ ht = malloc(l, M_DN_HEAP, M_NOWAIT | M_ZERO);
+ }
+ if (ht) {
+ ht->ht = (void **)(ht + 1);
+ ht->buckets = buckets;
+ ht->ofs = ofs;
+ ht->hash = h;
+ ht->match = match;
+ ht->new = new;
+ }
+ return ht;
+}
+
+/* dummy callback for dn_ht_free to unlink all */
+static int
+do_del(void *obj, void *arg)
+{
+ return DNHT_SCAN_DEL;
+}
+
+void
+dn_ht_free(struct dn_ht *ht, int flags)
+{
+ if (ht == NULL)
+ return;
+ if (flags & DNHT_REMOVE) {
+ (void)dn_ht_scan(ht, do_del, NULL);
+ } else {
+ if (ht->ht && ht->ht != (void *)(ht + 1))
+ free(ht->ht, M_DN_HEAP);
+ free(ht, M_DN_HEAP);
+ }
+}
+
+int
+dn_ht_entries(struct dn_ht *ht)
+{
+ return ht ? ht->entries : 0;
+}
+
+/* lookup and optionally create or delete element */
+void *
+dn_ht_find(struct dn_ht *ht, uintptr_t key, int flags, void *arg)
+{
+ int i;
+ void **pp, *p;
+
+ if (ht == NULL) /* easy on an empty hash */
+ return NULL;
+ i = (ht->buckets == 1) ? 0 :
+ (ht->hash(key, flags, arg) & ht->buckets);
+
+ for (pp = &ht->ht[i]; (p = *pp); pp = (void **)((char *)p + ht->ofs)) {
+ if (flags & DNHT_MATCH_PTR) {
+ if (key == (uintptr_t)p)
+ break;
+ } else if (ht->match(p, key, flags, arg)) /* found match */
+ break;
+ }
+ if (p) {
+ if (flags & DNHT_REMOVE) {
+ /* link in the next element */
+ *pp = *(void **)((char *)p + ht->ofs);
+ *(void **)((char *)p + ht->ofs) = NULL;
+ ht->entries--;
+ }
+ } else if (flags & DNHT_INSERT) {
+ // printf("%s before calling new, bucket %d ofs %d\n",
+ // __FUNCTION__, i, ht->ofs);
+ p = ht->new ? ht->new(key, flags, arg) : (void *)key;
+ // printf("%s new returns %p\n", __FUNCTION__, p);
+ if (p) {
+ ht->entries++;
+ *(void **)((char *)p + ht->ofs) = ht->ht[i];
+ ht->ht[i] = p;
+ }
+ }
+ return p;
+}
+
+/*
+ * do a scan with the option to delete the object. Extract next before
+ * running the callback because the element may be destroyed there.
+ */
+int
+dn_ht_scan(struct dn_ht *ht, int (*fn)(void *, void *), void *arg)
+{
+ int i, ret, found = 0;
+ void **curp, *cur, *next;
+
+ if (ht == NULL || fn == NULL)
+ return 0;
+ for (i = 0; i <= ht->buckets; i++) {
+ curp = &ht->ht[i];
+ while ( (cur = *curp) != NULL) {
+ next = *(void **)((char *)cur + ht->ofs);
+ ret = fn(cur, arg);
+ if (ret & DNHT_SCAN_DEL) {
+ found++;
+ ht->entries--;
+ *curp = next;
+ } else {
+ curp = (void **)((char *)cur + ht->ofs);
+ }
+ if (ret & DNHT_SCAN_END)
+ return found;
+ }
+ }
+ return found;
+}
+
+/*
+ * Similar to dn_ht_scan(), except thah the scan is performed only
+ * in the bucket 'bucket'. The function returns a correct bucket number if
+ * the original is invalid
+ */
+int
+dn_ht_scan_bucket(struct dn_ht *ht, int *bucket, int (*fn)(void *, void *),
+ void *arg)
+{
+ int i, ret, found = 0;
+ void **curp, *cur, *next;
+
+ if (ht == NULL || fn == NULL)
+ return 0;
+ if (*bucket > ht->buckets)
+ *bucket = 0;
+ i = *bucket;
+
+ curp = &ht->ht[i];
+ while ( (cur = *curp) != NULL) {
+ next = *(void **)((char *)cur + ht->ofs);
+ ret = fn(cur, arg);
+ if (ret & DNHT_SCAN_DEL) {
+ found++;
+ ht->entries--;
+ *curp = next;
+ } else {
+ curp = (void **)((char *)cur + ht->ofs);
+ }
+ if (ret & DNHT_SCAN_END)
+ return found;
+ }
+ return found;
+}
+
diff --git a/sys/netinet/ipfw/dn_heap.h b/sys/netinet/ipfw/dn_heap.h
new file mode 100644
index 0000000..a663f91
--- /dev/null
+++ b/sys/netinet/ipfw/dn_heap.h
@@ -0,0 +1,191 @@
+/*-
+ * Copyright (c) 1998-2010 Luigi Rizzo, Universita` di Pisa
+ * 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.
+ */
+
+/*
+ * Binary heap and hash tables, header file
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IP_DN_HEAP_H
+#define _IP_DN_HEAP_H
+
+#define DN_KEY_LT(a,b) ((int64_t)((a)-(b)) < 0)
+#define DN_KEY_LEQ(a,b) ((int64_t)((a)-(b)) <= 0)
+
+/*
+ * This module implements a binary heap supporting random extraction.
+ *
+ * A heap entry contains an uint64_t key and a pointer to object.
+ * DN_KEY_LT(a,b) returns true if key 'a' is smaller than 'b'
+ *
+ * The heap is a struct dn_heap plus a dynamically allocated
+ * array of dn_heap_entry entries. 'size' represents the size of
+ * the array, 'elements' count entries in use. The topmost
+ * element has the smallest key.
+ * The heap supports ordered insert, and extract from the top.
+ * To extract an object from the middle of the heap, we the object
+ * must reserve an 'int32_t' to store the position of the object
+ * in the heap itself, and the location of this field must be
+ * passed as an argument to heap_init() -- use -1 if the feature
+ * is not used.
+ */
+struct dn_heap_entry {
+ uint64_t key; /* sorting key, smallest comes first */
+ void *object; /* object pointer */
+};
+
+struct dn_heap {
+ int size; /* the size of the array */
+ int elements; /* elements in use */
+ int ofs; /* offset in the object of heap index */
+ struct dn_heap_entry *p; /* array of "size" entries */
+};
+
+enum {
+ HEAP_SCAN_DEL = 1,
+ HEAP_SCAN_END = 2,
+};
+
+/*
+ * heap_init() reinitializes the heap setting the size and the offset
+ * of the index for random extraction (use -1 if not used).
+ * The 'elements' counter is set to 0.
+ *
+ * SET_HEAP_OFS() indicates where, in the object, is stored the index
+ * for random extractions from the heap.
+ *
+ * heap_free() frees the memory associated to a heap.
+ *
+ * heap_insert() adds a key-pointer pair to the heap
+ *
+ * HEAP_TOP() returns a pointer to the top element of the heap,
+ * but makes no checks on its existance (XXX should we change ?)
+ *
+ * heap_extract() removes the entry at the top, returing the pointer.
+ * (the key should have been read before).
+ *
+ * heap_scan() invokes a callback on each entry of the heap.
+ * The callback can return a combination of HEAP_SCAN_DEL and
+ * HEAP_SCAN_END. HEAP_SCAN_DEL means the current element must
+ * be removed, and HEAP_SCAN_END means to terminate the scan.
+ * heap_scan() returns the number of elements removed.
+ * Because the order is not guaranteed, we should use heap_scan()
+ * only as a last resort mechanism.
+ */
+#define HEAP_TOP(h) ((h)->p)
+#define SET_HEAP_OFS(h, n) do { (h)->ofs = n; } while (0)
+int heap_init(struct dn_heap *h, int size, int ofs);
+int heap_insert(struct dn_heap *h, uint64_t key1, void *p);
+void heap_extract(struct dn_heap *h, void *obj);
+void heap_free(struct dn_heap *h);
+int heap_scan(struct dn_heap *, int (*)(void *, uintptr_t), uintptr_t);
+
+/*------------------------------------------------------
+ * This module implements a generic hash table with support for
+ * running callbacks on the entire table. To avoid allocating
+ * memory during hash table operations, objects must reserve
+ * space for a link field. XXX if the heap is moderately full,
+ * an SLIST suffices, and we can tolerate the cost of a hash
+ * computation on each removal.
+ *
+ * dn_ht_init() initializes the table, setting the number of
+ * buckets, the offset of the link field, the main callbacks.
+ * Callbacks are:
+ *
+ * hash(key, flags, arg) called to return a bucket index.
+ * match(obj, key, flags, arg) called to determine if key
+ * matches the current 'obj' in the heap
+ * new(key, flags, arg) optional, used to allocate a new
+ * object during insertions.
+ *
+ * dn_ht_free() frees the heap or unlink elements.
+ * DNHT_REMOVE unlink elements, 0 frees the heap.
+ * You need two calls to do both.
+ *
+ * dn_ht_find() is the main lookup function, which can also be
+ * used to insert or delete elements in the hash table.
+ * The final 'arg' is passed to all callbacks.
+ *
+ * dn_ht_scan() is used to invoke a callback on all entries of
+ * the heap, or possibly on just one bucket. The callback
+ * is invoked with a pointer to the object, and must return
+ * one of DNHT_SCAN_DEL or DNHT_SCAN_END to request the
+ * removal of the object from the heap and the end of the
+ * scan, respectively.
+ *
+ * dn_ht_scan_bucket() is similar to dn_ht_scan(), except that it scans
+ * only the specific bucket of the table. The bucket is a in-out
+ * parameter and return a valid bucket number if the original
+ * is invalid.
+ *
+ * A combination of flags can be used to modify the operation
+ * of the dn_ht_find(), and of the callbacks:
+ *
+ * DNHT_KEY_IS_OBJ means the key is the object pointer.
+ * It is usally of interest for the hash and match functions.
+ *
+ * DNHT_MATCH_PTR during a lookup, match pointers instead
+ * of calling match(). Normally used when removing specific
+ * entries. Does not imply KEY_IS_OBJ as the latter _is_ used
+ * by the match function.
+ *
+ * DNHT_INSERT insert the element if not found.
+ * Calls new() to allocates a new object unless
+ * DNHT_KEY_IS_OBJ is set.
+ *
+ * DNHT_UNIQUE only insert if object not found.
+ * XXX should it imply DNHT_INSERT ?
+ *
+ * DNHT_REMOVE remove objects if we find them.
+ */
+struct dn_ht; /* should be opaque */
+
+struct dn_ht *dn_ht_init(struct dn_ht *, int buckets, int ofs,
+ uint32_t (*hash)(uintptr_t, int, void *),
+ int (*match)(void *, uintptr_t, int, void *),
+ void *(*new)(uintptr_t, int, void *));
+void dn_ht_free(struct dn_ht *, int flags);
+
+void *dn_ht_find(struct dn_ht *, uintptr_t, int, void *);
+int dn_ht_scan(struct dn_ht *, int (*)(void *, void *), void *);
+int dn_ht_scan_bucket(struct dn_ht *, int * , int (*)(void *, void *), void *);
+int dn_ht_entries(struct dn_ht *);
+
+enum { /* flags values.
+ * first two are returned by the scan callback to indicate
+ * to delete the matching element or to end the scan
+ */
+ DNHT_SCAN_DEL = 0x0001,
+ DNHT_SCAN_END = 0x0002,
+ DNHT_KEY_IS_OBJ = 0x0004, /* key is the obj pointer */
+ DNHT_MATCH_PTR = 0x0008, /* match by pointer, not match() */
+ DNHT_INSERT = 0x0010, /* insert if not found */
+ DNHT_UNIQUE = 0x0020, /* report error if already there */
+ DNHT_REMOVE = 0x0040, /* remove on find or dn_ht_free */
+};
+
+#endif /* _IP_DN_HEAP_H */
diff --git a/sys/netinet/ipfw/dn_sched.h b/sys/netinet/ipfw/dn_sched.h
new file mode 100644
index 0000000..b1c1c8f
--- /dev/null
+++ b/sys/netinet/ipfw/dn_sched.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2010 Riccardo Panicucci, Luigi Rizzo, Universita` di Pisa
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * The API to write a packet scheduling algorithm for dummynet.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DN_SCHED_H
+#define _DN_SCHED_H
+
+#define DN_MULTIQUEUE 0x01
+/*
+ * Descriptor for a scheduling algorithm.
+ * Contains all function pointers for a given scheduler
+ * This is typically created when a module is loaded, and stored
+ * in a global list of schedulers.
+ */
+struct dn_alg {
+ uint32_t type; /* the scheduler type */
+ const char *name; /* scheduler name */
+ uint32_t flags; /* DN_MULTIQUEUE if supports multiple queues */
+
+ /*
+ * The following define the size of 3 optional data structures
+ * that may need to be allocated at runtime, and are appended
+ * to each of the base data structures: scheduler, sched.inst,
+ * and queue. We don't have a per-flowset structure.
+ */
+ /* + parameters attached to the template, e.g.
+ * default queue sizes, weights, quantum size, and so on;
+ */
+ size_t schk_datalen;
+
+ /* + per-instance parameters, such as timestamps,
+ * containers for queues, etc;
+ */
+ size_t si_datalen;
+
+ size_t q_datalen; /* per-queue parameters (e.g. S,F) */
+
+ /*
+ * Methods implemented by the scheduler:
+ * enqueue enqueue packet 'm' on scheduler 's', queue 'q'.
+ * q is NULL for !MULTIQUEUE.
+ * Return 0 on success, 1 on drop (packet consumed anyways).
+ *
+ * dequeue Called when scheduler instance 's' can
+ * dequeue a packet. Return NULL if none are available.
+ * XXX what about non work-conserving ?
+ *
+ * config called on 'sched X config ...', normally writes
+ * in the area of size sch_arg
+ *
+ * destroy called on 'sched delete', frees everything
+ * in sch_arg (other parts are handled by more specific
+ * functions)
+ *
+ * new_sched called when a new instance is created, e.g.
+ * to create the local queue for !MULTIQUEUE, set V or
+ * copy parameters for WFQ, and so on.
+ *
+ * free_sched called when deleting an instance, cleans
+ * extra data in the per-instance area.
+ *
+ * new_fsk called when a flowset is linked to a scheduler,
+ * e.g. to validate parameters such as weights etc.
+ * free_fsk when a flowset is unlinked from a scheduler.
+ * (probably unnecessary)
+ *
+ * new_queue called to set the per-queue parameters,
+ * e.g. S and F, adjust sum of weights in the parent, etc.
+ * If the queue has packets in it, add them to the scheduler
+ * as well.
+ *
+ * free_queue actions related to a queue removal, e.g. undo
+ * all the above. If the queue has data in it, also remove
+ * from the scheduler. This can e.g. happen during a reconfigure.
+ */
+ int (*enqueue)(struct dn_sch_inst *, struct dn_queue *,
+ struct mbuf *);
+ struct mbuf * (*dequeue)(struct dn_sch_inst *);
+
+ int (*config)(struct dn_schk *);
+ int (*destroy)(struct dn_schk*);
+ int (*new_sched)(struct dn_sch_inst *);
+ int (*free_sched)(struct dn_sch_inst *);
+ int (*new_fsk)(struct dn_fsk *f);
+ int (*free_fsk)(struct dn_fsk *f);
+ int (*new_queue)(struct dn_queue *q);
+ int (*free_queue)(struct dn_queue *q);
+
+ /* run-time fields */
+ int ref_count; /* XXX number of instances in the system */
+ SLIST_ENTRY(dn_alg) next; /* Next scheduler in the list */
+};
+
+/* MSVC does not support initializers so we need this ugly macro */
+#ifdef _WIN32
+#define _SI(fld)
+#else
+#define _SI(fld) fld
+#endif
+
+/*
+ * Additionally, dummynet exports some functions and macros
+ * to be used by schedulers:
+ */
+
+void dn_free_pkts(struct mbuf *mnext);
+int dn_enqueue(struct dn_queue *q, struct mbuf* m, int drop);
+/* bound a variable between min and max */
+int ipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg);
+
+/*
+ * Extract the head of a queue, update stats. Must be the very last
+ * thing done on a dequeue as the queue itself may go away.
+ */
+static __inline struct mbuf*
+dn_dequeue(struct dn_queue *q)
+{
+ struct mbuf *m = q->mq.head;
+ if (m == NULL)
+ return NULL;
+ q->mq.head = m->m_nextpkt;
+ q->ni.length--;
+ q->ni.len_bytes -= m->m_pkthdr.len;
+ if (q->_si) {
+ q->_si->ni.length--;
+ q->_si->ni.len_bytes -= m->m_pkthdr.len;
+ }
+ if (q->ni.length == 0) /* queue is now idle */
+ q->q_time = dn_cfg.curr_time;
+ return m;
+}
+
+int dn_sched_modevent(module_t mod, int cmd, void *arg);
+
+#define DECLARE_DNSCHED_MODULE(name, dnsched) \
+ static moduledata_t name##_mod = { \
+ #name, dn_sched_modevent, dnsched \
+ }; \
+ DECLARE_MODULE(name, name##_mod, \
+ SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); \
+ MODULE_DEPEND(name, dummynet, 3, 3, 3);
+#endif /* _DN_SCHED_H */
diff --git a/sys/netinet/ipfw/dn_sched_fifo.c b/sys/netinet/ipfw/dn_sched_fifo.c
new file mode 100644
index 0000000..0bb3800
--- /dev/null
+++ b/sys/netinet/ipfw/dn_sched_fifo.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2010 Riccardo Panicucci, Universita` di Pisa
+ * 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$
+ */
+
+#ifdef _KERNEL
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <net/if.h> /* IFNAMSIZ */
+#include <netinet/in.h>
+#include <netinet/ip_var.h> /* ipfw_rule_ref */
+#include <netinet/ip_fw.h> /* flow_id */
+#include <netinet/ip_dummynet.h>
+#include <netinet/ipfw/dn_heap.h>
+#include <netinet/ipfw/ip_dn_private.h>
+#include <netinet/ipfw/dn_sched.h>
+#else
+#include <dn_test.h>
+#endif
+
+/*
+ * This file implements a FIFO scheduler for a single queue.
+ * The queue is allocated as part of the scheduler instance,
+ * and there is a single flowset is in the template which stores
+ * queue size and policy.
+ * Enqueue and dequeue use the default library functions.
+ */
+static int
+fifo_enqueue(struct dn_sch_inst *si, struct dn_queue *q, struct mbuf *m)
+{
+ /* XXX if called with q != NULL and m=NULL, this is a
+ * re-enqueue from an existing scheduler, which we should
+ * handle.
+ */
+ return dn_enqueue((struct dn_queue *)(si+1), m, 0);
+}
+
+static struct mbuf *
+fifo_dequeue(struct dn_sch_inst *si)
+{
+ return dn_dequeue((struct dn_queue *)(si + 1));
+}
+
+static int
+fifo_new_sched(struct dn_sch_inst *si)
+{
+ /* This scheduler instance contains the queue */
+ struct dn_queue *q = (struct dn_queue *)(si + 1);
+
+ set_oid(&q->ni.oid, DN_QUEUE, sizeof(*q));
+ q->_si = si;
+ q->fs = si->sched->fs;
+ return 0;
+}
+
+static int
+fifo_free_sched(struct dn_sch_inst *si)
+{
+ struct dn_queue *q = (struct dn_queue *)(si + 1);
+ dn_free_pkts(q->mq.head);
+ bzero(q, sizeof(*q));
+ return 0;
+}
+
+/*
+ * FIFO scheduler descriptor
+ * contains the type of the scheduler, the name, the size of extra
+ * data structures, and function pointers.
+ */
+static struct dn_alg fifo_desc = {
+ _SI( .type = ) DN_SCHED_FIFO,
+ _SI( .name = ) "FIFO",
+ _SI( .flags = ) 0,
+
+ _SI( .schk_datalen = ) 0,
+ _SI( .si_datalen = ) sizeof(struct dn_queue),
+ _SI( .q_datalen = ) 0,
+
+ _SI( .enqueue = ) fifo_enqueue,
+ _SI( .dequeue = ) fifo_dequeue,
+ _SI( .config = ) NULL,
+ _SI( .destroy = ) NULL,
+ _SI( .new_sched = ) fifo_new_sched,
+ _SI( .free_sched = ) fifo_free_sched,
+ _SI( .new_fsk = ) NULL,
+ _SI( .free_fsk = ) NULL,
+ _SI( .new_queue = ) NULL,
+ _SI( .free_queue = ) NULL,
+};
+
+DECLARE_DNSCHED_MODULE(dn_fifo, &fifo_desc);
diff --git a/sys/netinet/ipfw/dn_sched_qfq.c b/sys/netinet/ipfw/dn_sched_qfq.c
new file mode 100644
index 0000000..44555ee
--- /dev/null
+++ b/sys/netinet/ipfw/dn_sched_qfq.c
@@ -0,0 +1,864 @@
+/*
+ * Copyright (c) 2010 Fabio Checconi, Luigi Rizzo, Paolo Valente
+ * 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$
+ */
+
+#ifdef _KERNEL
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <net/if.h> /* IFNAMSIZ */
+#include <netinet/in.h>
+#include <netinet/ip_var.h> /* ipfw_rule_ref */
+#include <netinet/ip_fw.h> /* flow_id */
+#include <netinet/ip_dummynet.h>
+#include <netinet/ipfw/dn_heap.h>
+#include <netinet/ipfw/ip_dn_private.h>
+#include <netinet/ipfw/dn_sched.h>
+#else
+#include <dn_test.h>
+#endif
+
+#ifdef QFQ_DEBUG
+struct qfq_sched;
+static void dump_sched(struct qfq_sched *q, const char *msg);
+#define NO(x) x
+#else
+#define NO(x)
+#endif
+#define DN_SCHED_QFQ 4 // XXX Where?
+typedef unsigned long bitmap;
+
+/*
+ * bitmaps ops are critical. Some linux versions have __fls
+ * and the bitmap ops. Some machines have ffs
+ */
+#if defined(_WIN32)
+int fls(unsigned int n)
+{
+ int i = 0;
+ for (i = 0; n > 0; n >>= 1, i++)
+ ;
+ return i;
+}
+#endif
+
+#if !defined(_KERNEL) || defined( __FreeBSD__ ) || defined(_WIN32)
+static inline unsigned long __fls(unsigned long word)
+{
+ return fls(word) - 1;
+}
+#endif
+
+#if !defined(_KERNEL) || !defined(__linux__)
+#ifdef QFQ_DEBUG
+int test_bit(int ix, bitmap *p)
+{
+ if (ix < 0 || ix > 31)
+ D("bad index %d", ix);
+ return *p & (1<<ix);
+}
+void __set_bit(int ix, bitmap *p)
+{
+ if (ix < 0 || ix > 31)
+ D("bad index %d", ix);
+ *p |= (1<<ix);
+}
+void __clear_bit(int ix, bitmap *p)
+{
+ if (ix < 0 || ix > 31)
+ D("bad index %d", ix);
+ *p &= ~(1<<ix);
+}
+#else /* !QFQ_DEBUG */
+/* XXX do we have fast version, or leave it to the compiler ? */
+#define test_bit(ix, pData) ((*pData) & (1<<(ix)))
+#define __set_bit(ix, pData) (*pData) |= (1<<(ix))
+#define __clear_bit(ix, pData) (*pData) &= ~(1<<(ix))
+#endif /* !QFQ_DEBUG */
+#endif /* !__linux__ */
+
+#ifdef __MIPSEL__
+#define __clear_bit(ix, pData) (*pData) &= ~(1<<(ix))
+#endif
+
+/*-------------------------------------------*/
+/*
+
+Virtual time computations.
+
+S, F and V are all computed in fixed point arithmetic with
+FRAC_BITS decimal bits.
+
+ QFQ_MAX_INDEX is the maximum index allowed for a group. We need
+ one bit per index.
+ QFQ_MAX_WSHIFT is the maximum power of two supported as a weight.
+ The layout of the bits is as below:
+
+ [ MTU_SHIFT ][ FRAC_BITS ]
+ [ MAX_INDEX ][ MIN_SLOT_SHIFT ]
+ ^.__grp->index = 0
+ *.__grp->slot_shift
+
+ where MIN_SLOT_SHIFT is derived by difference from the others.
+
+The max group index corresponds to Lmax/w_min, where
+Lmax=1<<MTU_SHIFT, w_min = 1 .
+From this, and knowing how many groups (MAX_INDEX) we want,
+we can derive the shift corresponding to each group.
+
+Because we often need to compute
+ F = S + len/w_i and V = V + len/wsum
+instead of storing w_i store the value
+ inv_w = (1<<FRAC_BITS)/w_i
+so we can do F = S + len * inv_w * wsum.
+We use W_TOT in the formulas so we can easily move between
+static and adaptive weight sum.
+
+The per-scheduler-instance data contain all the data structures
+for the scheduler: bitmaps and bucket lists.
+
+ */
+/*
+ * Maximum number of consecutive slots occupied by backlogged classes
+ * inside a group. This is approx lmax/lmin + 5.
+ * XXX check because it poses constraints on MAX_INDEX
+ */
+#define QFQ_MAX_SLOTS 32
+/*
+ * Shifts used for class<->group mapping. Class weights are
+ * in the range [1, QFQ_MAX_WEIGHT], we to map each class i to the
+ * group with the smallest index that can support the L_i / r_i
+ * configured for the class.
+ *
+ * grp->index is the index of the group; and grp->slot_shift
+ * is the shift for the corresponding (scaled) sigma_i.
+ *
+ * When computing the group index, we do (len<<FP_SHIFT)/weight,
+ * then compute an FLS (which is like a log2()), and if the result
+ * is below the MAX_INDEX region we use 0 (which is the same as
+ * using a larger len).
+ */
+#define QFQ_MAX_INDEX 19
+#define QFQ_MAX_WSHIFT 16 /* log2(max_weight) */
+
+#define QFQ_MAX_WEIGHT (1<<QFQ_MAX_WSHIFT)
+#define QFQ_MAX_WSUM (2*QFQ_MAX_WEIGHT)
+//#define IWSUM (q->i_wsum)
+#define IWSUM ((1<<FRAC_BITS)/QFQ_MAX_WSUM)
+
+#define FRAC_BITS 30 /* fixed point arithmetic */
+#define ONE_FP (1UL << FRAC_BITS)
+
+#define QFQ_MTU_SHIFT 11 /* log2(max_len) */
+#define QFQ_MIN_SLOT_SHIFT (FRAC_BITS + QFQ_MTU_SHIFT - QFQ_MAX_INDEX)
+
+/*
+ * Possible group states, also indexes for the bitmaps array in
+ * struct qfq_queue. We rely on ER, IR, EB, IB being numbered 0..3
+ */
+enum qfq_state { ER, IR, EB, IB, QFQ_MAX_STATE };
+
+struct qfq_group;
+/*
+ * additional queue info. Some of this info should come from
+ * the flowset, we copy them here for faster processing.
+ * This is an overlay of the struct dn_queue
+ */
+struct qfq_class {
+ struct dn_queue _q;
+ uint64_t S, F; /* flow timestamps (exact) */
+ struct qfq_class *next; /* Link for the slot list. */
+
+ /* group we belong to. In principle we would need the index,
+ * which is log_2(lmax/weight), but we never reference it
+ * directly, only the group.
+ */
+ struct qfq_group *grp;
+
+ /* these are copied from the flowset. */
+ uint32_t inv_w; /* ONE_FP/weight */
+ uint32_t lmax; /* Max packet size for this flow. */
+};
+
+/* Group descriptor, see the paper for details.
+ * Basically this contains the bucket lists
+ */
+struct qfq_group {
+ uint64_t S, F; /* group timestamps (approx). */
+ unsigned int slot_shift; /* Slot shift. */
+ unsigned int index; /* Group index. */
+ unsigned int front; /* Index of the front slot. */
+ bitmap full_slots; /* non-empty slots */
+
+ /* Array of lists of active classes. */
+ struct qfq_class *slots[QFQ_MAX_SLOTS];
+};
+
+/* scheduler instance descriptor. */
+struct qfq_sched {
+ uint64_t V; /* Precise virtual time. */
+ uint32_t wsum; /* weight sum */
+ NO(uint32_t i_wsum; /* ONE_FP/w_sum */
+ uint32_t _queued; /* debugging */
+ uint32_t loops; /* debugging */)
+ bitmap bitmaps[QFQ_MAX_STATE]; /* Group bitmaps. */
+ struct qfq_group groups[QFQ_MAX_INDEX + 1]; /* The groups. */
+};
+
+/*---- support functions ----------------------------*/
+
+/* Generic comparison function, handling wraparound. */
+static inline int qfq_gt(uint64_t a, uint64_t b)
+{
+ return (int64_t)(a - b) > 0;
+}
+
+/* Round a precise timestamp to its slotted value. */
+static inline uint64_t qfq_round_down(uint64_t ts, unsigned int shift)
+{
+ return ts & ~((1ULL << shift) - 1);
+}
+
+/* return the pointer to the group with lowest index in the bitmap */
+static inline struct qfq_group *qfq_ffs(struct qfq_sched *q,
+ unsigned long bitmap)
+{
+ int index = ffs(bitmap) - 1; // zero-based
+ return &q->groups[index];
+}
+
+/*
+ * Calculate a flow index, given its weight and maximum packet length.
+ * index = log_2(maxlen/weight) but we need to apply the scaling.
+ * This is used only once at flow creation.
+ */
+static int qfq_calc_index(uint32_t inv_w, unsigned int maxlen)
+{
+ uint64_t slot_size = (uint64_t)maxlen *inv_w;
+ unsigned long size_map;
+ int index = 0;
+
+ size_map = (unsigned long)(slot_size >> QFQ_MIN_SLOT_SHIFT);
+ if (!size_map)
+ goto out;
+
+ index = __fls(size_map) + 1; // basically a log_2()
+ index -= !(slot_size - (1ULL << (index + QFQ_MIN_SLOT_SHIFT - 1)));
+
+ if (index < 0)
+ index = 0;
+
+out:
+ ND("W = %d, L = %d, I = %d\n", ONE_FP/inv_w, maxlen, index);
+ return index;
+}
+/*---- end support functions ----*/
+
+/*-------- API calls --------------------------------*/
+/*
+ * Validate and copy parameters from flowset.
+ */
+static int
+qfq_new_queue(struct dn_queue *_q)
+{
+ struct qfq_sched *q = (struct qfq_sched *)(_q->_si + 1);
+ struct qfq_class *cl = (struct qfq_class *)_q;
+ int i;
+ uint32_t w; /* approximated weight */
+
+ /* import parameters from the flowset. They should be correct
+ * already.
+ */
+ w = _q->fs->fs.par[0];
+ cl->lmax = _q->fs->fs.par[1];
+ if (!w || w > QFQ_MAX_WEIGHT) {
+ w = 1;
+ D("rounding weight to 1");
+ }
+ cl->inv_w = ONE_FP/w;
+ w = ONE_FP/cl->inv_w;
+ if (q->wsum + w > QFQ_MAX_WSUM)
+ return EINVAL;
+
+ i = qfq_calc_index(cl->inv_w, cl->lmax);
+ cl->grp = &q->groups[i];
+ q->wsum += w;
+ // XXX cl->S = q->V; ?
+ // XXX compute q->i_wsum
+ return 0;
+}
+
+/* remove an empty queue */
+static int
+qfq_free_queue(struct dn_queue *_q)
+{
+ struct qfq_sched *q = (struct qfq_sched *)(_q->_si + 1);
+ struct qfq_class *cl = (struct qfq_class *)_q;
+ if (cl->inv_w) {
+ q->wsum -= ONE_FP/cl->inv_w;
+ cl->inv_w = 0; /* reset weight to avoid run twice */
+ }
+ return 0;
+}
+
+/* Calculate a mask to mimic what would be ffs_from(). */
+static inline unsigned long
+mask_from(unsigned long bitmap, int from)
+{
+ return bitmap & ~((1UL << from) - 1);
+}
+
+/*
+ * The state computation relies on ER=0, IR=1, EB=2, IB=3
+ * First compute eligibility comparing grp->S, q->V,
+ * then check if someone is blocking us and possibly add EB
+ */
+static inline unsigned int
+qfq_calc_state(struct qfq_sched *q, struct qfq_group *grp)
+{
+ /* if S > V we are not eligible */
+ unsigned int state = qfq_gt(grp->S, q->V);
+ unsigned long mask = mask_from(q->bitmaps[ER], grp->index);
+ struct qfq_group *next;
+
+ if (mask) {
+ next = qfq_ffs(q, mask);
+ if (qfq_gt(grp->F, next->F))
+ state |= EB;
+ }
+
+ return state;
+}
+
+/*
+ * In principle
+ * q->bitmaps[dst] |= q->bitmaps[src] & mask;
+ * q->bitmaps[src] &= ~mask;
+ * but we should make sure that src != dst
+ */
+static inline void
+qfq_move_groups(struct qfq_sched *q, unsigned long mask, int src, int dst)
+{
+ q->bitmaps[dst] |= q->bitmaps[src] & mask;
+ q->bitmaps[src] &= ~mask;
+}
+
+static inline void
+qfq_unblock_groups(struct qfq_sched *q, int index, uint64_t old_finish)
+{
+ unsigned long mask = mask_from(q->bitmaps[ER], index + 1);
+ struct qfq_group *next;
+
+ if (mask) {
+ next = qfq_ffs(q, mask);
+ if (!qfq_gt(next->F, old_finish))
+ return;
+ }
+
+ mask = (1UL << index) - 1;
+ qfq_move_groups(q, mask, EB, ER);
+ qfq_move_groups(q, mask, IB, IR);
+}
+
+/*
+ * perhaps
+ *
+ old_V ^= q->V;
+ old_V >>= QFQ_MIN_SLOT_SHIFT;
+ if (old_V) {
+ ...
+ }
+ *
+ */
+static inline void
+qfq_make_eligible(struct qfq_sched *q, uint64_t old_V)
+{
+ unsigned long mask, vslot, old_vslot;
+
+ vslot = q->V >> QFQ_MIN_SLOT_SHIFT;
+ old_vslot = old_V >> QFQ_MIN_SLOT_SHIFT;
+
+ if (vslot != old_vslot) {
+ mask = (2UL << (__fls(vslot ^ old_vslot))) - 1;
+ qfq_move_groups(q, mask, IR, ER);
+ qfq_move_groups(q, mask, IB, EB);
+ }
+}
+
+/*
+ * XXX we should make sure that slot becomes less than 32.
+ * This is guaranteed by the input values.
+ * roundedS is always cl->S rounded on grp->slot_shift bits.
+ */
+static inline void
+qfq_slot_insert(struct qfq_group *grp, struct qfq_class *cl, uint64_t roundedS)
+{
+ uint64_t slot = (roundedS - grp->S) >> grp->slot_shift;
+ unsigned int i = (grp->front + slot) % QFQ_MAX_SLOTS;
+
+ cl->next = grp->slots[i];
+ grp->slots[i] = cl;
+ __set_bit(slot, &grp->full_slots);
+}
+
+/*
+ * remove the entry from the slot
+ */
+static inline void
+qfq_front_slot_remove(struct qfq_group *grp)
+{
+ struct qfq_class **h = &grp->slots[grp->front];
+
+ *h = (*h)->next;
+ if (!*h)
+ __clear_bit(0, &grp->full_slots);
+}
+
+/*
+ * Returns the first full queue in a group. As a side effect,
+ * adjust the bucket list so the first non-empty bucket is at
+ * position 0 in full_slots.
+ */
+static inline struct qfq_class *
+qfq_slot_scan(struct qfq_group *grp)
+{
+ int i;
+
+ ND("grp %d full %x", grp->index, grp->full_slots);
+ if (!grp->full_slots)
+ return NULL;
+
+ i = ffs(grp->full_slots) - 1; // zero-based
+ if (i > 0) {
+ grp->front = (grp->front + i) % QFQ_MAX_SLOTS;
+ grp->full_slots >>= i;
+ }
+
+ return grp->slots[grp->front];
+}
+
+/*
+ * adjust the bucket list. When the start time of a group decreases,
+ * we move the index down (modulo QFQ_MAX_SLOTS) so we don't need to
+ * move the objects. The mask of occupied slots must be shifted
+ * because we use ffs() to find the first non-empty slot.
+ * This covers decreases in the group's start time, but what about
+ * increases of the start time ?
+ * Here too we should make sure that i is less than 32
+ */
+static inline void
+qfq_slot_rotate(struct qfq_sched *q, struct qfq_group *grp, uint64_t roundedS)
+{
+ unsigned int i = (grp->S - roundedS) >> grp->slot_shift;
+
+ grp->full_slots <<= i;
+ grp->front = (grp->front - i) % QFQ_MAX_SLOTS;
+}
+
+
+static inline void
+qfq_update_eligible(struct qfq_sched *q, uint64_t old_V)
+{
+ bitmap ineligible;
+
+ ineligible = q->bitmaps[IR] | q->bitmaps[IB];
+ if (ineligible) {
+ if (!q->bitmaps[ER]) {
+ struct qfq_group *grp;
+ grp = qfq_ffs(q, ineligible);
+ if (qfq_gt(grp->S, q->V))
+ q->V = grp->S;
+ }
+ qfq_make_eligible(q, old_V);
+ }
+}
+
+/*
+ * Updates the class, returns true if also the group needs to be updated.
+ */
+static inline int
+qfq_update_class(struct qfq_sched *q, struct qfq_group *grp,
+ struct qfq_class *cl)
+{
+
+ cl->S = cl->F;
+ if (cl->_q.mq.head == NULL) {
+ qfq_front_slot_remove(grp);
+ } else {
+ unsigned int len;
+ uint64_t roundedS;
+
+ len = cl->_q.mq.head->m_pkthdr.len;
+ cl->F = cl->S + (uint64_t)len * cl->inv_w;
+ roundedS = qfq_round_down(cl->S, grp->slot_shift);
+ if (roundedS == grp->S)
+ return 0;
+
+ qfq_front_slot_remove(grp);
+ qfq_slot_insert(grp, cl, roundedS);
+ }
+ return 1;
+}
+
+static struct mbuf *
+qfq_dequeue(struct dn_sch_inst *si)
+{
+ struct qfq_sched *q = (struct qfq_sched *)(si + 1);
+ struct qfq_group *grp;
+ struct qfq_class *cl;
+ struct mbuf *m;
+ uint64_t old_V;
+
+ NO(q->loops++;)
+ if (!q->bitmaps[ER]) {
+ NO(if (q->queued)
+ dump_sched(q, "start dequeue");)
+ return NULL;
+ }
+
+ grp = qfq_ffs(q, q->bitmaps[ER]);
+
+ cl = grp->slots[grp->front];
+ /* extract from the first bucket in the bucket list */
+ m = dn_dequeue(&cl->_q);
+
+ if (!m) {
+ D("BUG/* non-workconserving leaf */");
+ return NULL;
+ }
+ NO(q->queued--;)
+ old_V = q->V;
+ q->V += (uint64_t)m->m_pkthdr.len * IWSUM;
+ ND("m is %p F 0x%llx V now 0x%llx", m, cl->F, q->V);
+
+ if (qfq_update_class(q, grp, cl)) {
+ uint64_t old_F = grp->F;
+ cl = qfq_slot_scan(grp);
+ if (!cl) { /* group gone, remove from ER */
+ __clear_bit(grp->index, &q->bitmaps[ER]);
+ // grp->S = grp->F + 1; // XXX debugging only
+ } else {
+ uint64_t roundedS = qfq_round_down(cl->S, grp->slot_shift);
+ unsigned int s;
+
+ if (grp->S == roundedS)
+ goto skip_unblock;
+ grp->S = roundedS;
+ grp->F = roundedS + (2ULL << grp->slot_shift);
+ /* remove from ER and put in the new set */
+ __clear_bit(grp->index, &q->bitmaps[ER]);
+ s = qfq_calc_state(q, grp);
+ __set_bit(grp->index, &q->bitmaps[s]);
+ }
+ /* we need to unblock even if the group has gone away */
+ qfq_unblock_groups(q, grp->index, old_F);
+ }
+
+skip_unblock:
+ qfq_update_eligible(q, old_V);
+ NO(if (!q->bitmaps[ER] && q->queued)
+ dump_sched(q, "end dequeue");)
+
+ return m;
+}
+
+/*
+ * Assign a reasonable start time for a new flow k in group i.
+ * Admissible values for \hat(F) are multiples of \sigma_i
+ * no greater than V+\sigma_i . Larger values mean that
+ * we had a wraparound so we consider the timestamp to be stale.
+ *
+ * If F is not stale and F >= V then we set S = F.
+ * Otherwise we should assign S = V, but this may violate
+ * the ordering in ER. So, if we have groups in ER, set S to
+ * the F_j of the first group j which would be blocking us.
+ * We are guaranteed not to move S backward because
+ * otherwise our group i would still be blocked.
+ */
+static inline void
+qfq_update_start(struct qfq_sched *q, struct qfq_class *cl)
+{
+ unsigned long mask;
+ uint32_t limit, roundedF;
+ int slot_shift = cl->grp->slot_shift;
+
+ roundedF = qfq_round_down(cl->F, slot_shift);
+ limit = qfq_round_down(q->V, slot_shift) + (1UL << slot_shift);
+
+ if (!qfq_gt(cl->F, q->V) || qfq_gt(roundedF, limit)) {
+ /* timestamp was stale */
+ mask = mask_from(q->bitmaps[ER], cl->grp->index);
+ if (mask) {
+ struct qfq_group *next = qfq_ffs(q, mask);
+ if (qfq_gt(roundedF, next->F)) {
+ cl->S = next->F;
+ return;
+ }
+ }
+ cl->S = q->V;
+ } else { /* timestamp is not stale */
+ cl->S = cl->F;
+ }
+}
+
+static int
+qfq_enqueue(struct dn_sch_inst *si, struct dn_queue *_q, struct mbuf *m)
+{
+ struct qfq_sched *q = (struct qfq_sched *)(si + 1);
+ struct qfq_group *grp;
+ struct qfq_class *cl = (struct qfq_class *)_q;
+ uint64_t roundedS;
+ int s;
+
+ NO(q->loops++;)
+ DX(4, "len %d flow %p inv_w 0x%x grp %d", m->m_pkthdr.len,
+ _q, cl->inv_w, cl->grp->index);
+ /* XXX verify that the packet obeys the parameters */
+ if (m != _q->mq.head) {
+ if (dn_enqueue(_q, m, 0)) /* packet was dropped */
+ return 1;
+ NO(q->queued++;)
+ if (m != _q->mq.head)
+ return 0;
+ }
+ /* If reach this point, queue q was idle */
+ grp = cl->grp;
+ qfq_update_start(q, cl); /* adjust start time */
+ /* compute new finish time and rounded start. */
+ cl->F = cl->S + (uint64_t)(m->m_pkthdr.len) * cl->inv_w;
+ roundedS = qfq_round_down(cl->S, grp->slot_shift);
+
+ /*
+ * insert cl in the correct bucket.
+ * If cl->S >= grp->S we don't need to adjust the
+ * bucket list and simply go to the insertion phase.
+ * Otherwise grp->S is decreasing, we must make room
+ * in the bucket list, and also recompute the group state.
+ * Finally, if there were no flows in this group and nobody
+ * was in ER make sure to adjust V.
+ */
+ if (grp->full_slots) {
+ if (!qfq_gt(grp->S, cl->S))
+ goto skip_update;
+ /* create a slot for this cl->S */
+ qfq_slot_rotate(q, grp, roundedS);
+ /* group was surely ineligible, remove */
+ __clear_bit(grp->index, &q->bitmaps[IR]);
+ __clear_bit(grp->index, &q->bitmaps[IB]);
+ } else if (!q->bitmaps[ER] && qfq_gt(roundedS, q->V))
+ q->V = roundedS;
+
+ grp->S = roundedS;
+ grp->F = roundedS + (2ULL << grp->slot_shift); // i.e. 2\sigma_i
+ s = qfq_calc_state(q, grp);
+ __set_bit(grp->index, &q->bitmaps[s]);
+ ND("new state %d 0x%x", s, q->bitmaps[s]);
+ ND("S %llx F %llx V %llx", cl->S, cl->F, q->V);
+skip_update:
+ qfq_slot_insert(grp, cl, roundedS);
+
+ return 0;
+}
+
+
+#if 0
+static inline void
+qfq_slot_remove(struct qfq_sched *q, struct qfq_group *grp,
+ struct qfq_class *cl, struct qfq_class **pprev)
+{
+ unsigned int i, offset;
+ uint64_t roundedS;
+
+ roundedS = qfq_round_down(cl->S, grp->slot_shift);
+ offset = (roundedS - grp->S) >> grp->slot_shift;
+ i = (grp->front + offset) % QFQ_MAX_SLOTS;
+
+#ifdef notyet
+ if (!pprev) {
+ pprev = &grp->slots[i];
+ while (*pprev && *pprev != cl)
+ pprev = &(*pprev)->next;
+ }
+#endif
+
+ *pprev = cl->next;
+ if (!grp->slots[i])
+ __clear_bit(offset, &grp->full_slots);
+}
+
+/*
+ * called to forcibly destroy a queue.
+ * If the queue is not in the front bucket, or if it has
+ * other queues in the front bucket, we can simply remove
+ * the queue with no other side effects.
+ * Otherwise we must propagate the event up.
+ * XXX description to be completed.
+ */
+static void
+qfq_deactivate_class(struct qfq_sched *q, struct qfq_class *cl,
+ struct qfq_class **pprev)
+{
+ struct qfq_group *grp = &q->groups[cl->index];
+ unsigned long mask;
+ uint64_t roundedS;
+ int s;
+
+ cl->F = cl->S; // not needed if the class goes away.
+ qfq_slot_remove(q, grp, cl, pprev);
+
+ if (!grp->full_slots) {
+ /* nothing left in the group, remove from all sets.
+ * Do ER last because if we were blocking other groups
+ * we must unblock them.
+ */
+ __clear_bit(grp->index, &q->bitmaps[IR]);
+ __clear_bit(grp->index, &q->bitmaps[EB]);
+ __clear_bit(grp->index, &q->bitmaps[IB]);
+
+ if (test_bit(grp->index, &q->bitmaps[ER]) &&
+ !(q->bitmaps[ER] & ~((1UL << grp->index) - 1))) {
+ mask = q->bitmaps[ER] & ((1UL << grp->index) - 1);
+ if (mask)
+ mask = ~((1UL << __fls(mask)) - 1);
+ else
+ mask = ~0UL;
+ qfq_move_groups(q, mask, EB, ER);
+ qfq_move_groups(q, mask, IB, IR);
+ }
+ __clear_bit(grp->index, &q->bitmaps[ER]);
+ } else if (!grp->slots[grp->front]) {
+ cl = qfq_slot_scan(grp);
+ roundedS = qfq_round_down(cl->S, grp->slot_shift);
+ if (grp->S != roundedS) {
+ __clear_bit(grp->index, &q->bitmaps[ER]);
+ __clear_bit(grp->index, &q->bitmaps[IR]);
+ __clear_bit(grp->index, &q->bitmaps[EB]);
+ __clear_bit(grp->index, &q->bitmaps[IB]);
+ grp->S = roundedS;
+ grp->F = roundedS + (2ULL << grp->slot_shift);
+ s = qfq_calc_state(q, grp);
+ __set_bit(grp->index, &q->bitmaps[s]);
+ }
+ }
+ qfq_update_eligible(q, q->V);
+}
+#endif
+
+static int
+qfq_new_fsk(struct dn_fsk *f)
+{
+ ipdn_bound_var(&f->fs.par[0], 1, 1, QFQ_MAX_WEIGHT, "qfq weight");
+ ipdn_bound_var(&f->fs.par[1], 1500, 1, 2000, "qfq maxlen");
+ ND("weight %d len %d\n", f->fs.par[0], f->fs.par[1]);
+ return 0;
+}
+
+/*
+ * initialize a new scheduler instance
+ */
+static int
+qfq_new_sched(struct dn_sch_inst *si)
+{
+ struct qfq_sched *q = (struct qfq_sched *)(si + 1);
+ struct qfq_group *grp;
+ int i;
+
+ for (i = 0; i <= QFQ_MAX_INDEX; i++) {
+ grp = &q->groups[i];
+ grp->index = i;
+ grp->slot_shift = QFQ_MTU_SHIFT + FRAC_BITS -
+ (QFQ_MAX_INDEX - i);
+ }
+ return 0;
+}
+
+/*
+ * QFQ scheduler descriptor
+ */
+static struct dn_alg qfq_desc = {
+ _SI( .type = ) DN_SCHED_QFQ,
+ _SI( .name = ) "QFQ",
+ _SI( .flags = ) DN_MULTIQUEUE,
+
+ _SI( .schk_datalen = ) 0,
+ _SI( .si_datalen = ) sizeof(struct qfq_sched),
+ _SI( .q_datalen = ) sizeof(struct qfq_class) - sizeof(struct dn_queue),
+
+ _SI( .enqueue = ) qfq_enqueue,
+ _SI( .dequeue = ) qfq_dequeue,
+
+ _SI( .config = ) NULL,
+ _SI( .destroy = ) NULL,
+ _SI( .new_sched = ) qfq_new_sched,
+ _SI( .free_sched = ) NULL,
+ _SI( .new_fsk = ) qfq_new_fsk,
+ _SI( .free_fsk = ) NULL,
+ _SI( .new_queue = ) qfq_new_queue,
+ _SI( .free_queue = ) qfq_free_queue,
+};
+
+DECLARE_DNSCHED_MODULE(dn_qfq, &qfq_desc);
+
+#ifdef QFQ_DEBUG
+static void
+dump_groups(struct qfq_sched *q, uint32_t mask)
+{
+ int i, j;
+
+ for (i = 0; i < QFQ_MAX_INDEX + 1; i++) {
+ struct qfq_group *g = &q->groups[i];
+
+ if (0 == (mask & (1<<i)))
+ continue;
+ for (j = 0; j < QFQ_MAX_SLOTS; j++) {
+ if (g->slots[j])
+ D(" bucket %d %p", j, g->slots[j]);
+ }
+ D("full_slots 0x%x", g->full_slots);
+ D(" %2d S 0x%20llx F 0x%llx %c", i,
+ g->S, g->F,
+ mask & (1<<i) ? '1' : '0');
+ }
+}
+
+static void
+dump_sched(struct qfq_sched *q, const char *msg)
+{
+ D("--- in %s: ---", msg);
+ ND("loops %d queued %d V 0x%llx", q->loops, q->queued, q->V);
+ D(" ER 0x%08x", q->bitmaps[ER]);
+ D(" EB 0x%08x", q->bitmaps[EB]);
+ D(" IR 0x%08x", q->bitmaps[IR]);
+ D(" IB 0x%08x", q->bitmaps[IB]);
+ dump_groups(q, 0xffffffff);
+};
+#endif /* QFQ_DEBUG */
diff --git a/sys/netinet/ipfw/dn_sched_rr.c b/sys/netinet/ipfw/dn_sched_rr.c
new file mode 100644
index 0000000..fc7be00
--- /dev/null
+++ b/sys/netinet/ipfw/dn_sched_rr.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2010 Riccardo Panicucci, Universita` di Pisa
+ * 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$
+ */
+
+#ifdef _KERNEL
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <net/if.h> /* IFNAMSIZ */
+#include <netinet/in.h>
+#include <netinet/ip_var.h> /* ipfw_rule_ref */
+#include <netinet/ip_fw.h> /* flow_id */
+#include <netinet/ip_dummynet.h>
+#include <netinet/ipfw/dn_heap.h>
+#include <netinet/ipfw/ip_dn_private.h>
+#include <netinet/ipfw/dn_sched.h>
+#else
+#include <dn_test.h>
+#endif
+
+#define DN_SCHED_RR 3 // XXX Where?
+
+struct rr_queue {
+ struct dn_queue q; /* Standard queue */
+ int status; /* 1: queue is in the list */
+ int credit; /* Number of bytes to transmit */
+ int quantum; /* quantum * C */
+ struct rr_queue *qnext; /* */
+};
+
+/* struct rr_schk contains global config parameters
+ * and is right after dn_schk
+ */
+struct rr_schk {
+ int min_q; /* Min quantum */
+ int max_q; /* Max quantum */
+ int q_bytes; /* Bytes per quantum */
+};
+
+/* per-instance round robin list, right after dn_sch_inst */
+struct rr_si {
+ struct rr_queue *head, *tail; /* Pointer to current queue */
+};
+
+/* Append a queue to the rr list */
+static inline void
+rr_append(struct rr_queue *q, struct rr_si *si)
+{
+ q->status = 1; /* mark as in-rr_list */
+ q->credit = q->quantum; /* initialize credit */
+
+ /* append to the tail */
+ if (si->head == NULL)
+ si->head = q;
+ else
+ si->tail->qnext = q;
+ si->tail = q; /* advance the tail pointer */
+ q->qnext = si->head; /* make it circular */
+}
+
+/* Remove the head queue from circular list. */
+static inline void
+rr_remove_head(struct rr_si *si)
+{
+ if (si->head == NULL)
+ return; /* empty queue */
+ si->head->status = 0;
+
+ if (si->head == si->tail) {
+ si->head = si->tail = NULL;
+ return;
+ }
+
+ si->head = si->head->qnext;
+ si->tail->qnext = si->head;
+}
+
+/* Remove a queue from circular list.
+ * XXX see if ti can be merge with remove_queue()
+ */
+static inline void
+remove_queue_q(struct rr_queue *q, struct rr_si *si)
+{
+ struct rr_queue *prev;
+
+ if (q->status != 1)
+ return;
+ if (q == si->head) {
+ rr_remove_head(si);
+ return;
+ }
+
+ for (prev = si->head; prev; prev = prev->qnext) {
+ if (prev->qnext != q)
+ continue;
+ prev->qnext = q->qnext;
+ if (q == si->tail)
+ si->tail = prev;
+ q->status = 0;
+ break;
+ }
+}
+
+
+static inline void
+next_pointer(struct rr_si *si)
+{
+ if (si->head == NULL)
+ return; /* empty queue */
+
+ si->head = si->head->qnext;
+ si->tail = si->tail->qnext;
+}
+
+static int
+rr_enqueue(struct dn_sch_inst *_si, struct dn_queue *q, struct mbuf *m)
+{
+ struct rr_si *si;
+ struct rr_queue *rrq;
+
+ if (m != q->mq.head) {
+ if (dn_enqueue(q, m, 0)) /* packet was dropped */
+ return 1;
+ if (m != q->mq.head)
+ return 0;
+ }
+
+ /* If reach this point, queue q was idle */
+ si = (struct rr_si *)(_si + 1);
+ rrq = (struct rr_queue *)q;
+
+ if (rrq->status == 1) /* Queue is already in the queue list */
+ return 0;
+
+ /* Insert the queue in the queue list */
+ rr_append(rrq, si);
+
+ return 0;
+}
+
+static struct mbuf *
+rr_dequeue(struct dn_sch_inst *_si)
+{
+ /* Access scheduler instance private data */
+ struct rr_si *si = (struct rr_si *)(_si + 1);
+ struct rr_queue *rrq;
+ uint64_t len;
+
+ while ( (rrq = si->head) ) {
+ struct mbuf *m = rrq->q.mq.head;
+ if ( m == NULL) {
+ /* empty queue, remove from list */
+ rr_remove_head(si);
+ continue;
+ }
+ len = m->m_pkthdr.len;
+
+ if (len > rrq->credit) {
+ /* Packet too big */
+ rrq->credit += rrq->quantum;
+ /* Try next queue */
+ next_pointer(si);
+ } else {
+ rrq->credit -= len;
+ return dn_dequeue(&rrq->q);
+ }
+ }
+
+ /* no packet to dequeue*/
+ return NULL;
+}
+
+static int
+rr_config(struct dn_schk *_schk)
+{
+ struct rr_schk *schk = (struct rr_schk *)(_schk + 1);
+ ND("called");
+
+ /* use reasonable quantums (64..2k bytes, default 1500) */
+ schk->min_q = 64;
+ schk->max_q = 2048;
+ schk->q_bytes = 1500; /* quantum */
+
+ return 0;
+}
+
+static int
+rr_new_sched(struct dn_sch_inst *_si)
+{
+ struct rr_si *si = (struct rr_si *)(_si + 1);
+
+ ND("called");
+ si->head = si->tail = NULL;
+
+ return 0;
+}
+
+static int
+rr_free_sched(struct dn_sch_inst *_si)
+{
+ ND("called");
+ /* Nothing to do? */
+ return 0;
+}
+
+static int
+rr_new_fsk(struct dn_fsk *fs)
+{
+ struct rr_schk *schk = (struct rr_schk *)(fs->sched + 1);
+ /* par[0] is the weight, par[1] is the quantum step */
+ ipdn_bound_var(&fs->fs.par[0], 1,
+ 1, 65536, "RR weight");
+ ipdn_bound_var(&fs->fs.par[1], schk->q_bytes,
+ schk->min_q, schk->max_q, "RR quantum");
+ return 0;
+}
+
+static int
+rr_new_queue(struct dn_queue *_q)
+{
+ struct rr_queue *q = (struct rr_queue *)_q;
+
+ _q->ni.oid.subtype = DN_SCHED_RR;
+
+ q->quantum = _q->fs->fs.par[0] * _q->fs->fs.par[1];
+ ND("called, q->quantum %d", q->quantum);
+ q->credit = q->quantum;
+ q->status = 0;
+
+ if (_q->mq.head != NULL) {
+ /* Queue NOT empty, insert in the queue list */
+ rr_append(q, (struct rr_si *)(_q->_si + 1));
+ }
+ return 0;
+}
+
+static int
+rr_free_queue(struct dn_queue *_q)
+{
+ struct rr_queue *q = (struct rr_queue *)_q;
+
+ ND("called");
+ if (q->status == 1) {
+ struct rr_si *si = (struct rr_si *)(_q->_si + 1);
+ remove_queue_q(q, si);
+ }
+ return 0;
+}
+
+/*
+ * RR scheduler descriptor
+ * contains the type of the scheduler, the name, the size of the
+ * structures and function pointers.
+ */
+static struct dn_alg rr_desc = {
+ _SI( .type = ) DN_SCHED_RR,
+ _SI( .name = ) "RR",
+ _SI( .flags = ) DN_MULTIQUEUE,
+
+ _SI( .schk_datalen = ) 0,
+ _SI( .si_datalen = ) sizeof(struct rr_si),
+ _SI( .q_datalen = ) sizeof(struct rr_queue) - sizeof(struct dn_queue),
+
+ _SI( .enqueue = ) rr_enqueue,
+ _SI( .dequeue = ) rr_dequeue,
+
+ _SI( .config = ) rr_config,
+ _SI( .destroy = ) NULL,
+ _SI( .new_sched = ) rr_new_sched,
+ _SI( .free_sched = ) rr_free_sched,
+ _SI( .new_fsk = ) rr_new_fsk,
+ _SI( .free_fsk = ) NULL,
+ _SI( .new_queue = ) rr_new_queue,
+ _SI( .free_queue = ) rr_free_queue,
+};
+
+
+DECLARE_DNSCHED_MODULE(dn_rr, &rr_desc);
diff --git a/sys/netinet/ipfw/dn_sched_wf2q.c b/sys/netinet/ipfw/dn_sched_wf2q.c
new file mode 100644
index 0000000..1fbc120
--- /dev/null
+++ b/sys/netinet/ipfw/dn_sched_wf2q.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2010 Riccardo Panicucci, Universita` di Pisa
+ * Copyright (c) 2000-2002 Luigi Rizzo, Universita` di Pisa
+ * 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$
+ */
+
+#ifdef _KERNEL
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <net/if.h> /* IFNAMSIZ */
+#include <netinet/in.h>
+#include <netinet/ip_var.h> /* ipfw_rule_ref */
+#include <netinet/ip_fw.h> /* flow_id */
+#include <netinet/ip_dummynet.h>
+#include <netinet/ipfw/dn_heap.h>
+#include <netinet/ipfw/ip_dn_private.h>
+#include <netinet/ipfw/dn_sched.h>
+#else
+#include <dn_test.h>
+#endif
+
+#ifndef MAX64
+#define MAX64(x,y) (( (int64_t) ( (y)-(x) )) > 0 ) ? (y) : (x)
+#endif
+
+/*
+ * timestamps are computed on 64 bit using fixed point arithmetic.
+ * LMAX_BITS, WMAX_BITS are the max number of bits for the packet len
+ * and sum of weights, respectively. FRAC_BITS is the number of
+ * fractional bits. We want FRAC_BITS >> WMAX_BITS to avoid too large
+ * errors when computing the inverse, FRAC_BITS < 32 so we can do 1/w
+ * using an unsigned 32-bit division, and to avoid wraparounds we need
+ * LMAX_BITS + WMAX_BITS + FRAC_BITS << 64
+ * As an example
+ * FRAC_BITS = 26, LMAX_BITS=14, WMAX_BITS = 19
+ */
+#ifndef FRAC_BITS
+#define FRAC_BITS 28 /* shift for fixed point arithmetic */
+#define ONE_FP (1UL << FRAC_BITS)
+#endif
+
+/*
+ * Private information for the scheduler instance:
+ * sch_heap (key is Finish time) returns the next queue to serve
+ * ne_heap (key is Start time) stores not-eligible queues
+ * idle_heap (key=start/finish time) stores idle flows. It must
+ * support extract-from-middle.
+ * A flow is only in 1 of the three heaps.
+ * XXX todo: use a more efficient data structure, e.g. a tree sorted
+ * by F with min_subtree(S) in each node
+ */
+struct wf2qp_si {
+ struct dn_heap sch_heap; /* top extract - key Finish time */
+ struct dn_heap ne_heap; /* top extract - key Start time */
+ struct dn_heap idle_heap; /* random extract - key Start=Finish time */
+ uint64_t V; /* virtual time */
+ uint32_t inv_wsum; /* inverse of sum of weights */
+ uint32_t wsum; /* sum of weights */
+};
+
+struct wf2qp_queue {
+ struct dn_queue _q;
+ uint64_t S, F; /* start time, finish time */
+ uint32_t inv_w; /* ONE_FP / weight */
+ int32_t heap_pos; /* position (index) of struct in heap */
+};
+
+/*
+ * This file implements a WF2Q+ scheduler as it has been in dummynet
+ * since 2000.
+ * The scheduler supports per-flow queues and has O(log N) complexity.
+ *
+ * WF2Q+ needs to drain entries from the idle heap so that we
+ * can keep the sum of weights up to date. We can do it whenever
+ * we get a chance, or periodically, or following some other
+ * strategy. The function idle_check() drains at most N elements
+ * from the idle heap.
+ */
+static void
+idle_check(struct wf2qp_si *si, int n, int force)
+{
+ struct dn_heap *h = &si->idle_heap;
+ while (n-- > 0 && h->elements > 0 &&
+ (force || DN_KEY_LT(HEAP_TOP(h)->key, si->V))) {
+ struct dn_queue *q = HEAP_TOP(h)->object;
+ struct wf2qp_queue *alg_fq = (struct wf2qp_queue *)q;
+
+ heap_extract(h, NULL);
+ /* XXX to let the flowset delete the queue we should
+ * mark it as 'unused' by the scheduler.
+ */
+ alg_fq->S = alg_fq->F + 1; /* Mark timestamp as invalid. */
+ si->wsum -= q->fs->fs.par[0]; /* adjust sum of weights */
+ if (si->wsum > 0)
+ si->inv_wsum = ONE_FP/si->wsum;
+ }
+}
+
+static int
+wf2qp_enqueue(struct dn_sch_inst *_si, struct dn_queue *q, struct mbuf *m)
+{
+ struct dn_fsk *fs = q->fs;
+ struct wf2qp_si *si = (struct wf2qp_si *)(_si + 1);
+ struct wf2qp_queue *alg_fq;
+ uint64_t len = m->m_pkthdr.len;
+
+ if (m != q->mq.head) {
+ if (dn_enqueue(q, m, 0)) /* packet was dropped */
+ return 1;
+ if (m != q->mq.head) /* queue was already busy */
+ return 0;
+ }
+
+ /* If reach this point, queue q was idle */
+ alg_fq = (struct wf2qp_queue *)q;
+
+ if (DN_KEY_LT(alg_fq->F, alg_fq->S)) {
+ /* F<S means timestamps are invalid ->brand new queue. */
+ alg_fq->S = si->V; /* init start time */
+ si->wsum += fs->fs.par[0]; /* add weight of new queue. */
+ si->inv_wsum = ONE_FP/si->wsum;
+ } else { /* if it was idle then it was in the idle heap */
+ heap_extract(&si->idle_heap, q);
+ alg_fq->S = MAX64(alg_fq->F, si->V); /* compute new S */
+ }
+ alg_fq->F = alg_fq->S + len * alg_fq->inv_w;
+
+ /* if nothing is backlogged, make sure this flow is eligible */
+ if (si->ne_heap.elements == 0 && si->sch_heap.elements == 0)
+ si->V = MAX64(alg_fq->S, si->V);
+
+ /*
+ * Look at eligibility. A flow is not eligibile if S>V (when
+ * this happens, it means that there is some other flow already
+ * scheduled for the same pipe, so the sch_heap cannot be
+ * empty). If the flow is not eligible we just store it in the
+ * ne_heap. Otherwise, we store in the sch_heap.
+ * Note that for all flows in sch_heap (SCH), S_i <= V,
+ * and for all flows in ne_heap (NEH), S_i > V.
+ * So when we need to compute max(V, min(S_i)) forall i in
+ * SCH+NEH, we only need to look into NEH.
+ */
+ if (DN_KEY_LT(si->V, alg_fq->S)) {
+ /* S>V means flow Not eligible. */
+ if (si->sch_heap.elements == 0)
+ D("++ ouch! not eligible but empty scheduler!");
+ heap_insert(&si->ne_heap, alg_fq->S, q);
+ } else {
+ heap_insert(&si->sch_heap, alg_fq->F, q);
+ }
+ return 0;
+}
+
+/* XXX invariant: sch > 0 || V >= min(S in neh) */
+static struct mbuf *
+wf2qp_dequeue(struct dn_sch_inst *_si)
+{
+ /* Access scheduler instance private data */
+ struct wf2qp_si *si = (struct wf2qp_si *)(_si + 1);
+ struct mbuf *m;
+ struct dn_queue *q;
+ struct dn_heap *sch = &si->sch_heap;
+ struct dn_heap *neh = &si->ne_heap;
+ struct wf2qp_queue *alg_fq;
+
+ if (sch->elements == 0 && neh->elements == 0) {
+ /* we have nothing to do. We could kill the idle heap
+ * altogether and reset V
+ */
+ idle_check(si, 0x7fffffff, 1);
+ si->V = 0;
+ si->wsum = 0; /* should be set already */
+ return NULL; /* quick return if nothing to do */
+ }
+ idle_check(si, 1, 0); /* drain something from the idle heap */
+
+ /* make sure at least one element is eligible, bumping V
+ * and moving entries that have become eligible.
+ * We need to repeat the first part twice, before and
+ * after extracting the candidate, or enqueue() will
+ * find the data structure in a wrong state.
+ */
+ m = NULL;
+ for(;;) {
+ /*
+ * Compute V = max(V, min(S_i)). Remember that all elements
+ * in sch have by definition S_i <= V so if sch is not empty,
+ * V is surely the max and we must not update it. Conversely,
+ * if sch is empty we only need to look at neh.
+ * We don't need to move the queues, as it will be done at the
+ * next enqueue
+ */
+ if (sch->elements == 0 && neh->elements > 0) {
+ si->V = MAX64(si->V, HEAP_TOP(neh)->key);
+ }
+ while (neh->elements > 0 &&
+ DN_KEY_LEQ(HEAP_TOP(neh)->key, si->V)) {
+ q = HEAP_TOP(neh)->object;
+ alg_fq = (struct wf2qp_queue *)q;
+ heap_extract(neh, NULL);
+ heap_insert(sch, alg_fq->F, q);
+ }
+ if (m) /* pkt found in previous iteration */
+ break;
+ /* ok we have at least one eligible pkt */
+ q = HEAP_TOP(sch)->object;
+ alg_fq = (struct wf2qp_queue *)q;
+ m = dn_dequeue(q);
+ heap_extract(sch, NULL); /* Remove queue from heap. */
+ si->V += (uint64_t)(m->m_pkthdr.len) * si->inv_wsum;
+ alg_fq->S = alg_fq->F; /* Update start time. */
+ if (q->mq.head == 0) { /* not backlogged any more. */
+ heap_insert(&si->idle_heap, alg_fq->F, q);
+ } else { /* Still backlogged. */
+ /* Update F, store in neh or sch */
+ uint64_t len = q->mq.head->m_pkthdr.len;
+ alg_fq->F += len * alg_fq->inv_w;
+ if (DN_KEY_LEQ(alg_fq->S, si->V)) {
+ heap_insert(sch, alg_fq->F, q);
+ } else {
+ heap_insert(neh, alg_fq->S, q);
+ }
+ }
+ }
+ return m;
+}
+
+static int
+wf2qp_new_sched(struct dn_sch_inst *_si)
+{
+ struct wf2qp_si *si = (struct wf2qp_si *)(_si + 1);
+ int ofs = offsetof(struct wf2qp_queue, heap_pos);
+
+ /* all heaps support extract from middle */
+ if (heap_init(&si->idle_heap, 16, ofs) ||
+ heap_init(&si->sch_heap, 16, ofs) ||
+ heap_init(&si->ne_heap, 16, ofs)) {
+ heap_free(&si->ne_heap);
+ heap_free(&si->sch_heap);
+ heap_free(&si->idle_heap);
+ return ENOMEM;
+ }
+ return 0;
+}
+
+static int
+wf2qp_free_sched(struct dn_sch_inst *_si)
+{
+ struct wf2qp_si *si = (struct wf2qp_si *)(_si + 1);
+
+ heap_free(&si->sch_heap);
+ heap_free(&si->ne_heap);
+ heap_free(&si->idle_heap);
+
+ return 0;
+}
+
+static int
+wf2qp_new_fsk(struct dn_fsk *fs)
+{
+ ipdn_bound_var(&fs->fs.par[0], 1,
+ 1, 100, "WF2Q+ weight");
+ return 0;
+}
+
+static int
+wf2qp_new_queue(struct dn_queue *_q)
+{
+ struct wf2qp_queue *q = (struct wf2qp_queue *)_q;
+
+ _q->ni.oid.subtype = DN_SCHED_WF2QP;
+ q->F = 0; /* not strictly necessary */
+ q->S = q->F + 1; /* mark timestamp as invalid. */
+ q->inv_w = ONE_FP / _q->fs->fs.par[0];
+ if (_q->mq.head != NULL) {
+ wf2qp_enqueue(_q->_si, _q, _q->mq.head);
+ }
+ return 0;
+}
+
+/*
+ * Called when the infrastructure removes a queue (e.g. flowset
+ * is reconfigured). Nothing to do if we did not 'own' the queue,
+ * otherwise remove it from the right heap and adjust the sum
+ * of weights.
+ */
+static int
+wf2qp_free_queue(struct dn_queue *q)
+{
+ struct wf2qp_queue *alg_fq = (struct wf2qp_queue *)q;
+ struct wf2qp_si *si = (struct wf2qp_si *)(q->_si + 1);
+
+ if (alg_fq->S >= alg_fq->F + 1)
+ return 0; /* nothing to do, not in any heap */
+ si->wsum -= q->fs->fs.par[0];
+ if (si->wsum > 0)
+ si->inv_wsum = ONE_FP/si->wsum;
+
+ /* extract from the heap. XXX TODO we may need to adjust V
+ * to make sure the invariants hold.
+ */
+ if (q->mq.head == NULL) {
+ heap_extract(&si->idle_heap, q);
+ } else if (DN_KEY_LT(si->V, alg_fq->S)) {
+ heap_extract(&si->ne_heap, q);
+ } else {
+ heap_extract(&si->sch_heap, q);
+ }
+ return 0;
+}
+
+/*
+ * WF2Q+ scheduler descriptor
+ * contains the type of the scheduler, the name, the size of the
+ * structures and function pointers.
+ */
+static struct dn_alg wf2qp_desc = {
+ _SI( .type = ) DN_SCHED_WF2QP,
+ _SI( .name = ) "WF2Q+",
+ _SI( .flags = ) DN_MULTIQUEUE,
+
+ /* we need extra space in the si and the queue */
+ _SI( .schk_datalen = ) 0,
+ _SI( .si_datalen = ) sizeof(struct wf2qp_si),
+ _SI( .q_datalen = ) sizeof(struct wf2qp_queue) -
+ sizeof(struct dn_queue),
+
+ _SI( .enqueue = ) wf2qp_enqueue,
+ _SI( .dequeue = ) wf2qp_dequeue,
+
+ _SI( .config = ) NULL,
+ _SI( .destroy = ) NULL,
+ _SI( .new_sched = ) wf2qp_new_sched,
+ _SI( .free_sched = ) wf2qp_free_sched,
+
+ _SI( .new_fsk = ) wf2qp_new_fsk,
+ _SI( .free_fsk = ) NULL,
+
+ _SI( .new_queue = ) wf2qp_new_queue,
+ _SI( .free_queue = ) wf2qp_free_queue,
+};
+
+
+DECLARE_DNSCHED_MODULE(dn_wf2qp, &wf2qp_desc);
diff --git a/sys/netinet/ipfw/dummynet.txt b/sys/netinet/ipfw/dummynet.txt
new file mode 100644
index 0000000..0ed6ad1
--- /dev/null
+++ b/sys/netinet/ipfw/dummynet.txt
@@ -0,0 +1,860 @@
+#
+# $FreeBSD$
+#
+
+Notes on the internal structure of dummynet (2010 version)
+by Riccardo Panicucci and Luigi Rizzo
+Work supported by the EC project ONELAB2
+
+
+*********
+* INDEX *
+*********
+Implementation of new dummynet
+ Internal structure
+ Files
+Packet arrival
+ The reconfiguration routine
+dummynet_task()
+Configuration
+ Add a pipe
+ Add a scheduler
+ Add a flowset
+Listing object
+Delete of object
+ Delete a pipe
+ Delete a flowset
+ Delete a scheduler
+Compatibility with FreeBSD7.2 and FreeBSD 8 ipfw binary
+ ip_dummynet_glue.c
+ ip_fw_glue.c
+How to configure dummynet
+How to implement a new scheduler
+
+
+
+OPEN ISSUES
+------------------------------
+20100131 deleting RR causes infinite loop
+ presumably in the rr_free_queue() call -- seems to hang
+ forever when deleting a live flow
+------------------------------
+
+Dummynet is a traffic shaper and network emulator. Packets are
+selected by an external filter such as ipfw, and passed to the emulator
+with a tag such as "pipe 10" or "queue 5" which tells what to
+do with the packet. As an example
+
+ ipfw add queue 5 icmp from 10.0.0.2 to all
+
+All packets with the same tag belong to a "flowset", or a set
+of flows which can be further partitioned according to a mask.
+Flowsets are then passed to a scheduler for processing. The
+association of flowsets and schedulers is configurable e.g.
+
+ ipfw queue 5 config sched 10 weight 3 flow_mask xxxx
+ ipfw queue 8 config sched 10 weight 1 ...
+ ipfw queue 3 config sched 20 weight 1 ...
+
+"sched 10" represents one or more scheduler instances,
+selected through a mask on the 5-tuple itself.
+
+ ipfw sched 20 config type FIFO sched_mask yyy ...
+
+There are in fact two masks applied to each packet:
++ the "sched_mask" sends packets arriving to a scheduler_id to
+ one of many instances.
++ the "flow_mask" together with the flowset_id is used to
+ collect packets into independent flows on each scheduler.
+
+As an example, we can have
+ ipfw queue 5 config sched 10 flow_mask src-ip 0x000000ff
+ ipfw sched 10 config type WF2Q+ sched_mask src-ip 0xffffff00
+
+means that sched 10 will have one instance per /24 source subnet,
+and within that, each individual source will be a flow.
+
+Internal structure
+-----------------
+Dummynet-related data is split into several data structures,
+part of them constituting the userland-kernel API, and others
+specific to the kernel.
+NOTE: for up-to-date details please look at the relevant source
+ headers (ip_dummynet.h, ip_dn_private.h, dn_sched.h)
+
+USERLAND-KERNEL API (ip_dummynet.h)
+
+ struct dn_link:
+ contains data about the physical link such as
+ bandwith, delay, burst size;
+
+ struct dn_fs:
+ describes a flowset, i.e. a template for queues.
+ Main parameters are the scheduler we attach to, a flow_mask,
+ buckets, queue size, plr, weight, and other scheduler-specific
+ parameters.
+
+ struct dn_flow
+ contains information on a flow, including masks and
+ statistics
+
+ struct dn_sch:
+ defines a scheduler (and a link attached to it).
+ Parameters include scheduler type, sched_mask, number of
+ buckets, and possibly other scheduler-specific parameters,
+
+ struct dn_profile:
+ fields to simulate a delay profile
+
+
+KERNEL REPRESENTATION (ip_dn_private.h)
+
+ struct mq
+ a queue of mbufs with head and tail.
+
+ struct dn_queue
+ individual queue of packets, created by a flowset using
+ flow_mask and attached to a scheduler instance selected
+ through sched_mask.
+ A dn_queue has a pointer to the dn_fsk (which in turn counts
+ how many queues point to it), a pointer to the
+ dn_sch_inst it attaches to, and is in a hash table in the
+ flowset. scheduler instances also should store queues in
+ their own containers used for scheduling (lists, trees, etc.)
+ CREATE: done on packet arrivals when a flow matches a flowset.
+ DELETE: done only when deleting the parent dn_sch_inst
+ or draining memory.
+
+ struct dn_fsk
+ includes a dn_fs; a pointer to the dn_schk; a link field
+ for the list of dn_fsk attached to the same scheduler,
+ or for the unlinked list;
+ a refcount for the number of queues pointing to it;
+ The dn_fsk is in a hash table, fshash.
+ CREATE: done on configuration commands.
+ DELETE: on configuration commands.
+
+ struct dn_sch_inst
+ a scheduler instance, created from a dn_schk applying sched_mask.
+ Contains a delay line, a reference to the parent, and scheduler-
+ specific info. Both dn_sch_inst and its delay line can be in the
+ evheap if they have events to be processed.
+ CREATE: created from a dn_schk applying sched_mask
+ DELETE: configuration command delete a scheduler which in turn
+ sweeps the hash table of instances deleting them
+
+ struct dn_schk
+ includes dn_sch, dn_link, a pointer to dn_profile,
+ a hash table of dn_sch_inst, a list of dn_fsk
+ attached to it.
+ CREATE: configuration command. If there are flowsets that
+ refer to this number, they are attached and moved
+ to the hash table
+ DELETE: manual, see dn_sch_inst
+
+
+ fshash schedhash
+ +---------------+ sched +--------------+
+ | sched-------------------->| NEW_SCHK|
+ -<----*sch_chain |<-----------------*fsk_list |
+ |NEW_FSK |<----. | [dn_link] |
+ +---------------+ | +--------------+
+ |qht (hash) | | | siht(hash) |
+ | [dn_queue] | | | [dn_si] |
+ | [dn_queue] | | | [dn_si] |
+ | ... | | | ... |
+ | +--------+ | | | +---------+ |
+ | |dn_queue| | | | |dn_si | |
+ | | fs *----------' | | | |
+ | | si *---------------------->| | |
+ | +---------+ | | +---------+ |
+ +---------------+ +--------------+
+
+The following global data structures contain all
+schedulers and flowsets.
+
+- schedhash[x]: contains all scheduler templates in the system.
+ Looked up only on manual configurations, where flowsets
+ are attached to matching schedulers.
+ We have one entry per 'sched X config' command
+ (plus one for each 'pipe X config').
+
+- fshash[x]: contains all flowsets.
+ We do a lookup on this for each packet.
+ We have one entry for each 'queue X config'
+ (plus one for each 'pipe X config').
+
+Additionally, a list that contains all unlinked flowset:
+- fsu: contains flowset that are not linked with any scheduler.
+ Flowset are put in this list when they refer to a non
+ existing scheduler.
+ We don't need an efficient data structure as we never search
+ here on a packet arrivals.
+
+Scheduler instances and the delay lines associated with each scheduler
+instance need to be woken up at certain times. Because we have many
+such objects, we keep them in a priority heap (system_heap).
+
+Almost all objects in this implementation are preceded by a structure
+(struct dn_id) which makes it easier to identify them.
+
+
+Files
+-----
+The dummynet code is split in several files.
+All kernel code is in sys/netinet/ipfw except ip_dummynet.h
+All userland code is in sbin/ipfw.
+Files are
+- sys/netinet/ip_dummynet.h defines the kernel-userland API
+- ip_dn_private.h contains the kernel-specific APIs
+ and data structures
+- dn_sched.h defines the scheduler API
+- ip_dummynet.c cointains module glue and sockopt handlers, with all
+ functions to configure and list objects.
+- ip_dn_io.c contains the functions directly related to packet processing,
+ and run in the critical path. It also contains some functions
+ exported to the schedulers.
+- dn_heap.[ch] implement a binary heap and a generic hash table
+- dn_sched_* implement the various scheduler modules
+
+- dummynet.c is the file used to implement the user side of dummynet.
+ It contains the function to parsing command line, and functions to
+ show the output of dummynet objects.
+Moreover, there are two new file (ip_dummynet_glue.c and ip_fw_glue.c) that
+are used to allow compatibility with the "ipfw" binary from FreeBSD 7.2 and
+FreeBSD 8.
+
+LOCKING
+=======
+At the moment the entire processing occurs under a single lock
+which is expected to be acquired in exclusive mode
+DN_BH_WLOCK() / DN_BH_WUNLOCK().
+
+In perspective we aim at the following:
+- the 'busy' flag, 'pending' list and all structures modified by packet
+ arrivals and departures are protected by the BH_WLOCK.
+ This is normally acquired in exclusive mode by the packet processing
+ functions for short sections of code (exception -- the timer).
+ If 'busy' is not set, we can do regular packet processing.
+ If 'busy' is set, no pieces can be accessed.
+ We must enqueue the packet on 'pending' and return immediately.
+
+- the 'busy' flag is set/cleared by long sections of code as follows:
+ UH_WLOCK(); KASSERT(busy == 0);
+ BH_WLOCK(); busy=1; BH_WUNLOCK();
+ ... do processing ...
+ BH_WLOCK(); busy=0; drain_queue(pending); BH_WUNLOCK();
+ UH_WUNLOCK();
+ this normally happens when the upper half has something heavy
+ to do. The prologue and epilogue are not in the critical path.
+
+- the main containers (fshash, schedhash, ...) are protected by
+ UH_WLOCK.
+
+Packet processing
+=================
+A packet enters dummynet through dummynet_io(). We first lookup
+the flowset number in fshash using dn_ht_find(), then find the scheduler
+instance using ipdn_si_find(), then possibly identify the correct
+queue with ipdn_q_find().
+If successful, we call the scheduler's enqueue function(), and
+if needed start I/O on the link calling serve_sched().
+If the packet can be returned immediately, this is done by
+leaving *m0 set. Otherwise, the packet is absorbed by dummynet
+and we simply return, possibly with some appropriate error code.
+
+Reconfiguration
+---------------
+Reconfiguration is the complex part of the system because we need to
+keep track of the various objects and containers.
+At the moment we do not use reference counts for objects so all
+processing must be done under a lock.
+
+The main entry points for configuration is the ip_dn_ctl() handler
+for the IP_DUMMYNET3 sockopt (others are provided only for backward
+compatibility). Modifications to the configuration call do_config().
+The argument is a sequence of blocks each starting with a struct dn_id
+which specifies its content.
+The first dn_id must contain as obj.id the DN_API_VERSION
+The obj.type is DN_CMD_CONFIG (followed by actual objects),
+DN_CMD_DELETE (with the correct subtype and list of objects), or
+DN_CMD_FLUSH.
+
+DN_CMD_CONFIG is followed by objects to add/reconfigure. In general,
+if an object already exists it is reconfigured, otherwise it is
+created in a way that keeps the structure consistent.
+We have the following objects in the system, normally numbered with
+an identifier N between 1 and 65535. For certain objects we have
+"shadow" copies numbered I+NMAX and I+ 2*NMAX which are used to
+implement certain backward compatibility features.
+
+In general we have the following linking
+
+ TRADITIONAL DUMMYNET QUEUES "queue N config ... pipe M ..."
+ corresponds to a dn_fs object numbered N
+
+ TRADITIONAL DUMMYNET PIPES "pipe N config ..."
+ dn_fs N+2*NMAX --> dn_sch N+NMAX type FIFO --> dn_link N+NMAX
+
+ GENERIC SCHEDULER "sched N config ... "
+ [dn_fs N+NMAX] --> dn_sch N --> dn_link N
+ The flowset N+NMAX is created only if the scheduler is not
+ of type MULTIQUEUE.
+
+ DELAY PROFILE "pipe N config profile ..."
+ it is always attached to an existing dn_link N
+
+Because traditional dummynet pipes actually configure both a
+'standalone' instance and one that can be used by queues,
+we do the following:
+
+ "pipe N config ..." configures:
+ dn_sched N type WF2Q+
+ dn_sched N+NMAX type FIFO
+ dn_fs N+2NMAX attached to dn_sched N+NMAX
+ dn_pipe N
+ dn_pipe N+NMAX
+
+ "queue N config" configures
+ dn_fs N
+
+ "sched N config" configures
+ dn_sched N type as desired
+ dn_fs N+NMAX attached to dn_sched N
+
+
+dummynet_task()
+===============
+The dummynet_task() is the the main dummynet processing function and is
+called every tick. This function first calculate the new current time, then
+it checks if it is the time to wake up object from the system_heap comparing
+the current time and the key of the heap. Two types of object (really the
+heap contains pointer to objects) are in the
+system_heap:
+
+- scheduler instance: if a scheduler instance is waked up, the dequeue()
+ function is called until it has credit. If the dequeue() returns packets,
+ the scheduler instance is inserted in the heap with a new key depending of
+ the data that will be send out. If the scheduler instance remains with
+ some credit, it means that is hasn't other packet to send and so the
+ instance is no longer inserted in the heap.
+
+ If the scheduler instance extracted from the heap has the DELETE flag set,
+ the dequeue() is not called and the instance is destroyed now.
+
+- delay line: when extracting a delay line, the function transmit_event() is
+ called to send out packet from delay line.
+
+ If the scheduler instance associated with this delay line doesn't exists,
+ the delay line will be delete now.
+
+Configuration
+=============
+To create a pipe, queue or scheduler, the user should type commands like:
+"ipfw pipe x config"
+"ipfw queue y config pipe x"
+"ipfw pipe x config sched <type>"
+
+The userland side of dummynet will prepare a buffer contains data to pass to
+kernel side.
+The buffer contains all struct needed to configure an object. In more detail,
+to configure a pipe all three structs (dn_link, dn_sch, dn_fs) are needed,
+plus the delay profile struct if the pipe has a delay profile.
+
+If configuring a scheduler only the struct dn_sch is wrote in the buffer,
+while if configuring a flowset only the dn_fs struct is wrote.
+
+The first struct in the buffer contains the type of command request, that is
+if it is configuring a pipe, a queue, or a scheduler. Then there are structs
+need to configure the object, and finally there is the struct that mark
+the end of the buffer.
+
+To support the insertion of pipe and queue using the old syntax, when adding
+a pipe it's necessary to create a FIFO flowset and a FIFO scheduler, which
+have a number x + DN_PIPEOFFSET.
+
+Add a pipe
+----------
+A pipe is only a template for a link.
+If the pipe already exists, parameters are updated. If a delay profile exists
+it is deleted and a new one is created.
+If the pipe doesn't exist a new one is created. After the creation, the
+flowset unlinked list is scanned to see if there are some flowset that would
+be linked with this pipe. If so, these flowset will be of wf2q+ type (for
+compatibility) and a new wf2q+ scheduler is created now.
+
+Add a scheduler
+---------------
+If the scheduler already exists, and the type and the mask are the same, the
+scheduler is simply reconfigured calling the config_scheduler() scheduler
+function with the RECONFIGURE flag active.
+If the type or the mask differ, it is necessary to delete the old scheduler
+and create a new one.
+If the scheduler doesn't exists, a new one is created. If the scheduler has
+a mask, the hash table is created to store pointers to scheduler instances.
+When a new scheduler is created, it is necessary to scan the unlinked
+flowset list to search eventually flowset that would be linked with this
+scheduler number. If some are found, flowsets became of the type of this
+scheduler and they are configured properly.
+
+Add a flowset
+-------------
+Flowset pointers are store in the system in two list. The unlinked flowset list
+contains all flowset that aren't linked with a scheduler, the flowset list
+contains flowset linked to a scheduler, and so they have a type.
+When adding a new flowset, first it is checked if the flowset exists (that is,
+it is in the flowset list) and if it doesn't exists a new flowset is created
+and added to unlinked flowset list if the scheduler which the flowset would be
+linked doesn't exists, or added in the flowset list and configured properly if
+the scheduler exists. If the flowset (before to be created) was in the
+unlinked flowset list, it is removed and deleted, and then recreated.
+If the flowset exists, to allow reconfiguration of this flowset, the
+scheduler number and types must match with the one in memory. If this isn't
+so, the flowset is deleted and a new one will be created. Really, the flowset
+it isn't deleted now, but it is removed from flowset list and it will be
+deleted later because there could be some queues that are using it.
+
+Listing of object
+=================
+The user can request a list of object present in dummynet through the command
+"ipfw [-v] pipe|queue [x] list|show"
+The kernel side of dummynet send a buffer to user side that contains all
+pipe, all scheduler, all flowset, plus all scheduler instances and all queues.
+The dummynet user land will format the output and show only the relevant
+information.
+The buffer sent start with all pipe from the system. The entire struct dn_link
+is passed, except the delay_profile struct that is useless in user space.
+After pipes, all flowset are wrote in the buffer. The struct contains
+scheduler flowset specific data is linked with the flowset writing the
+'obj' id of the extension into the 'alg_fs' pointer.
+Then schedulers are wrote. If a scheduler has one or more scheduler instance,
+these are linked to the parent scheduler writing the id of the parent in the
+'ptr_sched' pointer. If a scheduler instance has queues, there are wrote in
+the buffer and linked thorugh the 'obj' and 'sched_inst' pointer.
+Finally, flowsets in the unlinked flowset list are write in the buffer, and
+then a struct gen in saved in the buffer to mark the last struct in the buffer.
+
+
+Delete of object
+================
+An object is usually removed by user through a command like
+"ipfw pipe|queue x delete". XXX sched?
+ipfw pass to the kernel a struct gen that contains the type and the number
+of the object to remove
+
+Delete of pipe x
+----------------
+A pipe can be deleted by the user throught the command 'ipfw pipe x delete'.
+To delete a pipe, the pipe is removed from the pipe list, and then deleted.
+Also the scheduler associated with this pipe should be deleted.
+For compatibility with old dummynet syntax, the associated FIFO scheduler and
+FIFO flowset must be deleted.
+
+Delete of flowset x
+-------------------
+To remove a flowset, we must be sure that is no loger referenced by any object.
+If the flowset to remove is in the unlinked flowset list, there is not any
+issue, the flowset can be safely removed calling a free() (the flowset
+extension is not yet created if the flowset is in this list).
+If the flowset is in the flowset list, first we remove from it so new packet
+are discarded when arrive. Next, the flowset is marked as delete.
+Now we must check if some queue is using this flowset.
+To do this, a counter (active_f) is provided. This counter indicate how many
+queues exist using this flowset.
+The active_f counter is automatically incremented when a queue is created
+and decremented when a queue is deleted.
+If the counter is 0, the flowset can be safely deleted, and the delete_alg_fs()
+scheduler function is called before deallocate memory.
+If the counter is not 0, the flowset remain in memory until the counter become
+zero. When a queue is delete (by dn_delete_queue() function) it is checked if
+the linked flowset is deleting and if so the counter is decrementing. If the
+counter reaches 0, the flowset is deleted.
+The deletion of a queue can be done only by the scheduler, or when the scheduler
+is destroyed.
+
+Delete of scheduler x
+---------------------
+To delete a scheduler we must be sure that any scheduler instance of this type
+are in the system_heap. To do so, a counter (inst_counter) is provided.
+This counter is managed by the system: it is incremented every time it is
+inserted in the system_heap, and decremented every time it is extracted from it.
+To delete the scheduler, first we remove it from the scheduler list, so new
+packet are discarded when they arrive, and mark the scheduler as deleting.
+
+If the counter is 0, we can remove the scheduler safely calling the
+really_deletescheduler() function. This function will scan all scheduler
+instances and call the delete_scheduler_instance() function that will delete
+the instance. When all instance are deleted, the scheduler template is
+deleted calling the delete_scheduler_template(). If the delay line associate
+with the scheduler is empty, it is deleted now, else it will be deleted when
+it will became empy.
+If the counter was not 0, we wait for it. Every time the dummynet_task()
+function extract a scheduler from the system_heap, the counter is decremented.
+If the scheduler has the delete flag enabled the dequeue() is not called and
+delete_scheduler_instance() is called to delete the instance.
+Obviously this scheduler instance is no loger inserted in the system_heap.
+If the counter reaches 0, the delete_scheduler_template() function is called
+all memory is released.
+NOTE: Flowsets that belong to this scheduler are not deleted, so if a new
+ scheduler with the same number is inserted will use these flowsets.
+ To do so, the best approach would be insert these flowset in the
+ unlinked flowset list, but doing this now will be very expensive.
+ So flowsets will remain in memory and linked with a scheduler that no
+ longer exists until a packet belonging to this flowset arrives. When
+ this packet arrives, the reconfigure() function is called because the
+ generation number mismatch with one contains in the flowset and so
+ the flowset will be moved into the flowset unlinked list, or will be
+ linked with the new scheduler if a new one was created.
+
+
+COMPATIBILITY WITH FREEBSD 7.2 AND FREEBSD 8 'IPFW' BINARY
+==========================================================
+Dummynet is not compatible with old ipfw binary because internal structs are
+changed. Moreover, the old ipfw binary is not compatible with new kernels
+because the struct that represents a firewall rule has changed. So, if a user
+install a new kernel on a FreeBSD 7.2, the ipfw (and possibly many other
+commands) will not work.
+New dummynet uses a new socket option: IP_DUMMYNET3, used for both set and get.
+The old option can be used to allow compatibility with the 'ipfw' binary of
+older version (tested with 7.2 and 8.0) of FreeBSD.
+Two file are provided for this purpose:
+- ip_dummynet_glue.c translates old dummynet requests to the new ones,
+- ip_fw_glue.c converts the rule format between 7.2 and 8 versions.
+Let see in detail these two files.
+
+IP_DUMMYNET_GLUE.C
+------------------
+The internal structs of new dummynet are very different from the original.
+Because of there are some difference from between dummynet in FreeBSD 7.2 and
+dummynet in FreeBSD 8 (the FreeBSD 8 version includes support to pipe delay
+profile and burst option), I have to include both header files. I copied
+the revision 191715 (for version 7.2) and the revision 196045 (for version 8)
+and I appended a number to each struct to mark them.
+
+The main function of this file is ip_dummynet_compat() that is called by
+ip_dn_ctl() when it receive a request of old socket option.
+
+A global variabile ('is7') store the version of 'ipfw' that FreeBSD is using.
+This variable is set every time a request of configuration is done, because
+with this request we receive a buffer of which size depending of ipfw version.
+Because of in general the first action is a configuration, this variable is
+usually set accordly. If the first action is a request of listing of pipes
+or queues, the system cannot know the version of ipfw, and we suppose that
+version 7.2 is used. If version is wrong, the output can be senseless, but
+the application should not crash.
+
+There are four request for old dummynet:
+- IP_DUMMYNET_FLUSH: the flush options have no parameter, so simply the
+ dummynet_flush() function is called;
+- IP_DUMMYNET_DEL: the delete option need to be translate.
+ It is only necessary to extract the number and the type of the object
+ (pipe or queue) to delete from the buffer received and build a new struct
+ gen contains the right parameters, then call the delete_object() function;
+- IP_DUMMYNET_CONFIGURE: the configure command receive a buffer depending of
+ the ipfw version. After the properly extraction of all data, that depends
+ by the ipfw version used, new structures are filled and then the dummynet
+ config_link() function is properly called. Note that the 7.2 version does
+ not support some parameter as burst or delay profile.
+- IP_DUMMYNET_GET: The get command should send to the ipfw the correct buffer
+ depending of its version. There are two function that build the
+ corrected buffer, ip_dummynet_get7() and ip_dummynet_get8(). These
+ functions reproduce the buffer exactly as 'ipfw' expect. The only difference
+ is that the weight parameter for a queue is no loger sent by dummynet and so
+ it is set to 0.
+ Moreover, because of the internal structure has changed, the bucket size
+ of a queue could not be correct, because now all flowset share the hash
+ table.
+ If the version of ipfw is wrong, the output could be senseless or truncated,
+ but the application should not crash.
+
+IP_FW_GLUE.C
+------------
+The ipfw binary also is used to add rules to FreeBSD firewall. Because of the
+struct ip_fw is changed from FreeBsd 7.2 to FreeBSD 8, it is necessary
+to write some glue code to allow use ipfw from FreeBSD 7.2 with the kernel
+provided with FreeBSD 8.
+This file contains two functions to convert a rule from FreeBSD 7.2 format to
+FreeBSD 8 format, and viceversa.
+The conversion should be done when a rule passes from userspace to kernel space
+and viceversa.
+I have to modify the ip_fw2.c file to manage these two case, and added a
+variable (is7) to store the ipfw version used, using an approach like the
+previous file:
+- when a new rule is added (option IP_FW_ADD) the is7 variable is set if the
+ size of the rule received corrispond to FreeBSD 7.2 ipfw version. If so, the
+ rule is converted to version 8 calling the function convert_rule_to_8().
+ Moreover, after the insertion of the rule, the rule is now reconverted to
+ version 7 because the ipfw binary will print it.
+- when the user request a list of rules (option IP_FW_GET) the is7 variable
+ should be set correctly because we suppose that a configure command was done,
+ else we suppose that the FreeBSD version is 8. The function ipfw_getrules()
+ in ip_fw2.c file return all rules, eventually converted to version 7 (if
+ the is7 is set) to the ipfw binary.
+The conversion of a rule is quite simple. The only difference between the
+two structures (struct ip_fw) is that in the new there is a new field
+(uint32_t id). So, I copy the entire rule in a buffer and the copy the rule in
+the right position in the new (or old) struct. The size of commands are not
+changed, and the copy is done into a cicle.
+
+How to configure dummynet
+=========================
+It is possible to configure dummynet through two main commands:
+'ipfw pipe' and 'ipfw queue'.
+To allow compatibility with old version, it is possible configure dummynet
+using the old command syntax. Doing so, obviously, it is only possible to
+configure a FIFO scheduler or a wf2q+ scheduler.
+A new command, 'ipfw pipe x config sched <type>' is supported to add a new
+scheduler to the system.
+
+- ipfw pipe x config ...
+ create a new pipe with the link parameters
+ create a new scheduler fifo (x + offset)
+ create a new flowset fifo (x + offset)
+ the mask is eventually stored in the FIFO scheduler
+
+- ipfw queue y config pipe x ...
+ create a new flowset y linked to sched x.
+ The type of flowset depends by the specified scheduler.
+ If the scheduler does not exist, this flowset is inserted in a special
+ list and will be not active.
+ If pipe x exists and sched does not exist, a new wf2q+ scheduler is
+ created and the flowset will be linked to this new scheduler (this is
+ done for compatibility with old syntax).
+
+- ipfw pipe x config sched <type> ...
+ create a new scheduler x of type <type>.
+ Search into the flowset unlinked list if there are some flowset that
+ should be linked with this new scheduler.
+
+- ipfw pipe x delete
+ delete the pipe x
+ delete the scheduler fifo (x + offset)
+ delete the scheduler x
+ delete the flowset fifo (x + offset)
+
+- ipfw queue x delete
+ delete the flowset x
+
+- ipfw sched x delete ///XXX
+ delete the scheduler x
+
+Follow now some examples to how configure dummynet:
+- Ex1:
+ ipfw pipe 10 config bw 1M delay 15 // create a pipe with band and delay
+ A FIFO flowset and scheduler is
+ also created
+ ipfw queue 5 config pipe 10 weight 56 // create a flowset. This flowset
+ will be of wf2q+ because a pipe 10
+ exists. Moreover, the wf2q+
+ scheduler is created now.
+- Ex2:
+ ipfw queue 5 config pipe 10 weight 56 // Create a flowset. Scheduler 10
+ does not exist, so this flowset
+ is inserted in the unlinked
+ flowset list.
+ ipfw pipe 10 config bw... // Create a pipe, a FIFO flowset and scheduler.
+ Because of a flowset with 'pipe 10' exists,
+ a wf2q+ scheduler is created now and that
+ flowset is linked with this sceduler.
+
+- Ex3:
+ ipfw pipe 10 config bw... // Create a pipe, a FIFO flowset and scheduler.
+ ipfw pipe 10 config sched rr // Create a scheduler of type RR, linked to
+ pipe 10
+ ipfw queue 5 config pipe 10 weight 56 // Create a flowset 5. This flowset
+ will belong to scheduler 10 and
+ it is of type RR
+
+- Ex4:
+ ipfw pipe 10 config sched rr // Create a scheduler of type RR, linked to
+ pipe 10 (not exist yet)
+ ipfw pipe 10 config bw... // Create a pipe, a FIFO flowset and scheduler.
+ ipfw queue 5 config pipe 10 weight 56 // Create a flowset 5.This flowset
+ will belong to scheduler 10 and
+ it is of type RR
+ ipfw pipe 10 config sched wf2q+ // Modify the type of scheduler 10. It
+ becomes a wf2q+ scheduler.
+ When a new packet of flowset 5 arrives,
+ the flowset 5 becomes to wf2q+ type.
+
+How to implement a new scheduler
+================================
+In dummynet, a scheduler algorithm is represented by two main structs, some
+functions and other minor structs.
+- A struct dn_sch_xyz (where xyz is the 'type' of scheduler algorithm
+ implemented) contains data relative to scheduler, as global parameter that
+ are common to all instances of the scheduler
+- A struct dn_sch_inst_xyz contains data relative to a single scheduler
+ instance, as local status variable depending for example by flows that
+ are linked with the scheduler, and so on.
+To add a scheduler to dummynet, the user should type a command like:
+'ipfw pipe x config sched <type> [mask ... ...]'
+This command creates a new struct dn_sch_xyz of type <type>, and
+store the optional parameter in that struct.
+
+The parameter mask determines how many scheduler instance of this
+scheduler may exist. For example, it is possible to divide traffic
+depending on the source port (or destination, or ip address...),
+so that every scheduler instance act as an independent scheduler.
+If the mask is not set, all traffic goes to the same instance.
+
+When a packet arrives to a scheduler, the system search the corrected
+scheduler instance, and if it does not exist it is created now (the
+struct dn_sch_inst_xyz is allocated by the system, and the scheduler
+fills the field correctly). It is a task of the scheduler to create
+the struct that contains all queues for a scheduler instance.
+Dummynet provides some function to create an hash table to store
+queues, but the schedule algorithm can choice the own struct.
+
+To link a flow to a scheduler, the user should type a command like:
+'ipfw queue z config pipe x [mask... ...]'
+
+This command creates a new 'dn_fs' struct that will be inserted
+in the system. If the scheduler x exists, this flowset will be
+linked to that scheduler and the flowset type become the same as
+the scheduler type. At this point, the function create_alg_fs_xyz()
+is called to allow store eventually parameter for the flowset that
+depend by scheduler (for example the 'weight' parameter for a wf2q+
+scheduler, or some priority...). A parameter mask can be used for
+a flowset. If the mask parameter is set, the scheduler instance can
+separate packet according to its flow id (src and dst ip, ports...)
+and assign it to a separate queue. This is done by the scheduler,
+so it can ignore the mask if it wants.
+
+See now the two main structs:
+struct dn_sch_xyz {
+ struct gen g; /* important the name g */
+ /* global params */
+};
+struct dn_sch_inst_xyz {
+ struct gen g; /* important the name g */
+ /* params of the instance */
+};
+It is important to embed the struct gen as first parameter. The struct gen
+contains some values that the scheduler instance must fill (the 'type' of
+scheduler, the 'len' of the struct...)
+The function create_scheduler_xyz() should be implemented to initialize global
+parameters in the first struct, and if memory allocation is done it is
+mandatory to implement the delete_scheduler_template() function to free that
+memory.
+The function create_scheduler_instance_xyz() must be implemented even if the
+scheduler instance does not use extra parameters. In this function the struct
+gen fields must be filled with corrected infos. The
+delete_scheduler_instance_xyz() function must bu implemented if the instance
+has allocated some memory in the previous function.
+
+To store data belonging to a flowset the follow struct is used:
+struct alg_fs_xyz {
+ struct gen g;
+ /* fill correctly the gen struct
+ g.subtype = DN_XYZ;
+ g.len = sizeof(struct alg_fs_xyz)
+ ...
+ */
+ /* params for the flow */
+};
+The create_alg_fs_xyz() function is mandatory, because it must fill the struct
+gen, but the delete_alg_fs_xyz() is mandatory only if the previous function
+has allocated some memory.
+
+A struct dn_queue contains packets belonging to a queue and some statistical
+data. The scheduler could have to store data in this struct, so it must define
+a dn_queue_xyz struct:
+struct dn_queue_xyz {
+ struct dn_queue q;
+ /* parameter for a queue */
+}
+
+All structures are allocated by the system. To do so, the scheduler must
+set the size of its structs in the scheduler descriptor:
+scheduler_size: sizeof(dn_sch_xyz)
+scheduler_i_size: sizeof(dn_sch_inst_xyz)
+flowset_size: sizeof(alg_fs_xyz)
+queue_size: sizeof(dn_queue_xyz);
+The scheduler_size could be 0, but other struct must have at least a struct gen.
+
+
+After the definition of structs, it is necessary to implement the
+scheduler functions.
+
+- int (*config_scheduler)(char *command, void *sch, int reconfigure);
+ Configure a scheduler, or reconfigure if 'reconfigure' == 1.
+ This function performs additional allocation and initialization of global
+ parameter for this scheduler.
+ If memory is allocated here, the delete_scheduler_template() function
+ should be implemented to remove this memory.
+- int (*delete_scheduler_template)(void* sch);
+ Delete a scheduler template. This function is mandatory if the scheduler
+ uses extra data respect the struct dn_sch.
+- int (*create_scheduler_instance)(void *s);
+ Create a new scheduler instance. The system allocate the necessary memory
+ and the schedulet can access it using the 's' pointer.
+ The scheduler instance stores all queues, and to do this can use the
+ hash table provided by the system.
+- int (*delete_scheduler_instance)(void *s);
+ Delete a scheduler instance. It is important to free memory allocated
+ by create_scheduler_instance() function. The memory allocated by system
+ is freed by the system itself. The struct contains all queue also has
+ to be deleted.
+- int (*enqueue)(void *s, struct gen *f, struct mbuf *m,
+ struct ipfw_flow_id *id);
+ Called when a packet arrives. The packet 'm' belongs to the scheduler
+ instance 's', has a flowset 'f' and the flowid 'id' has already been
+ masked. The enqueue() must call dn_queue_packet(q, m) function to really
+ enqueue packet in the queue q. The queue 'q' is chosen by the scheduler
+ and if it does not exist should be created calling the dn_create_queue()
+ function. If the schedule want to drop the packet, it must call the
+ dn_drop_packet() function and then return 1.
+- struct mbuf * (*dequeue)(void *s);
+ Called when the timer expires (or when a packet arrives and the scheduler
+ instance is idle).
+ This function is called when at least a packet can be send out. The
+ scheduler choices the packet and returns it; if no packet are in the
+ schedulerinstance, the function must return NULL.
+ Before return a packet, it is important to call the function
+ dn_return_packet() to update some statistic of the queue and update the
+ queue counters.
+- int (*drain_queue)(void *s, int flag);
+ The system request to scheduler to delete all queues that is not using
+ to free memory. The flag parameter indicate if a queue must be deleted
+ even if it is active.
+
+- int (*create_alg_fs)(char *command, struct gen *g, int reconfigure);
+ It is called when a flowset is linked with a scheduler. This is done
+ when the scheduler is defined, so we can know the type of flowset.
+ The function initialize the flowset paramenter parsing the command
+ line. The parameter will be stored in the g struct that have the right
+ size allocated by the system. If the reconfigure flag is set, it means
+ that the flowset is reconfiguring
+- int (*delete_alg_fs)(struct gen *f);
+ It is called when a flowset is deleting. Must remove the memory allocate
+ by the create_alg_fs() function.
+
+- int (*create_queue_alg)(struct dn_queue *q, struct gen *f);
+ Called when a queue is created. The function should link the queue
+ to the struct used by the scheduler instance to store all queues.
+- int (*delete_queue_alg)(struct dn_queue *q);
+ Called when a queue is deleting. The function should remove extra data
+ and update the struct contains all queues in the scheduler instance.
+
+The struct scheduler represent the scheduler descriptor that is passed to
+dummynet when a scheduler module is loaded.
+This struct contains the type of scheduler, the lenght of all structs and
+all function pointers.
+If a function is not implemented should be initialize to NULL. Some functions
+are mandatory, other are mandatory if some memory should be freed.
+Mandatory functions:
+- create_scheduler_instance()
+- enqueue()
+- dequeue()
+- create_alg_fs()
+- drain_queue()
+Optional functions:
+- config_scheduler()
+- create_queue_alg()
+Mandatory functions if the corresponding create...() has allocated memory:
+- delete_scheduler_template()
+- delete_scheduler_instance()
+- delete_alg_fs()
+- delete_queue_alg()
+
diff --git a/sys/netinet/ipfw/ip_dn_glue.c b/sys/netinet/ipfw/ip_dn_glue.c
new file mode 100644
index 0000000..69f189c
--- /dev/null
+++ b/sys/netinet/ipfw/ip_dn_glue.c
@@ -0,0 +1,843 @@
+/*-
+ * Copyright (c) 2010 Riccardo Panicucci, Universita` di Pisa
+ * 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$
+ *
+ * Binary compatibility support for /sbin/ipfw RELENG_7 and RELENG_8
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/rwlock.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/time.h>
+#include <sys/taskqueue.h>
+#include <net/if.h> /* IFNAMSIZ, struct ifaddr, ifq head, lock.h mutex.h */
+#include <netinet/in.h>
+#include <netinet/ip_var.h> /* ip_output(), IP_FORWARDING */
+#include <netinet/ip_fw.h>
+#include <netinet/ipfw/ip_fw_private.h>
+#include <netinet/ipfw/dn_heap.h>
+#include <netinet/ip_dummynet.h>
+#include <netinet/ipfw/ip_dn_private.h>
+#include <netinet/ipfw/dn_sched.h>
+
+/* FREEBSD7.2 ip_dummynet.h r191715*/
+
+struct dn_heap_entry7 {
+ int64_t key; /* sorting key. Topmost element is smallest one */
+ void *object; /* object pointer */
+};
+
+struct dn_heap7 {
+ int size;
+ int elements;
+ int offset; /* XXX if > 0 this is the offset of direct ptr to obj */
+ struct dn_heap_entry7 *p; /* really an array of "size" entries */
+};
+
+/* Common to 7.2 and 8 */
+struct dn_flow_set {
+ SLIST_ENTRY(dn_flow_set) next; /* linked list in a hash slot */
+
+ u_short fs_nr ; /* flow_set number */
+ u_short flags_fs;
+#define DNOLD_HAVE_FLOW_MASK 0x0001
+#define DNOLD_IS_RED 0x0002
+#define DNOLD_IS_GENTLE_RED 0x0004
+#define DNOLD_QSIZE_IS_BYTES 0x0008 /* queue size is measured in bytes */
+#define DNOLD_NOERROR 0x0010 /* do not report ENOBUFS on drops */
+#define DNOLD_HAS_PROFILE 0x0020 /* the pipe has a delay profile. */
+#define DNOLD_IS_PIPE 0x4000
+#define DNOLD_IS_QUEUE 0x8000
+
+ struct dn_pipe7 *pipe ; /* pointer to parent pipe */
+ u_short parent_nr ; /* parent pipe#, 0 if local to a pipe */
+
+ int weight ; /* WFQ queue weight */
+ int qsize ; /* queue size in slots or bytes */
+ int plr ; /* pkt loss rate (2^31-1 means 100%) */
+
+ struct ipfw_flow_id flow_mask ;
+
+ /* hash table of queues onto this flow_set */
+ int rq_size ; /* number of slots */
+ int rq_elements ; /* active elements */
+ struct dn_flow_queue7 **rq; /* array of rq_size entries */
+
+ u_int32_t last_expired ; /* do not expire too frequently */
+ int backlogged ; /* #active queues for this flowset */
+
+ /* RED parameters */
+#define SCALE_RED 16
+#define SCALE(x) ( (x) << SCALE_RED )
+#define SCALE_VAL(x) ( (x) >> SCALE_RED )
+#define SCALE_MUL(x,y) ( ( (x) * (y) ) >> SCALE_RED )
+ int w_q ; /* queue weight (scaled) */
+ int max_th ; /* maximum threshold for queue (scaled) */
+ int min_th ; /* minimum threshold for queue (scaled) */
+ int max_p ; /* maximum value for p_b (scaled) */
+ u_int c_1 ; /* max_p/(max_th-min_th) (scaled) */
+ u_int c_2 ; /* max_p*min_th/(max_th-min_th) (scaled) */
+ u_int c_3 ; /* for GRED, (1-max_p)/max_th (scaled) */
+ u_int c_4 ; /* for GRED, 1 - 2*max_p (scaled) */
+ u_int * w_q_lookup ; /* lookup table for computing (1-w_q)^t */
+ u_int lookup_depth ; /* depth of lookup table */
+ int lookup_step ; /* granularity inside the lookup table */
+ int lookup_weight ; /* equal to (1-w_q)^t / (1-w_q)^(t+1) */
+ int avg_pkt_size ; /* medium packet size */
+ int max_pkt_size ; /* max packet size */
+};
+SLIST_HEAD(dn_flow_set_head, dn_flow_set);
+
+#define DN_IS_PIPE 0x4000
+#define DN_IS_QUEUE 0x8000
+struct dn_flow_queue7 {
+ struct dn_flow_queue7 *next ;
+ struct ipfw_flow_id id ;
+
+ struct mbuf *head, *tail ; /* queue of packets */
+ u_int len ;
+ u_int len_bytes ;
+
+ u_long numbytes;
+
+ u_int64_t tot_pkts ; /* statistics counters */
+ u_int64_t tot_bytes ;
+ u_int32_t drops ;
+
+ int hash_slot ; /* debugging/diagnostic */
+
+ /* RED parameters */
+ int avg ; /* average queue length est. (scaled) */
+ int count ; /* arrivals since last RED drop */
+ int random ; /* random value (scaled) */
+ u_int32_t q_time; /* start of queue idle time */
+
+ /* WF2Q+ support */
+ struct dn_flow_set *fs ; /* parent flow set */
+ int heap_pos ; /* position (index) of struct in heap */
+ int64_t sched_time ; /* current time when queue enters ready_heap */
+
+ int64_t S,F ; /* start time, finish time */
+};
+
+struct dn_pipe7 { /* a pipe */
+ SLIST_ENTRY(dn_pipe7) next; /* linked list in a hash slot */
+
+ int pipe_nr ; /* number */
+ int bandwidth; /* really, bytes/tick. */
+ int delay ; /* really, ticks */
+
+ struct mbuf *head, *tail ; /* packets in delay line */
+
+ /* WF2Q+ */
+ struct dn_heap7 scheduler_heap ; /* top extract - key Finish time*/
+ struct dn_heap7 not_eligible_heap; /* top extract- key Start time */
+ struct dn_heap7 idle_heap ; /* random extract - key Start=Finish time */
+
+ int64_t V ; /* virtual time */
+ int sum; /* sum of weights of all active sessions */
+
+ int numbytes;
+
+ int64_t sched_time ; /* time pipe was scheduled in ready_heap */
+
+ /*
+ * When the tx clock come from an interface (if_name[0] != '\0'), its name
+ * is stored below, whereas the ifp is filled when the rule is configured.
+ */
+ char if_name[IFNAMSIZ];
+ struct ifnet *ifp ;
+ int ready ; /* set if ifp != NULL and we got a signal from it */
+
+ struct dn_flow_set fs ; /* used with fixed-rate flows */
+};
+SLIST_HEAD(dn_pipe_head7, dn_pipe7);
+
+
+/* FREEBSD8 ip_dummynet.h r196045 */
+struct dn_flow_queue8 {
+ struct dn_flow_queue8 *next ;
+ struct ipfw_flow_id id ;
+
+ struct mbuf *head, *tail ; /* queue of packets */
+ u_int len ;
+ u_int len_bytes ;
+
+ uint64_t numbytes ; /* credit for transmission (dynamic queues) */
+ int64_t extra_bits; /* extra bits simulating unavailable channel */
+
+ u_int64_t tot_pkts ; /* statistics counters */
+ u_int64_t tot_bytes ;
+ u_int32_t drops ;
+
+ int hash_slot ; /* debugging/diagnostic */
+
+ /* RED parameters */
+ int avg ; /* average queue length est. (scaled) */
+ int count ; /* arrivals since last RED drop */
+ int random ; /* random value (scaled) */
+ int64_t idle_time; /* start of queue idle time */
+
+ /* WF2Q+ support */
+ struct dn_flow_set *fs ; /* parent flow set */
+ int heap_pos ; /* position (index) of struct in heap */
+ int64_t sched_time ; /* current time when queue enters ready_heap */
+
+ int64_t S,F ; /* start time, finish time */
+};
+
+struct dn_pipe8 { /* a pipe */
+ SLIST_ENTRY(dn_pipe8) next; /* linked list in a hash slot */
+
+ int pipe_nr ; /* number */
+ int bandwidth; /* really, bytes/tick. */
+ int delay ; /* really, ticks */
+
+ struct mbuf *head, *tail ; /* packets in delay line */
+
+ /* WF2Q+ */
+ struct dn_heap7 scheduler_heap ; /* top extract - key Finish time*/
+ struct dn_heap7 not_eligible_heap; /* top extract- key Start time */
+ struct dn_heap7 idle_heap ; /* random extract - key Start=Finish time */
+
+ int64_t V ; /* virtual time */
+ int sum; /* sum of weights of all active sessions */
+
+ /* Same as in dn_flow_queue, numbytes can become large */
+ int64_t numbytes; /* bits I can transmit (more or less). */
+ uint64_t burst; /* burst size, scaled: bits * hz */
+
+ int64_t sched_time ; /* time pipe was scheduled in ready_heap */
+ int64_t idle_time; /* start of pipe idle time */
+
+ char if_name[IFNAMSIZ];
+ struct ifnet *ifp ;
+ int ready ; /* set if ifp != NULL and we got a signal from it */
+
+ struct dn_flow_set fs ; /* used with fixed-rate flows */
+
+ /* fields to simulate a delay profile */
+#define ED_MAX_NAME_LEN 32
+ char name[ED_MAX_NAME_LEN];
+ int loss_level;
+ int samples_no;
+ int *samples;
+};
+
+#define ED_MAX_SAMPLES_NO 1024
+struct dn_pipe_max8 {
+ struct dn_pipe8 pipe;
+ int samples[ED_MAX_SAMPLES_NO];
+};
+SLIST_HEAD(dn_pipe_head8, dn_pipe8);
+
+/*
+ * Changes from 7.2 to 8:
+ * dn_pipe:
+ * numbytes from int to int64_t
+ * add burst (int64_t)
+ * add idle_time (int64_t)
+ * add profile
+ * add struct dn_pipe_max
+ * add flag DN_HAS_PROFILE
+ *
+ * dn_flow_queue
+ * numbytes from u_long to int64_t
+ * add extra_bits (int64_t)
+ * q_time from u_int32_t to int64_t and name idle_time
+ *
+ * dn_flow_set unchanged
+ *
+ */
+
+/* NOTE:XXX copied from dummynet.c */
+#define O_NEXT(p, len) ((void *)((char *)p + len))
+static void
+oid_fill(struct dn_id *oid, int len, int type, uintptr_t id)
+{
+ oid->len = len;
+ oid->type = type;
+ oid->subtype = 0;
+ oid->id = id;
+}
+/* make room in the buffer and move the pointer forward */
+static void *
+o_next(struct dn_id **o, int len, int type)
+{
+ struct dn_id *ret = *o;
+ oid_fill(ret, len, type, 0);
+ *o = O_NEXT(*o, len);
+ return ret;
+}
+
+
+static size_t pipesize7 = sizeof(struct dn_pipe7);
+static size_t pipesize8 = sizeof(struct dn_pipe8);
+static size_t pipesizemax8 = sizeof(struct dn_pipe_max8);
+
+/* Indicate 'ipfw' version
+ * 1: from FreeBSD 7.2
+ * 0: from FreeBSD 8
+ * -1: unknow (for now is unused)
+ *
+ * It is update when a IP_DUMMYNET_DEL or IP_DUMMYNET_CONFIGURE request arrives
+ * NOTE: if a IP_DUMMYNET_GET arrives and the 'ipfw' version is unknow,
+ * it is suppose to be the FreeBSD 8 version.
+ */
+static int is7 = 0;
+
+static int
+convertflags2new(int src)
+{
+ int dst = 0;
+
+ if (src & DNOLD_HAVE_FLOW_MASK)
+ dst |= DN_HAVE_MASK;
+ if (src & DNOLD_QSIZE_IS_BYTES)
+ dst |= DN_QSIZE_BYTES;
+ if (src & DNOLD_NOERROR)
+ dst |= DN_NOERROR;
+ if (src & DNOLD_IS_RED)
+ dst |= DN_IS_RED;
+ if (src & DNOLD_IS_GENTLE_RED)
+ dst |= DN_IS_GENTLE_RED;
+ if (src & DNOLD_HAS_PROFILE)
+ dst |= DN_HAS_PROFILE;
+
+ return dst;
+}
+
+static int
+convertflags2old(int src)
+{
+ int dst = 0;
+
+ if (src & DN_HAVE_MASK)
+ dst |= DNOLD_HAVE_FLOW_MASK;
+ if (src & DN_IS_RED)
+ dst |= DNOLD_IS_RED;
+ if (src & DN_IS_GENTLE_RED)
+ dst |= DNOLD_IS_GENTLE_RED;
+ if (src & DN_NOERROR)
+ dst |= DNOLD_NOERROR;
+ if (src & DN_HAS_PROFILE)
+ dst |= DNOLD_HAS_PROFILE;
+ if (src & DN_QSIZE_BYTES)
+ dst |= DNOLD_QSIZE_IS_BYTES;
+
+ return dst;
+}
+
+static int
+dn_compat_del(void *v)
+{
+ struct dn_pipe7 *p = (struct dn_pipe7 *) v;
+ struct dn_pipe8 *p8 = (struct dn_pipe8 *) v;
+ struct {
+ struct dn_id oid;
+ uintptr_t a[1]; /* add more if we want a list */
+ } cmd;
+
+ /* XXX DN_API_VERSION ??? */
+ oid_fill((void *)&cmd, sizeof(cmd), DN_CMD_DELETE, DN_API_VERSION);
+
+ if (is7) {
+ if (p->pipe_nr == 0 && p->fs.fs_nr == 0)
+ return EINVAL;
+ if (p->pipe_nr != 0 && p->fs.fs_nr != 0)
+ return EINVAL;
+ } else {
+ if (p8->pipe_nr == 0 && p8->fs.fs_nr == 0)
+ return EINVAL;
+ if (p8->pipe_nr != 0 && p8->fs.fs_nr != 0)
+ return EINVAL;
+ }
+
+ if (p->pipe_nr != 0) { /* pipe x delete */
+ cmd.a[0] = p->pipe_nr;
+ cmd.oid.subtype = DN_LINK;
+ } else { /* queue x delete */
+ cmd.oid.subtype = DN_FS;
+ cmd.a[0] = (is7) ? p->fs.fs_nr : p8->fs.fs_nr;
+ }
+
+ return do_config(&cmd, cmd.oid.len);
+}
+
+static int
+dn_compat_config_queue(struct dn_fs *fs, void* v)
+{
+ struct dn_pipe7 *p7 = (struct dn_pipe7 *)v;
+ struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
+ struct dn_flow_set *f;
+
+ if (is7)
+ f = &p7->fs;
+ else
+ f = &p8->fs;
+
+ fs->fs_nr = f->fs_nr;
+ fs->sched_nr = f->parent_nr;
+ fs->flow_mask = f->flow_mask;
+ fs->buckets = f->rq_size;
+ fs->qsize = f->qsize;
+ fs->plr = f->plr;
+ fs->par[0] = f->weight;
+ fs->flags = convertflags2new(f->flags_fs);
+ if (fs->flags & DN_IS_GENTLE_RED || fs->flags & DN_IS_RED) {
+ fs->w_q = f->w_q;
+ fs->max_th = f->max_th;
+ fs->min_th = f->min_th;
+ fs->max_p = f->max_p;
+ }
+
+ return 0;
+}
+
+static int
+dn_compat_config_pipe(struct dn_sch *sch, struct dn_link *p,
+ struct dn_fs *fs, void* v)
+{
+ struct dn_pipe7 *p7 = (struct dn_pipe7 *)v;
+ struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
+ int i = p7->pipe_nr;
+
+ sch->sched_nr = i;
+ sch->oid.subtype = 0;
+ p->link_nr = i;
+ fs->fs_nr = i + 2*DN_MAX_ID;
+ fs->sched_nr = i + DN_MAX_ID;
+
+ /* Common to 7 and 8 */
+ p->bandwidth = p7->bandwidth;
+ p->delay = p7->delay;
+ if (!is7) {
+ /* FreeBSD 8 has burst */
+ p->burst = p8->burst;
+ }
+
+ /* fill the fifo flowset */
+ dn_compat_config_queue(fs, v);
+ fs->fs_nr = i + 2*DN_MAX_ID;
+ fs->sched_nr = i + DN_MAX_ID;
+
+ /* Move scheduler related parameter from fs to sch */
+ sch->buckets = fs->buckets; /*XXX*/
+ fs->buckets = 0;
+ if (fs->flags & DN_HAVE_MASK) {
+ sch->flags |= DN_HAVE_MASK;
+ fs->flags &= ~DN_HAVE_MASK;
+ sch->sched_mask = fs->flow_mask;
+ bzero(&fs->flow_mask, sizeof(struct ipfw_flow_id));
+ }
+
+ return 0;
+}
+
+static int
+dn_compat_config_profile(struct dn_profile *pf, struct dn_link *p,
+ void *v)
+{
+ struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
+
+ p8->samples = &(((struct dn_pipe_max8 *)p8)->samples[0]);
+
+ pf->link_nr = p->link_nr;
+ pf->loss_level = p8->loss_level;
+// pf->bandwidth = p->bandwidth; //XXX bandwidth redundant?
+ pf->samples_no = p8->samples_no;
+ strncpy(pf->name, p8->name,sizeof(pf->name));
+ bcopy(p8->samples, pf->samples, sizeof(pf->samples));
+
+ return 0;
+}
+
+/*
+ * If p->pipe_nr != 0 the command is 'pipe x config', so need to create
+ * the three main struct, else only a flowset is created
+ */
+static int
+dn_compat_configure(void *v)
+{
+ struct dn_id *buf, *base;
+ struct dn_sch *sch = NULL;
+ struct dn_link *p = NULL;
+ struct dn_fs *fs = NULL;
+ struct dn_profile *pf = NULL;
+ int lmax;
+ int error;
+
+ struct dn_pipe7 *p7 = (struct dn_pipe7 *)v;
+ struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
+
+ int i; /* number of object to configure */
+
+ lmax = sizeof(struct dn_id); /* command header */
+ lmax += sizeof(struct dn_sch) + sizeof(struct dn_link) +
+ sizeof(struct dn_fs) + sizeof(struct dn_profile);
+
+ base = buf = malloc(lmax, M_DUMMYNET, M_WAIT|M_ZERO);
+ o_next(&buf, sizeof(struct dn_id), DN_CMD_CONFIG);
+ base->id = DN_API_VERSION;
+
+ /* pipe_nr is the same in p7 and p8 */
+ i = p7->pipe_nr;
+ if (i != 0) { /* pipe config */
+ sch = o_next(&buf, sizeof(*sch), DN_SCH);
+ p = o_next(&buf, sizeof(*p), DN_LINK);
+ fs = o_next(&buf, sizeof(*fs), DN_FS);
+
+ error = dn_compat_config_pipe(sch, p, fs, v);
+ if (error) {
+ free(buf, M_DUMMYNET);
+ return error;
+ }
+ if (!is7 && p8->samples_no > 0) {
+ /* Add profiles*/
+ pf = o_next(&buf, sizeof(*pf), DN_PROFILE);
+ error = dn_compat_config_profile(pf, p, v);
+ if (error) {
+ free(buf, M_DUMMYNET);
+ return error;
+ }
+ }
+ } else { /* queue config */
+ fs = o_next(&buf, sizeof(*fs), DN_FS);
+ error = dn_compat_config_queue(fs, v);
+ if (error) {
+ free(buf, M_DUMMYNET);
+ return error;
+ }
+ }
+ error = do_config(base, (char *)buf - (char *)base);
+
+ return error;
+}
+
+int
+dn_compat_calc_size(struct dn_parms dn_cfg)
+{
+ int need = 0;
+ /* XXX use FreeBSD 8 struct size */
+ /* NOTE:
+ * - half scheduler: schk_count/2
+ * - all flowset: fsk_count
+ * - all flowset queues: queue_count
+ * - all pipe queue: si_count
+ */
+ need += dn_cfg.schk_count * sizeof(struct dn_pipe8) / 2;
+ need += dn_cfg.fsk_count * sizeof(struct dn_flow_set);
+ need += dn_cfg.si_count * sizeof(struct dn_flow_queue8);
+ need += dn_cfg.queue_count * sizeof(struct dn_flow_queue8);
+
+ return need;
+}
+
+int
+dn_c_copy_q (void *_ni, void *arg)
+{
+ struct copy_args *a = arg;
+ struct dn_flow_queue7 *fq7 = (struct dn_flow_queue7 *)*a->start;
+ struct dn_flow_queue8 *fq8 = (struct dn_flow_queue8 *)*a->start;
+ struct dn_flow *ni = (struct dn_flow *)_ni;
+ int size = 0;
+
+ /* XXX hash slot not set */
+ /* No difference between 7.2/8 */
+ fq7->len = ni->length;
+ fq7->len_bytes = ni->len_bytes;
+ fq7->id = ni->fid;
+
+ if (is7) {
+ size = sizeof(struct dn_flow_queue7);
+ fq7->tot_pkts = ni->tot_pkts;
+ fq7->tot_bytes = ni->tot_bytes;
+ fq7->drops = ni->drops;
+ } else {
+ size = sizeof(struct dn_flow_queue8);
+ fq8->tot_pkts = ni->tot_pkts;
+ fq8->tot_bytes = ni->tot_bytes;
+ fq8->drops = ni->drops;
+ }
+
+ *a->start += size;
+ return 0;
+}
+
+int
+dn_c_copy_pipe(struct dn_schk *s, struct copy_args *a, int nq)
+{
+ struct dn_link *l = &s->link;
+ struct dn_fsk *f = s->fs;
+
+ struct dn_pipe7 *pipe7 = (struct dn_pipe7 *)*a->start;
+ struct dn_pipe8 *pipe8 = (struct dn_pipe8 *)*a->start;
+ struct dn_flow_set *fs;
+ int size = 0;
+
+ if (is7) {
+ fs = &pipe7->fs;
+ size = sizeof(struct dn_pipe7);
+ } else {
+ fs = &pipe8->fs;
+ size = sizeof(struct dn_pipe8);
+ }
+
+ /* These 4 field are the same in pipe7 and pipe8 */
+ pipe7->next.sle_next = (struct dn_pipe7 *)DN_IS_PIPE;
+ pipe7->bandwidth = l->bandwidth;
+ pipe7->delay = l->delay;
+ pipe7->pipe_nr = l->link_nr - DN_MAX_ID;
+
+ if (!is7) {
+ if (s->profile) {
+ struct dn_profile *pf = s->profile;
+ strncpy(pipe8->name, pf->name, sizeof(pf->name));
+ pipe8->loss_level = pf->loss_level;
+ pipe8->samples_no = pf->samples_no;
+ }
+ pipe8->burst = div64(l->burst , 8 * hz);
+ }
+
+ fs->flow_mask = s->sch.sched_mask;
+ fs->rq_size = s->sch.buckets ? s->sch.buckets : 1;
+
+ fs->parent_nr = l->link_nr - DN_MAX_ID;
+ fs->qsize = f->fs.qsize;
+ fs->plr = f->fs.plr;
+ fs->w_q = f->fs.w_q;
+ fs->max_th = f->max_th;
+ fs->min_th = f->min_th;
+ fs->max_p = f->fs.max_p;
+ fs->rq_elements = nq;
+
+ fs->flags_fs = convertflags2old(f->fs.flags);
+
+ *a->start += size;
+ return 0;
+}
+
+
+int
+dn_compat_copy_pipe(struct copy_args *a, void *_o)
+{
+ int have = a->end - *a->start;
+ int need = 0;
+ int pipe_size = sizeof(struct dn_pipe8);
+ int queue_size = sizeof(struct dn_flow_queue8);
+ int n_queue = 0; /* number of queues */
+
+ struct dn_schk *s = (struct dn_schk *)_o;
+ /* calculate needed space:
+ * - struct dn_pipe
+ * - if there are instances, dn_queue * n_instances
+ */
+ n_queue = (s->sch.flags & DN_HAVE_MASK ? dn_ht_entries(s->siht) :
+ (s->siht ? 1 : 0));
+ need = pipe_size + queue_size * n_queue;
+ if (have < need) {
+ D("have %d < need %d", have, need);
+ return 1;
+ }
+ /* copy pipe */
+ dn_c_copy_pipe(s, a, n_queue);
+
+ /* copy queues */
+ if (s->sch.flags & DN_HAVE_MASK)
+ dn_ht_scan(s->siht, dn_c_copy_q, a);
+ else if (s->siht)
+ dn_c_copy_q(s->siht, a);
+ return 0;
+}
+
+int
+dn_c_copy_fs(struct dn_fsk *f, struct copy_args *a, int nq)
+{
+ struct dn_flow_set *fs = (struct dn_flow_set *)*a->start;
+
+ fs->next.sle_next = (struct dn_flow_set *)DN_IS_QUEUE;
+ fs->fs_nr = f->fs.fs_nr;
+ fs->qsize = f->fs.qsize;
+ fs->plr = f->fs.plr;
+ fs->w_q = f->fs.w_q;
+ fs->max_th = f->max_th;
+ fs->min_th = f->min_th;
+ fs->max_p = f->fs.max_p;
+ fs->flow_mask = f->fs.flow_mask;
+ fs->rq_elements = nq;
+ fs->rq_size = (f->fs.buckets ? f->fs.buckets : 1);
+ fs->parent_nr = f->fs.sched_nr;
+ fs->weight = f->fs.par[0];
+
+ fs->flags_fs = convertflags2old(f->fs.flags);
+ *a->start += sizeof(struct dn_flow_set);
+ return 0;
+}
+
+int
+dn_compat_copy_queue(struct copy_args *a, void *_o)
+{
+ int have = a->end - *a->start;
+ int need = 0;
+ int fs_size = sizeof(struct dn_flow_set);
+ int queue_size = sizeof(struct dn_flow_queue8);
+
+ struct dn_fsk *fs = (struct dn_fsk *)_o;
+ int n_queue = 0; /* number of queues */
+
+ n_queue = (fs->fs.flags & DN_HAVE_MASK ? dn_ht_entries(fs->qht) :
+ (fs->qht ? 1 : 0));
+
+ need = fs_size + queue_size * n_queue;
+ if (have < need) {
+ D("have < need");
+ return 1;
+ }
+
+ /* copy flowset */
+ dn_c_copy_fs(fs, a, n_queue);
+
+ /* copy queues */
+ if (fs->fs.flags & DN_HAVE_MASK)
+ dn_ht_scan(fs->qht, dn_c_copy_q, a);
+ else if (fs->qht)
+ dn_c_copy_q(fs->qht, a);
+
+ return 0;
+}
+
+int
+copy_data_helper_compat(void *_o, void *_arg)
+{
+ struct copy_args *a = _arg;
+
+ if (a->type == DN_COMPAT_PIPE) {
+ struct dn_schk *s = _o;
+ if (s->sch.oid.subtype != 1 || s->sch.sched_nr <= DN_MAX_ID) {
+ return 0; /* not old type */
+ }
+ /* copy pipe parameters, and if instance exists, copy
+ * other parameters and eventually queues.
+ */
+ if(dn_compat_copy_pipe(a, _o))
+ return DNHT_SCAN_END;
+ } else if (a->type == DN_COMPAT_QUEUE) {
+ struct dn_fsk *fs = _o;
+ if (fs->fs.fs_nr >= DN_MAX_ID)
+ return 0;
+ if (dn_compat_copy_queue(a, _o))
+ return DNHT_SCAN_END;
+ }
+ return 0;
+}
+
+/* Main function to manage old requests */
+int
+ip_dummynet_compat(struct sockopt *sopt)
+{
+ int error=0;
+ void *v = NULL;
+ struct dn_id oid;
+
+ /* Lenght of data, used to found ipfw version... */
+ int len = sopt->sopt_valsize;
+
+ /* len can be 0 if command was dummynet_flush */
+ if (len == pipesize7) {
+ D("setting compatibility with FreeBSD 7.2");
+ is7 = 1;
+ }
+ else if (len == pipesize8 || len == pipesizemax8) {
+ D("setting compatibility with FreeBSD 8");
+ is7 = 0;
+ }
+
+ switch (sopt->sopt_name) {
+ default:
+ printf("dummynet: -- unknown option %d", sopt->sopt_name);
+ error = EINVAL;
+ break;
+
+ case IP_DUMMYNET_FLUSH:
+ oid_fill(&oid, sizeof(oid), DN_CMD_FLUSH, DN_API_VERSION);
+ do_config(&oid, oid.len);
+ break;
+
+ case IP_DUMMYNET_DEL:
+ v = malloc(len, M_TEMP, M_WAITOK);
+ error = sooptcopyin(sopt, v, len, len);
+ if (error)
+ break;
+ error = dn_compat_del(v);
+ free(v, M_DUMMYNET);
+ break;
+
+ case IP_DUMMYNET_CONFIGURE:
+ v = malloc(len, M_TEMP, M_WAITOK);
+ error = sooptcopyin(sopt, v, len, len);
+ if (error)
+ break;
+ error = dn_compat_configure(v);
+ free(v, M_DUMMYNET);
+ break;
+
+ case IP_DUMMYNET_GET: {
+ void *buf;
+ int ret;
+ int original_size = sopt->sopt_valsize;
+ int size;
+
+ ret = dummynet_get(sopt, &buf);
+ if (ret)
+ return 0;//XXX ?
+ size = sopt->sopt_valsize;
+ sopt->sopt_valsize = original_size;
+ D("size=%d, buf=%p", size, buf);
+ ret = sooptcopyout(sopt, buf, size);
+ if (ret)
+ printf(" %s ERROR sooptcopyout\n", __FUNCTION__);
+ if (buf)
+ free(buf, M_DUMMYNET);
+ }
+ }
+
+ return error;
+}
+
+
diff --git a/sys/netinet/ipfw/ip_dn_io.c b/sys/netinet/ipfw/ip_dn_io.c
new file mode 100644
index 0000000..4219433
--- /dev/null
+++ b/sys/netinet/ipfw/ip_dn_io.c
@@ -0,0 +1,781 @@
+/*-
+ * Copyright (c) 2010 Luigi Rizzo, Riccardo Panicucci, Universita` di Pisa
+ * 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.
+ */
+
+/*
+ * Dummynet portions related to packet handling.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/rwlock.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+#include <net/if.h> /* IFNAMSIZ, struct ifaddr, ifq head, lock.h mutex.h */
+#include <net/netisr.h>
+#include <netinet/in.h>
+#include <netinet/ip.h> /* ip_len, ip_off */
+#include <netinet/ip_var.h> /* ip_output(), IP_FORWARDING */
+#include <netinet/ip_fw.h>
+#include <netinet/ipfw/ip_fw_private.h>
+#include <netinet/ipfw/dn_heap.h>
+#include <netinet/ip_dummynet.h>
+#include <netinet/ipfw/ip_dn_private.h>
+#include <netinet/ipfw/dn_sched.h>
+
+#include <netinet/if_ether.h> /* various ether_* routines */
+
+#include <netinet/ip6.h> /* for ip6_input, ip6_output prototypes */
+#include <netinet6/ip6_var.h>
+
+/*
+ * We keep a private variable for the simulation time, but we could
+ * probably use an existing one ("softticks" in sys/kern/kern_timeout.c)
+ * instead of dn_cfg.curr_time
+ */
+
+struct dn_parms dn_cfg;
+
+static long tick_last; /* Last tick duration (usec). */
+static long tick_delta; /* Last vs standard tick diff (usec). */
+static long tick_delta_sum; /* Accumulated tick difference (usec).*/
+static long tick_adjustment; /* Tick adjustments done. */
+static long tick_lost; /* Lost(coalesced) ticks number. */
+/* Adjusted vs non-adjusted curr_time difference (ticks). */
+static long tick_diff;
+
+static unsigned long io_pkt;
+static unsigned long io_pkt_fast;
+static unsigned long io_pkt_drop;
+
+/*
+ * We use a heap to store entities for which we have pending timer events.
+ * The heap is checked at every tick and all entities with expired events
+ * are extracted.
+ */
+
+MALLOC_DEFINE(M_DUMMYNET, "dummynet", "dummynet heap");
+
+extern void (*bridge_dn_p)(struct mbuf *, struct ifnet *);
+
+#ifdef SYSCTL_NODE
+
+SYSBEGIN(f4)
+
+SYSCTL_DECL(_net_inet);
+SYSCTL_DECL(_net_inet_ip);
+SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet, CTLFLAG_RW, 0, "Dummynet");
+
+/* parameters */
+SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, hash_size,
+ CTLFLAG_RW, &dn_cfg.hash_size, 0, "Default hash table size");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, pipe_slot_limit,
+ CTLFLAG_RW, &dn_cfg.slot_limit, 0,
+ "Upper limit in slots for pipe queue.");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, pipe_byte_limit,
+ CTLFLAG_RW, &dn_cfg.byte_limit, 0,
+ "Upper limit in bytes for pipe queue.");
+SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, io_fast,
+ CTLFLAG_RW, &dn_cfg.io_fast, 0, "Enable fast dummynet io.");
+SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, debug,
+ CTLFLAG_RW, &dn_cfg.debug, 0, "Dummynet debug level");
+
+/* RED parameters */
+SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_lookup_depth,
+ CTLFLAG_RD, &dn_cfg.red_lookup_depth, 0, "Depth of RED lookup table");
+SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_avg_pkt_size,
+ CTLFLAG_RD, &dn_cfg.red_avg_pkt_size, 0, "RED Medium packet size");
+SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_max_pkt_size,
+ CTLFLAG_RD, &dn_cfg.red_max_pkt_size, 0, "RED Max packet size");
+
+/* time adjustment */
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_delta,
+ CTLFLAG_RD, &tick_delta, 0, "Last vs standard tick difference (usec).");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_delta_sum,
+ CTLFLAG_RD, &tick_delta_sum, 0, "Accumulated tick difference (usec).");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_adjustment,
+ CTLFLAG_RD, &tick_adjustment, 0, "Tick adjustments done.");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_diff,
+ CTLFLAG_RD, &tick_diff, 0,
+ "Adjusted vs non-adjusted curr_time difference (ticks).");
+SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_lost,
+ CTLFLAG_RD, &tick_lost, 0,
+ "Number of ticks coalesced by dummynet taskqueue.");
+
+/* statistics */
+SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, schk_count,
+ CTLFLAG_RD, &dn_cfg.schk_count, 0, "Number of schedulers");
+SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, si_count,
+ CTLFLAG_RD, &dn_cfg.si_count, 0, "Number of scheduler instances");
+SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, fsk_count,
+ CTLFLAG_RD, &dn_cfg.fsk_count, 0, "Number of flowsets");
+SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, queue_count,
+ CTLFLAG_RD, &dn_cfg.queue_count, 0, "Number of queues");
+SYSCTL_ULONG(_net_inet_ip_dummynet, OID_AUTO, io_pkt,
+ CTLFLAG_RD, &io_pkt, 0,
+ "Number of packets passed to dummynet.");
+SYSCTL_ULONG(_net_inet_ip_dummynet, OID_AUTO, io_pkt_fast,
+ CTLFLAG_RD, &io_pkt_fast, 0,
+ "Number of packets bypassed dummynet scheduler.");
+SYSCTL_ULONG(_net_inet_ip_dummynet, OID_AUTO, io_pkt_drop,
+ CTLFLAG_RD, &io_pkt_drop, 0,
+ "Number of packets dropped by dummynet.");
+
+SYSEND
+
+#endif
+
+static void dummynet_send(struct mbuf *);
+
+/*
+ * Packets processed by dummynet have an mbuf tag associated with
+ * them that carries their dummynet state.
+ * Outside dummynet, only the 'rule' field is relevant, and it must
+ * be at the beginning of the structure.
+ */
+struct dn_pkt_tag {
+ struct ipfw_rule_ref rule; /* matching rule */
+
+ /* second part, dummynet specific */
+ int dn_dir; /* action when packet comes out.*/
+ /* see ip_fw_private.h */
+ uint64_t output_time; /* when the pkt is due for delivery*/
+ struct ifnet *ifp; /* interface, for ip_output */
+ struct _ip6dn_args ip6opt; /* XXX ipv6 options */
+};
+
+/*
+ * Return the mbuf tag holding the dummynet state (it should
+ * be the first one on the list).
+ */
+static struct dn_pkt_tag *
+dn_tag_get(struct mbuf *m)
+{
+ struct m_tag *mtag = m_tag_first(m);
+ KASSERT(mtag != NULL &&
+ mtag->m_tag_cookie == MTAG_ABI_COMPAT &&
+ mtag->m_tag_id == PACKET_TAG_DUMMYNET,
+ ("packet on dummynet queue w/o dummynet tag!"));
+ return (struct dn_pkt_tag *)(mtag+1);
+}
+
+static inline void
+mq_append(struct mq *q, struct mbuf *m)
+{
+ if (q->head == NULL)
+ q->head = m;
+ else
+ q->tail->m_nextpkt = m;
+ q->tail = m;
+ m->m_nextpkt = NULL;
+}
+
+/*
+ * Dispose a list of packet. Use a functions so if we need to do
+ * more work, this is a central point to do it.
+ */
+void dn_free_pkts(struct mbuf *mnext)
+{
+ struct mbuf *m;
+
+ while ((m = mnext) != NULL) {
+ mnext = m->m_nextpkt;
+ FREE_PKT(m);
+ }
+}
+
+static int
+red_drops (struct dn_queue *q, int len)
+{
+ /*
+ * RED algorithm
+ *
+ * RED calculates the average queue size (avg) using a low-pass filter
+ * with an exponential weighted (w_q) moving average:
+ * avg <- (1-w_q) * avg + w_q * q_size
+ * where q_size is the queue length (measured in bytes or * packets).
+ *
+ * If q_size == 0, we compute the idle time for the link, and set
+ * avg = (1 - w_q)^(idle/s)
+ * where s is the time needed for transmitting a medium-sized packet.
+ *
+ * Now, if avg < min_th the packet is enqueued.
+ * If avg > max_th the packet is dropped. Otherwise, the packet is
+ * dropped with probability P function of avg.
+ */
+
+ struct dn_fsk *fs = q->fs;
+ int64_t p_b = 0;
+
+ /* Queue in bytes or packets? */
+ uint32_t q_size = (fs->fs.flags & DN_QSIZE_BYTES) ?
+ q->ni.len_bytes : q->ni.length;
+
+ /* Average queue size estimation. */
+ if (q_size != 0) {
+ /* Queue is not empty, avg <- avg + (q_size - avg) * w_q */
+ int diff = SCALE(q_size) - q->avg;
+ int64_t v = SCALE_MUL((int64_t)diff, (int64_t)fs->w_q);
+
+ q->avg += (int)v;
+ } else {
+ /*
+ * Queue is empty, find for how long the queue has been
+ * empty and use a lookup table for computing
+ * (1 - * w_q)^(idle_time/s) where s is the time to send a
+ * (small) packet.
+ * XXX check wraps...
+ */
+ if (q->avg) {
+ u_int t = div64((dn_cfg.curr_time - q->q_time), fs->lookup_step);
+
+ q->avg = (t < fs->lookup_depth) ?
+ SCALE_MUL(q->avg, fs->w_q_lookup[t]) : 0;
+ }
+ }
+
+ /* Should i drop? */
+ if (q->avg < fs->min_th) {
+ q->count = -1;
+ return (0); /* accept packet */
+ }
+ if (q->avg >= fs->max_th) { /* average queue >= max threshold */
+ if (fs->fs.flags & DN_IS_GENTLE_RED) {
+ /*
+ * According to Gentle-RED, if avg is greater than
+ * max_th the packet is dropped with a probability
+ * p_b = c_3 * avg - c_4
+ * where c_3 = (1 - max_p) / max_th
+ * c_4 = 1 - 2 * max_p
+ */
+ p_b = SCALE_MUL((int64_t)fs->c_3, (int64_t)q->avg) -
+ fs->c_4;
+ } else {
+ q->count = -1;
+ return (1);
+ }
+ } else if (q->avg > fs->min_th) {
+ /*
+ * We compute p_b using the linear dropping function
+ * p_b = c_1 * avg - c_2
+ * where c_1 = max_p / (max_th - min_th)
+ * c_2 = max_p * min_th / (max_th - min_th)
+ */
+ p_b = SCALE_MUL((int64_t)fs->c_1, (int64_t)q->avg) - fs->c_2;
+ }
+
+ if (fs->fs.flags & DN_QSIZE_BYTES)
+ p_b = div64((p_b * len) , fs->max_pkt_size);
+ if (++q->count == 0)
+ q->random = random() & 0xffff;
+ else {
+ /*
+ * q->count counts packets arrived since last drop, so a greater
+ * value of q->count means a greater packet drop probability.
+ */
+ if (SCALE_MUL(p_b, SCALE((int64_t)q->count)) > q->random) {
+ q->count = 0;
+ /* After a drop we calculate a new random value. */
+ q->random = random() & 0xffff;
+ return (1); /* drop */
+ }
+ }
+ /* End of RED algorithm. */
+
+ return (0); /* accept */
+
+}
+
+/*
+ * Enqueue a packet in q, subject to space and queue management policy
+ * (whose parameters are in q->fs).
+ * Update stats for the queue and the scheduler.
+ * Return 0 on success, 1 on drop. The packet is consumed anyways.
+ */
+int
+dn_enqueue(struct dn_queue *q, struct mbuf* m, int drop)
+{
+ struct dn_fs *f;
+ struct dn_flow *ni; /* stats for scheduler instance */
+ uint64_t len;
+
+ if (q->fs == NULL || q->_si == NULL) {
+ printf("%s fs %p si %p, dropping\n",
+ __FUNCTION__, q->fs, q->_si);
+ FREE_PKT(m);
+ return 1;
+ }
+ f = &(q->fs->fs);
+ ni = &q->_si->ni;
+ len = m->m_pkthdr.len;
+ /* Update statistics, then check reasons to drop pkt. */
+ q->ni.tot_bytes += len;
+ q->ni.tot_pkts++;
+ ni->tot_bytes += len;
+ ni->tot_pkts++;
+ if (drop)
+ goto drop;
+ if (f->plr && random() < f->plr)
+ goto drop;
+ if (f->flags & DN_IS_RED && red_drops(q, m->m_pkthdr.len))
+ goto drop;
+ if (f->flags & DN_QSIZE_BYTES) {
+ if (q->ni.len_bytes > f->qsize)
+ goto drop;
+ } else if (q->ni.length >= f->qsize) {
+ goto drop;
+ }
+ mq_append(&q->mq, m);
+ q->ni.length++;
+ q->ni.len_bytes += len;
+ ni->length++;
+ ni->len_bytes += len;
+ return 0;
+
+drop:
+ io_pkt_drop++;
+ q->ni.drops++;
+ ni->drops++;
+ FREE_PKT(m);
+ return 1;
+}
+
+/*
+ * Fetch packets from the delay line which are due now. If there are
+ * leftover packets, reinsert the delay line in the heap.
+ * Runs under scheduler lock.
+ */
+static void
+transmit_event(struct mq *q, struct delay_line *dline, uint64_t now)
+{
+ struct mbuf *m;
+ struct dn_pkt_tag *pkt = NULL;
+
+ dline->oid.subtype = 0; /* not in heap */
+ while ((m = dline->mq.head) != NULL) {
+ pkt = dn_tag_get(m);
+ if (!DN_KEY_LEQ(pkt->output_time, now))
+ break;
+ dline->mq.head = m->m_nextpkt;
+ mq_append(q, m);
+ }
+ if (m != NULL) {
+ dline->oid.subtype = 1; /* in heap */
+ heap_insert(&dn_cfg.evheap, pkt->output_time, dline);
+ }
+}
+
+/*
+ * Convert the additional MAC overheads/delays into an equivalent
+ * number of bits for the given data rate. The samples are
+ * in milliseconds so we need to divide by 1000.
+ */
+static uint64_t
+extra_bits(struct mbuf *m, struct dn_schk *s)
+{
+ int index;
+ uint64_t bits;
+ struct dn_profile *pf = s->profile;
+
+ if (!pf || pf->samples_no == 0)
+ return 0;
+ index = random() % pf->samples_no;
+ bits = div64((uint64_t)pf->samples[index] * s->link.bandwidth, 1000);
+ if (index >= pf->loss_level) {
+ struct dn_pkt_tag *dt = dn_tag_get(m);
+ if (dt)
+ dt->dn_dir = DIR_DROP;
+ }
+ return bits;
+}
+
+/*
+ * Send traffic from a scheduler instance due by 'now'.
+ * Return a pointer to the head of the queue.
+ */
+static struct mbuf *
+serve_sched(struct mq *q, struct dn_sch_inst *si, uint64_t now)
+{
+ struct mq def_q;
+ struct dn_schk *s = si->sched;
+ struct mbuf *m = NULL;
+ int delay_line_idle = (si->dline.mq.head == NULL);
+ int done, bw;
+
+ if (q == NULL) {
+ q = &def_q;
+ q->head = NULL;
+ }
+
+ bw = s->link.bandwidth;
+ si->kflags &= ~DN_ACTIVE;
+
+ if (bw > 0)
+ si->credit += (now - si->sched_time) * bw;
+ else
+ si->credit = 0;
+ si->sched_time = now;
+ done = 0;
+ while (si->credit >= 0 && (m = s->fp->dequeue(si)) != NULL) {
+ uint64_t len_scaled;
+ done++;
+ len_scaled = (bw == 0) ? 0 : hz *
+ (m->m_pkthdr.len * 8 + extra_bits(m, s));
+ si->credit -= len_scaled;
+ /* Move packet in the delay line */
+ dn_tag_get(m)->output_time += s->link.delay ;
+ mq_append(&si->dline.mq, m);
+ }
+ /*
+ * If credit >= 0 the instance is idle, mark time.
+ * Otherwise put back in the heap, and adjust the output
+ * time of the last inserted packet, m, which was too early.
+ */
+ if (si->credit >= 0) {
+ si->idle_time = now;
+ } else {
+ uint64_t t;
+ KASSERT (bw > 0, ("bw=0 and credit<0 ?"));
+ t = div64(bw - 1 - si->credit, bw);
+ if (m)
+ dn_tag_get(m)->output_time += t;
+ si->kflags |= DN_ACTIVE;
+ heap_insert(&dn_cfg.evheap, now + t, si);
+ }
+ if (delay_line_idle && done)
+ transmit_event(q, &si->dline, now);
+ return q->head;
+}
+
+/*
+ * The timer handler for dummynet. Time is computed in ticks, but
+ * but the code is tolerant to the actual rate at which this is called.
+ * Once complete, the function reschedules itself for the next tick.
+ */
+void
+dummynet_task(void *context, int pending)
+{
+ struct timeval t;
+ struct mq q = { NULL, NULL }; /* queue to accumulate results */
+
+ DN_BH_WLOCK();
+
+ /* Update number of lost(coalesced) ticks. */
+ tick_lost += pending - 1;
+
+ getmicrouptime(&t);
+ /* Last tick duration (usec). */
+ tick_last = (t.tv_sec - dn_cfg.prev_t.tv_sec) * 1000000 +
+ (t.tv_usec - dn_cfg.prev_t.tv_usec);
+ /* Last tick vs standard tick difference (usec). */
+ tick_delta = (tick_last * hz - 1000000) / hz;
+ /* Accumulated tick difference (usec). */
+ tick_delta_sum += tick_delta;
+
+ dn_cfg.prev_t = t;
+
+ /*
+ * Adjust curr_time if the accumulated tick difference is
+ * greater than the 'standard' tick. Since curr_time should
+ * be monotonically increasing, we do positive adjustments
+ * as required, and throttle curr_time in case of negative
+ * adjustment.
+ */
+ dn_cfg.curr_time++;
+ if (tick_delta_sum - tick >= 0) {
+ int diff = tick_delta_sum / tick;
+
+ dn_cfg.curr_time += diff;
+ tick_diff += diff;
+ tick_delta_sum %= tick;
+ tick_adjustment++;
+ } else if (tick_delta_sum + tick <= 0) {
+ dn_cfg.curr_time--;
+ tick_diff--;
+ tick_delta_sum += tick;
+ tick_adjustment++;
+ }
+
+ /* serve pending events, accumulate in q */
+ for (;;) {
+ struct dn_id *p; /* generic parameter to handler */
+
+ if (dn_cfg.evheap.elements == 0 ||
+ DN_KEY_LT(dn_cfg.curr_time, HEAP_TOP(&dn_cfg.evheap)->key))
+ break;
+ p = HEAP_TOP(&dn_cfg.evheap)->object;
+ heap_extract(&dn_cfg.evheap, NULL);
+
+ if (p->type == DN_SCH_I) {
+ serve_sched(&q, (struct dn_sch_inst *)p, dn_cfg.curr_time);
+ } else { /* extracted a delay line */
+ transmit_event(&q, (struct delay_line *)p, dn_cfg.curr_time);
+ }
+ }
+ dn_drain_scheduler();
+ dn_drain_queue();
+
+ DN_BH_WUNLOCK();
+ dn_reschedule();
+ if (q.head != NULL)
+ dummynet_send(q.head);
+}
+
+/*
+ * forward a chain of packets to the proper destination.
+ * This runs outside the dummynet lock.
+ */
+static void
+dummynet_send(struct mbuf *m)
+{
+ struct mbuf *n;
+
+ for (; m != NULL; m = n) {
+ struct ifnet *ifp = NULL; /* gcc 3.4.6 complains */
+ struct m_tag *tag;
+ int dst;
+
+ n = m->m_nextpkt;
+ m->m_nextpkt = NULL;
+ tag = m_tag_first(m);
+ if (tag == NULL) { /* should not happen */
+ dst = DIR_DROP;
+ } else {
+ struct dn_pkt_tag *pkt = dn_tag_get(m);
+ /* extract the dummynet info, rename the tag
+ * to carry reinject info.
+ */
+ dst = pkt->dn_dir;
+ ifp = pkt->ifp;
+ tag->m_tag_cookie = MTAG_IPFW_RULE;
+ tag->m_tag_id = 0;
+ }
+
+ switch (dst) {
+ case DIR_OUT:
+ SET_HOST_IPLEN(mtod(m, struct ip *));
+ ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
+ break ;
+
+ case DIR_IN :
+ /* put header in network format for ip_input() */
+ //SET_NET_IPLEN(mtod(m, struct ip *));
+ netisr_dispatch(NETISR_IP, m);
+ break;
+
+#ifdef INET6
+ case DIR_IN | PROTO_IPV6:
+ netisr_dispatch(NETISR_IPV6, m);
+ break;
+
+ case DIR_OUT | PROTO_IPV6:
+ SET_HOST_IPLEN(mtod(m, struct ip *));
+ ip6_output(m, NULL, NULL, IPV6_FORWARDING, NULL, NULL, NULL);
+ break;
+#endif
+
+ case DIR_FWD | PROTO_IFB: /* DN_TO_IFB_FWD: */
+ if (bridge_dn_p != NULL)
+ ((*bridge_dn_p)(m, ifp));
+ else
+ printf("dummynet: if_bridge not loaded\n");
+
+ break;
+
+ case DIR_IN | PROTO_LAYER2: /* DN_TO_ETH_DEMUX: */
+ /*
+ * The Ethernet code assumes the Ethernet header is
+ * contiguous in the first mbuf header.
+ * Insure this is true.
+ */
+ if (m->m_len < ETHER_HDR_LEN &&
+ (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {
+ printf("dummynet/ether: pullup failed, "
+ "dropping packet\n");
+ break;
+ }
+ ether_demux(m->m_pkthdr.rcvif, m);
+ break;
+
+ case DIR_OUT | PROTO_LAYER2: /* N_TO_ETH_OUT: */
+ ether_output_frame(ifp, m);
+ break;
+
+ case DIR_DROP:
+ /* drop the packet after some time */
+ FREE_PKT(m);
+ break;
+
+ default:
+ printf("dummynet: bad switch %d!\n", dst);
+ FREE_PKT(m);
+ break;
+ }
+ }
+}
+
+static inline int
+tag_mbuf(struct mbuf *m, int dir, struct ip_fw_args *fwa)
+{
+ struct dn_pkt_tag *dt;
+ struct m_tag *mtag;
+
+ mtag = m_tag_get(PACKET_TAG_DUMMYNET,
+ sizeof(*dt), M_NOWAIT | M_ZERO);
+ if (mtag == NULL)
+ return 1; /* Cannot allocate packet header. */
+ m_tag_prepend(m, mtag); /* Attach to mbuf chain. */
+ dt = (struct dn_pkt_tag *)(mtag + 1);
+ dt->rule = fwa->rule;
+ dt->rule.info &= IPFW_ONEPASS; /* only keep this info */
+ dt->dn_dir = dir;
+ dt->ifp = fwa->oif;
+ /* dt->output tame is updated as we move through */
+ dt->output_time = dn_cfg.curr_time;
+ return 0;
+}
+
+
+/*
+ * dummynet hook for packets.
+ * We use the argument to locate the flowset fs and the sched_set sch
+ * associated to it. The we apply flow_mask and sched_mask to
+ * determine the queue and scheduler instances.
+ *
+ * dir where shall we send the packet after dummynet.
+ * *m0 the mbuf with the packet
+ * ifp the 'ifp' parameter from the caller.
+ * NULL in ip_input, destination interface in ip_output,
+ */
+int
+dummynet_io(struct mbuf **m0, int dir, struct ip_fw_args *fwa)
+{
+ struct mbuf *m = *m0;
+ struct dn_fsk *fs = NULL;
+ struct dn_sch_inst *si;
+ struct dn_queue *q = NULL; /* default */
+
+ int fs_id = (fwa->rule.info & IPFW_INFO_MASK) +
+ ((fwa->rule.info & IPFW_IS_PIPE) ? 2*DN_MAX_ID : 0);
+ DN_BH_WLOCK();
+ io_pkt++;
+ /* we could actually tag outside the lock, but who cares... */
+ if (tag_mbuf(m, dir, fwa))
+ goto dropit;
+ if (dn_cfg.busy) {
+ /* if the upper half is busy doing something expensive,
+ * lets queue the packet and move forward
+ */
+ mq_append(&dn_cfg.pending, m);
+ m = *m0 = NULL; /* consumed */
+ goto done; /* already active, nothing to do */
+ }
+ /* XXX locate_flowset could be optimised with a direct ref. */
+ fs = dn_ht_find(dn_cfg.fshash, fs_id, 0, NULL);
+ if (fs == NULL)
+ goto dropit; /* This queue/pipe does not exist! */
+ if (fs->sched == NULL) /* should not happen */
+ goto dropit;
+ /* find scheduler instance, possibly applying sched_mask */
+ si = ipdn_si_find(fs->sched, &(fwa->f_id));
+ if (si == NULL)
+ goto dropit;
+ /*
+ * If the scheduler supports multiple queues, find the right one
+ * (otherwise it will be ignored by enqueue).
+ */
+ if (fs->sched->fp->flags & DN_MULTIQUEUE) {
+ q = ipdn_q_find(fs, si, &(fwa->f_id));
+ if (q == NULL)
+ goto dropit;
+ }
+ if (fs->sched->fp->enqueue(si, q, m)) {
+ printf("%s dropped by enqueue\n", __FUNCTION__);
+ /* packet was dropped by enqueue() */
+ m = *m0 = NULL;
+ goto dropit;
+ }
+
+ if (si->kflags & DN_ACTIVE) {
+ m = *m0 = NULL; /* consumed */
+ goto done; /* already active, nothing to do */
+ }
+
+ /* compute the initial allowance */
+ {
+ struct dn_link *p = &fs->sched->link;
+ si->credit = dn_cfg.io_fast ? p->bandwidth : 0;
+ if (p->burst) {
+ uint64_t burst = (dn_cfg.curr_time - si->idle_time) * p->bandwidth;
+ if (burst > p->burst)
+ burst = p->burst;
+ si->credit += burst;
+ }
+ }
+ /* pass through scheduler and delay line */
+ m = serve_sched(NULL, si, dn_cfg.curr_time);
+
+ /* optimization -- pass it back to ipfw for immediate send */
+ /* XXX Don't call dummynet_send() if scheduler return the packet
+ * just enqueued. This avoid a lock order reversal.
+ *
+ */
+ if (/*dn_cfg.io_fast &&*/ m == *m0 && (dir & PROTO_LAYER2) == 0 ) {
+ /* fast io */
+ io_pkt_fast++;
+ if (m->m_nextpkt != NULL) {
+ printf("dummynet: fast io: pkt chain detected!\n");
+ m->m_nextpkt = NULL;
+ }
+ m = NULL;
+ } else {
+ *m0 = NULL;
+ }
+done:
+ DN_BH_WUNLOCK();
+ if (m)
+ dummynet_send(m);
+ return 0;
+
+dropit:
+ io_pkt_drop++;
+ DN_BH_WUNLOCK();
+ if (m)
+ FREE_PKT(m);
+ *m0 = NULL;
+ return (fs && (fs->fs.flags & DN_NOERROR)) ? 0 : ENOBUFS;
+}
diff --git a/sys/netinet/ipfw/ip_dn_private.h b/sys/netinet/ipfw/ip_dn_private.h
new file mode 100644
index 0000000..0f66fef
--- /dev/null
+++ b/sys/netinet/ipfw/ip_dn_private.h
@@ -0,0 +1,387 @@
+/*-
+ * Copyright (c) 2010 Luigi Rizzo, Riccardo Panicucci, Universita` di Pisa
+ * 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.
+ */
+
+/*
+ * internal dummynet APIs.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IP_DN_PRIVATE_H
+#define _IP_DN_PRIVATE_H
+
+/* debugging support
+ * use ND() to remove debugging, D() to print a line,
+ * DX(level, ...) to print above a certain level
+ * If you redefine D() you are expected to redefine all.
+ */
+#ifndef D
+#define ND(fmt, ...) do {} while (0)
+#define D1(fmt, ...) do {} while (0)
+#define D(fmt, ...) printf("%-10s " fmt "\n", \
+ __FUNCTION__, ## __VA_ARGS__)
+#define DX(lev, fmt, ...) do { \
+ if (dn_cfg.debug > lev) D(fmt, ## __VA_ARGS__); } while (0)
+#endif
+
+MALLOC_DECLARE(M_DUMMYNET);
+
+#ifndef FREE_PKT
+#define FREE_PKT(m) m_freem(m)
+#endif
+
+#ifndef __linux__
+#define div64(a, b) ((int64_t)(a) / (int64_t)(b))
+#endif
+
+#define DN_LOCK_INIT() do { \
+ mtx_init(&dn_cfg.uh_mtx, "dn_uh", NULL, MTX_DEF); \
+ mtx_init(&dn_cfg.bh_mtx, "dn_bh", NULL, MTX_DEF); \
+ } while (0)
+#define DN_LOCK_DESTROY() do { \
+ mtx_destroy(&dn_cfg.uh_mtx); \
+ mtx_destroy(&dn_cfg.bh_mtx); \
+ } while (0)
+#if 0 /* not used yet */
+#define DN_UH_RLOCK() mtx_lock(&dn_cfg.uh_mtx)
+#define DN_UH_RUNLOCK() mtx_unlock(&dn_cfg.uh_mtx)
+#define DN_UH_WLOCK() mtx_lock(&dn_cfg.uh_mtx)
+#define DN_UH_WUNLOCK() mtx_unlock(&dn_cfg.uh_mtx)
+#define DN_UH_LOCK_ASSERT() mtx_assert(&dn_cfg.uh_mtx, MA_OWNED)
+#endif
+
+#define DN_BH_RLOCK() mtx_lock(&dn_cfg.uh_mtx)
+#define DN_BH_RUNLOCK() mtx_unlock(&dn_cfg.uh_mtx)
+#define DN_BH_WLOCK() mtx_lock(&dn_cfg.uh_mtx)
+#define DN_BH_WUNLOCK() mtx_unlock(&dn_cfg.uh_mtx)
+#define DN_BH_LOCK_ASSERT() mtx_assert(&dn_cfg.uh_mtx, MA_OWNED)
+
+SLIST_HEAD(dn_schk_head, dn_schk);
+SLIST_HEAD(dn_sch_inst_head, dn_sch_inst);
+SLIST_HEAD(dn_fsk_head, dn_fsk);
+SLIST_HEAD(dn_queue_head, dn_queue);
+SLIST_HEAD(dn_alg_head, dn_alg);
+
+struct mq { /* a basic queue of packets*/
+ struct mbuf *head, *tail;
+};
+
+static inline void
+set_oid(struct dn_id *o, int type, int len)
+{
+ o->type = type;
+ o->len = len;
+ o->subtype = 0;
+};
+
+/*
+ * configuration and global data for a dummynet instance
+ *
+ * When a configuration is modified from userland, 'id' is incremented
+ * so we can use the value to check for stale pointers.
+ */
+struct dn_parms {
+ uint32_t id; /* configuration version */
+
+ /* defaults (sysctl-accessible) */
+ int red_lookup_depth;
+ int red_avg_pkt_size;
+ int red_max_pkt_size;
+ int hash_size;
+ int max_hash_size;
+ long byte_limit; /* max queue sizes */
+ long slot_limit;
+
+ int io_fast;
+ int debug;
+
+ /* timekeeping */
+ struct timeval prev_t; /* last time dummynet_tick ran */
+ struct dn_heap evheap; /* scheduled events */
+
+ /* counters of objects -- used for reporting space */
+ int schk_count;
+ int si_count;
+ int fsk_count;
+ int queue_count;
+
+ /* ticks and other stuff */
+ uint64_t curr_time;
+ /* flowsets and schedulers are in hash tables, with 'hash_size'
+ * buckets. fshash is looked up at every packet arrival
+ * so better be generous if we expect many entries.
+ */
+ struct dn_ht *fshash;
+ struct dn_ht *schedhash;
+ /* list of flowsets without a scheduler -- use sch_chain */
+ struct dn_fsk_head fsu; /* list of unlinked flowsets */
+ struct dn_alg_head schedlist; /* list of algorithms */
+
+ /* Store the fs/sch to scan when draining. The value is the
+ * bucket number of the hash table
+ **/
+ int drain_fs;
+ int drain_sch;
+
+ /* if the upper half is busy doing something long,
+ * can set the busy flag and we will enqueue packets in
+ * a queue for later processing.
+ */
+ int busy;
+ struct mq pending;
+
+#ifdef _KERNEL
+ /*
+ * This file is normally used in the kernel, unless we do
+ * some userland tests, in which case we do not need a mtx.
+ * uh_mtx arbitrates between system calls and also
+ * protects fshash, schedhash and fsunlinked.
+ * These structures are readonly for the lower half.
+ * bh_mtx protects all other structures which may be
+ * modified upon packet arrivals
+ */
+#if defined( __linux__ ) || defined( _WIN32 )
+ spinlock_t uh_mtx;
+ spinlock_t bh_mtx;
+#else
+ struct mtx uh_mtx;
+ struct mtx bh_mtx;
+#endif
+
+#endif /* _KERNEL */
+};
+
+/*
+ * Delay line, contains all packets on output from a link.
+ * Every scheduler instance has one.
+ */
+struct delay_line {
+ struct dn_id oid;
+ struct dn_sch_inst *si;
+ struct mq mq;
+};
+
+/*
+ * The kernel side of a flowset. It is linked in a hash table
+ * of flowsets, and in a list of children of their parent scheduler.
+ * qht is either the queue or (if HAVE_MASK) a hash table queues.
+ * Note that the mask to use is the (flow_mask|sched_mask), which
+ * changes as we attach/detach schedulers. So we store it here.
+ *
+ * XXX If we want to add scheduler-specific parameters, we need to
+ * put them in external storage because the scheduler may not be
+ * available when the fsk is created.
+ */
+struct dn_fsk { /* kernel side of a flowset */
+ struct dn_fs fs;
+ SLIST_ENTRY(dn_fsk) fsk_next; /* hash chain for fshash */
+
+ struct ipfw_flow_id fsk_mask;
+
+ /* qht is a hash table of queues, or just a single queue
+ * a bit in fs.flags tells us which one
+ */
+ struct dn_ht *qht;
+ struct dn_schk *sched; /* Sched we are linked to */
+ SLIST_ENTRY(dn_fsk) sch_chain; /* list of fsk attached to sched */
+
+ /* bucket index used by drain routine to drain queues for this
+ * flowset
+ */
+ int drain_bucket;
+ /* Parameter realted to RED / GRED */
+ /* original values are in dn_fs*/
+ int w_q ; /* queue weight (scaled) */
+ int max_th ; /* maximum threshold for queue (scaled) */
+ int min_th ; /* minimum threshold for queue (scaled) */
+ int max_p ; /* maximum value for p_b (scaled) */
+
+ u_int c_1 ; /* max_p/(max_th-min_th) (scaled) */
+ u_int c_2 ; /* max_p*min_th/(max_th-min_th) (scaled) */
+ u_int c_3 ; /* for GRED, (1-max_p)/max_th (scaled) */
+ u_int c_4 ; /* for GRED, 1 - 2*max_p (scaled) */
+ u_int * w_q_lookup ; /* lookup table for computing (1-w_q)^t */
+ u_int lookup_depth ; /* depth of lookup table */
+ int lookup_step ; /* granularity inside the lookup table */
+ int lookup_weight ; /* equal to (1-w_q)^t / (1-w_q)^(t+1) */
+ int avg_pkt_size ; /* medium packet size */
+ int max_pkt_size ; /* max packet size */
+};
+
+/*
+ * A queue is created as a child of a flowset unless it belongs to
+ * a !MULTIQUEUE scheduler. It is normally in a hash table in the
+ * flowset. fs always points to the parent flowset.
+ * si normally points to the sch_inst, unless the flowset has been
+ * detached from the scheduler -- in this case si == NULL and we
+ * should not enqueue.
+ */
+struct dn_queue {
+ struct dn_flow ni; /* oid, flow_id, stats */
+ struct mq mq; /* packets queue */
+ struct dn_sch_inst *_si; /* owner scheduler instance */
+ SLIST_ENTRY(dn_queue) q_next; /* hash chain list for qht */
+ struct dn_fsk *fs; /* parent flowset. */
+
+ /* RED parameters */
+ int avg; /* average queue length est. (scaled) */
+ int count; /* arrivals since last RED drop */
+ int random; /* random value (scaled) */
+ uint64_t q_time; /* start of queue idle time */
+
+};
+
+/*
+ * The kernel side of a scheduler. Contains the userland config,
+ * a link, pointer to extra config arguments from command line,
+ * kernel flags, and a pointer to the scheduler methods.
+ * It is stored in a hash table, and holds a list of all
+ * flowsets and scheduler instances.
+ * XXX sch must be at the beginning, see schk_hash().
+ */
+struct dn_schk {
+ struct dn_sch sch;
+ struct dn_alg *fp; /* Pointer to scheduler functions */
+ struct dn_link link; /* The link, embedded */
+ struct dn_profile *profile; /* delay profile, if any */
+ struct dn_id *cfg; /* extra config arguments */
+
+ SLIST_ENTRY(dn_schk) schk_next; /* hash chain for schedhash */
+
+ struct dn_fsk_head fsk_list; /* all fsk linked to me */
+ struct dn_fsk *fs; /* Flowset for !MULTIQUEUE */
+
+ /* bucket index used by the drain routine to drain the scheduler
+ * instance for this flowset.
+ */
+ int drain_bucket;
+
+ /* Hash table of all instances (through sch.sched_mask)
+ * or single instance if no mask. Always valid.
+ */
+ struct dn_ht *siht;
+};
+
+
+/*
+ * Scheduler instance.
+ * Contains variables and all queues relative to a this instance.
+ * This struct is created a runtime.
+ */
+struct dn_sch_inst {
+ struct dn_flow ni; /* oid, flowid and stats */
+ SLIST_ENTRY(dn_sch_inst) si_next; /* hash chain for siht */
+ struct delay_line dline;
+ struct dn_schk *sched; /* the template */
+ int kflags; /* DN_ACTIVE */
+
+ int64_t credit; /* bits I can transmit (more or less). */
+ uint64_t sched_time; /* time link was scheduled in ready_heap */
+ uint64_t idle_time; /* start of scheduler instance idle time */
+
+ /* q_count is the number of queues that this instance is using.
+ * The counter is incremented or decremented when
+ * a reference from the queue is created or deleted.
+ * It is used to make sure that a scheduler instance can be safely
+ * deleted by the drain routine. See notes below.
+ */
+ int q_count;
+
+};
+
+/*
+ * NOTE about object drain.
+ * The system will automatically (XXX check when) drain queues and
+ * scheduler instances when they are idle.
+ * A queue is idle when it has no packets; an instance is idle when
+ * it is not in the evheap heap, and the corresponding delay line is empty.
+ * A queue can be safely deleted when it is idle because of the scheduler
+ * function xxx_free_queue() will remove any references to it.
+ * An instance can be only deleted when no queues reference it. To be sure
+ * of that, a counter (q_count) stores the number of queues that are pointing
+ * to the instance.
+ *
+ * XXX
+ * Order of scan:
+ * - take all flowset in a bucket for the flowset hash table
+ * - take all queues in a bucket for the flowset
+ * - increment the queue bucket
+ * - scan next flowset bucket
+ * Nothing is done if a bucket contains no entries.
+ *
+ * The same schema is used for sceduler instances
+ */
+
+
+/* kernel-side flags. Linux has DN_DELETE in fcntl.h
+ */
+enum {
+ /* 1 and 2 are reserved for the SCAN flags */
+ DN_DESTROY = 0x0004, /* destroy */
+ DN_DELETE_FS = 0x0008, /* destroy flowset */
+ DN_DETACH = 0x0010,
+ DN_ACTIVE = 0x0020, /* object is in evheap */
+ DN_F_DLINE = 0x0040, /* object is a delay line */
+ DN_F_SCHI = 0x00C0, /* object is a sched.instance */
+ DN_QHT_IS_Q = 0x0100, /* in flowset, qht is a single queue */
+};
+
+extern struct dn_parms dn_cfg;
+
+int dummynet_io(struct mbuf **, int , struct ip_fw_args *);
+void dummynet_task(void *context, int pending);
+void dn_reschedule(void);
+
+struct dn_queue *ipdn_q_find(struct dn_fsk *, struct dn_sch_inst *,
+ struct ipfw_flow_id *);
+struct dn_sch_inst *ipdn_si_find(struct dn_schk *, struct ipfw_flow_id *);
+
+/* helper structure to copy objects returned to userland */
+struct copy_args {
+ char **start;
+ char *end;
+ int flags;
+ int type;
+ int extra; /* extra filtering */
+};
+
+struct sockopt;
+int ip_dummynet_compat(struct sockopt *sopt);
+int dummynet_get(struct sockopt *sopt, void **compat);
+int dn_c_copy_q (void *_ni, void *arg);
+int dn_c_copy_pipe(struct dn_schk *s, struct copy_args *a, int nq);
+int dn_c_copy_fs(struct dn_fsk *f, struct copy_args *a, int nq);
+int dn_compat_copy_queue(struct copy_args *a, void *_o);
+int dn_compat_copy_pipe(struct copy_args *a, void *_o);
+int copy_data_helper_compat(void *_o, void *_arg);
+int dn_compat_calc_size(struct dn_parms dn_cfg);
+int do_config(void *p, int l);
+
+/* function to drain idle object */
+void dn_drain_scheduler(void);
+void dn_drain_queue(void);
+
+#endif /* _IP_DN_PRIVATE_H */
diff --git a/sys/netinet/ipfw/ip_dummynet.c b/sys/netinet/ipfw/ip_dummynet.c
index 267776f..20b776f 100644
--- a/sys/netinet/ipfw/ip_dummynet.c
+++ b/sys/netinet/ipfw/ip_dummynet.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1998-2002 Luigi Rizzo, Universita` di Pisa
+ * Copyright (c) 1998-2002,2010 Luigi Rizzo, Universita` di Pisa
* Portions Copyright (c) 2000 Akamba Corp.
* All rights reserved
*
@@ -28,32 +28,12 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#define DUMMYNET_DEBUG
-
-#include "opt_inet6.h"
-
/*
- * This module implements IP dummynet, a bandwidth limiter/delay emulator
- * used in conjunction with the ipfw package.
- * Description of the data structures used is in ip_dummynet.h
- * Here you mainly find the following blocks of code:
- * + variable declarations;
- * + heap management functions;
- * + scheduler and dummynet functions;
- * + configuration and initialization.
- *
- * NOTA BENE: critical sections are protected by the "dummynet lock".
- *
- * Most important Changes:
- *
- * 011004: KLDable
- * 010124: Fixed WF2Q behaviour
- * 010122: Fixed spl protection.
- * 000601: WF2Q support
- * 000106: large rewrite, use heaps to handle very many pipes.
- * 980513: initial release
+ * Configuration and internal object management for dummynet.
*/
+#include "opt_inet6.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
@@ -67,2197 +47,2012 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/time.h>
-#include <sys/sysctl.h>
#include <sys/taskqueue.h>
#include <net/if.h> /* IFNAMSIZ, struct ifaddr, ifq head, lock.h mutex.h */
-#include <net/netisr.h>
#include <netinet/in.h>
-#include <netinet/ip.h> /* ip_len, ip_off */
#include <netinet/ip_var.h> /* ip_output(), IP_FORWARDING */
#include <netinet/ip_fw.h>
#include <netinet/ipfw/ip_fw_private.h>
+#include <netinet/ipfw/dn_heap.h>
#include <netinet/ip_dummynet.h>
+#include <netinet/ipfw/ip_dn_private.h>
+#include <netinet/ipfw/dn_sched.h>
+
+/* which objects to copy */
+#define DN_C_LINK 0x01
+#define DN_C_SCH 0x02
+#define DN_C_FLOW 0x04
+#define DN_C_FS 0x08
+#define DN_C_QUEUE 0x10
+
+/* we use this argument in case of a schk_new */
+struct schk_new_arg {
+ struct dn_alg *fp;
+ struct dn_sch *sch;
+};
-#include <netinet/if_ether.h> /* various ether_* routines */
-
-#include <netinet/ip6.h> /* for ip6_input, ip6_output prototypes */
-#include <netinet6/ip6_var.h>
-
-/*
- * We keep a private variable for the simulation time, but we could
- * probably use an existing one ("softticks" in sys/kern/kern_timeout.c)
- */
-static dn_key curr_time = 0 ; /* current simulation time */
-
-static int dn_hash_size = 64 ; /* default hash size */
-
-/* statistics on number of queue searches and search steps */
-static long searches, search_steps ;
-static int pipe_expire = 1 ; /* expire queue if empty */
-static int dn_max_ratio = 16 ; /* max queues/buckets ratio */
-
-static long pipe_slot_limit = 100; /* Foot shooting limit for pipe queues. */
-static long pipe_byte_limit = 1024 * 1024;
-
-static int red_lookup_depth = 256; /* RED - default lookup table depth */
-static int red_avg_pkt_size = 512; /* RED - default medium packet size */
-static int red_max_pkt_size = 1500; /* RED - default max packet size */
-
-static struct timeval prev_t;
-static long tick_last; /* Last tick duration (usec). */
-static long tick_delta; /* Last vs standard tick diff (usec). */
-static long tick_delta_sum; /* Accumulated tick difference (usec).*/
-static long tick_adjustment; /* Tick adjustments done. */
-static long tick_lost; /* Lost(coalesced) ticks number. */
-/* Adjusted vs non-adjusted curr_time difference (ticks). */
-static long tick_diff;
-
-static int io_fast;
-static unsigned long io_pkt;
-static unsigned long io_pkt_fast;
-static unsigned long io_pkt_drop;
-
-/*
- * Three heaps contain queues and pipes that the scheduler handles:
- *
- * ready_heap contains all dn_flow_queue related to fixed-rate pipes.
- *
- * wfq_ready_heap contains the pipes associated with WF2Q flows
- *
- * extract_heap contains pipes associated with delay lines.
- *
- */
-
-MALLOC_DEFINE(M_DUMMYNET, "dummynet", "dummynet heap");
-
-static struct dn_heap ready_heap, extract_heap, wfq_ready_heap ;
-
-static int heap_init(struct dn_heap *h, int size);
-static int heap_insert (struct dn_heap *h, dn_key key1, void *p);
-static void heap_extract(struct dn_heap *h, void *obj);
-static void transmit_event(struct dn_pipe *pipe, struct mbuf **head,
- struct mbuf **tail);
-static void ready_event(struct dn_flow_queue *q, struct mbuf **head,
- struct mbuf **tail);
-static void ready_event_wfq(struct dn_pipe *p, struct mbuf **head,
- struct mbuf **tail);
-
-#define HASHSIZE 16
-#define HASH(num) ((((num) >> 8) ^ ((num) >> 4) ^ (num)) & 0x0f)
-static struct dn_pipe_head pipehash[HASHSIZE]; /* all pipes */
-static struct dn_flow_set_head flowsethash[HASHSIZE]; /* all flowsets */
-
+/*---- callout hooks. ----*/
static struct callout dn_timeout;
+static struct task dn_task;
+static struct taskqueue *dn_tq = NULL;
-extern void (*bridge_dn_p)(struct mbuf *, struct ifnet *);
+static void
+dummynet(void * __unused unused)
+{
-#ifdef SYSCTL_NODE
-SYSCTL_DECL(_net_inet);
-SYSCTL_DECL(_net_inet_ip);
+ taskqueue_enqueue(dn_tq, &dn_task);
+}
-SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet, CTLFLAG_RW, 0, "Dummynet");
-SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, hash_size,
- CTLFLAG_RW, &dn_hash_size, 0, "Default hash table size");
-#if 0 /* curr_time is 64 bit */
-SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, curr_time,
- CTLFLAG_RD, &curr_time, 0, "Current tick");
-#endif
-SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, ready_heap,
- CTLFLAG_RD, &ready_heap.size, 0, "Size of ready heap");
-SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, extract_heap,
- CTLFLAG_RD, &extract_heap.size, 0, "Size of extract heap");
-SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, searches,
- CTLFLAG_RD, &searches, 0, "Number of queue searches");
-SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, search_steps,
- CTLFLAG_RD, &search_steps, 0, "Number of queue search steps");
-SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, expire,
- CTLFLAG_RW, &pipe_expire, 0, "Expire queue if empty");
-SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, max_chain_len,
- CTLFLAG_RW, &dn_max_ratio, 0,
- "Max ratio between dynamic queues and buckets");
-SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_lookup_depth,
- CTLFLAG_RD, &red_lookup_depth, 0, "Depth of RED lookup table");
-SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_avg_pkt_size,
- CTLFLAG_RD, &red_avg_pkt_size, 0, "RED Medium packet size");
-SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_max_pkt_size,
- CTLFLAG_RD, &red_max_pkt_size, 0, "RED Max packet size");
-SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_delta,
- CTLFLAG_RD, &tick_delta, 0, "Last vs standard tick difference (usec).");
-SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_delta_sum,
- CTLFLAG_RD, &tick_delta_sum, 0, "Accumulated tick difference (usec).");
-SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_adjustment,
- CTLFLAG_RD, &tick_adjustment, 0, "Tick adjustments done.");
-SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_diff,
- CTLFLAG_RD, &tick_diff, 0,
- "Adjusted vs non-adjusted curr_time difference (ticks).");
-SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_lost,
- CTLFLAG_RD, &tick_lost, 0,
- "Number of ticks coalesced by dummynet taskqueue.");
-SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, io_fast,
- CTLFLAG_RW, &io_fast, 0, "Enable fast dummynet io.");
-SYSCTL_ULONG(_net_inet_ip_dummynet, OID_AUTO, io_pkt,
- CTLFLAG_RD, &io_pkt, 0,
- "Number of packets passed to dummynet.");
-SYSCTL_ULONG(_net_inet_ip_dummynet, OID_AUTO, io_pkt_fast,
- CTLFLAG_RD, &io_pkt_fast, 0,
- "Number of packets bypassed dummynet scheduler.");
-SYSCTL_ULONG(_net_inet_ip_dummynet, OID_AUTO, io_pkt_drop,
- CTLFLAG_RD, &io_pkt_drop, 0,
- "Number of packets dropped by dummynet.");
-SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, pipe_slot_limit,
- CTLFLAG_RW, &pipe_slot_limit, 0, "Upper limit in slots for pipe queue.");
-SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, pipe_byte_limit,
- CTLFLAG_RW, &pipe_byte_limit, 0, "Upper limit in bytes for pipe queue.");
-#endif
+void
+dn_reschedule(void)
+{
+ callout_reset(&dn_timeout, 1, dummynet, NULL);
+}
+/*----- end of callout hooks -----*/
-#ifdef DUMMYNET_DEBUG
-int dummynet_debug = 0;
-#ifdef SYSCTL_NODE
-SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, debug, CTLFLAG_RW, &dummynet_debug,
- 0, "control debugging printfs");
-#endif
-#define DPRINTF(X) if (dummynet_debug) printf X
-#else
-#define DPRINTF(X)
-#endif
+/* Return a scheduler descriptor given the type or name. */
+static struct dn_alg *
+find_sched_type(int type, char *name)
+{
+ struct dn_alg *d;
-static struct task dn_task;
-static struct taskqueue *dn_tq = NULL;
-static void dummynet_task(void *, int);
+ SLIST_FOREACH(d, &dn_cfg.schedlist, next) {
+ if (d->type == type || (name && !strcmp(d->name, name)))
+ return d;
+ }
+ return NULL; /* not found */
+}
-static struct mtx dummynet_mtx;
-#define DUMMYNET_LOCK_INIT() \
- mtx_init(&dummynet_mtx, "dummynet", NULL, MTX_DEF)
-#define DUMMYNET_LOCK_DESTROY() mtx_destroy(&dummynet_mtx)
-#define DUMMYNET_LOCK() mtx_lock(&dummynet_mtx)
-#define DUMMYNET_UNLOCK() mtx_unlock(&dummynet_mtx)
-#define DUMMYNET_LOCK_ASSERT() mtx_assert(&dummynet_mtx, MA_OWNED)
+int
+ipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg)
+{
+ int oldv = *v;
+ const char *op = NULL;
+ if (oldv < lo) {
+ *v = dflt;
+ op = "Bump";
+ } else if (oldv > hi) {
+ *v = hi;
+ op = "Clamp";
+ } else
+ return *v;
+ if (op && msg)
+ printf("%s %s to %d (was %d)\n", op, msg, *v, oldv);
+ return *v;
+}
-static int config_pipe(struct dn_pipe *p);
-static int ip_dn_ctl(struct sockopt *sopt);
+/*---- flow_id mask, hash and compare functions ---*/
+static struct ipfw_flow_id *
+flow_id_mask(struct ipfw_flow_id *mask, struct ipfw_flow_id *id)
+{
+ int is_v6 = IS_IP6_FLOW_ID(id);
-static void dummynet(void *);
-static void dummynet_flush(void);
-static void dummynet_send(struct mbuf *);
-static int dummynet_io(struct mbuf **, int , struct ip_fw_args *);
+ id->dst_port &= mask->dst_port;
+ id->src_port &= mask->src_port;
+ id->proto &= mask->proto;
+ id->flags = 0; /* we don't care about this one */
+ if (is_v6) {
+ APPLY_MASK(&id->dst_ip6, &mask->dst_ip6);
+ APPLY_MASK(&id->src_ip6, &mask->src_ip6);
+ id->flow_id6 &= mask->flow_id6;
+ } else {
+ id->dst_ip &= mask->dst_ip;
+ id->src_ip &= mask->src_ip;
+ }
+ return id;
+}
-/*
- * Flow queue is idle if:
- * 1) it's empty for at least 1 tick
- * 2) it has invalid timestamp (WF2Q case)
- * 3) parent pipe has no 'exhausted' burst.
- */
-#define QUEUE_IS_IDLE(q) ((q)->head == NULL && (q)->S == (q)->F + 1 && \
- curr_time > (q)->idle_time + 1 && \
- ((q)->numbytes + (curr_time - (q)->idle_time - 1) * \
- (q)->fs->pipe->bandwidth >= (q)->fs->pipe->burst))
+/* computes an OR of two masks, result in dst and also returned */
+static struct ipfw_flow_id *
+flow_id_or(struct ipfw_flow_id *src, struct ipfw_flow_id *dst)
+{
+ int is_v6 = IS_IP6_FLOW_ID(dst);
-/*
- * Heap management functions.
- *
- * In the heap, first node is element 0. Children of i are 2i+1 and 2i+2.
- * Some macros help finding parent/children so we can optimize them.
- *
- * heap_init() is called to expand the heap when needed.
- * Increment size in blocks of 16 entries.
- * XXX failure to allocate a new element is a pretty bad failure
- * as we basically stall a whole queue forever!!
- * Returns 1 on error, 0 on success
- */
-#define HEAP_FATHER(x) ( ( (x) - 1 ) / 2 )
-#define HEAP_LEFT(x) ( 2*(x) + 1 )
-#define HEAP_IS_LEFT(x) ( (x) & 1 )
-#define HEAP_RIGHT(x) ( 2*(x) + 2 )
-#define HEAP_SWAP(a, b, buffer) { buffer = a ; a = b ; b = buffer ; }
-#define HEAP_INCREMENT 15
+ dst->dst_port |= src->dst_port;
+ dst->src_port |= src->src_port;
+ dst->proto |= src->proto;
+ dst->flags = 0; /* we don't care about this one */
+ if (is_v6) {
+#define OR_MASK(_d, _s) \
+ (_d)->__u6_addr.__u6_addr32[0] |= (_s)->__u6_addr.__u6_addr32[0]; \
+ (_d)->__u6_addr.__u6_addr32[1] |= (_s)->__u6_addr.__u6_addr32[1]; \
+ (_d)->__u6_addr.__u6_addr32[2] |= (_s)->__u6_addr.__u6_addr32[2]; \
+ (_d)->__u6_addr.__u6_addr32[3] |= (_s)->__u6_addr.__u6_addr32[3];
+ OR_MASK(&dst->dst_ip6, &src->dst_ip6);
+ OR_MASK(&dst->src_ip6, &src->src_ip6);
+#undef OR_MASK
+ dst->flow_id6 |= src->flow_id6;
+ } else {
+ dst->dst_ip |= src->dst_ip;
+ dst->src_ip |= src->src_ip;
+ }
+ return dst;
+}
static int
-heap_init(struct dn_heap *h, int new_size)
+nonzero_mask(struct ipfw_flow_id *m)
{
- struct dn_heap_entry *p;
+ if (m->dst_port || m->src_port || m->proto)
+ return 1;
+ if (IS_IP6_FLOW_ID(m)) {
+ return
+ m->dst_ip6.__u6_addr.__u6_addr32[0] ||
+ m->dst_ip6.__u6_addr.__u6_addr32[1] ||
+ m->dst_ip6.__u6_addr.__u6_addr32[2] ||
+ m->dst_ip6.__u6_addr.__u6_addr32[3] ||
+ m->src_ip6.__u6_addr.__u6_addr32[0] ||
+ m->src_ip6.__u6_addr.__u6_addr32[1] ||
+ m->src_ip6.__u6_addr.__u6_addr32[2] ||
+ m->src_ip6.__u6_addr.__u6_addr32[3] ||
+ m->flow_id6;
+ } else {
+ return m->dst_ip || m->src_ip;
+ }
+}
- if (h->size >= new_size ) {
- printf("dummynet: %s, Bogus call, have %d want %d\n", __func__,
- h->size, new_size);
- return 0 ;
- }
- new_size = (new_size + HEAP_INCREMENT ) & ~HEAP_INCREMENT ;
- p = malloc(new_size * sizeof(*p), M_DUMMYNET, M_NOWAIT);
- if (p == NULL) {
- printf("dummynet: %s, resize %d failed\n", __func__, new_size );
- return 1 ; /* error */
- }
- if (h->size > 0) {
- bcopy(h->p, p, h->size * sizeof(*p) );
- free(h->p, M_DUMMYNET);
+/* XXX we may want a better hash function */
+static uint32_t
+flow_id_hash(struct ipfw_flow_id *id)
+{
+ uint32_t i;
+
+ if (IS_IP6_FLOW_ID(id)) {
+ uint32_t *d = (uint32_t *)&id->dst_ip6;
+ uint32_t *s = (uint32_t *)&id->src_ip6;
+ i = (d[0] ) ^ (d[1]) ^
+ (d[2] ) ^ (d[3]) ^
+ (d[0] >> 15) ^ (d[1] >> 15) ^
+ (d[2] >> 15) ^ (d[3] >> 15) ^
+ (s[0] << 1) ^ (s[1] << 1) ^
+ (s[2] << 1) ^ (s[3] << 1) ^
+ (s[0] << 16) ^ (s[1] << 16) ^
+ (s[2] << 16) ^ (s[3] << 16) ^
+ (id->dst_port << 1) ^ (id->src_port) ^
+ (id->proto ) ^ (id->flow_id6);
+ } else {
+ i = (id->dst_ip) ^ (id->dst_ip >> 15) ^
+ (id->src_ip << 1) ^ (id->src_ip >> 16) ^
+ (id->dst_port << 1) ^ (id->src_port) ^ (id->proto);
}
- h->p = p ;
- h->size = new_size ;
- return 0 ;
+ return i;
}
-/*
- * Insert element in heap. Normally, p != NULL, we insert p in
- * a new position and bubble up. If p == NULL, then the element is
- * already in place, and key is the position where to start the
- * bubble-up.
- * Returns 1 on failure (cannot allocate new heap entry)
- *
- * If offset > 0 the position (index, int) of the element in the heap is
- * also stored in the element itself at the given offset in bytes.
- */
-#define SET_OFFSET(heap, node) \
- if (heap->offset > 0) \
- *((int *)((char *)(heap->p[node].object) + heap->offset)) = node ;
-/*
- * RESET_OFFSET is used for sanity checks. It sets offset to an invalid value.
- */
-#define RESET_OFFSET(heap, node) \
- if (heap->offset > 0) \
- *((int *)((char *)(heap->p[node].object) + heap->offset)) = -1 ;
+/* Like bcmp, returns 0 if ids match, 1 otherwise. */
static int
-heap_insert(struct dn_heap *h, dn_key key1, void *p)
-{
- int son = h->elements ;
-
- if (p == NULL) /* data already there, set starting point */
- son = key1 ;
- else { /* insert new element at the end, possibly resize */
- son = h->elements ;
- if (son == h->size) /* need resize... */
- if (heap_init(h, h->elements+1) )
- return 1 ; /* failure... */
- h->p[son].object = p ;
- h->p[son].key = key1 ;
- h->elements++ ;
- }
- while (son > 0) { /* bubble up */
- int father = HEAP_FATHER(son) ;
- struct dn_heap_entry tmp ;
-
- if (DN_KEY_LT( h->p[father].key, h->p[son].key ) )
- break ; /* found right position */
- /* son smaller than father, swap and repeat */
- HEAP_SWAP(h->p[son], h->p[father], tmp) ;
- SET_OFFSET(h, son);
- son = father ;
- }
- SET_OFFSET(h, son);
- return 0 ;
+flow_id_cmp(struct ipfw_flow_id *id1, struct ipfw_flow_id *id2)
+{
+ int is_v6 = IS_IP6_FLOW_ID(id1);
+
+ if (is_v6 != IS_IP6_FLOW_ID(id2))
+ return 1; /* a ipv4 and a ipv6 flow */
+
+ if (!is_v6 && id1->dst_ip == id2->dst_ip &&
+ id1->src_ip == id2->src_ip &&
+ id1->dst_port == id2->dst_port &&
+ id1->src_port == id2->src_port &&
+ id1->proto == id2->proto &&
+ id1->flags == id2->flags)
+ return 0;
+
+ if (is_v6 &&
+ !bcmp(&id1->dst_ip6,&id2->dst_ip6, sizeof(id1->dst_ip6)) &&
+ !bcmp(&id1->src_ip6,&id2->src_ip6, sizeof(id1->src_ip6)) &&
+ id1->dst_port == id2->dst_port &&
+ id1->src_port == id2->src_port &&
+ id1->proto == id2->proto &&
+ id1->flags == id2->flags &&
+ id1->flow_id6 == id2->flow_id6)
+ return 0;
+
+ /* Masks differ */
+ return 1;
}
+/*--------- end of flow-id mask, hash and compare ---------*/
-/*
- * remove top element from heap, or obj if obj != NULL
+/*--- support functions for the qht hashtable ----
+ * Entries are hashed by flow-id
*/
-static void
-heap_extract(struct dn_heap *h, void *obj)
+static uint32_t
+q_hash(uintptr_t key, int flags, void *arg)
{
- int child, father, max = h->elements - 1 ;
+ /* compute the hash slot from the flow id */
+ struct ipfw_flow_id *id = (flags & DNHT_KEY_IS_OBJ) ?
+ &((struct dn_queue *)key)->ni.fid :
+ (struct ipfw_flow_id *)key;
- if (max < 0) {
- printf("dummynet: warning, extract from empty heap 0x%p\n", h);
- return ;
- }
- father = 0 ; /* default: move up smallest child */
- if (obj != NULL) { /* extract specific element, index is at offset */
- if (h->offset <= 0)
- panic("dummynet: heap_extract from middle not supported on this heap!!!\n");
- father = *((int *)((char *)obj + h->offset)) ;
- if (father < 0 || father >= h->elements) {
- printf("dummynet: heap_extract, father %d out of bound 0..%d\n",
- father, h->elements);
- panic("dummynet: heap_extract");
+ return flow_id_hash(id);
+}
+
+static int
+q_match(void *obj, uintptr_t key, int flags, void *arg)
+{
+ struct dn_queue *o = (struct dn_queue *)obj;
+ struct ipfw_flow_id *id2;
+
+ if (flags & DNHT_KEY_IS_OBJ) {
+ /* compare pointers */
+ id2 = &((struct dn_queue *)key)->ni.fid;
+ } else {
+ id2 = (struct ipfw_flow_id *)key;
}
- }
- RESET_OFFSET(h, father);
- child = HEAP_LEFT(father) ; /* left child */
- while (child <= max) { /* valid entry */
- if (child != max && DN_KEY_LT(h->p[child+1].key, h->p[child].key) )
- child = child+1 ; /* take right child, otherwise left */
- h->p[father] = h->p[child] ;
- SET_OFFSET(h, father);
- father = child ;
- child = HEAP_LEFT(child) ; /* left child for next loop */
- }
- h->elements-- ;
- if (father != max) {
- /*
- * Fill hole with last entry and bubble up, reusing the insert code
- */
- h->p[father] = h->p[max] ;
- heap_insert(h, father, NULL); /* this one cannot fail */
- }
+ return (0 == flow_id_cmp(&o->ni.fid, id2));
}
-#if 0
/*
- * change object position and update references
- * XXX this one is never used!
+ * create a new queue instance for the given 'key'.
*/
-static void
-heap_move(struct dn_heap *h, dn_key new_key, void *object)
-{
- int temp;
- int i ;
- int max = h->elements-1 ;
- struct dn_heap_entry buf ;
-
- if (h->offset <= 0)
- panic("cannot move items on this heap");
-
- i = *((int *)((char *)object + h->offset));
- if (DN_KEY_LT(new_key, h->p[i].key) ) { /* must move up */
- h->p[i].key = new_key ;
- for (; i>0 && DN_KEY_LT(new_key, h->p[(temp = HEAP_FATHER(i))].key) ;
- i = temp ) { /* bubble up */
- HEAP_SWAP(h->p[i], h->p[temp], buf) ;
- SET_OFFSET(h, i);
- }
- } else { /* must move down */
- h->p[i].key = new_key ;
- while ( (temp = HEAP_LEFT(i)) <= max ) { /* found left child */
- if ((temp != max) && DN_KEY_GT(h->p[temp].key, h->p[temp+1].key))
- temp++ ; /* select child with min key */
- if (DN_KEY_GT(new_key, h->p[temp].key)) { /* go down */
- HEAP_SWAP(h->p[i], h->p[temp], buf) ;
- SET_OFFSET(h, i);
- } else
- break ;
- i = temp ;
+static void *
+q_new(uintptr_t key, int flags, void *arg)
+{
+ struct dn_queue *q, *template = arg;
+ struct dn_fsk *fs = template->fs;
+ int size = sizeof(*q) + fs->sched->fp->q_datalen;
+
+ q = malloc(size, M_DUMMYNET, M_NOWAIT | M_ZERO);
+ if (q == NULL) {
+ D("no memory for new queue");
+ return NULL;
}
- }
- SET_OFFSET(h, i);
+
+ set_oid(&q->ni.oid, DN_QUEUE, size);
+ if (fs->fs.flags & DN_QHT_HASH)
+ q->ni.fid = *(struct ipfw_flow_id *)key;
+ q->fs = fs;
+ q->_si = template->_si;
+ q->_si->q_count++;
+
+ if (fs->sched->fp->new_queue)
+ fs->sched->fp->new_queue(q);
+ dn_cfg.queue_count++;
+ return q;
}
-#endif /* heap_move, unused */
/*
- * heapify() will reorganize data inside an array to maintain the
- * heap property. It is needed when we delete a bunch of entries.
+ * Notify schedulers that a queue is going away.
+ * If (flags & DN_DESTROY), also free the packets.
+ * The version for callbacks is called q_delete_cb().
*/
static void
-heapify(struct dn_heap *h)
+dn_delete_queue(struct dn_queue *q, int flags)
{
- int i ;
+ struct dn_fsk *fs = q->fs;
+
+ // D("fs %p si %p\n", fs, q->_si);
+ /* notify the parent scheduler that the queue is going away */
+ if (fs && fs->sched->fp->free_queue)
+ fs->sched->fp->free_queue(q);
+ q->_si->q_count--;
+ q->_si = NULL;
+ if (flags & DN_DESTROY) {
+ if (q->mq.head)
+ dn_free_pkts(q->mq.head);
+ bzero(q, sizeof(*q)); // safety
+ free(q, M_DUMMYNET);
+ dn_cfg.queue_count--;
+ }
+}
- for (i = 0 ; i < h->elements ; i++ )
- heap_insert(h, i , NULL) ;
+static int
+q_delete_cb(void *q, void *arg)
+{
+ int flags = (int)(uintptr_t)arg;
+ dn_delete_queue(q, flags);
+ return (flags & DN_DESTROY) ? DNHT_SCAN_DEL : 0;
}
/*
- * cleanup the heap and free data structure
+ * calls dn_delete_queue/q_delete_cb on all queues,
+ * which notifies the parent scheduler and possibly drains packets.
+ * flags & DN_DESTROY: drains queues and destroy qht;
*/
static void
-heap_free(struct dn_heap *h)
+qht_delete(struct dn_fsk *fs, int flags)
{
- if (h->size >0 )
- free(h->p, M_DUMMYNET);
- bzero(h, sizeof(*h) );
+ ND("fs %d start flags %d qht %p",
+ fs->fs.fs_nr, flags, fs->qht);
+ if (!fs->qht)
+ return;
+ if (fs->fs.flags & DN_QHT_HASH) {
+ dn_ht_scan(fs->qht, q_delete_cb, (void *)(uintptr_t)flags);
+ if (flags & DN_DESTROY) {
+ dn_ht_free(fs->qht, 0);
+ fs->qht = NULL;
+ }
+ } else {
+ dn_delete_queue((struct dn_queue *)(fs->qht), flags);
+ if (flags & DN_DESTROY)
+ fs->qht = NULL;
+ }
}
/*
- * --- end of heap management functions ---
+ * Find and possibly create the queue for a MULTIQUEUE scheduler.
+ * We never call it for !MULTIQUEUE (the queue is in the sch_inst).
*/
+struct dn_queue *
+ipdn_q_find(struct dn_fsk *fs, struct dn_sch_inst *si,
+ struct ipfw_flow_id *id)
+{
+ struct dn_queue template;
+
+ template._si = si;
+ template.fs = fs;
+
+ if (fs->fs.flags & DN_QHT_HASH) {
+ struct ipfw_flow_id masked_id;
+ if (fs->qht == NULL) {
+ fs->qht = dn_ht_init(NULL, fs->fs.buckets,
+ offsetof(struct dn_queue, q_next),
+ q_hash, q_match, q_new);
+ if (fs->qht == NULL)
+ return NULL;
+ }
+ masked_id = *id;
+ flow_id_mask(&fs->fsk_mask, &masked_id);
+ return dn_ht_find(fs->qht, (uintptr_t)&masked_id,
+ DNHT_INSERT, &template);
+ } else {
+ if (fs->qht == NULL)
+ fs->qht = q_new(0, 0, &template);
+ return (struct dn_queue *)fs->qht;
+ }
+}
+/*--- end of queue hash table ---*/
-/*
- * Dispose a list of packet. Use an inline functions so if we
- * need to free extra state associated to a packet, this is a
- * central point to do it.
+/*--- support functions for the sch_inst hashtable ----
+ *
+ * These are hashed by flow-id
*/
-
-static __inline void dn_free_pkts(struct mbuf *mnext)
+static uint32_t
+si_hash(uintptr_t key, int flags, void *arg)
{
- struct mbuf *m;
+ /* compute the hash slot from the flow id */
+ struct ipfw_flow_id *id = (flags & DNHT_KEY_IS_OBJ) ?
+ &((struct dn_sch_inst *)key)->ni.fid :
+ (struct ipfw_flow_id *)key;
- while ((m = mnext) != NULL) {
- mnext = m->m_nextpkt;
- FREE_PKT(m);
- }
+ return flow_id_hash(id);
}
-/*
- * Return the mbuf tag holding the dummynet state. As an optimization
- * this is assumed to be the first tag on the list. If this turns out
- * wrong we'll need to search the list.
- */
-static struct dn_pkt_tag *
-dn_tag_get(struct mbuf *m)
+static int
+si_match(void *obj, uintptr_t key, int flags, void *arg)
{
- struct m_tag *mtag = m_tag_first(m);
- KASSERT(mtag != NULL &&
- mtag->m_tag_cookie == MTAG_ABI_COMPAT &&
- mtag->m_tag_id == PACKET_TAG_DUMMYNET,
- ("packet on dummynet queue w/o dummynet tag!"));
- return (struct dn_pkt_tag *)(mtag+1);
+ struct dn_sch_inst *o = obj;
+ struct ipfw_flow_id *id2;
+
+ id2 = (flags & DNHT_KEY_IS_OBJ) ?
+ &((struct dn_sch_inst *)key)->ni.fid :
+ (struct ipfw_flow_id *)key;
+ return flow_id_cmp(&o->ni.fid, id2) == 0;
}
/*
- * Scheduler functions:
- *
- * transmit_event() is called when the delay-line needs to enter
- * the scheduler, either because of existing pkts getting ready,
- * or new packets entering the queue. The event handled is the delivery
- * time of the packet.
- *
- * ready_event() does something similar with fixed-rate queues, and the
- * event handled is the finish time of the head pkt.
- *
- * wfq_ready_event() does something similar with WF2Q queues, and the
- * event handled is the start time of the head pkt.
- *
- * In all cases, we make sure that the data structures are consistent
- * before passing pkts out, because this might trigger recursive
- * invocations of the procedures.
+ * create a new instance for the given 'key'
+ * Allocate memory for instance, delay line and scheduler private data.
*/
-static void
-transmit_event(struct dn_pipe *pipe, struct mbuf **head, struct mbuf **tail)
+static void *
+si_new(uintptr_t key, int flags, void *arg)
{
- struct mbuf *m;
- struct dn_pkt_tag *pkt;
-
- DUMMYNET_LOCK_ASSERT();
-
- while ((m = pipe->head) != NULL) {
- pkt = dn_tag_get(m);
- if (!DN_KEY_LEQ(pkt->output_time, curr_time))
- break;
-
- pipe->head = m->m_nextpkt;
- if (*tail != NULL)
- (*tail)->m_nextpkt = m;
- else
- *head = m;
- *tail = m;
+ struct dn_schk *s = arg;
+ struct dn_sch_inst *si;
+ int l = sizeof(*si) + s->fp->si_datalen;
+
+ si = malloc(l, M_DUMMYNET, M_NOWAIT | M_ZERO);
+ if (si == NULL)
+ goto error;
+ /* Set length only for the part passed up to userland. */
+ set_oid(&si->ni.oid, DN_SCH_I, sizeof(struct dn_flow));
+ set_oid(&(si->dline.oid), DN_DELAY_LINE,
+ sizeof(struct delay_line));
+ /* mark si and dline as outside the event queue */
+ si->ni.oid.id = si->dline.oid.id = -1;
+
+ si->sched = s;
+ si->dline.si = si;
+
+ if (s->fp->new_sched && s->fp->new_sched(si)) {
+ D("new_sched error");
+ goto error;
}
- if (*tail != NULL)
- (*tail)->m_nextpkt = NULL;
+ if (s->sch.flags & DN_HAVE_MASK)
+ si->ni.fid = *(struct ipfw_flow_id *)key;
- /* If there are leftover packets, put into the heap for next event. */
- if ((m = pipe->head) != NULL) {
- pkt = dn_tag_get(m);
- /*
- * XXX Should check errors on heap_insert, by draining the
- * whole pipe p and hoping in the future we are more successful.
- */
- heap_insert(&extract_heap, pkt->output_time, pipe);
+ dn_cfg.si_count++;
+ return si;
+
+error:
+ if (si) {
+ bzero(si, sizeof(*si)); // safety
+ free(si, M_DUMMYNET);
}
+ return NULL;
}
-#define div64(a, b) ((int64_t)(a) / (int64_t)(b))
/*
- * Compute how many ticks we have to wait before being able to send
- * a packet. This is computed as the "wire time" for the packet
- * (length + extra bits), minus the credit available, scaled to ticks.
- * Check that the result is not be negative (it could be if we have
- * too much leftover credit in q->numbytes).
+ * Callback from siht to delete all scheduler instances. Remove
+ * si and delay line from the system heap, destroy all queues.
+ * We assume that all flowset have been notified and do not
+ * point to us anymore.
*/
-static inline dn_key
-set_ticks(struct mbuf *m, struct dn_flow_queue *q, struct dn_pipe *p)
+static int
+si_destroy(void *_si, void *arg)
{
- int64_t ret;
-
- ret = div64( (m->m_pkthdr.len * 8 + q->extra_bits) * hz
- - q->numbytes + p->bandwidth - 1 , p->bandwidth);
- if (ret < 0)
- ret = 0;
- return ret;
+ struct dn_sch_inst *si = _si;
+ struct dn_schk *s = si->sched;
+ struct delay_line *dl = &si->dline;
+
+ if (dl->oid.subtype) /* remove delay line from event heap */
+ heap_extract(&dn_cfg.evheap, dl);
+ dn_free_pkts(dl->mq.head); /* drain delay line */
+ if (si->kflags & DN_ACTIVE) /* remove si from event heap */
+ heap_extract(&dn_cfg.evheap, si);
+ if (s->fp->free_sched)
+ s->fp->free_sched(si);
+ bzero(si, sizeof(*si)); /* safety */
+ free(si, M_DUMMYNET);
+ dn_cfg.si_count--;
+ return DNHT_SCAN_DEL;
}
/*
- * Convert the additional MAC overheads/delays into an equivalent
- * number of bits for the given data rate. The samples are in milliseconds
- * so we need to divide by 1000.
+ * Find the scheduler instance for this packet. If we need to apply
+ * a mask, do on a local copy of the flow_id to preserve the original.
+ * Assume siht is always initialized if we have a mask.
*/
-static dn_key
-compute_extra_bits(struct mbuf *pkt, struct dn_pipe *p)
+struct dn_sch_inst *
+ipdn_si_find(struct dn_schk *s, struct ipfw_flow_id *id)
{
- int index;
- dn_key extra_bits;
- if (!p->samples || p->samples_no == 0)
- return 0;
- index = random() % p->samples_no;
- extra_bits = div64((dn_key)p->samples[index] * p->bandwidth, 1000);
- if (index >= p->loss_level) {
- struct dn_pkt_tag *dt = dn_tag_get(pkt);
- if (dt)
- dt->dn_dir = DIR_DROP;
+ if (s->sch.flags & DN_HAVE_MASK) {
+ struct ipfw_flow_id id_t = *id;
+ flow_id_mask(&s->sch.sched_mask, &id_t);
+ return dn_ht_find(s->siht, (uintptr_t)&id_t,
+ DNHT_INSERT, s);
}
- return extra_bits;
+ if (!s->siht)
+ s->siht = si_new(0, 0, s);
+ return (struct dn_sch_inst *)s->siht;
}
-static void
-free_pipe(struct dn_pipe *p)
+/* callback to flush credit for the scheduler instance */
+static int
+si_reset_credit(void *_si, void *arg)
{
- if (p->samples)
- free(p->samples, M_DUMMYNET);
- free(p, M_DUMMYNET);
+ struct dn_sch_inst *si = _si;
+ struct dn_link *p = &si->sched->link;
+
+ si->credit = p->burst + (dn_cfg.io_fast ? p->bandwidth : 0);
+ return 0;
}
-/*
- * extract pkt from queue, compute output time (could be now)
- * and put into delay line (p_queue)
- */
static void
-move_pkt(struct mbuf *pkt, struct dn_flow_queue *q, struct dn_pipe *p,
- int len)
+schk_reset_credit(struct dn_schk *s)
{
- struct dn_pkt_tag *dt = dn_tag_get(pkt);
-
- q->head = pkt->m_nextpkt ;
- q->len-- ;
- q->len_bytes -= len ;
-
- dt->output_time = curr_time + p->delay ;
-
- if (p->head == NULL)
- p->head = pkt;
- else
- p->tail->m_nextpkt = pkt;
- p->tail = pkt;
- p->tail->m_nextpkt = NULL;
+ if (s->sch.flags & DN_HAVE_MASK)
+ dn_ht_scan(s->siht, si_reset_credit, NULL);
+ else if (s->siht)
+ si_reset_credit(s->siht, NULL);
}
+/*---- end of sch_inst hashtable ---------------------*/
-/*
- * ready_event() is invoked every time the queue must enter the
- * scheduler, either because the first packet arrives, or because
- * a previously scheduled event fired.
- * On invokation, drain as many pkts as possible (could be 0) and then
- * if there are leftover packets reinsert the pkt in the scheduler.
+/*-------------------------------------------------------
+ * flowset hash (fshash) support. Entries are hashed by fs_nr.
+ * New allocations are put in the fsunlinked list, from which
+ * they are removed when they point to a specific scheduler.
*/
-static void
-ready_event(struct dn_flow_queue *q, struct mbuf **head, struct mbuf **tail)
+static uint32_t
+fsk_hash(uintptr_t key, int flags, void *arg)
{
- struct mbuf *pkt;
- struct dn_pipe *p = q->fs->pipe;
- int p_was_empty;
-
- DUMMYNET_LOCK_ASSERT();
+ uint32_t i = !(flags & DNHT_KEY_IS_OBJ) ? key :
+ ((struct dn_fsk *)key)->fs.fs_nr;
- if (p == NULL) {
- printf("dummynet: ready_event- pipe is gone\n");
- return;
- }
- p_was_empty = (p->head == NULL);
+ return ( (i>>8)^(i>>4)^i );
+}
- /*
- * Schedule fixed-rate queues linked to this pipe:
- * account for the bw accumulated since last scheduling, then
- * drain as many pkts as allowed by q->numbytes and move to
- * the delay line (in p) computing output time.
- * bandwidth==0 (no limit) means we can drain the whole queue,
- * setting len_scaled = 0 does the job.
- */
- q->numbytes += (curr_time - q->sched_time) * p->bandwidth;
- while ((pkt = q->head) != NULL) {
- int len = pkt->m_pkthdr.len;
- dn_key len_scaled = p->bandwidth ? len*8*hz
- + q->extra_bits*hz
- : 0;
-
- if (DN_KEY_GT(len_scaled, q->numbytes))
- break;
- q->numbytes -= len_scaled;
- move_pkt(pkt, q, p, len);
- if (q->head)
- q->extra_bits = compute_extra_bits(q->head, p);
- }
- /*
- * If we have more packets queued, schedule next ready event
- * (can only occur when bandwidth != 0, otherwise we would have
- * flushed the whole queue in the previous loop).
- * To this purpose we record the current time and compute how many
- * ticks to go for the finish time of the packet.
- */
- if ((pkt = q->head) != NULL) { /* this implies bandwidth != 0 */
- dn_key t = set_ticks(pkt, q, p); /* ticks i have to wait */
+static int
+fsk_match(void *obj, uintptr_t key, int flags, void *arg)
+{
+ struct dn_fsk *fs = obj;
+ int i = !(flags & DNHT_KEY_IS_OBJ) ? key :
+ ((struct dn_fsk *)key)->fs.fs_nr;
- q->sched_time = curr_time;
- heap_insert(&ready_heap, curr_time + t, (void *)q);
- /*
- * XXX Should check errors on heap_insert, and drain the whole
- * queue on error hoping next time we are luckier.
- */
- } else /* RED needs to know when the queue becomes empty. */
- q->idle_time = curr_time;
+ return (fs->fs.fs_nr == i);
+}
- /*
- * If the delay line was empty call transmit_event() now.
- * Otherwise, the scheduler will take care of it.
- */
- if (p_was_empty)
- transmit_event(p, head, tail);
+static void *
+fsk_new(uintptr_t key, int flags, void *arg)
+{
+ struct dn_fsk *fs;
+
+ fs = malloc(sizeof(*fs), M_DUMMYNET, M_NOWAIT | M_ZERO);
+ if (fs) {
+ set_oid(&fs->fs.oid, DN_FS, sizeof(fs->fs));
+ dn_cfg.fsk_count++;
+ fs->drain_bucket = 0;
+ SLIST_INSERT_HEAD(&dn_cfg.fsu, fs, sch_chain);
+ }
+ return fs;
}
/*
- * Called when we can transmit packets on WF2Q queues. Take pkts out of
- * the queues at their start time, and enqueue into the delay line.
- * Packets are drained until p->numbytes < 0. As long as
- * len_scaled >= p->numbytes, the packet goes into the delay line
- * with a deadline p->delay. For the last packet, if p->numbytes < 0,
- * there is an additional delay.
+ * detach flowset from its current scheduler. Flags as follows:
+ * DN_DETACH removes from the fsk_list
+ * DN_DESTROY deletes individual queues
+ * DN_DELETE_FS destroys the flowset (otherwise goes in unlinked).
*/
static void
-ready_event_wfq(struct dn_pipe *p, struct mbuf **head, struct mbuf **tail)
+fsk_detach(struct dn_fsk *fs, int flags)
{
- int p_was_empty = (p->head == NULL);
- struct dn_heap *sch = &(p->scheduler_heap);
- struct dn_heap *neh = &(p->not_eligible_heap);
- int64_t p_numbytes = p->numbytes;
-
- /*
- * p->numbytes is only 32bits in FBSD7, but we might need 64 bits.
- * Use a local variable for the computations, and write back the
- * results when done, saturating if needed.
- * The local variable has no impact on performance and helps
- * reducing diffs between the various branches.
- */
-
- DUMMYNET_LOCK_ASSERT();
-
- if (p->if_name[0] == 0) /* tx clock is simulated */
- p_numbytes += (curr_time - p->sched_time) * p->bandwidth;
- else { /*
- * tx clock is for real,
- * the ifq must be empty or this is a NOP.
- */
- if (p->ifp && p->ifp->if_snd.ifq_head != NULL)
- return;
- else {
- DPRINTF(("dummynet: pipe %d ready from %s --\n",
- p->pipe_nr, p->if_name));
- }
- }
-
- /*
- * While we have backlogged traffic AND credit, we need to do
- * something on the queue.
- */
- while (p_numbytes >= 0 && (sch->elements > 0 || neh->elements > 0)) {
- if (sch->elements > 0) {
- /* Have some eligible pkts to send out. */
- struct dn_flow_queue *q = sch->p[0].object;
- struct mbuf *pkt = q->head;
- struct dn_flow_set *fs = q->fs;
- uint64_t len = pkt->m_pkthdr.len;
- int len_scaled = p->bandwidth ? len * 8 * hz : 0;
-
- heap_extract(sch, NULL); /* Remove queue from heap. */
- p_numbytes -= len_scaled;
- move_pkt(pkt, q, p, len);
-
- p->V += div64((len << MY_M), p->sum); /* Update V. */
- q->S = q->F; /* Update start time. */
- if (q->len == 0) {
- /* Flow not backlogged any more. */
- fs->backlogged--;
- heap_insert(&(p->idle_heap), q->F, q);
- } else {
- /* Still backlogged. */
-
- /*
- * Update F and position in backlogged queue,
- * then put flow in not_eligible_heap
- * (we will fix this later).
- */
- len = (q->head)->m_pkthdr.len;
- q->F += div64((len << MY_M), fs->weight);
- if (DN_KEY_LEQ(q->S, p->V))
- heap_insert(neh, q->S, q);
- else
- heap_insert(sch, q->F, q);
- }
- }
- /*
- * Now compute V = max(V, min(S_i)). Remember that all elements
- * in sch have by definition S_i <= V so if sch is not empty,
- * V is surely the max and we must not update it. Conversely,
- * if sch is empty we only need to look at neh.
- */
- if (sch->elements == 0 && neh->elements > 0)
- p->V = MAX64(p->V, neh->p[0].key);
- /* Move from neh to sch any packets that have become eligible */
- while (neh->elements > 0 && DN_KEY_LEQ(neh->p[0].key, p->V)) {
- struct dn_flow_queue *q = neh->p[0].object;
- heap_extract(neh, NULL);
- heap_insert(sch, q->F, q);
- }
-
- if (p->if_name[0] != '\0') { /* Tx clock is from a real thing */
- p_numbytes = -1; /* Mark not ready for I/O. */
- break;
- }
- }
- if (sch->elements == 0 && neh->elements == 0 && p_numbytes >= 0) {
- p->idle_time = curr_time;
- /*
- * No traffic and no events scheduled.
- * We can get rid of idle-heap.
- */
- if (p->idle_heap.elements > 0) {
- int i;
-
- for (i = 0; i < p->idle_heap.elements; i++) {
- struct dn_flow_queue *q;
-
- q = p->idle_heap.p[i].object;
- q->F = 0;
- q->S = q->F + 1;
- }
- p->sum = 0;
- p->V = 0;
- p->idle_heap.elements = 0;
- }
+ if (flags & DN_DELETE_FS)
+ flags |= DN_DESTROY;
+ ND("fs %d from sched %d flags %s %s %s",
+ fs->fs.fs_nr, fs->fs.sched_nr,
+ (flags & DN_DELETE_FS) ? "DEL_FS":"",
+ (flags & DN_DESTROY) ? "DEL":"",
+ (flags & DN_DETACH) ? "DET":"");
+ if (flags & DN_DETACH) { /* detach from the list */
+ struct dn_fsk_head *h;
+ h = fs->sched ? &fs->sched->fsk_list : &dn_cfg.fsu;
+ SLIST_REMOVE(h, fs, dn_fsk, sch_chain);
}
- /*
- * If we are getting clocks from dummynet (not a real interface) and
- * If we are under credit, schedule the next ready event.
- * Also fix the delivery time of the last packet.
- */
- if (p->if_name[0]==0 && p_numbytes < 0) { /* This implies bw > 0. */
- dn_key t = 0; /* Number of ticks i have to wait. */
-
- if (p->bandwidth > 0)
- t = div64(p->bandwidth - 1 - p_numbytes, p->bandwidth);
- dn_tag_get(p->tail)->output_time += t;
- p->sched_time = curr_time;
- heap_insert(&wfq_ready_heap, curr_time + t, (void *)p);
- /*
- * XXX Should check errors on heap_insert, and drain the whole
- * queue on error hoping next time we are luckier.
- */
+ qht_delete(fs, flags);
+ if (fs->sched && fs->sched->fp->free_fsk)
+ fs->sched->fp->free_fsk(fs);
+ fs->sched = NULL;
+ if (flags & DN_DELETE_FS) {
+ bzero(fs, sizeof(fs)); /* safety */
+ free(fs, M_DUMMYNET);
+ dn_cfg.fsk_count--;
+ } else {
+ SLIST_INSERT_HEAD(&dn_cfg.fsu, fs, sch_chain);
}
-
- /* Write back p_numbytes (adjust 64->32bit if necessary). */
- p->numbytes = p_numbytes;
-
- /*
- * If the delay line was empty call transmit_event() now.
- * Otherwise, the scheduler will take care of it.
- */
- if (p_was_empty)
- transmit_event(p, head, tail);
}
/*
- * This is called one tick, after previous run. It is used to
- * schedule next run.
+ * Detach or destroy all flowsets in a list.
+ * flags specifies what to do:
+ * DN_DESTROY: flush all queues
+ * DN_DELETE_FS: DN_DESTROY + destroy flowset
+ * DN_DELETE_FS implies DN_DESTROY
*/
static void
-dummynet(void * __unused unused)
+fsk_detach_list(struct dn_fsk_head *h, int flags)
{
-
- taskqueue_enqueue(dn_tq, &dn_task);
+ struct dn_fsk *fs;
+ int n = 0; /* only for stats */
+
+ ND("head %p flags %x", h, flags);
+ while ((fs = SLIST_FIRST(h))) {
+ SLIST_REMOVE_HEAD(h, sch_chain);
+ n++;
+ fsk_detach(fs, flags);
+ }
+ ND("done %d flowsets", n);
}
/*
- * The timer handler for dummynet. Time is computed in ticks, but
- * but the code is tolerant to the actual rate at which this is called.
- * Once complete, the function reschedules itself for the next tick.
+ * called on 'queue X delete' -- removes the flowset from fshash,
+ * deletes all queues for the flowset, and removes the flowset.
*/
-static void
-dummynet_task(void *context, int pending)
+static int
+delete_fs(int i, int locked)
{
- struct mbuf *head = NULL, *tail = NULL;
- struct dn_pipe *pipe;
- struct dn_heap *heaps[3];
- struct dn_heap *h;
- void *p; /* generic parameter to handler */
- int i;
- struct timeval t;
-
- DUMMYNET_LOCK();
-
- heaps[0] = &ready_heap; /* fixed-rate queues */
- heaps[1] = &wfq_ready_heap; /* wfq queues */
- heaps[2] = &extract_heap; /* delay line */
-
- /* Update number of lost(coalesced) ticks. */
- tick_lost += pending - 1;
-
- getmicrouptime(&t);
- /* Last tick duration (usec). */
- tick_last = (t.tv_sec - prev_t.tv_sec) * 1000000 +
- (t.tv_usec - prev_t.tv_usec);
- /* Last tick vs standard tick difference (usec). */
- tick_delta = (tick_last * hz - 1000000) / hz;
- /* Accumulated tick difference (usec). */
- tick_delta_sum += tick_delta;
-
- prev_t = t;
-
- /*
- * Adjust curr_time if accumulated tick difference greater than
- * 'standard' tick. Since curr_time should be monotonically increasing,
- * we do positive adjustment as required and throttle curr_time in
- * case of negative adjustment.
- */
- curr_time++;
- if (tick_delta_sum - tick >= 0) {
- int diff = tick_delta_sum / tick;
-
- curr_time += diff;
- tick_diff += diff;
- tick_delta_sum %= tick;
- tick_adjustment++;
- } else if (tick_delta_sum + tick <= 0) {
- curr_time--;
- tick_diff--;
- tick_delta_sum += tick;
- tick_adjustment++;
- }
-
- for (i = 0; i < 3; i++) {
- h = heaps[i];
- while (h->elements > 0 && DN_KEY_LEQ(h->p[0].key, curr_time)) {
- if (h->p[0].key > curr_time)
- printf("dummynet: warning, "
- "heap %d is %d ticks late\n",
- i, (int)(curr_time - h->p[0].key));
- /* store a copy before heap_extract */
- p = h->p[0].object;
- /* need to extract before processing */
- heap_extract(h, NULL);
- if (i == 0)
- ready_event(p, &head, &tail);
- else if (i == 1) {
- struct dn_pipe *pipe = p;
- if (pipe->if_name[0] != '\0')
- printf("dummynet: bad ready_event_wfq "
- "for pipe %s\n", pipe->if_name);
- else
- ready_event_wfq(p, &head, &tail);
- } else
- transmit_event(p, &head, &tail);
- }
- }
-
- /* Sweep pipes trying to expire idle flow_queues. */
- for (i = 0; i < HASHSIZE; i++) {
- SLIST_FOREACH(pipe, &pipehash[i], next) {
- if (pipe->idle_heap.elements > 0 &&
- DN_KEY_LT(pipe->idle_heap.p[0].key, pipe->V)) {
- struct dn_flow_queue *q =
- pipe->idle_heap.p[0].object;
-
- heap_extract(&(pipe->idle_heap), NULL);
- /* Mark timestamp as invalid. */
- q->S = q->F + 1;
- pipe->sum -= q->fs->weight;
- }
- }
- }
-
- DUMMYNET_UNLOCK();
+ struct dn_fsk *fs;
+ int err = 0;
+
+ if (!locked)
+ DN_BH_WLOCK();
+ fs = dn_ht_find(dn_cfg.fshash, i, DNHT_REMOVE, NULL);
+ ND("fs %d found %p", i, fs);
+ if (fs) {
+ fsk_detach(fs, DN_DETACH | DN_DELETE_FS);
+ err = 0;
+ } else
+ err = EINVAL;
+ if (!locked)
+ DN_BH_WUNLOCK();
+ return err;
+}
- if (head != NULL)
- dummynet_send(head);
+/*----- end of flowset hashtable support -------------*/
- callout_reset(&dn_timeout, 1, dummynet, NULL);
+/*------------------------------------------------------------
+ * Scheduler hash. When searching by index we pass sched_nr,
+ * otherwise we pass struct dn_sch * which is the first field in
+ * struct dn_schk so we can cast between the two. We use this trick
+ * because in the create phase (but it should be fixed).
+ */
+static uint32_t
+schk_hash(uintptr_t key, int flags, void *_arg)
+{
+ uint32_t i = !(flags & DNHT_KEY_IS_OBJ) ? key :
+ ((struct dn_schk *)key)->sch.sched_nr;
+ return ( (i>>8)^(i>>4)^i );
}
-static void
-dummynet_send(struct mbuf *m)
+static int
+schk_match(void *obj, uintptr_t key, int flags, void *_arg)
{
- struct mbuf *n;
-
- for (; m != NULL; m = n) {
- struct ifnet *ifp;
- int dst;
- struct m_tag *tag;
-
- n = m->m_nextpkt;
- m->m_nextpkt = NULL;
- tag = m_tag_first(m);
- if (tag == NULL) {
- dst = DIR_DROP;
- } else {
- struct dn_pkt_tag *pkt = dn_tag_get(m);
- /* extract the dummynet info, rename the tag */
- dst = pkt->dn_dir;
- ifp = pkt->ifp;
- /* rename the tag so it carries reinject info */
- tag->m_tag_cookie = MTAG_IPFW_RULE;
- tag->m_tag_id = 0;
- }
-
- switch (dst) {
- case DIR_OUT:
- SET_HOST_IPLEN(mtod(m, struct ip *));
- ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
- break ;
- case DIR_IN :
- /* put header in network format for ip_input() */
- //SET_NET_IPLEN(mtod(m, struct ip *));
- netisr_dispatch(NETISR_IP, m);
- break;
-#ifdef INET6
- case DIR_IN | PROTO_IPV6:
- netisr_dispatch(NETISR_IPV6, m);
- break;
-
- case DIR_OUT | PROTO_IPV6:
- SET_HOST_IPLEN(mtod(m, struct ip *));
- ip6_output(m, NULL, NULL, IPV6_FORWARDING, NULL, NULL, NULL);
- break;
-#endif
- case DIR_FWD | PROTO_IFB: /* DN_TO_IFB_FWD: */
- if (bridge_dn_p != NULL)
- ((*bridge_dn_p)(m, ifp));
- else
- printf("dummynet: if_bridge not loaded\n");
-
- break;
- case DIR_IN | PROTO_LAYER2: /* DN_TO_ETH_DEMUX: */
- /*
- * The Ethernet code assumes the Ethernet header is
- * contiguous in the first mbuf header.
- * Insure this is true.
- */
- if (m->m_len < ETHER_HDR_LEN &&
- (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {
- printf("dummynet/ether: pullup failed, "
- "dropping packet\n");
- break;
- }
- ether_demux(m->m_pkthdr.rcvif, m);
- break;
- case DIR_OUT | PROTO_LAYER2: /* N_TO_ETH_OUT: */
- ether_output_frame(ifp, m);
- break;
-
- case DIR_DROP:
- /* drop the packet after some time */
- FREE_PKT(m);
- break;
-
- default:
- printf("dummynet: bad switch %d!\n", dst);
- FREE_PKT(m);
- break;
- }
- }
+ struct dn_schk *s = (struct dn_schk *)obj;
+ int i = !(flags & DNHT_KEY_IS_OBJ) ? key :
+ ((struct dn_schk *)key)->sch.sched_nr;
+ return (s->sch.sched_nr == i);
}
/*
- * Unconditionally expire empty queues in case of shortage.
- * Returns the number of queues freed.
+ * Create the entry and intialize with the sched hash if needed.
+ * Leave s->fp unset so we can tell whether a dn_ht_find() returns
+ * a new object or a previously existing one.
*/
-static int
-expire_queues(struct dn_flow_set *fs)
-{
- struct dn_flow_queue *q, *prev ;
- int i, initial_elements = fs->rq_elements ;
-
- if (fs->last_expired == time_uptime)
- return 0 ;
- fs->last_expired = time_uptime ;
- for (i = 0 ; i <= fs->rq_size ; i++) { /* last one is overflow */
- for (prev=NULL, q = fs->rq[i] ; q != NULL ; ) {
- if (!QUEUE_IS_IDLE(q)) {
- prev = q ;
- q = q->next ;
- } else { /* entry is idle, expire it */
- struct dn_flow_queue *old_q = q ;
-
- if (prev != NULL)
- prev->next = q = q->next ;
- else
- fs->rq[i] = q = q->next ;
- fs->rq_elements-- ;
- free(old_q, M_DUMMYNET);
- }
+static void *
+schk_new(uintptr_t key, int flags, void *arg)
+{
+ struct schk_new_arg *a = arg;
+ struct dn_schk *s;
+ int l = sizeof(*s) +a->fp->schk_datalen;
+
+ s = malloc(l, M_DUMMYNET, M_NOWAIT | M_ZERO);
+ if (s == NULL)
+ return NULL;
+ set_oid(&s->link.oid, DN_LINK, sizeof(s->link));
+ s->sch = *a->sch; // copy initial values
+ s->link.link_nr = s->sch.sched_nr;
+ SLIST_INIT(&s->fsk_list);
+ /* initialize the hash table or create the single instance */
+ s->fp = a->fp; /* si_new needs this */
+ s->drain_bucket = 0;
+ if (s->sch.flags & DN_HAVE_MASK) {
+ s->siht = dn_ht_init(NULL, s->sch.buckets,
+ offsetof(struct dn_sch_inst, si_next),
+ si_hash, si_match, si_new);
+ if (s->siht == NULL) {
+ free(s, M_DUMMYNET);
+ return NULL;
+ }
}
- }
- return initial_elements - fs->rq_elements ;
+ s->fp = NULL; /* mark as a new scheduler */
+ dn_cfg.schk_count++;
+ return s;
}
/*
- * If room, create a new queue and put at head of slot i;
- * otherwise, create or use the default queue.
+ * Callback for sched delete. Notify all attached flowsets to
+ * detach from the scheduler, destroy the internal flowset, and
+ * all instances. The scheduler goes away too.
+ * arg is 0 (only detach flowsets and destroy instances)
+ * DN_DESTROY (detach & delete queues, delete schk)
+ * or DN_DELETE_FS (delete queues and flowsets, delete schk)
*/
-static struct dn_flow_queue *
-create_queue(struct dn_flow_set *fs, int i)
+static int
+schk_delete_cb(void *obj, void *arg)
{
- struct dn_flow_queue *q;
-
- if (fs->rq_elements > fs->rq_size * dn_max_ratio &&
- expire_queues(fs) == 0) {
- /* No way to get room, use or create overflow queue. */
- i = fs->rq_size;
- if (fs->rq[i] != NULL)
- return fs->rq[i];
- }
- q = malloc(sizeof(*q), M_DUMMYNET, M_NOWAIT | M_ZERO);
- if (q == NULL) {
- printf("dummynet: sorry, cannot allocate queue for new flow\n");
- return (NULL);
+ struct dn_schk *s = obj;
+#if 0
+ int a = (int)arg;
+ ND("sched %d arg %s%s",
+ s->sch.sched_nr,
+ a&DN_DESTROY ? "DEL ":"",
+ a&DN_DELETE_FS ? "DEL_FS":"");
+#endif
+ fsk_detach_list(&s->fsk_list, arg ? DN_DESTROY : 0);
+ /* no more flowset pointing to us now */
+ if (s->sch.flags & DN_HAVE_MASK)
+ dn_ht_scan(s->siht, si_destroy, NULL);
+ else if (s->siht)
+ si_destroy(s->siht, NULL);
+ if (s->profile) {
+ free(s->profile, M_DUMMYNET);
+ s->profile = NULL;
}
- q->fs = fs;
- q->hash_slot = i;
- q->next = fs->rq[i];
- q->S = q->F + 1; /* hack - mark timestamp as invalid. */
- q->numbytes = fs->pipe->burst + (io_fast ? fs->pipe->bandwidth : 0);
- fs->rq[i] = q;
- fs->rq_elements++;
- return (q);
+ s->siht = NULL;
+ if (s->fp->destroy)
+ s->fp->destroy(s);
+ bzero(s, sizeof(*s)); // safety
+ free(obj, M_DUMMYNET);
+ dn_cfg.schk_count--;
+ return DNHT_SCAN_DEL;
}
/*
- * Given a flow_set and a pkt in last_pkt, find a matching queue
- * after appropriate masking. The queue is moved to front
- * so that further searches take less time.
+ * called on a 'sched X delete' command. Deletes a single scheduler.
+ * This is done by removing from the schedhash, unlinking all
+ * flowsets and deleting their traffic.
*/
-static struct dn_flow_queue *
-find_queue(struct dn_flow_set *fs, struct ipfw_flow_id *id)
-{
- int i = 0 ; /* we need i and q for new allocations */
- struct dn_flow_queue *q, *prev;
- int is_v6 = IS_IP6_FLOW_ID(id);
-
- if ( !(fs->flags_fs & DN_HAVE_FLOW_MASK) )
- q = fs->rq[0] ;
- else {
- /* first, do the masking, then hash */
- id->dst_port &= fs->flow_mask.dst_port ;
- id->src_port &= fs->flow_mask.src_port ;
- id->proto &= fs->flow_mask.proto ;
- id->flags = 0 ; /* we don't care about this one */
- if (is_v6) {
- APPLY_MASK(&id->dst_ip6, &fs->flow_mask.dst_ip6);
- APPLY_MASK(&id->src_ip6, &fs->flow_mask.src_ip6);
- id->flow_id6 &= fs->flow_mask.flow_id6;
-
- i = ((id->dst_ip6.__u6_addr.__u6_addr32[0]) & 0xffff)^
- ((id->dst_ip6.__u6_addr.__u6_addr32[1]) & 0xffff)^
- ((id->dst_ip6.__u6_addr.__u6_addr32[2]) & 0xffff)^
- ((id->dst_ip6.__u6_addr.__u6_addr32[3]) & 0xffff)^
-
- ((id->dst_ip6.__u6_addr.__u6_addr32[0] >> 15) & 0xffff)^
- ((id->dst_ip6.__u6_addr.__u6_addr32[1] >> 15) & 0xffff)^
- ((id->dst_ip6.__u6_addr.__u6_addr32[2] >> 15) & 0xffff)^
- ((id->dst_ip6.__u6_addr.__u6_addr32[3] >> 15) & 0xffff)^
-
- ((id->src_ip6.__u6_addr.__u6_addr32[0] << 1) & 0xfffff)^
- ((id->src_ip6.__u6_addr.__u6_addr32[1] << 1) & 0xfffff)^
- ((id->src_ip6.__u6_addr.__u6_addr32[2] << 1) & 0xfffff)^
- ((id->src_ip6.__u6_addr.__u6_addr32[3] << 1) & 0xfffff)^
-
- ((id->src_ip6.__u6_addr.__u6_addr32[0] << 16) & 0xffff)^
- ((id->src_ip6.__u6_addr.__u6_addr32[1] << 16) & 0xffff)^
- ((id->src_ip6.__u6_addr.__u6_addr32[2] << 16) & 0xffff)^
- ((id->src_ip6.__u6_addr.__u6_addr32[3] << 16) & 0xffff)^
-
- (id->dst_port << 1) ^ (id->src_port) ^
- (id->proto ) ^
- (id->flow_id6);
- } else {
- id->dst_ip &= fs->flow_mask.dst_ip ;
- id->src_ip &= fs->flow_mask.src_ip ;
-
- i = ( (id->dst_ip) & 0xffff ) ^
- ( (id->dst_ip >> 15) & 0xffff ) ^
- ( (id->src_ip << 1) & 0xffff ) ^
- ( (id->src_ip >> 16 ) & 0xffff ) ^
- (id->dst_port << 1) ^ (id->src_port) ^
- (id->proto );
- }
- i = i % fs->rq_size ;
- /* finally, scan the current list for a match */
- searches++ ;
- for (prev=NULL, q = fs->rq[i] ; q ; ) {
- search_steps++;
- if (is_v6 &&
- IN6_ARE_ADDR_EQUAL(&id->dst_ip6,&q->id.dst_ip6) &&
- IN6_ARE_ADDR_EQUAL(&id->src_ip6,&q->id.src_ip6) &&
- id->dst_port == q->id.dst_port &&
- id->src_port == q->id.src_port &&
- id->proto == q->id.proto &&
- id->flags == q->id.flags &&
- id->flow_id6 == q->id.flow_id6)
- break ; /* found */
-
- if (!is_v6 && id->dst_ip == q->id.dst_ip &&
- id->src_ip == q->id.src_ip &&
- id->dst_port == q->id.dst_port &&
- id->src_port == q->id.src_port &&
- id->proto == q->id.proto &&
- id->flags == q->id.flags)
- break ; /* found */
-
- /* No match. Check if we can expire the entry */
- if (pipe_expire && QUEUE_IS_IDLE(q)) {
- /* entry is idle and not in any heap, expire it */
- struct dn_flow_queue *old_q = q ;
-
- if (prev != NULL)
- prev->next = q = q->next ;
- else
- fs->rq[i] = q = q->next ;
- fs->rq_elements-- ;
- free(old_q, M_DUMMYNET);
- continue ;
- }
- prev = q ;
- q = q->next ;
- }
- if (q && prev != NULL) { /* found and not in front */
- prev->next = q->next ;
- q->next = fs->rq[i] ;
- fs->rq[i] = q ;
- }
- }
- if (q == NULL) { /* no match, need to allocate a new entry */
- q = create_queue(fs, i);
- if (q != NULL)
- q->id = *id ;
- }
- return q ;
+static int
+delete_schk(int i)
+{
+ struct dn_schk *s;
+
+ s = dn_ht_find(dn_cfg.schedhash, i, DNHT_REMOVE, NULL);
+ ND("%d %p", i, s);
+ if (!s)
+ return EINVAL;
+ delete_fs(i + DN_MAX_ID, 1); /* first delete internal fs */
+ /* then detach flowsets, delete traffic */
+ schk_delete_cb(s, (void*)(uintptr_t)DN_DESTROY);
+ return 0;
}
+/*--- end of schk hashtable support ---*/
static int
-red_drops(struct dn_flow_set *fs, struct dn_flow_queue *q, int len)
+copy_obj(char **start, char *end, void *_o, const char *msg, int i)
{
- /*
- * RED algorithm
- *
- * RED calculates the average queue size (avg) using a low-pass filter
- * with an exponential weighted (w_q) moving average:
- * avg <- (1-w_q) * avg + w_q * q_size
- * where q_size is the queue length (measured in bytes or * packets).
- *
- * If q_size == 0, we compute the idle time for the link, and set
- * avg = (1 - w_q)^(idle/s)
- * where s is the time needed for transmitting a medium-sized packet.
- *
- * Now, if avg < min_th the packet is enqueued.
- * If avg > max_th the packet is dropped. Otherwise, the packet is
- * dropped with probability P function of avg.
- */
+ struct dn_id *o = _o;
+ int have = end - *start;
- int64_t p_b = 0;
-
- /* Queue in bytes or packets? */
- u_int q_size = (fs->flags_fs & DN_QSIZE_IS_BYTES) ?
- q->len_bytes : q->len;
-
- DPRINTF(("\ndummynet: %d q: %2u ", (int)curr_time, q_size));
-
- /* Average queue size estimation. */
- if (q_size != 0) {
- /* Queue is not empty, avg <- avg + (q_size - avg) * w_q */
- int diff = SCALE(q_size) - q->avg;
- int64_t v = SCALE_MUL((int64_t)diff, (int64_t)fs->w_q);
-
- q->avg += (int)v;
- } else {
- /*
- * Queue is empty, find for how long the queue has been
- * empty and use a lookup table for computing
- * (1 - * w_q)^(idle_time/s) where s is the time to send a
- * (small) packet.
- * XXX check wraps...
- */
- if (q->avg) {
- u_int t = div64(curr_time - q->idle_time,
- fs->lookup_step);
-
- q->avg = (t < fs->lookup_depth) ?
- SCALE_MUL(q->avg, fs->w_q_lookup[t]) : 0;
- }
- }
- DPRINTF(("dummynet: avg: %u ", SCALE_VAL(q->avg)));
-
- /* Should i drop? */
- if (q->avg < fs->min_th) {
- q->count = -1;
- return (0); /* accept packet */
- }
- if (q->avg >= fs->max_th) { /* average queue >= max threshold */
- if (fs->flags_fs & DN_IS_GENTLE_RED) {
- /*
- * According to Gentle-RED, if avg is greater than
- * max_th the packet is dropped with a probability
- * p_b = c_3 * avg - c_4
- * where c_3 = (1 - max_p) / max_th
- * c_4 = 1 - 2 * max_p
- */
- p_b = SCALE_MUL((int64_t)fs->c_3, (int64_t)q->avg) -
- fs->c_4;
- } else {
- q->count = -1;
- DPRINTF(("dummynet: - drop"));
- return (1);
- }
- } else if (q->avg > fs->min_th) {
- /*
- * We compute p_b using the linear dropping function
- * p_b = c_1 * avg - c_2
- * where c_1 = max_p / (max_th - min_th)
- * c_2 = max_p * min_th / (max_th - min_th)
- */
- p_b = SCALE_MUL((int64_t)fs->c_1, (int64_t)q->avg) - fs->c_2;
+ if (have < o->len || o->len == 0 || o->type == 0) {
+ D("ERROR type %d %s %d have %d need %d",
+ o->type, msg, i, have, o->len);
+ return 1;
}
-
- if (fs->flags_fs & DN_QSIZE_IS_BYTES)
- p_b = div64(p_b * len, fs->max_pkt_size);
- if (++q->count == 0)
- q->random = random() & 0xffff;
- else {
- /*
- * q->count counts packets arrived since last drop, so a greater
- * value of q->count means a greater packet drop probability.
- */
- if (SCALE_MUL(p_b, SCALE((int64_t)q->count)) > q->random) {
- q->count = 0;
- DPRINTF(("dummynet: - red drop"));
- /* After a drop we calculate a new random value. */
- q->random = random() & 0xffff;
- return (1); /* drop */
- }
+ ND("type %d %s %d len %d", o->type, msg, i, o->len);
+ bcopy(_o, *start, o->len);
+ if (o->type == DN_LINK) {
+ /* Adjust burst parameter for link */
+ struct dn_link *l = (struct dn_link *)*start;
+ l->burst = div64(l->burst, 8 * hz);
+ } else if (o->type == DN_SCH) {
+ /* Set id->id to the number of instances */
+ struct dn_schk *s = _o;
+ struct dn_id *id = (struct dn_id *)(*start);
+ id->id = (s->sch.flags & DN_HAVE_MASK) ?
+ dn_ht_entries(s->siht) : (s->siht ? 1 : 0);
}
- /* End of RED algorithm. */
-
- return (0); /* accept */
+ *start += o->len;
+ return 0;
}
-static __inline struct dn_flow_set *
-locate_flowset(int fs_nr)
+/* Specific function to copy a queue.
+ * It copies only the common part of a queue, and correctly set
+ * the length
+ */
+static int
+copy_obj_q(char **start, char *end, void *_o, const char *msg, int i)
{
- struct dn_flow_set *fs;
-
- SLIST_FOREACH(fs, &flowsethash[HASH(fs_nr)], next)
- if (fs->fs_nr == fs_nr)
- return (fs);
-
- return (NULL);
+ struct dn_id *o = _o;
+ int have = end - *start;
+ int len = sizeof(struct dn_queue);
+
+ if (have < len || o->len == 0 || o->type != DN_QUEUE) {
+ D("ERROR type %d %s %d have %d need %d",
+ o->type, msg, i, have, len);
+ return 1;
+ }
+ ND("type %d %s %d len %d", o->type, msg, i, len);
+ bcopy(_o, *start, len);
+ ((struct dn_id*)(*start))->len = len;
+ *start += len;
+ return 0;
}
-static __inline struct dn_pipe *
-locate_pipe(int pipe_nr)
+static int
+copy_q_cb(void *obj, void *arg)
{
- struct dn_pipe *pipe;
-
- SLIST_FOREACH(pipe, &pipehash[HASH(pipe_nr)], next)
- if (pipe->pipe_nr == pipe_nr)
- return (pipe);
-
- return (NULL);
+ struct dn_queue *q = obj;
+ struct copy_args *a = arg;
+ struct dn_flow *ni = (struct dn_flow *)(*a->start);
+ if (copy_obj_q(a->start, a->end, &q->ni, "queue", -1))
+ return DNHT_SCAN_END;
+ ni->oid.type = DN_FLOW; /* override the DN_QUEUE */
+ ni->oid.id = si_hash((uintptr_t)&ni->fid, 0, NULL);
+ return 0;
}
-/*
- * dummynet hook for packets. Below 'pipe' is a pipe or a queue
- * depending on whether WF2Q or fixed bw is used.
- *
- * pipe_nr pipe or queue the packet is destined for.
- * dir where shall we send the packet after dummynet.
- * m the mbuf with the packet
- * ifp the 'ifp' parameter from the caller.
- * NULL in ip_input, destination interface in ip_output,
- * rule matching rule, in case of multiple passes
- */
static int
-dummynet_io(struct mbuf **m0, int dir, struct ip_fw_args *fwa)
-{
- struct mbuf *m = *m0, *head = NULL, *tail = NULL;
- struct dn_pkt_tag *pkt;
- struct m_tag *mtag;
- struct dn_flow_set *fs = NULL;
- struct dn_pipe *pipe;
- uint64_t len = m->m_pkthdr.len;
- struct dn_flow_queue *q = NULL;
- int is_pipe = fwa->rule.info & IPFW_IS_PIPE;
-
- KASSERT(m->m_nextpkt == NULL,
- ("dummynet_io: mbuf queue passed to dummynet"));
-
- DUMMYNET_LOCK();
- io_pkt++;
- /*
- * This is a dummynet rule, so we expect an O_PIPE or O_QUEUE rule.
- */
- if (is_pipe) {
- pipe = locate_pipe(fwa->rule.info & IPFW_INFO_MASK);
- if (pipe != NULL)
- fs = &(pipe->fs);
- } else
- fs = locate_flowset(fwa->rule.info & IPFW_INFO_MASK);
-
- if (fs == NULL)
- goto dropit; /* This queue/pipe does not exist! */
- pipe = fs->pipe;
- if (pipe == NULL) { /* Must be a queue, try find a matching pipe. */
- pipe = locate_pipe(fs->parent_nr);
- if (pipe != NULL)
- fs->pipe = pipe;
- else {
- printf("dummynet: no pipe %d for queue %d, drop pkt\n",
- fs->parent_nr, fs->fs_nr);
- goto dropit;
- }
- }
- q = find_queue(fs, &(fwa->f_id));
- if (q == NULL)
- goto dropit; /* Cannot allocate queue. */
-
- /* Update statistics, then check reasons to drop pkt. */
- q->tot_bytes += len;
- q->tot_pkts++;
- if (fs->plr && random() < fs->plr)
- goto dropit; /* Random pkt drop. */
- if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
- if (q->len_bytes > fs->qsize)
- goto dropit; /* Queue size overflow. */
- } else {
- if (q->len >= fs->qsize)
- goto dropit; /* Queue count overflow. */
- }
- if (fs->flags_fs & DN_IS_RED && red_drops(fs, q, len))
- goto dropit;
-
- /* XXX expensive to zero, see if we can remove it. */
- mtag = m_tag_get(PACKET_TAG_DUMMYNET,
- sizeof(struct dn_pkt_tag), M_NOWAIT | M_ZERO);
- if (mtag == NULL)
- goto dropit; /* Cannot allocate packet header. */
- m_tag_prepend(m, mtag); /* Attach to mbuf chain. */
-
- pkt = (struct dn_pkt_tag *)(mtag + 1);
- /*
- * Ok, i can handle the pkt now...
- * Build and enqueue packet + parameters.
- */
- pkt->rule = fwa->rule;
- pkt->rule.info &= IPFW_ONEPASS; /* only keep this info */
- pkt->dn_dir = dir;
- pkt->ifp = fwa->oif;
-
- if (q->head == NULL)
- q->head = m;
+copy_q(struct copy_args *a, struct dn_fsk *fs, int flags)
+{
+ if (!fs->qht)
+ return 0;
+ if (fs->fs.flags & DN_QHT_HASH)
+ dn_ht_scan(fs->qht, copy_q_cb, a);
else
- q->tail->m_nextpkt = m;
- q->tail = m;
- q->len++;
- q->len_bytes += len;
-
- if (q->head != m) /* Flow was not idle, we are done. */
- goto done;
-
- if (is_pipe) { /* Fixed rate queues. */
- if (q->idle_time < curr_time) {
- /* Calculate available burst size. */
- q->numbytes +=
- (curr_time - q->idle_time - 1) * pipe->bandwidth;
- if (q->numbytes > pipe->burst)
- q->numbytes = pipe->burst;
- if (io_fast)
- q->numbytes += pipe->bandwidth;
- }
- } else { /* WF2Q. */
- if (pipe->idle_time < curr_time &&
- pipe->scheduler_heap.elements == 0 &&
- pipe->not_eligible_heap.elements == 0) {
- /* Calculate available burst size. */
- pipe->numbytes +=
- (curr_time - pipe->idle_time - 1) * pipe->bandwidth;
- if (pipe->numbytes > 0 && pipe->numbytes > pipe->burst)
- pipe->numbytes = pipe->burst;
- if (io_fast)
- pipe->numbytes += pipe->bandwidth;
- }
- pipe->idle_time = curr_time;
- }
- /* Necessary for both: fixed rate & WF2Q queues. */
- q->idle_time = curr_time;
-
- /*
- * If we reach this point the flow was previously idle, so we need
- * to schedule it. This involves different actions for fixed-rate or
- * WF2Q queues.
- */
- if (is_pipe) {
- /* Fixed-rate queue: just insert into the ready_heap. */
- dn_key t = 0;
-
- if (pipe->bandwidth) {
- q->extra_bits = compute_extra_bits(m, pipe);
- t = set_ticks(m, q, pipe);
- }
- q->sched_time = curr_time;
- if (t == 0) /* Must process it now. */
- ready_event(q, &head, &tail);
- else
- heap_insert(&ready_heap, curr_time + t , q);
- } else {
- /*
- * WF2Q. First, compute start time S: if the flow was
- * idle (S = F + 1) set S to the virtual time V for the
- * controlling pipe, and update the sum of weights for the pipe;
- * otherwise, remove flow from idle_heap and set S to max(F,V).
- * Second, compute finish time F = S + len / weight.
- * Third, if pipe was idle, update V = max(S, V).
- * Fourth, count one more backlogged flow.
- */
- if (DN_KEY_GT(q->S, q->F)) { /* Means timestamps are invalid. */
- q->S = pipe->V;
- pipe->sum += fs->weight; /* Add weight of new queue. */
- } else {
- heap_extract(&(pipe->idle_heap), q);
- q->S = MAX64(q->F, pipe->V);
- }
- q->F = q->S + div64(len << MY_M, fs->weight);
-
- if (pipe->not_eligible_heap.elements == 0 &&
- pipe->scheduler_heap.elements == 0)
- pipe->V = MAX64(q->S, pipe->V);
- fs->backlogged++;
- /*
- * Look at eligibility. A flow is not eligibile if S>V (when
- * this happens, it means that there is some other flow already
- * scheduled for the same pipe, so the scheduler_heap cannot be
- * empty). If the flow is not eligible we just store it in the
- * not_eligible_heap. Otherwise, we store in the scheduler_heap
- * and possibly invoke ready_event_wfq() right now if there is
- * leftover credit.
- * Note that for all flows in scheduler_heap (SCH), S_i <= V,
- * and for all flows in not_eligible_heap (NEH), S_i > V.
- * So when we need to compute max(V, min(S_i)) forall i in
- * SCH+NEH, we only need to look into NEH.
- */
- if (DN_KEY_GT(q->S, pipe->V)) { /* Not eligible. */
- if (pipe->scheduler_heap.elements == 0)
- printf("dummynet: ++ ouch! not eligible but empty scheduler!\n");
- heap_insert(&(pipe->not_eligible_heap), q->S, q);
- } else {
- heap_insert(&(pipe->scheduler_heap), q->F, q);
- if (pipe->numbytes >= 0) { /* Pipe is idle. */
- if (pipe->scheduler_heap.elements != 1)
- printf("dummynet: OUCH! pipe should have been idle!\n");
- DPRINTF(("dummynet: waking up pipe %d at %d\n",
- pipe->pipe_nr, (int)(q->F >> MY_M)));
- pipe->sched_time = curr_time;
- ready_event_wfq(pipe, &head, &tail);
- }
- }
- }
-done:
- if (head == m && (dir & PROTO_LAYER2) == 0 ) {
- /* Fast io. */
- io_pkt_fast++;
- if (m->m_nextpkt != NULL)
- printf("dummynet: fast io: pkt chain detected!\n");
- head = m->m_nextpkt = NULL;
- } else
- *m0 = NULL; /* Normal io. */
-
- DUMMYNET_UNLOCK();
- if (head != NULL)
- dummynet_send(head);
- return (0);
-
-dropit:
- io_pkt_drop++;
- if (q)
- q->drops++;
- DUMMYNET_UNLOCK();
- FREE_PKT(m);
- *m0 = NULL;
- return ((fs && (fs->flags_fs & DN_NOERROR)) ? 0 : ENOBUFS);
+ copy_q_cb(fs->qht, a);
+ return 0;
}
/*
- * Dispose all packets and flow_queues on a flow_set.
- * If all=1, also remove red lookup table and other storage,
- * including the descriptor itself.
- * For the one in dn_pipe MUST also cleanup ready_heap...
+ * This routine only copies the initial part of a profile ? XXX
*/
-static void
-purge_flow_set(struct dn_flow_set *fs, int all)
+static int
+copy_profile(struct copy_args *a, struct dn_profile *p)
{
- struct dn_flow_queue *q, *qn;
- int i;
+ int have = a->end - *a->start;
+ /* XXX here we check for max length */
+ int profile_len = sizeof(struct dn_profile) -
+ ED_MAX_SAMPLES_NO*sizeof(int);
- DUMMYNET_LOCK_ASSERT();
-
- for (i = 0; i <= fs->rq_size; i++) {
- for (q = fs->rq[i]; q != NULL; q = qn) {
- dn_free_pkts(q->head);
- qn = q->next;
- free(q, M_DUMMYNET);
- }
- fs->rq[i] = NULL;
+ if (p == NULL)
+ return 0;
+ if (have < profile_len) {
+ D("error have %d need %d", have, profile_len);
+ return 1;
}
+ bcopy(p, *a->start, profile_len);
+ ((struct dn_id *)(*a->start))->len = profile_len;
+ *a->start += profile_len;
+ return 0;
+}
- fs->rq_elements = 0;
- if (all) {
- /* RED - free lookup table. */
- if (fs->w_q_lookup != NULL)
- free(fs->w_q_lookup, M_DUMMYNET);
- if (fs->rq != NULL)
- free(fs->rq, M_DUMMYNET);
- /* If this fs is not part of a pipe, free it. */
- if (fs->pipe == NULL || fs != &(fs->pipe->fs))
- free(fs, M_DUMMYNET);
+static int
+copy_flowset(struct copy_args *a, struct dn_fsk *fs, int flags)
+{
+ struct dn_fs *ufs = (struct dn_fs *)(*a->start);
+ if (!fs)
+ return 0;
+ ND("flowset %d", fs->fs.fs_nr);
+ if (copy_obj(a->start, a->end, &fs->fs, "flowset", fs->fs.fs_nr))
+ return DNHT_SCAN_END;
+ ufs->oid.id = (fs->fs.flags & DN_QHT_HASH) ?
+ dn_ht_entries(fs->qht) : (fs->qht ? 1 : 0);
+ if (flags) { /* copy queues */
+ copy_q(a, fs, 0);
}
+ return 0;
}
-/*
- * Dispose all packets queued on a pipe (not a flow_set).
- * Also free all resources associated to a pipe, which is about
- * to be deleted.
- */
-static void
-purge_pipe(struct dn_pipe *pipe)
+static int
+copy_si_cb(void *obj, void *arg)
{
+ struct dn_sch_inst *si = obj;
+ struct copy_args *a = arg;
+ struct dn_flow *ni = (struct dn_flow *)(*a->start);
+ if (copy_obj(a->start, a->end, &si->ni, "inst",
+ si->sched->sch.sched_nr))
+ return DNHT_SCAN_END;
+ ni->oid.type = DN_FLOW; /* override the DN_SCH_I */
+ ni->oid.id = si_hash((uintptr_t)si, DNHT_KEY_IS_OBJ, NULL);
+ return 0;
+}
- purge_flow_set( &(pipe->fs), 1 );
-
- dn_free_pkts(pipe->head);
-
- heap_free( &(pipe->scheduler_heap) );
- heap_free( &(pipe->not_eligible_heap) );
- heap_free( &(pipe->idle_heap) );
+static int
+copy_si(struct copy_args *a, struct dn_schk *s, int flags)
+{
+ if (s->sch.flags & DN_HAVE_MASK)
+ dn_ht_scan(s->siht, copy_si_cb, a);
+ else if (s->siht)
+ copy_si_cb(s->siht, a);
+ return 0;
}
/*
- * Delete all pipes and heaps returning memory. Must also
- * remove references from all ipfw rules to all pipes.
+ * compute a list of children of a scheduler and copy up
*/
-static void
-dummynet_flush(void)
+static int
+copy_fsk_list(struct copy_args *a, struct dn_schk *s, int flags)
{
- struct dn_pipe *pipe, *pipe1;
- struct dn_flow_set *fs, *fs1;
- int i;
-
- DUMMYNET_LOCK();
- /* Free heaps so we don't have unwanted events. */
- heap_free(&ready_heap);
- heap_free(&wfq_ready_heap);
- heap_free(&extract_heap);
+ struct dn_fsk *fs;
+ struct dn_id *o;
+ uint32_t *p;
+
+ int n = 0, space = sizeof(*o);
+ SLIST_FOREACH(fs, &s->fsk_list, sch_chain) {
+ if (fs->fs.fs_nr < DN_MAX_ID)
+ n++;
+ }
+ space += n * sizeof(uint32_t);
+ DX(3, "sched %d has %d flowsets", s->sch.sched_nr, n);
+ if (a->end - *(a->start) < space)
+ return DNHT_SCAN_END;
+ o = (struct dn_id *)(*(a->start));
+ o->len = space;
+ *a->start += o->len;
+ o->type = DN_TEXT;
+ p = (uint32_t *)(o+1);
+ SLIST_FOREACH(fs, &s->fsk_list, sch_chain)
+ if (fs->fs.fs_nr < DN_MAX_ID)
+ *p++ = fs->fs.fs_nr;
+ return 0;
+}
- /*
- * Now purge all queued pkts and delete all pipes.
- *
- * XXXGL: can we merge the for(;;) cycles into one or not?
- */
- for (i = 0; i < HASHSIZE; i++)
- SLIST_FOREACH_SAFE(fs, &flowsethash[i], next, fs1) {
- SLIST_REMOVE(&flowsethash[i], fs, dn_flow_set, next);
- purge_flow_set(fs, 1);
+static int
+copy_data_helper(void *_o, void *_arg)
+{
+ struct copy_args *a = _arg;
+
+ if (a->type == DN_LINK || /* pipe show */
+ a->type == DN_SCH) { /* sched show */
+ struct dn_schk *s = _o; /* we get only schedulers */
+ if (a->type == DN_SCH && s->sch.sched_nr >= DN_MAX_ID)
+ return 0; /* not valid scheduler */
+ if (a->type == DN_LINK && s->sch.sched_nr <= DN_MAX_ID)
+ return 0; /* not valid pipe */
+ if (a->flags & DN_C_LINK) {
+ if (copy_obj(a->start, a->end, &s->link,
+ "link", s->sch.sched_nr))
+ return DNHT_SCAN_END;
+ if (copy_profile(a, s->profile))
+ return DNHT_SCAN_END;
+ if (copy_flowset(a, s->fs, 0))
+ return DNHT_SCAN_END;
}
- for (i = 0; i < HASHSIZE; i++)
- SLIST_FOREACH_SAFE(pipe, &pipehash[i], next, pipe1) {
- SLIST_REMOVE(&pipehash[i], pipe, dn_pipe, next);
- purge_pipe(pipe);
- free_pipe(pipe);
+ if (a->flags & DN_C_SCH) {
+ if (copy_obj(a->start, a->end, &s->sch,
+ "sched", s->sch.sched_nr))
+ return DNHT_SCAN_END;
+
+ /* list all attached flowsets */
+ if (copy_fsk_list(a, s, 0))
+ return DNHT_SCAN_END;
}
- DUMMYNET_UNLOCK();
+ if (a->flags & DN_C_FLOW) {
+ copy_si(a, s, 0);
+ }
+ }
+ if (a->type == DN_FS) { /* queue show, skip internal flowsets */
+ struct dn_fsk *fs = _o;
+ if (fs->fs.fs_nr >= DN_MAX_ID)
+ return 0;
+ if (copy_flowset(a, fs, 0))
+ return DNHT_SCAN_END;
+ copy_q(a, fs, 0);
+ }
+ return 0;
+}
+
+static inline struct dn_schk *
+locate_scheduler(int i)
+{
+ return dn_ht_find(dn_cfg.schedhash, i, 0, NULL);
}
/*
- * setup RED parameters
+ * red parameters are in fixed point arithmetic.
*/
static int
-config_red(struct dn_flow_set *p, struct dn_flow_set *x)
+config_red(struct dn_fsk *fs)
{
- int i;
-
- x->w_q = p->w_q;
- x->min_th = SCALE(p->min_th);
- x->max_th = SCALE(p->max_th);
- x->max_p = p->max_p;
-
- x->c_1 = p->max_p / (p->max_th - p->min_th);
- x->c_2 = SCALE_MUL(x->c_1, SCALE(p->min_th));
-
- if (x->flags_fs & DN_IS_GENTLE_RED) {
- x->c_3 = (SCALE(1) - p->max_p) / p->max_th;
- x->c_4 = SCALE(1) - 2 * p->max_p;
+ int64_t s, idle, weight, w0;
+ int t, i;
+
+ fs->w_q = fs->fs.w_q;
+ fs->max_p = fs->fs.max_p;
+ D("called");
+ /* Doing stuff that was in userland */
+ i = fs->sched->link.bandwidth;
+ s = (i <= 0) ? 0 :
+ hz * dn_cfg.red_avg_pkt_size * 8 * SCALE(1) / i;
+
+ idle = div64((s * 3) , fs->w_q); /* s, fs->w_q scaled; idle not scaled */
+ fs->lookup_step = div64(idle , dn_cfg.red_lookup_depth);
+ /* fs->lookup_step not scaled, */
+ if (!fs->lookup_step)
+ fs->lookup_step = 1;
+ w0 = weight = SCALE(1) - fs->w_q; //fs->w_q scaled
+
+ for (t = fs->lookup_step; t > 1; --t)
+ weight = SCALE_MUL(weight, w0);
+ fs->lookup_weight = (int)(weight); // scaled
+
+ /* Now doing stuff that was in kerneland */
+ fs->min_th = SCALE(fs->fs.min_th);
+ fs->max_th = SCALE(fs->fs.max_th);
+
+ fs->c_1 = fs->max_p / (fs->fs.max_th - fs->fs.min_th);
+ fs->c_2 = SCALE_MUL(fs->c_1, SCALE(fs->fs.min_th));
+
+ if (fs->fs.flags & DN_IS_GENTLE_RED) {
+ fs->c_3 = (SCALE(1) - fs->max_p) / fs->fs.max_th;
+ fs->c_4 = SCALE(1) - 2 * fs->max_p;
}
/* If the lookup table already exist, free and create it again. */
- if (x->w_q_lookup) {
- free(x->w_q_lookup, M_DUMMYNET);
- x->w_q_lookup = NULL;
+ if (fs->w_q_lookup) {
+ free(fs->w_q_lookup, M_DUMMYNET);
+ fs->w_q_lookup = NULL;
}
- if (red_lookup_depth == 0) {
+ if (dn_cfg.red_lookup_depth == 0) {
printf("\ndummynet: net.inet.ip.dummynet.red_lookup_depth"
"must be > 0\n");
- free(x, M_DUMMYNET);
+ fs->fs.flags &= ~DN_IS_RED;
+ fs->fs.flags &= ~DN_IS_GENTLE_RED;
return (EINVAL);
}
- x->lookup_depth = red_lookup_depth;
- x->w_q_lookup = (u_int *)malloc(x->lookup_depth * sizeof(int),
+ fs->lookup_depth = dn_cfg.red_lookup_depth;
+ fs->w_q_lookup = (u_int *)malloc(fs->lookup_depth * sizeof(int),
M_DUMMYNET, M_NOWAIT);
- if (x->w_q_lookup == NULL) {
+ if (fs->w_q_lookup == NULL) {
printf("dummynet: sorry, cannot allocate red lookup table\n");
- free(x, M_DUMMYNET);
+ fs->fs.flags &= ~DN_IS_RED;
+ fs->fs.flags &= ~DN_IS_GENTLE_RED;
return(ENOSPC);
}
/* Fill the lookup table with (1 - w_q)^x */
- x->lookup_step = p->lookup_step;
- x->lookup_weight = p->lookup_weight;
- x->w_q_lookup[0] = SCALE(1) - x->w_q;
-
- for (i = 1; i < x->lookup_depth; i++)
- x->w_q_lookup[i] =
- SCALE_MUL(x->w_q_lookup[i - 1], x->lookup_weight);
+ fs->w_q_lookup[0] = SCALE(1) - fs->w_q;
+
+ for (i = 1; i < fs->lookup_depth; i++)
+ fs->w_q_lookup[i] =
+ SCALE_MUL(fs->w_q_lookup[i - 1], fs->lookup_weight);
+
+ if (dn_cfg.red_avg_pkt_size < 1)
+ dn_cfg.red_avg_pkt_size = 512;
+ fs->avg_pkt_size = dn_cfg.red_avg_pkt_size;
+ if (dn_cfg.red_max_pkt_size < 1)
+ dn_cfg.red_max_pkt_size = 1500;
+ fs->max_pkt_size = dn_cfg.red_max_pkt_size;
+ D("exit");
+ return 0;
+}
- if (red_avg_pkt_size < 1)
- red_avg_pkt_size = 512;
- x->avg_pkt_size = red_avg_pkt_size;
- if (red_max_pkt_size < 1)
- red_max_pkt_size = 1500;
- x->max_pkt_size = red_max_pkt_size;
- return (0);
+/* Scan all flowset attached to this scheduler and update red */
+static void
+update_red(struct dn_schk *s)
+{
+ struct dn_fsk *fs;
+ SLIST_FOREACH(fs, &s->fsk_list, sch_chain) {
+ if (fs && (fs->fs.flags & DN_IS_RED))
+ config_red(fs);
+ }
}
-static int
-alloc_hash(struct dn_flow_set *x, struct dn_flow_set *pfs)
-{
- if (x->flags_fs & DN_HAVE_FLOW_MASK) { /* allocate some slots */
- int l = pfs->rq_size;
-
- if (l == 0)
- l = dn_hash_size;
- if (l < 4)
- l = 4;
- else if (l > DN_MAX_HASH_SIZE)
- l = DN_MAX_HASH_SIZE;
- x->rq_size = l;
- } else /* one is enough for null mask */
- x->rq_size = 1;
- x->rq = malloc((1 + x->rq_size) * sizeof(struct dn_flow_queue *),
- M_DUMMYNET, M_NOWAIT | M_ZERO);
- if (x->rq == NULL) {
- printf("dummynet: sorry, cannot allocate queue\n");
- return (ENOMEM);
- }
- x->rq_elements = 0;
- return 0 ;
+/* attach flowset to scheduler s, possibly requeue */
+static void
+fsk_attach(struct dn_fsk *fs, struct dn_schk *s)
+{
+ ND("remove fs %d from fsunlinked, link to sched %d",
+ fs->fs.fs_nr, s->sch.sched_nr);
+ SLIST_REMOVE(&dn_cfg.fsu, fs, dn_fsk, sch_chain);
+ fs->sched = s;
+ SLIST_INSERT_HEAD(&s->fsk_list, fs, sch_chain);
+ if (s->fp->new_fsk)
+ s->fp->new_fsk(fs);
+ /* XXX compute fsk_mask */
+ fs->fsk_mask = fs->fs.flow_mask;
+ if (fs->sched->sch.flags & DN_HAVE_MASK)
+ flow_id_or(&fs->sched->sch.sched_mask, &fs->fsk_mask);
+ if (fs->qht) {
+ /*
+ * we must drain qht according to the old
+ * type, and reinsert according to the new one.
+ * The requeue is complex -- in general we need to
+ * reclassify every single packet.
+ * For the time being, let's hope qht is never set
+ * when we reach this point.
+ */
+ D("XXX TODO requeue from fs %d to sch %d",
+ fs->fs.fs_nr, s->sch.sched_nr);
+ fs->qht = NULL;
+ }
+ /* set the new type for qht */
+ if (nonzero_mask(&fs->fsk_mask))
+ fs->fs.flags |= DN_QHT_HASH;
+ else
+ fs->fs.flags &= ~DN_QHT_HASH;
+
+ /* XXX config_red() can fail... */
+ if (fs->fs.flags & DN_IS_RED)
+ config_red(fs);
}
+/* update all flowsets which may refer to this scheduler */
static void
-set_fs_parms(struct dn_flow_set *x, struct dn_flow_set *src)
-{
- x->flags_fs = src->flags_fs;
- x->qsize = src->qsize;
- x->plr = src->plr;
- x->flow_mask = src->flow_mask;
- if (x->flags_fs & DN_QSIZE_IS_BYTES) {
- if (x->qsize > pipe_byte_limit)
- x->qsize = 1024 * 1024;
- } else {
- if (x->qsize == 0)
- x->qsize = 50;
- if (x->qsize > pipe_slot_limit)
- x->qsize = 50;
+update_fs(struct dn_schk *s)
+{
+ struct dn_fsk *fs, *tmp;
+
+ SLIST_FOREACH_SAFE(fs, &dn_cfg.fsu, sch_chain, tmp) {
+ if (s->sch.sched_nr != fs->fs.sched_nr) {
+ D("fs %d for sch %d not %d still unlinked",
+ fs->fs.fs_nr, fs->fs.sched_nr,
+ s->sch.sched_nr);
+ continue;
+ }
+ fsk_attach(fs, s);
}
- /* Configuring RED. */
- if (x->flags_fs & DN_IS_RED)
- config_red(src, x); /* XXX should check errors */
}
/*
- * Setup pipe or queue parameters.
+ * Configuration -- to preserve backward compatibility we use
+ * the following scheme (N is 65536)
+ * NUMBER SCHED LINK FLOWSET
+ * 1 .. N-1 (1)WFQ (2)WFQ (3)queue
+ * N+1 .. 2N-1 (4)FIFO (5)FIFO (6)FIFO for sched 1..N-1
+ * 2N+1 .. 3N-1 -- -- (7)FIFO for sched N+1..2N-1
+ *
+ * "pipe i config" configures #1, #2 and #3
+ * "sched i config" configures #1 and possibly #6
+ * "queue i config" configures #3
+ * #1 is configured with 'pipe i config' or 'sched i config'
+ * #2 is configured with 'pipe i config', and created if not
+ * existing with 'sched i config'
+ * #3 is configured with 'queue i config'
+ * #4 is automatically configured after #1, can only be FIFO
+ * #5 is automatically configured after #2
+ * #6 is automatically created when #1 is !MULTIQUEUE,
+ * and can be updated.
+ * #7 is automatically configured after #2
+ */
+
+/*
+ * configure a link (and its FIFO instance)
*/
static int
-config_pipe(struct dn_pipe *p)
+config_link(struct dn_link *p, struct dn_id *arg)
{
- struct dn_flow_set *pfs = &(p->fs);
- struct dn_flow_queue *q;
- int i, error;
+ int i;
+ if (p->oid.len != sizeof(*p)) {
+ D("invalid pipe len %d", p->oid.len);
+ return EINVAL;
+ }
+ i = p->link_nr;
+ if (i <= 0 || i >= DN_MAX_ID)
+ return EINVAL;
/*
* The config program passes parameters as follows:
* bw = bits/second (0 means no limits),
* delay = ms, must be translated into ticks.
* qsize = slots/bytes
+ * burst ???
*/
p->delay = (p->delay * hz) / 1000;
/* Scale burst size: bytes -> bits * hz */
p->burst *= 8 * hz;
- /* We need either a pipe number or a flow_set number. */
- if (p->pipe_nr == 0 && pfs->fs_nr == 0)
- return (EINVAL);
- if (p->pipe_nr != 0 && pfs->fs_nr != 0)
- return (EINVAL);
- if (p->pipe_nr != 0) { /* this is a pipe */
- struct dn_pipe *pipe;
-
- DUMMYNET_LOCK();
- pipe = locate_pipe(p->pipe_nr); /* locate pipe */
-
- if (pipe == NULL) { /* new pipe */
- pipe = malloc(sizeof(struct dn_pipe), M_DUMMYNET,
- M_NOWAIT | M_ZERO);
- if (pipe == NULL) {
- DUMMYNET_UNLOCK();
- printf("dummynet: no memory for new pipe\n");
- return (ENOMEM);
- }
- pipe->pipe_nr = p->pipe_nr;
- pipe->fs.pipe = pipe;
- /*
- * idle_heap is the only one from which
- * we extract from the middle.
- */
- pipe->idle_heap.size = pipe->idle_heap.elements = 0;
- pipe->idle_heap.offset =
- offsetof(struct dn_flow_queue, heap_pos);
- } else {
- /* Flush accumulated credit for all queues. */
- for (i = 0; i <= pipe->fs.rq_size; i++) {
- for (q = pipe->fs.rq[i]; q; q = q->next) {
- q->numbytes = p->burst +
- (io_fast ? p->bandwidth : 0);
- }
- }
- }
- pipe->bandwidth = p->bandwidth;
- pipe->burst = p->burst;
- pipe->numbytes = pipe->burst + (io_fast ? pipe->bandwidth : 0);
- bcopy(p->if_name, pipe->if_name, sizeof(p->if_name));
- pipe->ifp = NULL; /* reset interface ptr */
- pipe->delay = p->delay;
- set_fs_parms(&(pipe->fs), pfs);
-
- /* Handle changes in the delay profile. */
- if (p->samples_no > 0) {
- if (pipe->samples_no != p->samples_no) {
- if (pipe->samples != NULL)
- free(pipe->samples, M_DUMMYNET);
- pipe->samples =
- malloc(p->samples_no*sizeof(dn_key),
- M_DUMMYNET, M_NOWAIT | M_ZERO);
- if (pipe->samples == NULL) {
- DUMMYNET_UNLOCK();
- printf("dummynet: no memory "
- "for new samples\n");
- return (ENOMEM);
- }
- pipe->samples_no = p->samples_no;
- }
+ DN_BH_WLOCK();
+ /* do it twice, base link and FIFO link */
+ for (; i < 2*DN_MAX_ID; i += DN_MAX_ID) {
+ struct dn_schk *s = locate_scheduler(i);
+ if (s == NULL) {
+ DN_BH_WUNLOCK();
+ D("sched %d not found", i);
+ return EINVAL;
+ }
+ /* remove profile if exists */
+ if (s->profile) {
+ free(s->profile, M_DUMMYNET);
+ s->profile = NULL;
+ }
+ /* copy all parameters */
+ s->link.oid = p->oid;
+ s->link.link_nr = i;
+ s->link.delay = p->delay;
+ if (s->link.bandwidth != p->bandwidth) {
+ /* XXX bandwidth changes, need to update red params */
+ s->link.bandwidth = p->bandwidth;
+ update_red(s);
+ }
+ s->link.burst = p->burst;
+ schk_reset_credit(s);
+ }
+ dn_cfg.id++;
+ DN_BH_WUNLOCK();
+ return 0;
+}
- strncpy(pipe->name,p->name,sizeof(pipe->name));
- pipe->loss_level = p->loss_level;
- for (i = 0; i<pipe->samples_no; ++i)
- pipe->samples[i] = p->samples[i];
- } else if (pipe->samples != NULL) {
- free(pipe->samples, M_DUMMYNET);
- pipe->samples = NULL;
- pipe->samples_no = 0;
- }
+/*
+ * configure a flowset. Can be called from inside with locked=1,
+ */
+static struct dn_fsk *
+config_fs(struct dn_fs *nfs, struct dn_id *arg, int locked)
+{
+ int i;
+ struct dn_fsk *fs;
- if (pipe->fs.rq == NULL) { /* a new pipe */
- error = alloc_hash(&(pipe->fs), pfs);
- if (error) {
- DUMMYNET_UNLOCK();
- free_pipe(pipe);
- return (error);
- }
- SLIST_INSERT_HEAD(&pipehash[HASH(pipe->pipe_nr)],
- pipe, next);
- }
- DUMMYNET_UNLOCK();
- } else { /* config queue */
- struct dn_flow_set *fs;
+ if (nfs->oid.len != sizeof(*nfs)) {
+ D("invalid flowset len %d", nfs->oid.len);
+ return NULL;
+ }
+ i = nfs->fs_nr;
+ if (i <= 0 || i >= 3*DN_MAX_ID)
+ return NULL;
+ ND("flowset %d", i);
+ /* XXX other sanity checks */
+ if (nfs->flags & DN_QSIZE_BYTES) {
+ ipdn_bound_var(&nfs->qsize, 16384,
+ 1500, dn_cfg.byte_limit, NULL); // "queue byte size");
+ } else {
+ ipdn_bound_var(&nfs->qsize, 50,
+ 1, dn_cfg.slot_limit, NULL); // "queue slot size");
+ }
+ if (nfs->flags & DN_HAVE_MASK) {
+ /* make sure we have some buckets */
+ ipdn_bound_var(&nfs->buckets, dn_cfg.hash_size,
+ 1, dn_cfg.max_hash_size, "flowset buckets");
+ } else {
+ nfs->buckets = 1; /* we only need 1 */
+ }
+ if (!locked)
+ DN_BH_WLOCK();
+ do { /* exit with break when done */
+ struct dn_schk *s;
+ int flags = nfs->sched_nr ? DNHT_INSERT : 0;
+ int j;
+ int oldc = dn_cfg.fsk_count;
+ fs = dn_ht_find(dn_cfg.fshash, i, flags, NULL);
+ if (fs == NULL) {
+ D("missing sched for flowset %d", i);
+ break;
+ }
+ /* grab some defaults from the existing one */
+ if (nfs->sched_nr == 0) /* reuse */
+ nfs->sched_nr = fs->fs.sched_nr;
+ for (j = 0; j < sizeof(nfs->par)/sizeof(nfs->par[0]); j++) {
+ if (nfs->par[j] == -1) /* reuse */
+ nfs->par[j] = fs->fs.par[j];
+ }
+ if (bcmp(&fs->fs, nfs, sizeof(*nfs)) == 0) {
+ ND("flowset %d unchanged", i);
+ break; /* no change, nothing to do */
+ }
+ if (oldc != dn_cfg.fsk_count) /* new item */
+ dn_cfg.id++;
+ s = locate_scheduler(nfs->sched_nr);
+ /* detach from old scheduler if needed, preserving
+ * queues if we need to reattach. Then update the
+ * configuration, and possibly attach to the new sched.
+ */
+ DX(2, "fs %d changed sched %d@%p to %d@%p",
+ fs->fs.fs_nr,
+ fs->fs.sched_nr, fs->sched, nfs->sched_nr, s);
+ if (fs->sched) {
+ int flags = s ? DN_DETACH : (DN_DETACH | DN_DESTROY);
+ flags |= DN_DESTROY; /* XXX temporary */
+ fsk_detach(fs, flags);
+ }
+ fs->fs = *nfs; /* copy configuration */
+ if (s != NULL)
+ fsk_attach(fs, s);
+ } while (0);
+ if (!locked)
+ DN_BH_WUNLOCK();
+ return fs;
+}
- DUMMYNET_LOCK();
- fs = locate_flowset(pfs->fs_nr); /* locate flow_set */
+/*
+ * config/reconfig a scheduler and its FIFO variant.
+ * For !MULTIQUEUE schedulers, also set up the flowset.
+ *
+ * On reconfigurations (detected because s->fp is set),
+ * detach existing flowsets preserving traffic, preserve link,
+ * and delete the old scheduler creating a new one.
+ */
+static int
+config_sched(struct dn_sch *_nsch, struct dn_id *arg)
+{
+ struct dn_schk *s;
+ struct schk_new_arg a; /* argument for schk_new */
+ int i;
+ struct dn_link p; /* copy of oldlink */
+ struct dn_profile *pf; /* copy of old link profile */
+ /* Used to preserv mask parameter */
+ struct ipfw_flow_id new_mask;
+ int new_buckets = 0;
+ int new_flags = 0;
+ int pipe_cmd;
+
+ a.sch = _nsch;
+ if (a.sch->oid.len != sizeof(*a.sch)) {
+ D("bad sched len %d", a.sch->oid.len);
+ return EINVAL;
+ }
+ i = a.sch->sched_nr;
+ if (i <= 0 || i >= DN_MAX_ID)
+ return EINVAL;
+ /* make sure we have some buckets */
+ if (a.sch->flags & DN_HAVE_MASK)
+ ipdn_bound_var(&a.sch->buckets, dn_cfg.hash_size,
+ 1, dn_cfg.max_hash_size, "sched buckets");
+ /* XXX other sanity checks */
+ bzero(&p, sizeof(p));
+ pf = malloc(sizeof(struct dn_profile), M_DUMMYNET, M_NOWAIT | M_ZERO);
+ if (pf == NULL) {
+ D("Error allocating profile");
+ return ENOMEM;
+ }
- if (fs == NULL) { /* new */
- if (pfs->parent_nr == 0) { /* need link to a pipe */
- DUMMYNET_UNLOCK();
- return (EINVAL);
- }
- fs = malloc(sizeof(struct dn_flow_set), M_DUMMYNET,
- M_NOWAIT | M_ZERO);
- if (fs == NULL) {
- DUMMYNET_UNLOCK();
- printf(
- "dummynet: no memory for new flow_set\n");
- return (ENOMEM);
- }
- fs->fs_nr = pfs->fs_nr;
- fs->parent_nr = pfs->parent_nr;
- fs->weight = pfs->weight;
- if (fs->weight == 0)
- fs->weight = 1;
- else if (fs->weight > 100)
- fs->weight = 100;
+ pipe_cmd = a.sch->flags & DN_PIPE_CMD;
+ a.sch->flags &= ~DN_PIPE_CMD; //XXX do it even if is not set?
+ if (pipe_cmd) {
+ /* Copy mask parameter */
+ new_mask = a.sch->sched_mask;
+ new_buckets = a.sch->buckets;
+ new_flags = a.sch->flags;
+ }
+ DN_BH_WLOCK();
+again: /* run twice, for wfq and fifo */
+ /*
+ * lookup the type. If not supplied, use the previous one
+ * or default to WF2Q+. Otherwise, return an error.
+ */
+ dn_cfg.id++;
+ a.fp = find_sched_type(a.sch->oid.subtype, a.sch->name);
+ if (a.fp != NULL) {
+ /* found. Lookup or create entry */
+ s = dn_ht_find(dn_cfg.schedhash, i, DNHT_INSERT, &a);
+ } else if (a.sch->oid.subtype == 0 && !a.sch->name[0]) {
+ /* No type. search existing s* or retry with WF2Q+ */
+ s = dn_ht_find(dn_cfg.schedhash, i, 0, &a);
+ if (s != NULL) {
+ a.fp = s->fp;
+ /* Scheduler exists, skip to FIFO scheduler
+ * if command was pipe config...
+ */
+ if (pipe_cmd)
+ goto next;
} else {
- /*
- * Change parent pipe not allowed;
- * must delete and recreate.
+ /* New scheduler, create a wf2q+ with no mask
+ * if command was pipe config...
*/
- if (pfs->parent_nr != 0 &&
- fs->parent_nr != pfs->parent_nr) {
- DUMMYNET_UNLOCK();
- return (EINVAL);
+ if (pipe_cmd) {
+ /* clear mask parameter */
+ bzero(&a.sch->sched_mask, sizeof(new_mask));
+ a.sch->buckets = 0;
+ a.sch->flags &= ~DN_HAVE_MASK;
}
+ a.sch->oid.subtype = DN_SCHED_WF2QP;
+ goto again;
}
-
- set_fs_parms(fs, pfs);
-
- if (fs->rq == NULL) { /* a new flow_set */
- error = alloc_hash(fs, pfs);
- if (error) {
- DUMMYNET_UNLOCK();
- free(fs, M_DUMMYNET);
- return (error);
+ } else {
+ DN_BH_WUNLOCK();
+ D("invalid scheduler type %d %s",
+ a.sch->oid.subtype, a.sch->name);
+ return EINVAL;
+ }
+ /* normalize name and subtype */
+ a.sch->oid.subtype = a.fp->type;
+ bzero(a.sch->name, sizeof(a.sch->name));
+ strlcpy(a.sch->name, a.fp->name, sizeof(a.sch->name));
+ if (s == NULL) {
+ DN_BH_WUNLOCK();
+ D("cannot allocate scheduler %d", i);
+ return ENOMEM;
+ }
+ /* restore existing link if any */
+ if (p.link_nr) {
+ s->link = p;
+ if (pf->link_nr == p.link_nr) /* Restore profile */
+ s->profile = pf;
+ else
+ s->profile = NULL; /* XXX maybe not needed */
+ }
+ p.link_nr = 0;
+ if (s->fp == NULL) {
+ DX(2, "sched %d new type %s", i, a.fp->name);
+ } else if (s->fp != a.fp ||
+ bcmp(a.sch, &s->sch, sizeof(*a.sch)) ) {
+ /* already existing. */
+ DX(2, "sched %d type changed from %s to %s",
+ i, s->fp->name, a.fp->name);
+ DX(4, " type/sub %d/%d -> %d/%d",
+ s->sch.oid.type, s->sch.oid.subtype,
+ a.sch->oid.type, a.sch->oid.subtype);
+ if (s->link.link_nr == 0)
+ D("XXX WARNING link 0 for sched %d", i);
+ p = s->link; /* preserve link */
+ if (s->profile) /* preserve profile */
+ bcopy(s->profile, pf, sizeof(struct dn_profile));
+ /* remove from the hash */
+ dn_ht_find(dn_cfg.schedhash, i, DNHT_REMOVE, NULL);
+ /* Detach flowsets, preserve queues. */
+ // schk_delete_cb(s, NULL);
+ // XXX temporarily, kill queues
+ schk_delete_cb(s, (void *)DN_DESTROY);
+ goto again;
+ } else {
+ DX(4, "sched %d unchanged type %s", i, a.fp->name);
+ }
+ /* complete initialization */
+ s->sch = *a.sch;
+ s->fp = a.fp;
+ s->cfg = arg;
+ // XXX schk_reset_credit(s);
+ /* create the internal flowset if needed,
+ * trying to reuse existing ones if available
+ */
+ if (!(s->fp->flags & DN_MULTIQUEUE) && !s->fs) {
+ s->fs = dn_ht_find(dn_cfg.fshash, i, 0, NULL);
+ if (!s->fs) {
+ struct dn_fs fs;
+ bzero(&fs, sizeof(fs));
+ set_oid(&fs.oid, DN_FS, sizeof(fs));
+ fs.fs_nr = i + DN_MAX_ID;
+ fs.sched_nr = i;
+ s->fs = config_fs(&fs, NULL, 1 /* locked */);
+ }
+ if (!s->fs) {
+ schk_delete_cb(s, (void *)DN_DESTROY);
+ D("error creating internal fs for %d", i);
+ DN_BH_WUNLOCK();
+ return ENOMEM;
+ }
+ }
+ /* call init function after the flowset is created */
+ if (s->fp->config)
+ s->fp->config(s);
+ update_fs(s);
+next:
+ if (i < DN_MAX_ID) { /* now configure the FIFO instance */
+ i += DN_MAX_ID;
+ if (pipe_cmd) {
+ /* Restore mask parameter for FIFO */
+ a.sch->sched_mask = new_mask;
+ a.sch->buckets = new_buckets;
+ a.sch->flags = new_flags;
+ } else {
+ /* sched config shouldn't modify the FIFO scheduler */
+ if (dn_ht_find(dn_cfg.schedhash, i, 0, &a) != NULL) {
+ /* FIFO already exist, don't touch it */
+ DN_BH_WUNLOCK();
+ return 0;
}
- SLIST_INSERT_HEAD(&flowsethash[HASH(fs->fs_nr)],
- fs, next);
}
- DUMMYNET_UNLOCK();
+ a.sch->sched_nr = i;
+ a.sch->oid.subtype = DN_SCHED_FIFO;
+ bzero(a.sch->name, sizeof(a.sch->name));
+ goto again;
}
- return (0);
+ DN_BH_WUNLOCK();
+ return 0;
}
/*
- * Helper function to remove from a heap queues which are linked to
- * a flow_set about to be deleted.
+ * attach a profile to a link
*/
-static void
-fs_remove_from_heap(struct dn_heap *h, struct dn_flow_set *fs)
+static int
+config_profile(struct dn_profile *pf, struct dn_id *arg)
{
- int i, found;
+ struct dn_schk *s;
+ int i, olen, err = 0;
- for (i = found = 0 ; i < h->elements ;) {
- if ( ((struct dn_flow_queue *)h->p[i].object)->fs == fs) {
- h->elements-- ;
- h->p[i] = h->p[h->elements] ;
- found++ ;
- } else
- i++ ;
- }
- if (found)
- heapify(h);
+ if (pf->oid.len < sizeof(*pf)) {
+ D("short profile len %d", pf->oid.len);
+ return EINVAL;
+ }
+ i = pf->link_nr;
+ if (i <= 0 || i >= DN_MAX_ID)
+ return EINVAL;
+ /* XXX other sanity checks */
+ DN_BH_WLOCK();
+ for (; i < 2*DN_MAX_ID; i += DN_MAX_ID) {
+ s = locate_scheduler(i);
+
+ if (s == NULL) {
+ err = EINVAL;
+ break;
+ }
+ dn_cfg.id++;
+ /*
+ * If we had a profile and the new one does not fit,
+ * or it is deleted, then we need to free memory.
+ */
+ if (s->profile && (pf->samples_no == 0 ||
+ s->profile->oid.len < pf->oid.len)) {
+ free(s->profile, M_DUMMYNET);
+ s->profile = NULL;
+ }
+ if (pf->samples_no == 0)
+ continue;
+ /*
+ * new profile, possibly allocate memory
+ * and copy data.
+ */
+ if (s->profile == NULL)
+ s->profile = malloc(pf->oid.len,
+ M_DUMMYNET, M_NOWAIT | M_ZERO);
+ if (s->profile == NULL) {
+ D("no memory for profile %d", i);
+ err = ENOMEM;
+ break;
+ }
+ /* preserve larger length XXX double check */
+ olen = s->profile->oid.len;
+ if (olen < pf->oid.len)
+ olen = pf->oid.len;
+ bcopy(pf, s->profile, pf->oid.len);
+ s->profile->oid.len = olen;
+ }
+ DN_BH_WUNLOCK();
+ return err;
}
/*
- * helper function to remove a pipe from a heap (can be there at most once)
+ * Delete all objects:
*/
static void
-pipe_remove_from_heap(struct dn_heap *h, struct dn_pipe *p)
+dummynet_flush(void)
{
- int i;
- for (i=0; i < h->elements ; i++ ) {
- if (h->p[i].object == p) { /* found it */
- h->elements-- ;
- h->p[i] = h->p[h->elements] ;
- heapify(h);
- break ;
- }
- }
+ /* delete all schedulers and related links/queues/flowsets */
+ dn_ht_scan(dn_cfg.schedhash, schk_delete_cb,
+ (void *)(uintptr_t)DN_DELETE_FS);
+ /* delete all remaining (unlinked) flowsets */
+ DX(4, "still %d unlinked fs", dn_cfg.fsk_count);
+ dn_ht_free(dn_cfg.fshash, DNHT_REMOVE);
+ fsk_detach_list(&dn_cfg.fsu, DN_DELETE_FS);
+ /* Reinitialize system heap... */
+ heap_init(&dn_cfg.evheap, 16, offsetof(struct dn_id, id));
}
/*
- * Fully delete a pipe or a queue, cleaning up associated info.
+ * Main handler for configuration. We are guaranteed to be called
+ * with an oid which is at least a dn_id.
+ * - the first object is the command (config, delete, flush, ...)
+ * - config_link must be issued after the corresponding config_sched
+ * - parameters (DN_TXT) for an object must preceed the object
+ * processed on a config_sched.
*/
-static int
-delete_pipe(struct dn_pipe *p)
+int
+do_config(void *p, int l)
{
+ struct dn_id *next, *o;
+ int err = 0, err2 = 0;
+ struct dn_id *arg = NULL;
+ uintptr_t *a;
+
+ o = p;
+ if (o->id != DN_API_VERSION) {
+ D("invalid api version got %d need %d",
+ o->id, DN_API_VERSION);
+ return EINVAL;
+ }
+ for (; l >= sizeof(*o); o = next) {
+ struct dn_id *prev = arg;
+ if (o->len < sizeof(*o) || l < o->len) {
+ D("bad len o->len %d len %d", o->len, l);
+ err = EINVAL;
+ break;
+ }
+ l -= o->len;
+ next = (struct dn_id *)((char *)o + o->len);
+ err = 0;
+ switch (o->type) {
+ default:
+ D("cmd %d not implemented", o->type);
+ break;
+#ifdef EMULATE_SYSCTL
+ /* sysctl emulation.
+ * if we recognize the command, jump to the correct
+ * handler and return
+ */
+ case DN_SYSCTL_SET:
+ err = kesysctl_emu_set(p, l);
+ return err;
+#endif
+ case DN_CMD_CONFIG: /* simply a header */
+ break;
- if (p->pipe_nr == 0 && p->fs.fs_nr == 0)
- return EINVAL ;
- if (p->pipe_nr != 0 && p->fs.fs_nr != 0)
- return EINVAL ;
- if (p->pipe_nr != 0) { /* this is an old-style pipe */
- struct dn_pipe *pipe;
- struct dn_flow_set *fs;
- int i;
+ case DN_CMD_DELETE:
+ /* the argument is in the first uintptr_t after o */
+ a = (uintptr_t *)(o+1);
+ if (o->len < sizeof(*o) + sizeof(*a)) {
+ err = EINVAL;
+ break;
+ }
+ switch (o->subtype) {
+ case DN_LINK:
+ /* delete base and derived schedulers */
+ DN_BH_WLOCK();
+ err = delete_schk(*a);
+ err2 = delete_schk(*a + DN_MAX_ID);
+ DN_BH_WUNLOCK();
+ if (!err)
+ err = err2;
+ break;
- DUMMYNET_LOCK();
- pipe = locate_pipe(p->pipe_nr); /* locate pipe */
+ default:
+ D("invalid delete type %d",
+ o->subtype);
+ err = EINVAL;
+ break;
+
+ case DN_FS:
+ err = (*a <1 || *a >= DN_MAX_ID) ?
+ EINVAL : delete_fs(*a, 0) ;
+ break;
+ }
+ break;
- if (pipe == NULL) {
- DUMMYNET_UNLOCK();
- return (ENOENT); /* not found */
+ case DN_CMD_FLUSH:
+ DN_BH_WLOCK();
+ dummynet_flush();
+ DN_BH_WUNLOCK();
+ break;
+ case DN_TEXT: /* store argument the next block */
+ prev = NULL;
+ arg = o;
+ break;
+ case DN_LINK:
+ err = config_link((struct dn_link *)o, arg);
+ break;
+ case DN_PROFILE:
+ err = config_profile((struct dn_profile *)o, arg);
+ break;
+ case DN_SCH:
+ err = config_sched((struct dn_sch *)o, arg);
+ break;
+ case DN_FS:
+ err = (NULL==config_fs((struct dn_fs *)o, arg, 0));
+ break;
+ }
+ if (prev)
+ arg = NULL;
+ if (err != 0)
+ break;
}
+ return err;
+}
- /* Unlink from list of pipes. */
- SLIST_REMOVE(&pipehash[HASH(pipe->pipe_nr)], pipe, dn_pipe, next);
+static int
+compute_space(struct dn_id *cmd, int *to_copy)
+{
+ int x = 0, need = 0;
+ int profile_size = sizeof(struct dn_profile) -
+ ED_MAX_SAMPLES_NO*sizeof(int);
+
+ /* NOTE about compute space:
+ * NP = dn_cfg.schk_count
+ * NSI = dn_cfg.si_count
+ * NF = dn_cfg.fsk_count
+ * NQ = dn_cfg.queue_count
+ * - ipfw pipe show
+ * (NP/2)*(dn_link + dn_sch + dn_id + dn_fs) only half scheduler
+ * link, scheduler template, flowset
+ * integrated in scheduler and header
+ * for flowset list
+ * (NSI)*(dn_flow + dn_queue) all scheduler instance + one
+ * queue per instance
+ * - ipfw sched show
+ * (NP/2)*(dn_link + dn_sch + dn_id + dn_fs) only half scheduler
+ * link, scheduler template, flowset
+ * integrated in scheduler and header
+ * for flowset list
+ * (NSI * dn_flow) all scheduler instances
+ * (NF * sizeof(uint_32)) space for flowset list linked to scheduler
+ * (NQ * dn_queue) all queue [XXXfor now not listed]
+ * - ipfw queue show
+ * (NF * dn_fs) all flowset
+ * (NQ * dn_queue) all queues
+ */
+ switch (cmd->subtype) {
+ default:
+ return -1;
+ /* XXX where do LINK and SCH differ ? */
+ case DN_LINK: /* pipe show */
+ x = DN_C_LINK | DN_C_SCH | DN_C_FLOW;
+ need += dn_cfg.schk_count *
+ (sizeof(struct dn_fs) + profile_size) / 2;
+ need += dn_cfg.si_count * sizeof(struct dn_queue);
+ need += dn_cfg.fsk_count * sizeof(uint32_t);
+ break;
+ case DN_SCH: /* sched show */
+ need += dn_cfg.schk_count *
+ (sizeof(struct dn_fs) + profile_size) / 2;
+ need += dn_cfg.fsk_count * sizeof(uint32_t);
+ x = DN_C_SCH | DN_C_LINK | DN_C_FLOW;
+ break;
+ case DN_FS: /* queue show */
+ x = DN_C_FS | DN_C_QUEUE;
+ break;
+ case DN_GET_COMPAT: /* compatibility mode */
+ need = dn_compat_calc_size(dn_cfg);
+ break;
+ }
+ *to_copy = x;
+ if (x & DN_C_SCH) {
+ need += dn_cfg.schk_count * sizeof(struct dn_sch) / 2;
+ /* NOT also, each fs might be attached to a sched */
+ need += dn_cfg.schk_count * sizeof(struct dn_id) / 2;
+ }
+ if (x & DN_C_FS)
+ need += dn_cfg.fsk_count * sizeof(struct dn_fs);
+ if (x & DN_C_LINK) {
+ need += dn_cfg.schk_count * sizeof(struct dn_link) / 2;
+ }
+ /* XXX queue space might be variable */
+ if (x & DN_C_QUEUE)
+ need += dn_cfg.queue_count * sizeof(struct dn_queue);
+ if (x & DN_C_FLOW)
+ need += dn_cfg.si_count * (sizeof(struct dn_flow));
+ return need;
+}
- /* Remove all references to this pipe from flow_sets. */
- for (i = 0; i < HASHSIZE; i++) {
- SLIST_FOREACH(fs, &flowsethash[i], next) {
- if (fs->pipe == pipe) {
- printf("dummynet: ++ ref to pipe %d from fs %d\n",
- p->pipe_nr, fs->fs_nr);
- fs->pipe = NULL ;
- purge_flow_set(fs, 0);
+/*
+ * If compat != NULL dummynet_get is called in compatibility mode.
+ * *compat will be the pointer to the buffer to pass to ipfw
+ */
+int
+dummynet_get(struct sockopt *sopt, void **compat)
+{
+ int have, i, need, error;
+ char *start = NULL, *buf;
+ size_t sopt_valsize;
+ struct dn_id cmd;
+ struct copy_args a;
+
+ /* save and restore original sopt_valsize around copyin */
+ sopt_valsize = sopt->sopt_valsize;
+ if (!compat) {
+ error = sooptcopyin(sopt, &cmd, sizeof(cmd), sizeof(cmd));
+ if (error)
+ return error;
+ sopt->sopt_valsize = sopt_valsize;
+#ifdef EMULATE_SYSCTL
+ /* sysctl emulation. */
+ if (cmd.type == DN_SYSCTL_GET)
+ return kesysctl_emu_get(sopt);
+#endif
+ } else {
+ error = 0;
+ cmd.type = DN_CMD_GET;
+ cmd.len = sizeof(struct dn_id);
+ cmd.subtype = DN_GET_COMPAT;
+ // cmd.id = sopt_valsize;
+ D("compatibility mode");
+ }
+ /* Count space (under lock) and allocate (outside lock).
+ * Exit with lock held if we manage to get enough buffer.
+ * Try a few times then give up.
+ */
+ for (have = 0, i = 0; i < 10; i++) {
+ DN_BH_WLOCK();
+ need = compute_space(&cmd, &a.flags);
+ if (need < 0) {
+ DN_BH_WUNLOCK();
+ return EINVAL;
}
- }
+ need += sizeof(cmd);
+ cmd.id = need;
+ if (have >= need)
+ break;
+ DN_BH_WUNLOCK();
+ if (start)
+ free(start, M_DUMMYNET);
+ start = NULL;
+ if (need > sopt_valsize)
+ break;
+ have = need;
+ start = malloc(have, M_DUMMYNET, M_WAITOK | M_ZERO);
+ if (start == NULL)
+ return ENOMEM;
+ }
+ if (start == NULL) {
+ if (compat) {
+ *compat = NULL;
+ return 1; // XXX
+ }
+ return sooptcopyout(sopt, &cmd, sizeof(cmd));
}
- fs_remove_from_heap(&ready_heap, &(pipe->fs));
- purge_pipe(pipe); /* remove all data associated to this pipe */
- /* remove reference to here from extract_heap and wfq_ready_heap */
- pipe_remove_from_heap(&extract_heap, pipe);
- pipe_remove_from_heap(&wfq_ready_heap, pipe);
- DUMMYNET_UNLOCK();
+ ND("have %d:%d sched %d, %d:%d links %d, %d:%d flowsets %d, "
+ "%d:%d si %d, %d:%d queues %d",
+ dn_cfg.schk_count, sizeof(struct dn_sch), DN_SCH,
+ dn_cfg.schk_count, sizeof(struct dn_link), DN_LINK,
+ dn_cfg.fsk_count, sizeof(struct dn_fs), DN_FS,
+ dn_cfg.si_count, sizeof(struct dn_flow), DN_SCH_I,
+ dn_cfg.queue_count, sizeof(struct dn_queue), DN_QUEUE);
+ sopt->sopt_valsize = sopt_valsize;
+ a.type = cmd.subtype;
+ if (compat == NULL) {
+ bcopy(&cmd, start, sizeof(cmd));
+ buf = start + sizeof(cmd);
+ } else
+ buf = start;
+ a.start = &buf;
+ a.end = start + have;
+ /* start copying other objects */
+ if (compat) {
+ a.type = DN_COMPAT_PIPE;
+ dn_ht_scan(dn_cfg.schedhash, copy_data_helper_compat, &a);
+ a.type = DN_COMPAT_QUEUE;
+ dn_ht_scan(dn_cfg.fshash, copy_data_helper_compat, &a);
+ } else if (a.type == DN_FS)
+ dn_ht_scan(dn_cfg.fshash, copy_data_helper, &a);
+ else
+ dn_ht_scan(dn_cfg.schedhash, copy_data_helper, &a);
+ DN_BH_WUNLOCK();
+ if (compat) {
+ *compat = start;
+ sopt->sopt_valsize = buf - start;
+ /* free() is done by ip_dummynet_compat() */
+ } else {
+ error = sooptcopyout(sopt, start, buf - start);
+ free(start, M_DUMMYNET);
+ }
+ return error;
+}
- free_pipe(pipe);
- } else { /* this is a WF2Q queue (dn_flow_set) */
- struct dn_flow_set *fs;
+/* Callback called on scheduler instance to delete it if idle */
+static int
+drain_scheduler_cb(void *_si, void *arg)
+{
+ struct dn_sch_inst *si = _si;
- DUMMYNET_LOCK();
- fs = locate_flowset(p->fs.fs_nr); /* locate set */
+ if ((si->kflags & DN_ACTIVE) || si->dline.mq.head != NULL)
+ return 0;
- if (fs == NULL) {
- DUMMYNET_UNLOCK();
- return (ENOENT); /* not found */
+ if (si->sched->fp->flags & DN_MULTIQUEUE) {
+ if (si->q_count == 0)
+ return si_destroy(si, NULL);
+ else
+ return 0;
+ } else { /* !DN_MULTIQUEUE */
+ if ((si+1)->ni.length == 0)
+ return si_destroy(si, NULL);
+ else
+ return 0;
}
+ return 0; /* unreachable */
+}
- /* Unlink from list of flowsets. */
- SLIST_REMOVE( &flowsethash[HASH(fs->fs_nr)], fs, dn_flow_set, next);
+/* Callback called on scheduler to check if it has instances */
+static int
+drain_scheduler_sch_cb(void *_s, void *arg)
+{
+ struct dn_schk *s = _s;
- if (fs->pipe != NULL) {
- /* Update total weight on parent pipe and cleanup parent heaps. */
- fs->pipe->sum -= fs->weight * fs->backlogged ;
- fs_remove_from_heap(&(fs->pipe->not_eligible_heap), fs);
- fs_remove_from_heap(&(fs->pipe->scheduler_heap), fs);
-#if 1 /* XXX should i remove from idle_heap as well ? */
- fs_remove_from_heap(&(fs->pipe->idle_heap), fs);
-#endif
+ if (s->sch.flags & DN_HAVE_MASK) {
+ dn_ht_scan_bucket(s->siht, &s->drain_bucket,
+ drain_scheduler_cb, NULL);
+ s->drain_bucket++;
+ } else {
+ if (s->siht) {
+ if (drain_scheduler_cb(s->siht, NULL) == DNHT_SCAN_DEL)
+ s->siht = NULL;
+ }
}
- purge_flow_set(fs, 1);
- DUMMYNET_UNLOCK();
- }
- return 0 ;
+ return 0;
}
-/*
- * helper function used to copy data from kernel in DUMMYNET_GET
- */
-static char *
-dn_copy_set(struct dn_flow_set *set, char *bp)
-{
- int i, copied = 0 ;
- struct dn_flow_queue *q, *qp = (struct dn_flow_queue *)bp;
-
- DUMMYNET_LOCK_ASSERT();
-
- for (i = 0 ; i <= set->rq_size ; i++) {
- for (q = set->rq[i] ; q ; q = q->next, qp++ ) {
- if (q->hash_slot != i)
- printf("dummynet: ++ at %d: wrong slot (have %d, "
- "should be %d)\n", copied, q->hash_slot, i);
- if (q->fs != set)
- printf("dummynet: ++ at %d: wrong fs ptr (have %p, should be %p)\n",
- i, q->fs, set);
- copied++ ;
- bcopy(q, qp, sizeof( *q ) );
- /* cleanup pointers */
- qp->next = NULL ;
- qp->head = qp->tail = NULL ;
- qp->fs = NULL ;
- }
- }
- if (copied != set->rq_elements)
- printf("dummynet: ++ wrong count, have %d should be %d\n",
- copied, set->rq_elements);
- return (char *)qp ;
-}
-
-static size_t
-dn_calc_size(void)
-{
- struct dn_flow_set *fs;
- struct dn_pipe *pipe;
- size_t size = 0;
- int i;
-
- DUMMYNET_LOCK_ASSERT();
- /*
- * Compute size of data structures: list of pipes and flow_sets.
- */
- for (i = 0; i < HASHSIZE; i++) {
- SLIST_FOREACH(pipe, &pipehash[i], next)
- size += sizeof(*pipe) +
- pipe->fs.rq_elements * sizeof(struct dn_flow_queue);
- SLIST_FOREACH(fs, &flowsethash[i], next)
- size += sizeof (*fs) +
- fs->rq_elements * sizeof(struct dn_flow_queue);
- }
- return size;
+/* Called every tick, try to delete a 'bucket' of scheduler */
+void
+dn_drain_scheduler(void)
+{
+ dn_ht_scan_bucket(dn_cfg.schedhash, &dn_cfg.drain_sch,
+ drain_scheduler_sch_cb, NULL);
+ dn_cfg.drain_sch++;
}
+/* Callback called on queue to delete if it is idle */
static int
-dummynet_get(struct sockopt *sopt)
-{
- char *buf, *bp ; /* bp is the "copy-pointer" */
- size_t size ;
- struct dn_flow_set *fs;
- struct dn_pipe *pipe;
- int error=0, i ;
-
- /* XXX lock held too long */
- DUMMYNET_LOCK();
- /*
- * XXX: Ugly, but we need to allocate memory with M_WAITOK flag and we
- * cannot use this flag while holding a mutex.
- */
- for (i = 0; i < 10; i++) {
- size = dn_calc_size();
- DUMMYNET_UNLOCK();
- buf = malloc(size, M_TEMP, M_WAITOK);
- DUMMYNET_LOCK();
- if (size >= dn_calc_size())
- break;
- free(buf, M_TEMP);
- buf = NULL;
- }
- if (buf == NULL) {
- DUMMYNET_UNLOCK();
- return ENOBUFS ;
- }
- bp = buf;
- for (i = 0; i < HASHSIZE; i++) {
- SLIST_FOREACH(pipe, &pipehash[i], next) {
- struct dn_pipe *pipe_bp = (struct dn_pipe *)bp;
-
- /*
- * Copy pipe descriptor into *bp, convert delay back to ms,
- * then copy the flow_set descriptor(s) one at a time.
- * After each flow_set, copy the queue descriptor it owns.
- */
- bcopy(pipe, bp, sizeof(*pipe));
- pipe_bp->delay = (pipe_bp->delay * 1000) / hz;
- pipe_bp->burst = div64(pipe_bp->burst, 8 * hz);
- /*
- * XXX the following is a hack based on ->next being the
- * first field in dn_pipe and dn_flow_set. The correct
- * solution would be to move the dn_flow_set to the beginning
- * of struct dn_pipe.
- */
- pipe_bp->next.sle_next = (struct dn_pipe *)DN_IS_PIPE;
- /* Clean pointers. */
- pipe_bp->head = pipe_bp->tail = NULL;
- pipe_bp->fs.next.sle_next = NULL;
- pipe_bp->fs.pipe = NULL;
- pipe_bp->fs.rq = NULL;
- pipe_bp->samples = NULL;
+drain_queue_cb(void *_q, void *arg)
+{
+ struct dn_queue *q = _q;
- bp += sizeof(*pipe) ;
- bp = dn_copy_set(&(pipe->fs), bp);
+ if (q->ni.length == 0) {
+ dn_delete_queue(q, DN_DESTROY);
+ return DNHT_SCAN_DEL; /* queue is deleted */
}
- }
- for (i = 0; i < HASHSIZE; i++) {
- SLIST_FOREACH(fs, &flowsethash[i], next) {
- struct dn_flow_set *fs_bp = (struct dn_flow_set *)bp;
+ return 0; /* queue isn't deleted */
+}
- bcopy(fs, bp, sizeof(*fs));
- /* XXX same hack as above */
- fs_bp->next.sle_next = (struct dn_flow_set *)DN_IS_QUEUE;
- fs_bp->pipe = NULL;
- fs_bp->rq = NULL;
- bp += sizeof(*fs);
- bp = dn_copy_set(fs, bp);
- }
- }
+/* Callback called on flowset used to check if it has queues */
+static int
+drain_queue_fs_cb(void *_fs, void *arg)
+{
+ struct dn_fsk *fs = _fs;
- DUMMYNET_UNLOCK();
+ if (fs->fs.flags & DN_QHT_HASH) {
+ /* Flowset has a hash table for queues */
+ dn_ht_scan_bucket(fs->qht, &fs->drain_bucket,
+ drain_queue_cb, NULL);
+ fs->drain_bucket++;
+ }
+ else {
+ /* No hash table for this flowset, null the pointer
+ * if the queue is deleted
+ */
+ if (fs->qht) {
+ if (drain_queue_cb(fs->qht, NULL) == DNHT_SCAN_DEL)
+ fs->qht = NULL;
+ }
+ }
+ return 0;
+}
- error = sooptcopyout(sopt, buf, size);
- free(buf, M_TEMP);
- return error ;
+/* Called every tick, try to delete a 'bucket' of queue */
+void
+dn_drain_queue(void)
+{
+ /* scan a bucket of flowset */
+ dn_ht_scan_bucket(dn_cfg.fshash, &dn_cfg.drain_fs,
+ drain_queue_fs_cb, NULL);
+ dn_cfg.drain_fs++;
}
/*
- * Handler for the various dummynet socket options (get, flush, config, del)
+ * Handler for the various dummynet socket options
*/
static int
ip_dn_ctl(struct sockopt *sopt)
{
- int error;
- struct dn_pipe *p = NULL;
+ void *p = NULL;
+ int error, l;
- error = priv_check(sopt->sopt_td, PRIV_NETINET_DUMMYNET);
- if (error)
- return (error);
-
- /* Disallow sets in really-really secure mode. */
- if (sopt->sopt_dir == SOPT_SET) {
-#if __FreeBSD_version >= 500034
- error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
+ error = priv_check(sopt->sopt_td, PRIV_NETINET_DUMMYNET);
if (error)
- return (error);
-#else
- if (securelevel >= 3)
- return (EPERM);
-#endif
- }
-
- switch (sopt->sopt_name) {
- default :
- printf("dummynet: -- unknown option %d", sopt->sopt_name);
- error = EINVAL ;
- break;
+ return (error);
- case IP_DUMMYNET_GET :
- error = dummynet_get(sopt);
- break ;
-
- case IP_DUMMYNET_FLUSH :
- dummynet_flush() ;
- break ;
-
- case IP_DUMMYNET_CONFIGURE :
- p = malloc(sizeof(struct dn_pipe_max), M_TEMP, M_WAITOK);
- error = sooptcopyin(sopt, p, sizeof(struct dn_pipe_max), sizeof *p);
- if (error)
- break ;
- if (p->samples_no > 0)
- p->samples = &(((struct dn_pipe_max *)p)->samples[0]);
+ /* Disallow sets in really-really secure mode. */
+ if (sopt->sopt_dir == SOPT_SET) {
+ error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
+ if (error)
+ return (error);
+ }
- error = config_pipe(p);
- break ;
+ switch (sopt->sopt_name) {
+ default :
+ D("dummynet: unknown option %d", sopt->sopt_name);
+ error = EINVAL;
+ break;
- case IP_DUMMYNET_DEL : /* remove a pipe or queue */
- p = malloc(sizeof(struct dn_pipe), M_TEMP, M_WAITOK);
- error = sooptcopyin(sopt, p, sizeof(struct dn_pipe), sizeof *p);
- if (error)
- break ;
+ case IP_DUMMYNET_FLUSH:
+ case IP_DUMMYNET_CONFIGURE:
+ case IP_DUMMYNET_DEL: /* remove a pipe or queue */
+ case IP_DUMMYNET_GET:
+ D("dummynet: compat option %d", sopt->sopt_name);
+ error = ip_dummynet_compat(sopt);
+ break;
- error = delete_pipe(p);
- break ;
- }
+ case IP_DUMMYNET3 :
+ if (sopt->sopt_dir == SOPT_GET) {
+ error = dummynet_get(sopt, NULL);
+ break;
+ }
+ l = sopt->sopt_valsize;
+ if (l < sizeof(struct dn_id) || l > 12000) {
+ D("argument len %d invalid", l);
+ break;
+ }
+ p = malloc(l, M_TEMP, M_WAITOK); // XXX can it fail ?
+ error = sooptcopyin(sopt, p, l, l);
+ if (error)
+ break ;
+ error = do_config(p, l);
+ break;
+ }
- if (p != NULL)
- free(p, M_TEMP);
+ if (p != NULL)
+ free(p, M_TEMP);
- return error ;
+ return error ;
}
+
static void
ip_dn_init(void)
{
- int i;
+ static int init_done = 0;
+ if (init_done)
+ return;
+ init_done = 1;
if (bootverbose)
- printf("DUMMYNET with IPv6 initialized (040826)\n");
+ printf("DUMMYNET with IPv6 initialized (100131)\n");
- DUMMYNET_LOCK_INIT();
-
- for (i = 0; i < HASHSIZE; i++) {
- SLIST_INIT(&pipehash[i]);
- SLIST_INIT(&flowsethash[i]);
- }
- ready_heap.size = ready_heap.elements = 0;
- ready_heap.offset = 0;
+ /* init defaults here, MSVC does not accept initializers */
+ /* queue limits */
+ dn_cfg.slot_limit = 100; /* Foot shooting limit for queues. */
+ dn_cfg.byte_limit = 1024 * 1024;
- wfq_ready_heap.size = wfq_ready_heap.elements = 0;
- wfq_ready_heap.offset = 0;
+ /* RED parameters */
+ dn_cfg.red_lookup_depth = 256; /* default lookup table depth */
+ dn_cfg.red_avg_pkt_size = 512; /* default medium packet size */
+ dn_cfg.red_max_pkt_size = 1500; /* default max packet size */
- extract_heap.size = extract_heap.elements = 0;
- extract_heap.offset = 0;
+ /* hash tables */
+ dn_cfg.max_hash_size = 1024; /* max in the hash tables */
+ dn_cfg.hash_size = 64; /* default hash size */
+ /* create hash tables for schedulers and flowsets.
+ * In both we search by key and by pointer.
+ */
+ dn_cfg.schedhash = dn_ht_init(NULL, dn_cfg.hash_size,
+ offsetof(struct dn_schk, schk_next),
+ schk_hash, schk_match, schk_new);
+ dn_cfg.fshash = dn_ht_init(NULL, dn_cfg.hash_size,
+ offsetof(struct dn_fsk, fsk_next),
+ fsk_hash, fsk_match, fsk_new);
+
+ /* bucket index to drain object */
+ dn_cfg.drain_fs = 0;
+ dn_cfg.drain_sch = 0;
+
+ heap_init(&dn_cfg.evheap, 16, offsetof(struct dn_id, id));
+ SLIST_INIT(&dn_cfg.fsu);
+ SLIST_INIT(&dn_cfg.schedlist);
+
+ DN_LOCK_INIT();
ip_dn_ctl_ptr = ip_dn_ctl;
ip_dn_io_ptr = dummynet_io;
@@ -2270,25 +2065,28 @@ ip_dn_init(void)
callout_reset(&dn_timeout, 1, dummynet, NULL);
/* Initialize curr_time adjustment mechanics. */
- getmicrouptime(&prev_t);
+ getmicrouptime(&dn_cfg.prev_t);
}
#ifdef KLD_MODULE
static void
ip_dn_destroy(void)
{
+ DN_BH_WLOCK();
ip_dn_ctl_ptr = NULL;
ip_dn_io_ptr = NULL;
- DUMMYNET_LOCK();
callout_stop(&dn_timeout);
- DUMMYNET_UNLOCK();
+ dummynet_flush();
+ DN_BH_WUNLOCK();
taskqueue_drain(dn_tq, &dn_task);
taskqueue_free(dn_tq);
- dummynet_flush();
+ dn_ht_free(dn_cfg.schedhash, 0);
+ dn_ht_free(dn_cfg.fshash, 0);
+ heap_free(&dn_cfg.evheap);
- DUMMYNET_LOCK_DESTROY();
+ DN_LOCK_DESTROY();
}
#endif /* KLD_MODULE */
@@ -2296,36 +2094,98 @@ static int
dummynet_modevent(module_t mod, int type, void *data)
{
- switch (type) {
- case MOD_LOAD:
+ if (type == MOD_LOAD) {
if (ip_dn_io_ptr) {
- printf("DUMMYNET already loaded\n");
- return EEXIST ;
+ printf("DUMMYNET already loaded\n");
+ return EEXIST ;
}
ip_dn_init();
- break;
-
- case MOD_UNLOAD:
+ return 0;
+ } else if (type == MOD_UNLOAD) {
#if !defined(KLD_MODULE)
printf("dummynet statically compiled, cannot unload\n");
return EINVAL ;
#else
ip_dn_destroy();
+ return 0;
#endif
- break ;
- default:
+ } else
return EOPNOTSUPP;
- break ;
+}
+
+/* modevent helpers for the modules */
+static int
+load_dn_sched(struct dn_alg *d)
+{
+ struct dn_alg *s;
+
+ if (d == NULL)
+ return 1; /* error */
+ ip_dn_init(); /* just in case, we need the lock */
+
+ /* Check that mandatory funcs exists */
+ if (d->enqueue == NULL || d->dequeue == NULL) {
+ D("missing enqueue or dequeue for %s", d->name);
+ return 1;
+ }
+
+ /* Search if scheduler already exists */
+ DN_BH_WLOCK();
+ SLIST_FOREACH(s, &dn_cfg.schedlist, next) {
+ if (strcmp(s->name, d->name) == 0) {
+ D("%s already loaded", d->name);
+ break; /* scheduler already exists */
+ }
+ }
+ if (s == NULL)
+ SLIST_INSERT_HEAD(&dn_cfg.schedlist, d, next);
+ DN_BH_WUNLOCK();
+ D("dn_sched %s %sloaded", d->name, s ? "not ":"");
+ return s ? 1 : 0;
+}
+
+static int
+unload_dn_sched(struct dn_alg *s)
+{
+ struct dn_alg *tmp, *r;
+ int err = EINVAL;
+
+ D("called for %s", s->name);
+
+ DN_BH_WLOCK();
+ SLIST_FOREACH_SAFE(r, &dn_cfg.schedlist, next, tmp) {
+ if (strcmp(s->name, r->name) != 0)
+ continue;
+ D("ref_count = %d", r->ref_count);
+ err = (r->ref_count != 0) ? EBUSY : 0;
+ if (err == 0)
+ SLIST_REMOVE(&dn_cfg.schedlist, r, dn_alg, next);
+ break;
}
- return 0 ;
+ DN_BH_WUNLOCK();
+ D("dn_sched %s %sunloaded", s->name, err ? "not ":"");
+ return err;
+}
+
+int
+dn_sched_modevent(module_t mod, int cmd, void *arg)
+{
+ struct dn_alg *sch = arg;
+
+ if (cmd == MOD_LOAD)
+ return load_dn_sched(sch);
+ else if (cmd == MOD_UNLOAD)
+ return unload_dn_sched(sch);
+ else
+ return EINVAL;
}
static moduledata_t dummynet_mod = {
- "dummynet",
- dummynet_modevent,
- NULL
+ "dummynet", dummynet_modevent, NULL
};
-DECLARE_MODULE(dummynet, dummynet_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
+
+DECLARE_MODULE(dummynet, dummynet_mod,
+ SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY-1);
MODULE_DEPEND(dummynet, ipfw, 2, 2, 2);
MODULE_VERSION(dummynet, 1);
/* end of file */
diff --git a/sys/netinet/ipfw/ip_fw2.c b/sys/netinet/ipfw/ip_fw2.c
index 724536c..e7ad107 100644
--- a/sys/netinet/ipfw/ip_fw2.c
+++ b/sys/netinet/ipfw/ip_fw2.c
@@ -142,6 +142,11 @@ ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr;
ipfw_nat_cfg_t *ipfw_nat_get_log_ptr;
#ifdef SYSCTL_NODE
+uint32_t dummy_def = IPFW_DEFAULT_RULE;
+uint32_t dummy_tables_max = IPFW_TABLES_MAX;
+
+SYSBEGIN(f3)
+
SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, one_pass,
CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_one_pass), 0,
@@ -156,10 +161,10 @@ SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit,
CTLFLAG_RW, &VNET_NAME(verbose_limit), 0,
"Set upper limit of matches of ipfw rules logged");
SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, default_rule, CTLFLAG_RD,
- NULL, IPFW_DEFAULT_RULE,
+ &dummy_def, 0,
"The default/max possible rule number.");
SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, tables_max, CTLFLAG_RD,
- NULL, IPFW_TABLES_MAX,
+ &dummy_tables_max, 0,
"The maximum number of tables.");
SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, default_to_accept, CTLFLAG_RDTUN,
&default_to_accept, 0,
@@ -177,6 +182,8 @@ SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, deny_unknown_exthdrs,
"Deny packets with unknown IPv6 Extension Headers");
#endif /* INET6 */
+SYSEND
+
#endif /* SYSCTL_NODE */
@@ -344,6 +351,7 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
return(1);
}
} else {
+#ifdef __FreeBSD__ /* and OSX too ? */
struct ifaddr *ia;
if_addr_rlock(ifp);
@@ -357,6 +365,7 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
}
}
if_addr_runlock(ifp);
+#endif /* __FreeBSD__ */
}
return(0); /* no match, fail ... */
}
@@ -385,6 +394,9 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
static int
verify_path(struct in_addr src, struct ifnet *ifp, u_int fib)
{
+#ifndef __FreeBSD__
+ return 0;
+#else
struct route ro;
struct sockaddr_in *dst;
@@ -427,6 +439,7 @@ verify_path(struct in_addr src, struct ifnet *ifp, u_int fib)
/* found valid route */
RTFREE(ro.ro_rt);
return 1;
+#endif /* __FreeBSD__ */
}
#ifdef INET6
@@ -634,9 +647,14 @@ send_reject(struct ip_fw_args *args, int code, int iplen, struct ip *ip)
static int
check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip,
- u_int16_t src_port, struct ucred **uc, int *ugid_lookupp,
- struct inpcb *inp)
+ u_int16_t src_port, int *ugid_lookupp,
+ struct ucred **uc, struct inpcb *inp)
{
+#ifndef __FreeBSD__
+ return cred_check(insn, proto, oif,
+ dst_ip, dst_port, src_ip, src_port,
+ (struct bsd_ucred *)uc, ugid_lookupp, ((struct mbuf *)inp)->m_skb);
+#else /* FreeBSD */
struct inpcbinfo *pi;
int wildcard;
struct inpcb *pcb;
@@ -703,6 +721,7 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
else if (insn->o.opcode == O_JAIL)
match = ((*uc)->cr_prison->pr_id == (int)insn->d[0]);
return match;
+#endif /* __FreeBSD__ */
}
/*
@@ -794,7 +813,11 @@ ipfw_chk(struct ip_fw_args *args)
* these types of constraints, as well as decrease contention
* on pcb related locks.
*/
+#ifndef __FreeBSD__
+ struct bsd_ucred ucred_cache;
+#else
struct ucred *ucred_cache = NULL;
+#endif
int ucred_lookup = 0;
/*
@@ -1233,8 +1256,13 @@ do { \
(ipfw_insn_u32 *)cmd,
proto, oif,
dst_ip, dst_port,
- src_ip, src_port, &ucred_cache,
- &ucred_lookup, args->inp);
+ src_ip, src_port, &ucred_lookup,
+#ifdef __FreeBSD__
+ &ucred_cache, args->inp);
+#else
+ (void *)&ucred_cache,
+ (struct inpcb *)args->m);
+#endif
break;
case O_RECV:
@@ -1348,12 +1376,21 @@ do { \
(ipfw_insn_u32 *)cmd,
proto, oif,
dst_ip, dst_port,
- src_ip, src_port, &ucred_cache,
- &ucred_lookup, args->inp);
+ src_ip, src_port, &ucred_lookup,
+#ifdef __FreeBSD__
+ &ucred_cache, args->inp);
if (v == 4 /* O_UID */)
key = ucred_cache->cr_uid;
else if (v == 5 /* O_JAIL */)
key = ucred_cache->cr_prison->pr_id;
+#else /* !__FreeBSD__ */
+ (void *)&ucred_cache,
+ (struct inpcb *)args->m);
+ if (v ==4 /* O_UID */)
+ key = ucred_cache.uid;
+ else if (v == 5 /* O_JAIL */)
+ key = ucred_cache.xid;
+#endif /* !__FreeBSD__ */
key = htonl(key);
} else
break;
@@ -1392,11 +1429,10 @@ do { \
match = (tif != NULL);
break;
}
- /* FALLTHROUGH */
#ifdef INET6
+ /* FALLTHROUGH */
case O_IP6_SRC_ME:
- match = is_ipv6 &&
- search_ip6_addr_net(&args->f_id.src_ip6);
+ match= is_ipv6 && search_ip6_addr_net(&args->f_id.src_ip6);
#endif
break;
@@ -1432,14 +1468,14 @@ do { \
match = (tif != NULL);
break;
}
- /* FALLTHROUGH */
#ifdef INET6
+ /* FALLTHROUGH */
case O_IP6_DST_ME:
- match = is_ipv6 &&
- search_ip6_addr_net(&args->f_id.dst_ip6);
+ match= is_ipv6 && search_ip6_addr_net(&args->f_id.dst_ip6);
#endif
break;
+
case O_IP_SRCPORT:
case O_IP_DSTPORT:
/*
@@ -2164,8 +2200,10 @@ do { \
printf("ipfw: ouch!, skip past end of rules, denying packet\n");
}
IPFW_RUNLOCK(chain);
+#ifdef __FreeBSD__
if (ucred_cache != NULL)
crfree(ucred_cache);
+#endif
return (retval);
pullup_failed:
diff --git a/sys/netinet/ipfw/ip_fw_dynamic.c b/sys/netinet/ipfw/ip_fw_dynamic.c
index ad5599a..3aa8f20 100644
--- a/sys/netinet/ipfw/ip_fw_dynamic.c
+++ b/sys/netinet/ipfw/ip_fw_dynamic.c
@@ -128,7 +128,11 @@ static VNET_DEFINE(struct callout, ipfw_timeout);
#define V_ipfw_timeout VNET(ipfw_timeout)
static uma_zone_t ipfw_dyn_rule_zone;
+#ifndef __FreeBSD__
+DEFINE_SPINLOCK(ipfw_dyn_mtx);
+#else
static struct mtx ipfw_dyn_mtx; /* mutex guarding dynamic rules */
+#endif
#define IPFW_DYN_LOCK_INIT() \
mtx_init(&ipfw_dyn_mtx, "IPFW dynamic rules", NULL, MTX_DEF)
@@ -183,6 +187,9 @@ static VNET_DEFINE(u_int32_t, dyn_max); /* max # of dynamic rules */
#define V_dyn_max VNET(dyn_max)
#ifdef SYSCTL_NODE
+
+SYSBEGIN(f2)
+
SYSCTL_DECL(_net_inet_ip_fw);
SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_buckets,
CTLFLAG_RW, &VNET_NAME(dyn_buckets), 0,
@@ -217,6 +224,9 @@ SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_short_lifetime,
SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_keepalive,
CTLFLAG_RW, &VNET_NAME(dyn_keepalive), 0,
"Enable keepalives for dyn. rules");
+
+SYSEND
+
#endif /* SYSCTL_NODE */
@@ -884,6 +894,9 @@ struct mbuf *
ipfw_send_pkt(struct mbuf *replyto, struct ipfw_flow_id *id, u_int32_t seq,
u_int32_t ack, int flags)
{
+#ifndef __FreeBSD__
+ return NULL;
+#else
struct mbuf *m;
int len, dir;
struct ip *h = NULL; /* stupid compiler */
@@ -1020,6 +1033,7 @@ ipfw_send_pkt(struct mbuf *replyto, struct ipfw_flow_id *id, u_int32_t seq,
}
return (m);
+#endif /* __FreeBSD__ */
}
/*
diff --git a/sys/netinet/ipfw/ip_fw_log.c b/sys/netinet/ipfw/ip_fw_log.c
index a5178db..23a1737 100644
--- a/sys/netinet/ipfw/ip_fw_log.c
+++ b/sys/netinet/ipfw/ip_fw_log.c
@@ -413,6 +413,7 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
(ipoff & IP_MF) ? "+" : "");
}
}
+#ifdef __FreeBSD__
if (oif || m->m_pkthdr.rcvif)
log(LOG_SECURITY | LOG_INFO,
"ipfw: %d %s %s %s via %s%s\n",
@@ -421,6 +422,7 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
oif ? oif->if_xname : m->m_pkthdr.rcvif->if_xname,
fragment);
else
+#endif
log(LOG_SECURITY | LOG_INFO,
"ipfw: %d %s %s [no if info]%s\n",
f ? f->rulenum : -1,
diff --git a/sys/netinet/ipfw/ip_fw_pfil.c b/sys/netinet/ipfw/ip_fw_pfil.c
index a7aa5aa..b4e31d4 100644
--- a/sys/netinet/ipfw/ip_fw_pfil.c
+++ b/sys/netinet/ipfw/ip_fw_pfil.c
@@ -77,6 +77,9 @@ int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
static int ipfw_divert(struct mbuf **, int, struct ipfw_rule_ref *, int);
#ifdef SYSCTL_NODE
+
+SYSBEGIN(f1)
+
SYSCTL_DECL(_net_inet_ip_fw);
SYSCTL_VNET_PROC(_net_inet_ip_fw, OID_AUTO, enable,
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_enable), 0,
@@ -87,6 +90,9 @@ SYSCTL_VNET_PROC(_net_inet6_ip6_fw, OID_AUTO, enable,
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw6_enable), 0,
ipfw_chg_hook, "I", "Enable ipfw+6");
#endif /* INET6 */
+
+SYSEND
+
#endif /* SYSCTL_NODE */
/*
@@ -94,7 +100,7 @@ SYSCTL_VNET_PROC(_net_inet6_ip6_fw, OID_AUTO, enable,
* dummynet, divert, netgraph or other modules.
* The packet may be consumed.
*/
-static int
+int
ipfw_check_hook(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
struct inpcb *inp)
{
diff --git a/sys/netinet/ipfw/ip_fw_private.h b/sys/netinet/ipfw/ip_fw_private.h
index 92508f1..094c22f 100644
--- a/sys/netinet/ipfw/ip_fw_private.h
+++ b/sys/netinet/ipfw/ip_fw_private.h
@@ -35,6 +35,18 @@
#ifdef _KERNEL
+/*
+ * For platforms that do not have SYSCTL support, we wrap the
+ * SYSCTL_* into a function (one per file) to collect the values
+ * into an array at module initialization. The wrapping macros,
+ * SYSBEGIN() and SYSEND, are empty in the default case.
+ */
+#ifndef SYSBEGIN
+#define SYSBEGIN(x)
+#endif
+#ifndef SYSEND
+#define SYSEND
+#endif
/* Return values from ipfw_chk() */
enum {
@@ -119,7 +131,13 @@ enum {
};
/* wrapper for freeing a packet, in case we need to do more work */
+#ifndef FREE_PKT
+#if defined(__linux__) || defined(_WIN32)
+#define FREE_PKT(m) netisr_dispatch(-1, m)
+#else
#define FREE_PKT(m) m_freem(m)
+#endif
+#endif /* !FREE_PKT */
/*
* Function definitions.
@@ -199,8 +217,13 @@ struct ip_fw_chain {
struct ip_fw **map; /* array of rule ptrs to ease lookup */
LIST_HEAD(nat_list, cfg_nat) nat; /* list of nat entries */
struct radix_node_head *tables[IPFW_TABLES_MAX];
+#if defined( __linux__ ) || defined( _WIN32 )
+ spinlock_t rwmtx;
+ spinlock_t uh_lock;
+#else
struct rwlock rwmtx;
struct rwlock uh_lock; /* lock for upper half */
+#endif
uint32_t id; /* ruleset id */
};
@@ -240,6 +263,10 @@ int ipfw_ctl(struct sockopt *sopt);
int ipfw_chk(struct ip_fw_args *args);
void ipfw_reap_rules(struct ip_fw *head);
+/* In ip_fw_pfil */
+int ipfw_check_hook(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
+ struct inpcb *inp);
+
/* In ip_fw_table.c */
struct radix_node;
int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
diff --git a/sys/netinet/ipfw/ip_fw_sockopt.c b/sys/netinet/ipfw/ip_fw_sockopt.c
index 3d0fc55..f61c126 100644
--- a/sys/netinet/ipfw/ip_fw_sockopt.c
+++ b/sys/netinet/ipfw/ip_fw_sockopt.c
@@ -115,7 +115,8 @@ get_map(struct ip_fw_chain *chain, int extra, int locked)
int i;
i = chain->n_rules + extra;
- map = malloc(i * sizeof(struct ip_fw *), M_IPFW, M_WAITOK);
+ map = malloc(i * sizeof(struct ip_fw *), M_IPFW,
+ locked ? M_NOWAIT : M_WAITOK);
if (map == NULL) {
printf("%s: cannot allocate map\n", __FUNCTION__);
return NULL;
@@ -771,6 +772,44 @@ bad_size:
return EINVAL;
}
+
+/*
+ * Translation of requests for compatibility with FreeBSD 7.2/8.
+ * a static variable tells us if we have an old client from userland,
+ * and if necessary we translate requests and responses between the
+ * two formats.
+ */
+static int is7 = 0;
+
+struct ip_fw7 {
+ struct ip_fw7 *next; /* linked list of rules */
+ struct ip_fw7 *next_rule; /* ptr to next [skipto] rule */
+ /* 'next_rule' is used to pass up 'set_disable' status */
+
+ uint16_t act_ofs; /* offset of action in 32-bit units */
+ uint16_t cmd_len; /* # of 32-bit words in cmd */
+ uint16_t rulenum; /* rule number */
+ uint8_t set; /* rule set (0..31) */
+ // #define RESVD_SET 31 /* set for default and persistent rules */
+ uint8_t _pad; /* padding */
+ // uint32_t id; /* rule id, only in v.8 */
+ /* These fields are present in all rules. */
+ uint64_t pcnt; /* Packet counter */
+ uint64_t bcnt; /* Byte counter */
+ uint32_t timestamp; /* tv_sec of last match */
+
+ ipfw_insn cmd[1]; /* storage for commands */
+};
+
+ int convert_rule_to_7(struct ip_fw *rule);
+int convert_rule_to_8(struct ip_fw *rule);
+
+#ifndef RULESIZE7
+#define RULESIZE7(rule) (sizeof(struct ip_fw7) + \
+ ((struct ip_fw7 *)(rule))->cmd_len * 4 - 4)
+#endif
+
+
/*
* Copy the static and dynamic rules to the supplied buffer
* and return the amount of space actually used.
@@ -788,6 +827,32 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
boot_seconds = boottime.tv_sec;
for (i = 0; i < chain->n_rules; i++) {
rule = chain->map[i];
+
+ if (is7) {
+ /* Convert rule to FreeBSd 7.2 format */
+ l = RULESIZE7(rule);
+ if (bp + l + sizeof(uint32_t) <= ep) {
+ int error;
+ bcopy(rule, bp, l + sizeof(uint32_t));
+ error = convert_rule_to_7((struct ip_fw *) bp);
+ if (error)
+ return 0; /*XXX correct? */
+ /*
+ * XXX HACK. Store the disable mask in the "next"
+ * pointer in a wild attempt to keep the ABI the same.
+ * Why do we do this on EVERY rule?
+ */
+ bcopy(&V_set_disable,
+ &(((struct ip_fw7 *)bp)->next_rule),
+ sizeof(V_set_disable));
+ if (((struct ip_fw7 *)bp)->timestamp)
+ ((struct ip_fw7 *)bp)->timestamp += boot_seconds;
+ bp += l;
+ }
+ continue; /* go to next rule */
+ }
+
+ /* normal mode, don't touch rules */
l = RULESIZE(rule);
if (bp + l > ep) { /* should not happen */
printf("overflow dumping static rules\n");
@@ -887,15 +952,42 @@ ipfw_ctl(struct sockopt *sopt)
rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK);
error = sooptcopyin(sopt, rule, RULE_MAXSIZE,
sizeof(struct ip_fw) );
+
+ /*
+ * If the size of commands equals RULESIZE7 then we assume
+ * a FreeBSD7.2 binary is talking to us (set is7=1).
+ * is7 is persistent so the next 'ipfw list' command
+ * will use this format.
+ * NOTE: If wrong version is guessed (this can happen if
+ * the first ipfw command is 'ipfw [pipe] list')
+ * the ipfw binary may crash or loop infinitly...
+ */
+ if (sopt->sopt_valsize == RULESIZE7(rule)) {
+ is7 = 1;
+ error = convert_rule_to_8(rule);
+ if (error)
+ return error;
+ if (error == 0)
+ error = check_ipfw_struct(rule, RULESIZE(rule));
+ } else {
+ is7 = 0;
if (error == 0)
error = check_ipfw_struct(rule, sopt->sopt_valsize);
+ }
if (error == 0) {
/* locking is done within ipfw_add_rule() */
error = ipfw_add_rule(chain, rule);
size = RULESIZE(rule);
- if (!error && sopt->sopt_dir == SOPT_GET)
+ if (!error && sopt->sopt_dir == SOPT_GET) {
+ if (is7) {
+ error = convert_rule_to_7(rule);
+ size = RULESIZE7(rule);
+ if (error)
+ return error;
+ }
error = sooptcopyout(sopt, rule, size);
}
+ }
free(rule, M_TEMP);
break;
@@ -1078,4 +1170,104 @@ ipfw_ctl(struct sockopt *sopt)
return (error);
#undef RULE_MAXSIZE
}
+
+
+#define RULE_MAXSIZE (256*sizeof(u_int32_t))
+
+/* Functions to convert rules 7.2 <==> 8.0 */
+int
+convert_rule_to_7(struct ip_fw *rule)
+{
+ /* Used to modify original rule */
+ struct ip_fw7 *rule7 = (struct ip_fw7 *)rule;
+ /* copy of original rule, version 8 */
+ struct ip_fw *tmp;
+
+ /* Used to copy commands */
+ ipfw_insn *ccmd, *dst;
+ int ll = 0, ccmdlen = 0;
+
+ tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO);
+ if (tmp == NULL) {
+ return 1; //XXX error
+ }
+ bcopy(rule, tmp, RULE_MAXSIZE);
+
+ /* Copy fields */
+ rule7->_pad = tmp->_pad;
+ rule7->set = tmp->set;
+ rule7->rulenum = tmp->rulenum;
+ rule7->cmd_len = tmp->cmd_len;
+ rule7->act_ofs = tmp->act_ofs;
+ rule7->next_rule = (struct ip_fw7 *)tmp->next_rule;
+ rule7->next = (struct ip_fw7 *)tmp->x_next;
+ rule7->cmd_len = tmp->cmd_len;
+ rule7->pcnt = tmp->pcnt;
+ rule7->bcnt = tmp->bcnt;
+ rule7->timestamp = tmp->timestamp;
+
+ /* Copy commands */
+ for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule7->cmd ;
+ ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) {
+ ccmdlen = F_LEN(ccmd);
+
+ bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t));
+ if (ccmdlen > ll) {
+ printf("ipfw: opcode %d size truncated\n",
+ ccmd->opcode);
+ return EINVAL;
+ }
+ }
+ free(tmp, M_TEMP);
+
+ return 0;
+}
+
+int
+convert_rule_to_8(struct ip_fw *rule)
+{
+ /* Used to modify original rule */
+ struct ip_fw7 *rule7 = (struct ip_fw7 *) rule;
+
+ /* Used to copy commands */
+ ipfw_insn *ccmd, *dst;
+ int ll = 0, ccmdlen = 0;
+
+ /* Copy of original rule */
+ struct ip_fw7 *tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO);
+ if (tmp == NULL) {
+ return 1; //XXX error
+ }
+
+ bcopy(rule7, tmp, RULE_MAXSIZE);
+
+ for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule->cmd ;
+ ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) {
+ ccmdlen = F_LEN(ccmd);
+
+ bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t));
+ if (ccmdlen > ll) {
+ printf("ipfw: opcode %d size truncated\n",
+ ccmd->opcode);
+ return EINVAL;
+ }
+ }
+
+ rule->_pad = tmp->_pad;
+ rule->set = tmp->set;
+ rule->rulenum = tmp->rulenum;
+ rule->cmd_len = tmp->cmd_len;
+ rule->act_ofs = tmp->act_ofs;
+ rule->next_rule = (struct ip_fw *)tmp->next_rule;
+ rule->x_next = (struct ip_fw *)tmp->next;
+ rule->cmd_len = tmp->cmd_len;
+ rule->id = 0; /* XXX see if is ok = 0 */
+ rule->pcnt = tmp->pcnt;
+ rule->bcnt = tmp->bcnt;
+ rule->timestamp = tmp->timestamp;
+
+ free (tmp, M_TEMP);
+ return 0;
+}
+
/* end of file */
diff --git a/sys/netinet/ipfw/ip_fw_table.c b/sys/netinet/ipfw/ip_fw_table.c
index 0d8625a..5854e97 100644
--- a/sys/netinet/ipfw/ip_fw_table.c
+++ b/sys/netinet/ipfw/ip_fw_table.c
@@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
#include <netinet/ip_var.h> /* struct ipfw_rule_ref */
#include <netinet/ip_fw.h>
+#include <sys/queue.h> /* LIST_HEAD */
#include <netinet/ipfw/ip_fw_private.h>
#ifdef MAC
diff --git a/sys/netinet/ipfw/test/Makefile b/sys/netinet/ipfw/test/Makefile
new file mode 100644
index 0000000..bbeb942
--- /dev/null
+++ b/sys/netinet/ipfw/test/Makefile
@@ -0,0 +1,50 @@
+#
+# $FreeBSD$
+#
+# Makefile for building userland tests
+# this is written in a form compatible with gmake
+
+SCHED_SRCS = test_dn_sched.c
+SCHED_SRCS += dn_sched_fifo.c
+SCHED_SRCS += dn_sched_wf2q.c
+SCHED_SRCS += dn_sched_qfq.c
+SCHED_SRCS += dn_sched_rr.c
+SCHED_SRCS += dn_heap.c
+SCHED_SRCS += main.c
+
+SCHED_OBJS=$(SCHED_SRCS:.c=.o)
+
+HEAP_SRCS = dn_heap.c test_dn_heap.c
+HEAP_OBJS=$(HEAP_SRCS:.c=.o)
+
+VPATH= .:..
+
+CFLAGS = -I.. -I. -Wall -Werror -O3 -DIPFW
+TARGETS= test_sched # no test_heap by default
+
+all: $(TARGETS)
+
+test_heap : $(HEAP_OBJS)
+ $(CC) -o $@ $(HEAP_OBJS)
+
+test_sched : $(SCHED_OBJS)
+ $(CC) -o $@ $(SCHED_OBJS)
+
+$(SCHED_OBJS): dn_test.h
+main.o: mylist.h
+
+clean:
+ - rm *.o $(TARGETS) *.core
+
+ALLSRCS = $(SCHED_SRCS) dn_test.h mylist.h \
+ dn_sched.h dn_heap.h ip_dn_private.h Makefile
+TMPBASE = /tmp/testXYZ
+TMPDIR = $(TMPBASE)/test
+
+tgz:
+ -rm -rf $(TMPDIR)
+ mkdir -p $(TMPDIR)
+ -cp -p $(ALLSRCS) $(TMPDIR)
+ -(cd ..; cp -p $(ALLSRCS) $(TMPDIR))
+ ls -la $(TMPDIR)
+ (cd $(TMPBASE); tar cvzf /tmp/test.tgz test)
diff --git a/sys/netinet/ipfw/test/dn_test.h b/sys/netinet/ipfw/test/dn_test.h
new file mode 100644
index 0000000..c56aa6a
--- /dev/null
+++ b/sys/netinet/ipfw/test/dn_test.h
@@ -0,0 +1,155 @@
+/*
+ * $FreeBSD$
+ *
+ * userspace compatibility code for dummynet schedulers
+ */
+
+#ifndef _DN_TEST_H
+#define _DN_TEST_H
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h> /* bzero, ffs, ... */
+#include <string.h> /* strcmp */
+#include <errno.h>
+#include <inttypes.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+
+extern int debug;
+#define ND(fmt, args...) do {} while (0)
+#define D1(fmt, args...) do {} while (0)
+#define D(fmt, args...) fprintf(stderr, "%-8s " fmt "\n", \
+ __FUNCTION__, ## args)
+#define DX(lev, fmt, args...) do { \
+ if (debug > lev) D(fmt, ## args); } while (0)
+
+
+#define offsetof(t,m) (int)((&((t *)0L)->m))
+
+#include <mylist.h>
+
+/* prevent include of other system headers */
+#define _NETINET_IP_VAR_H_ /* ip_fw_args */
+#define _IPFW2_H
+#define _SYS_MBUF_H_
+
+enum {
+ DN_QUEUE,
+};
+
+enum {
+ DN_SCHED_FIFO,
+ DN_SCHED_WF2QP,
+};
+
+struct dn_id {
+ int type, subtype, len, id;
+};
+struct dn_fs {
+ int par[4]; /* flowset parameters */
+
+ /* simulation entries.
+ * 'index' is not strictly necessary
+ * y is used for the inverse mapping ,
+ */
+ int index;
+ int y; /* inverse mapping */
+ int base_y; /* inverse mapping */
+ int next_y; /* inverse mapping */
+ int n_flows;
+ int first_flow;
+ int next_flow; /* first_flow + n_flows */
+ /*
+ * when generating, let 'cur' go from 0 to n_flows-1,
+ * then point to flow first_flow + cur
+ */
+ int cur;
+};
+struct dn_sch {
+};
+struct dn_flow {
+ struct dn_id oid;
+ int length;
+ int len_bytes;
+ int drops;
+ uint64_t tot_bytes;
+ uint32_t flow_id;
+ struct list_head h; /* used by the generator */
+};
+struct dn_link {
+};
+
+struct ip_fw_args {
+};
+
+struct mbuf {
+ struct {
+ int len;
+ } m_pkthdr;
+ struct mbuf *m_nextpkt;
+ int flow_id; /* for testing, index of a flow */
+ //int flowset_id; /* for testing, index of a flowset */
+ void *cfg; /* config args */
+};
+
+#define MALLOC_DECLARE(x)
+#define KASSERT(x, y) do { if (!(x)) printf y ; exit(0); } while (0)
+struct ipfw_flow_id {
+};
+
+typedef void * module_t;
+struct _md_t {
+ const char *name;
+ int (*f)(module_t, int, void *);
+ void *p;
+};
+typedef struct _md_t moduledata_t;
+#define DECLARE_MODULE(name, b, c, d) \
+ moduledata_t *_g_##name = & b
+#define MODULE_DEPEND(a, b, c, d, e)
+
+#ifdef IPFW
+#include <dn_heap.h>
+#include <ip_dn_private.h>
+#include <dn_sched.h>
+#else
+struct dn_queue {
+ struct dn_fsk *fs; /* parent flowset. */
+ struct dn_sch_inst *_si; /* parent sched instance. */
+};
+struct dn_schk {
+};
+struct dn_fsk {
+ struct dn_fs fs;
+ struct dn_schk *sched;
+};
+struct dn_sch_inst {
+ struct dn_schk *sched;
+};
+struct dn_alg {
+ int type;
+ const char *name;
+ void *enqueue, *dequeue;
+ int q_datalen, si_datalen, schk_datalen;
+ int (*config)(struct dn_schk *);
+ int (*new_sched)(struct dn_sch_inst *);
+ int (*new_fsk)(struct dn_fsk *);
+ int (*new_queue)(struct dn_queue *q);
+};
+
+#endif
+
+static inline void
+mq_append(struct mq *q, struct mbuf *m)
+{
+ if (q->head == NULL)
+ q->head = m;
+ else
+ q->tail->m_nextpkt = m;
+ q->tail = m;
+ m->m_nextpkt = NULL;
+}
+
+#endif /* _DN_TEST_H */
diff --git a/sys/netinet/ipfw/test/main.c b/sys/netinet/ipfw/test/main.c
new file mode 100644
index 0000000..be9fdf5
--- /dev/null
+++ b/sys/netinet/ipfw/test/main.c
@@ -0,0 +1,636 @@
+/*
+ * $FreeBSD$
+ *
+ * Testing program for schedulers
+ *
+ * The framework include a simple controller which, at each
+ * iteration, decides whether we can enqueue and/or dequeue.
+ * Then the mainloop runs the required number of tests,
+ * keeping track of statistics.
+ */
+
+#include "dn_test.h"
+
+struct q_list {
+ struct list_head h;
+};
+
+struct cfg_s {
+ int ac;
+ char * const *av;
+
+ const char *name;
+ int loops;
+ struct timeval time;
+
+ /* running counters */
+ uint32_t _enqueue;
+ uint32_t drop;
+ uint32_t pending;
+ uint32_t dequeue;
+
+ /* generator parameters */
+ int th_min, th_max;
+ int maxburst;
+ int lmin, lmax; /* packet len */
+ int flows; /* number of flows */
+ int flowsets; /* number of flowsets */
+ int wsum; /* sum of weights of all flows */
+ int max_y; /* max random number in the generation */
+ int cur_y, cur_fs; /* used in generation, between 0 and max_y - 1 */
+ const char *fs_config; /* flowset config */
+ int can_dequeue;
+ int burst; /* count of packets sent in a burst */
+ struct mbuf *tosend; /* packet to send -- also flag to enqueue */
+
+ struct mbuf *freelist;
+
+ struct mbuf *head, *tail; /* a simple tailq */
+
+ /* scheduler hooks */
+ int (*enq)(struct dn_sch_inst *, struct dn_queue *,
+ struct mbuf *);
+ struct mbuf * (*deq)(struct dn_sch_inst *);
+ /* size of the three fields including sched-specific areas */
+ int schk_len;
+ int q_len; /* size of a queue including sched-fields */
+ int si_len; /* size of a sch_inst including sched-fields */
+ char *q; /* array of flow queues */
+ /* use a char* because size is variable */
+ struct dn_fsk *fs; /* array of flowsets */
+ struct dn_sch_inst *si;
+ struct dn_schk *sched;
+
+ /* generator state */
+ int state; /* 0 = going up, 1: going down */
+
+ /*
+ * We keep lists for each backlog level, and always serve
+ * the one with shortest backlog. llmask contains a bitmap
+ * of lists, and ll are the heads of the lists. The last
+ * entry (BACKLOG) contains all entries considered 'full'
+ * XXX to optimize things, entry i could contain queues with
+ * 2^{i-1}+1 .. 2^i entries.
+ */
+#define BACKLOG 30
+ uint32_t llmask;
+ struct list_head ll[BACKLOG + 10];
+};
+
+/* FI2Q and Q2FI converts from flow_id to dn_queue and back.
+ * We cannot easily use pointer arithmetic because it is variable size.
+ */
+#define FI2Q(c, i) ((struct dn_queue *)((c)->q + (c)->q_len * (i)))
+#define Q2FI(c, q) (((char *)(q) - (c)->q)/(c)->q_len)
+
+int debug = 0;
+
+struct dn_parms dn_cfg;
+
+static void controller(struct cfg_s *c);
+
+/* release a packet: put the mbuf in the freelist, and the queue in
+ * the bucket.
+ */
+int
+drop(struct cfg_s *c, struct mbuf *m)
+{
+ struct dn_queue *q;
+ int i;
+
+ c->drop++;
+ q = FI2Q(c, m->flow_id);
+ i = q->ni.length; // XXX or ffs...
+
+ ND("q %p id %d current length %d", q, m->flow_id, i);
+ if (i < BACKLOG) {
+ struct list_head *h = &q->ni.h;
+ c->llmask &= ~(1<<(i+1));
+ c->llmask |= (1<<(i));
+ list_del(h);
+ list_add_tail(h, &c->ll[i]);
+ }
+ m->m_nextpkt = c->freelist;
+ c->freelist = m;
+ return 0;
+}
+
+/* dequeue returns NON-NULL when a packet is dropped */
+static int
+enqueue(struct cfg_s *c, void *_m)
+{
+ struct mbuf *m = _m;
+ if (c->enq)
+ return c->enq(c->si, FI2Q(c, m->flow_id), m);
+ if (c->head == NULL)
+ c->head = m;
+ else
+ c->tail->m_nextpkt = m;
+ c->tail = m;
+ return 0; /* default - success */
+}
+
+/* dequeue returns NON-NULL when a packet is available */
+static void *
+dequeue(struct cfg_s *c)
+{
+ struct mbuf *m;
+ if (c->deq)
+ return c->deq(c->si);
+ if ((m = c->head)) {
+ m = c->head;
+ c->head = m->m_nextpkt;
+ m->m_nextpkt = NULL;
+ }
+ return m;
+}
+
+static int
+mainloop(struct cfg_s *c)
+{
+ int i;
+ struct mbuf *m;
+
+ for (i=0; i < c->loops; i++) {
+ /* implement histeresis */
+ controller(c);
+ DX(3, "loop %d enq %d send %p rx %d",
+ i, c->_enqueue, c->tosend, c->can_dequeue);
+ if ( (m = c->tosend) ) {
+ c->_enqueue++;
+ if (enqueue(c, m)) {
+ drop(c, m);
+ ND("loop %d enqueue fail", i );
+ } else {
+ ND("enqueue ok");
+ c->pending++;
+ }
+ }
+ if (c->can_dequeue) {
+ c->dequeue++;
+ if ((m = dequeue(c))) {
+ c->pending--;
+ drop(c, m);
+ c->drop--; /* compensate */
+ }
+ }
+ }
+ DX(1, "mainloop ends %d", i);
+ return 0;
+}
+
+int
+dump(struct cfg_s *c)
+{
+ int i;
+ struct dn_queue *q;
+
+ for (i=0; i < c->flows; i++) {
+ q = FI2Q(c, i);
+ DX(1, "queue %4d tot %10lld", i, q->ni.tot_bytes);
+ }
+ DX(1, "done %d loops\n", c->loops);
+ return 0;
+}
+
+/* interpret a number in human form */
+static long
+getnum(const char *s, char **next, const char *key)
+{
+ char *end = NULL;
+ long l;
+
+ if (next) /* default */
+ *next = NULL;
+ if (s && *s) {
+ DX(3, "token is <%s> %s", s, key ? key : "-");
+ l = strtol(s, &end, 0);
+ } else {
+ DX(3, "empty string");
+ l = -1;
+ }
+ if (l < 0) {
+ DX(2, "invalid %s for %s", s ? s : "NULL", (key ? key : "") );
+ return 0; // invalid
+ }
+ if (!end || !*end)
+ return l;
+ if (*end == 'n')
+ l = -l; /* multiply by n */
+ else if (*end == 'K')
+ l = l*1000;
+ else if (*end == 'M')
+ l = l*1000000;
+ else if (*end == 'k')
+ l = l*1024;
+ else if (*end == 'm')
+ l = l*1024*1024;
+ else if (*end == 'w')
+ ;
+ else {/* not recognized */
+ D("suffix %s for %s, next %p", end, key, next);
+ end--;
+ }
+ end++;
+ DX(3, "suffix now %s for %s, next %p", end, key, next);
+ if (next && *end) {
+ DX(3, "setting next to %s for %s", end, key);
+ *next = end;
+ }
+ return l;
+}
+
+/*
+ * flowsets are a comma-separated list of
+ * weight:maxlen:flows
+ * indicating how many flows are hooked to that fs.
+ * Both weight and range can be min-max-steps.
+ * In a first pass we just count the number of flowsets and flows,
+ * in a second pass we complete the setup.
+ */
+static void
+parse_flowsets(struct cfg_s *c, const char *fs, int pass)
+{
+ char *s, *cur, *next;
+ int n_flows = 0, n_fs = 0, wsum = 0;
+ int i, j;
+ struct dn_fs *prev = NULL;
+
+ DX(3, "--- pass %d flows %d flowsets %d", pass, c->flows, c->flowsets);
+ if (pass == 0)
+ c->fs_config = fs;
+ s = c->fs_config ? strdup(c->fs_config) : NULL;
+ if (s == NULL) {
+ if (pass == 0)
+ D("no fsconfig");
+ return;
+ }
+ for (next = s; (cur = strsep(&next, ","));) {
+ char *p = NULL;
+ int w, w_h, w_steps, wi;
+ int len, len_h, l_steps, li;
+ int flows;
+
+ w = getnum(strsep(&cur, ":"), &p, "weight");
+ if (w <= 0)
+ w = 1;
+ w_h = p ? getnum(p+1, &p, "weight_max") : w;
+ w_steps = p ? getnum(p+1, &p, "w_steps") : (w_h == w ?1:2);
+ len = getnum(strsep(&cur, ":"), &p, "len");
+ if (len <= 0)
+ len = 1000;
+ len_h = p ? getnum(p+1, &p, "len_max") : len;
+ l_steps = p ? getnum(p+1, &p, "l_steps") : (len_h == len ? 1 : 2);
+ flows = getnum(strsep(&cur, ":"), NULL, "flows");
+ if (flows == 0)
+ flows = 1;
+ DX(4, "weight %d..%d (%d) len %d..%d (%d) flows %d",
+ w, w_h, w_steps, len, len_h, l_steps, flows);
+ if (w == 0 || w_h < w || len == 0 || len_h < len ||
+ flows == 0) {
+ DX(4,"wrong parameters %s", fs);
+ return;
+ }
+ n_flows += flows * w_steps * l_steps;
+ for (i = 0; i < w_steps; i++) {
+ wi = w + ((w_h - w)* i)/(w_steps == 1 ? 1 : (w_steps-1));
+ for (j = 0; j < l_steps; j++, n_fs++) {
+ struct dn_fs *fs = &c->fs[n_fs].fs; // tentative
+ int x;
+
+ li = len + ((len_h - len)* j)/(l_steps == 1 ? 1 : (l_steps-1));
+ x = (wi*2048)/li;
+ DX(3, "----- fs %4d weight %4d lmax %4d X %4d flows %d",
+ n_fs, wi, li, x, flows);
+ if (pass == 0)
+ continue;
+ if (c->fs == NULL || c->flowsets <= n_fs) {
+ D("error in number of flowsets");
+ return;
+ }
+ wsum += wi * flows;
+ fs->par[0] = wi;
+ fs->par[1] = li;
+ fs->index = n_fs;
+ fs->n_flows = flows;
+ fs->cur = fs->first_flow = prev==NULL ? 0 : prev->next_flow;
+ fs->next_flow = fs->first_flow + fs->n_flows;
+ fs->y = x * flows;
+ fs->base_y = (prev == NULL) ? 0 : prev->next_y;
+ fs->next_y = fs->base_y + fs->y;
+ prev = fs;
+ }
+ }
+ }
+ c->max_y = prev ? prev->base_y + prev->y : 0;
+ c->flows = n_flows;
+ c->flowsets = n_fs;
+ c->wsum = wsum;
+ if (pass == 0)
+ return;
+
+ /* now link all flows to their parent flowsets */
+ DX(1,"%d flows on %d flowsets max_y %d", c->flows, c->flowsets, c->max_y);
+ for (i=0; i < c->flowsets; i++) {
+ struct dn_fs *fs = &c->fs[i].fs;
+ DX(1, "fs %3d w %5d l %4d flow %5d .. %5d y %6d .. %6d",
+ i, fs->par[0], fs->par[1],
+ fs->first_flow, fs->next_flow,
+ fs->base_y, fs->next_y);
+ for (j = fs->first_flow; j < fs->next_flow; j++) {
+ struct dn_queue *q = FI2Q(c, j);
+ q->fs = &c->fs[i];
+ }
+ }
+}
+
+static int
+init(struct cfg_s *c)
+{
+ int i;
+ int ac = c->ac;
+ char * const *av = c->av;
+
+ c->si_len = sizeof(struct dn_sch_inst);
+ c->q_len = sizeof(struct dn_queue);
+ moduledata_t *mod = NULL;
+ struct dn_alg *p = NULL;
+
+ c->th_min = 0;
+ c->th_max = -20;/* 20 packets per flow */
+ c->lmin = c->lmax = 1280; /* packet len */
+ c->flows = 1;
+ c->flowsets = 1;
+ c->name = "null";
+ ac--; av++;
+ while (ac > 1) {
+ if (!strcmp(*av, "-n")) {
+ c->loops = getnum(av[1], NULL, av[0]);
+ } else if (!strcmp(*av, "-d")) {
+ debug = atoi(av[1]);
+ } else if (!strcmp(*av, "-alg")) {
+ extern moduledata_t *_g_dn_fifo;
+ extern moduledata_t *_g_dn_wf2qp;
+ extern moduledata_t *_g_dn_rr;
+ extern moduledata_t *_g_dn_qfq;
+#ifdef WITH_KPS
+ extern moduledata_t *_g_dn_kps;
+#endif
+ if (!strcmp(av[1], "rr"))
+ mod = _g_dn_rr;
+ else if (!strcmp(av[1], "wf2qp"))
+ mod = _g_dn_wf2qp;
+ else if (!strcmp(av[1], "fifo"))
+ mod = _g_dn_fifo;
+ else if (!strcmp(av[1], "qfq"))
+ mod = _g_dn_qfq;
+#ifdef WITH_KPS
+ else if (!strcmp(av[1], "kps"))
+ mod = _g_dn_kps;
+#endif
+ else
+ mod = NULL;
+ c->name = mod ? mod->name : "NULL";
+ DX(3, "using scheduler %s", c->name);
+ } else if (!strcmp(*av, "-len")) {
+ c->lmin = getnum(av[1], NULL, av[0]);
+ c->lmax = c->lmin;
+ DX(3, "setting max to %d", c->th_max);
+ } else if (!strcmp(*av, "-burst")) {
+ c->maxburst = getnum(av[1], NULL, av[0]);
+ DX(3, "setting max to %d", c->th_max);
+ } else if (!strcmp(*av, "-qmax")) {
+ c->th_max = getnum(av[1], NULL, av[0]);
+ DX(3, "setting max to %d", c->th_max);
+ } else if (!strcmp(*av, "-qmin")) {
+ c->th_min = getnum(av[1], NULL, av[0]);
+ DX(3, "setting min to %d", c->th_min);
+ } else if (!strcmp(*av, "-flows")) {
+ c->flows = getnum(av[1], NULL, av[0]);
+ DX(3, "setting flows to %d", c->flows);
+ } else if (!strcmp(*av, "-flowsets")) {
+ parse_flowsets(c, av[1], 0);
+ DX(3, "setting flowsets to %d", c->flowsets);
+ } else {
+ D("option %s not recognised, ignore", *av);
+ }
+ ac -= 2; av += 2;
+ }
+ if (c->maxburst <= 0)
+ c->maxburst = 1;
+ if (c->loops <= 0)
+ c->loops = 1;
+ if (c->flows <= 0)
+ c->flows = 1;
+ if (c->flowsets <= 0)
+ c->flowsets = 1;
+ if (c->lmin <= 0)
+ c->lmin = 1;
+ if (c->lmax <= 0)
+ c->lmax = 1;
+ /* multiply by N */
+ if (c->th_min < 0)
+ c->th_min = c->flows * -c->th_min;
+ if (c->th_max < 0)
+ c->th_max = c->flows * -c->th_max;
+ if (c->th_max <= c->th_min)
+ c->th_max = c->th_min + 1;
+ if (mod) {
+ p = mod->p;
+ DX(3, "using module %s f %p p %p", mod->name, mod->f, mod->p);
+ DX(3, "modname %s ty %d", p->name, p->type);
+ c->enq = p->enqueue;
+ c->deq = p->dequeue;
+ c->si_len += p->si_datalen;
+ c->q_len += p->q_datalen;
+ c->schk_len += p->schk_datalen;
+ }
+ /* allocate queues, flowsets and one scheduler */
+ c->q = calloc(c->flows, c->q_len);
+ c->fs = calloc(c->flowsets, sizeof(struct dn_fsk));
+ c->si = calloc(1, c->si_len);
+ c->sched = calloc(c->flows, c->schk_len);
+ if (c->q == NULL || c->fs == NULL) {
+ D("error allocating memory for flows");
+ exit(1);
+ }
+ c->si->sched = c->sched;
+ if (p) {
+ if (p->config)
+ p->config(c->sched);
+ if (p->new_sched)
+ p->new_sched(c->si);
+ }
+ /* parse_flowsets links queues to their flowsets */
+ parse_flowsets(c, av[1], 1);
+ /* complete the work calling new_fsk */
+ for (i = 0; i < c->flowsets; i++) {
+ if (c->fs[i].fs.par[1] == 0)
+ c->fs[i].fs.par[1] = 1000; /* default pkt len */
+ c->fs[i].sched = c->sched;
+ if (p && p->new_fsk)
+ p->new_fsk(&c->fs[i]);
+ }
+
+ /* initialize the lists for the generator, and put
+ * all flows in the list for backlog = 0
+ */
+ for (i=0; i <= BACKLOG+5; i++)
+ INIT_LIST_HEAD(&c->ll[i]);
+
+ for (i = 0; i < c->flows; i++) {
+ struct dn_queue *q = FI2Q(c, i);
+ if (q->fs == NULL)
+ q->fs = &c->fs[0]; /* XXX */
+ q->_si = c->si;
+ if (p && p->new_queue)
+ p->new_queue(q);
+ INIT_LIST_HEAD(&q->ni.h);
+ list_add_tail(&q->ni.h, &c->ll[0]);
+ }
+ c->llmask = 1;
+ return 0;
+}
+
+
+int
+main(int ac, char *av[])
+{
+ struct cfg_s c;
+ struct timeval end;
+ double ll;
+ int i;
+ char msg[40];
+
+ bzero(&c, sizeof(c));
+ c.ac = ac;
+ c.av = av;
+ init(&c);
+ gettimeofday(&c.time, NULL);
+ mainloop(&c);
+ gettimeofday(&end, NULL);
+ end.tv_sec -= c.time.tv_sec;
+ end.tv_usec -= c.time.tv_usec;
+ if (end.tv_usec < 0) {
+ end.tv_usec += 1000000;
+ end.tv_sec--;
+ }
+ c.time = end;
+ ll = end.tv_sec*1000000 + end.tv_usec;
+ ll *= 1000; /* convert to nanoseconds */
+ ll /= c._enqueue;
+ sprintf(msg, "1::%d", c.flows);
+ D("%-8s n %d %d time %d.%06d %8.3f qlen %d %d flows %s drops %d",
+ c.name, c._enqueue, c.loops,
+ (int)c.time.tv_sec, (int)c.time.tv_usec, ll,
+ c.th_min, c.th_max,
+ c.fs_config ? c.fs_config : msg, c.drop);
+ dump(&c);
+ DX(1, "done ac %d av %p", ac, av);
+ for (i=0; i < ac; i++)
+ DX(1, "arg %d %s", i, av[i]);
+ return 0;
+}
+
+/*
+ * The controller decides whether in this iteration we should send
+ * (the packet is in c->tosend) and/or receive (flag c->can_dequeue)
+ */
+static void
+controller(struct cfg_s *c)
+{
+ struct mbuf *m;
+ struct dn_fs *fs;
+ int flow_id;
+
+ /* histeresis between max and min */
+ if (c->state == 0 && c->pending >= c->th_max)
+ c->state = 1;
+ else if (c->state == 1 && c->pending <= c->th_min)
+ c->state = 0;
+ ND(1, "state %d pending %2d", c->state, c->pending);
+ c->can_dequeue = c->state;
+ c->tosend = NULL;
+ if (c->state)
+ return;
+
+ if (1) {
+ int i;
+ struct dn_queue *q;
+ struct list_head *h;
+
+ i = ffs(c->llmask) - 1;
+ if (i < 0) {
+ DX(2, "no candidate");
+ c->can_dequeue = 1;
+ return;
+ }
+ h = &c->ll[i];
+ ND(1, "backlog %d p %p prev %p next %p", i, h, h->prev, h->next);
+ q = list_first_entry(h, struct dn_queue, ni.h);
+ list_del(&q->ni.h);
+ flow_id = Q2FI(c, q);
+ DX(2, "extracted flow %p %d backlog %d", q, flow_id, i);
+ if (list_empty(h)) {
+ ND(2, "backlog %d empty", i);
+ c->llmask &= ~(1<<i);
+ }
+ ND(1, "before %d p %p prev %p next %p", i+1, h+1, h[1].prev, h[1].next);
+ list_add_tail(&q->ni.h, h+1);
+ ND(1, " after %d p %p prev %p next %p", i+1, h+1, h[1].prev, h[1].next);
+ if (i < BACKLOG) {
+ ND(2, "backlog %d full", i+1);
+ c->llmask |= 1<<(1+i);
+ }
+ fs = &q->fs->fs;
+ c->cur_fs = q->fs - c->fs;
+ fs->cur = flow_id;
+ } else {
+ /* XXX this does not work ? */
+ /* now decide whom to send the packet, and the length */
+ /* lookup in the flow table */
+ if (c->cur_y >= c->max_y) { /* handle wraparound */
+ c->cur_y = 0;
+ c->cur_fs = 0;
+ }
+ fs = &c->fs[c->cur_fs].fs;
+ flow_id = fs->cur++;
+ if (fs->cur >= fs->next_flow)
+ fs->cur = fs->first_flow;
+ c->cur_y++;
+ if (c->cur_y >= fs->next_y)
+ c->cur_fs++;
+ }
+
+ /* construct a packet */
+ if (c->freelist) {
+ m = c->tosend = c->freelist;
+ c->freelist = c->freelist->m_nextpkt;
+ } else {
+ m = c->tosend = calloc(1, sizeof(struct mbuf));
+ }
+ if (m == NULL)
+ return;
+
+ m->cfg = c;
+ m->m_nextpkt = NULL;
+ m->m_pkthdr.len = fs->par[1]; // XXX maxlen
+ m->flow_id = flow_id;
+
+ ND(2,"y %6d flow %5d fs %3d weight %4d len %4d",
+ c->cur_y, m->flow_id, c->cur_fs,
+ fs->par[0], m->m_pkthdr.len);
+
+}
+
+/*
+Packet allocation:
+to achieve a distribution that matches weights, for each X=w/lmax class
+we should generate a number of packets proportional to Y = X times the number
+of flows in the class.
+So we construct an array with the cumulative distribution of Y's,
+and use it to identify the flow via inverse mapping (if the Y's are
+not too many we can use an array for the lookup). In practice,
+each flow will have X entries [virtually] pointing to it.
+
+*/
diff --git a/sys/netinet/ipfw/test/mylist.h b/sys/netinet/ipfw/test/mylist.h
new file mode 100644
index 0000000..ebc7d11
--- /dev/null
+++ b/sys/netinet/ipfw/test/mylist.h
@@ -0,0 +1,49 @@
+/*
+ * $FreeBSD$
+ *
+ * linux-like bidirectional lists
+ */
+
+#ifndef _MYLIST_H
+#define _MYLIST_H
+struct list_head {
+ struct list_head *prev, *next;
+};
+
+#define INIT_LIST_HEAD(l) do { (l)->prev = (l)->next = (l); } while (0)
+#define list_empty(l) ( (l)->next == l )
+static inline void
+__list_add(struct list_head *new, struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+static inline void
+list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+#define list_first_entry(pL, ty, member) \
+ (ty *)((char *)((pL)->next) - offsetof(ty, member))
+
+static inline void
+__list_del(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+static inline void
+list_del(struct list_head *entry)
+{
+ ND("called on %p", entry);
+ __list_del(entry->prev, entry->next);
+ entry->next = entry->prev = NULL;
+}
+
+#endif /* _MYLIST_H */
diff --git a/sys/netinet/ipfw/test/test_dn_heap.c b/sys/netinet/ipfw/test/test_dn_heap.c
new file mode 100644
index 0000000..d460cf2
--- /dev/null
+++ b/sys/netinet/ipfw/test/test_dn_heap.c
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 1998-2002,2010 Luigi Rizzo, Universita` di Pisa
+ * 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.
+ */
+
+/*
+ * Userland code for testing binary heaps and hash tables
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+
+#include "dn_heap.h"
+#define log(x, arg...) fprintf(stderr, ## arg)
+#define panic(x...) fprintf(stderr, ## x), exit(1)
+
+#include <string.h>
+
+struct x {
+ struct x *ht_link;
+ char buf[0];
+};
+
+uint32_t hf(uintptr_t key, int flags, void *arg)
+{
+ return (flags & DNHT_KEY_IS_OBJ) ?
+ ((struct x *)key)->buf[0] : *(char *)key;
+}
+
+int matchf(void *obj, uintptr_t key, int flags, void *arg)
+{
+ char *s = (flags & DNHT_KEY_IS_OBJ) ?
+ ((struct x *)key)->buf : (char *)key;
+ return (strcmp(((struct x *)obj)->buf, s) == 0);
+}
+
+void *newfn(uintptr_t key, int flags, void *arg)
+{
+ char *s = (char *)key;
+ struct x *p = malloc(sizeof(*p) + 1 + strlen(s));
+ if (p)
+ strcpy(p->buf, s);
+ return p;
+}
+
+char *strings[] = {
+ "undici", "unico", "doppio", "devoto",
+ "uno", "due", "tre", "quattro", "cinque", "sei",
+ "uno", "due", "tre", "quattro", "cinque", "sei",
+ NULL,
+};
+
+int doprint(void *_x, void *arg)
+{
+ struct x *x = _x;
+ printf("found element <%s>\n", x->buf);
+ return (int)arg;
+}
+
+static void
+test_hash()
+{
+ char **p;
+ struct dn_ht *h;
+ uintptr_t x = 0;
+ uintptr_t x1 = 0;
+
+ /* first, find and allocate */
+ h = dn_ht_init(NULL, 10, 0, hf, matchf, newfn);
+
+ for (p = strings; *p; p++) {
+ dn_ht_find(h, (uintptr_t)*p, DNHT_INSERT, NULL);
+ }
+ dn_ht_scan(h, doprint, 0);
+ printf("/* second -- find without allocate */\n");
+ h = dn_ht_init(NULL, 10, 0, hf, matchf, NULL);
+ for (p = strings; *p; p++) {
+ void **y = newfn((uintptr_t)*p, 0, NULL);
+ if (x == 0)
+ x = (uintptr_t)y;
+ else {
+ if (x1 == 0)
+ x1 = (uintptr_t)*p;
+ }
+ dn_ht_find(h, (uintptr_t)y, DNHT_INSERT | DNHT_KEY_IS_OBJ, NULL);
+ }
+ dn_ht_scan(h, doprint, 0);
+ printf("remove %p gives %p\n", (void *)x,
+ dn_ht_find(h, x, DNHT_KEY_IS_OBJ | DNHT_REMOVE, NULL));
+ printf("remove %p gives %p\n", (void *)x,
+ dn_ht_find(h, x, DNHT_KEY_IS_OBJ | DNHT_REMOVE, NULL));
+ printf("remove %p gives %p\n", (void *)x,
+ dn_ht_find(h, x1, DNHT_REMOVE, NULL));
+ printf("remove %p gives %p\n", (void *)x,
+ dn_ht_find(h, x1, DNHT_REMOVE, NULL));
+ dn_ht_scan(h, doprint, 0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct dn_heap h;
+ int i, n, n2, n3;
+
+ test_hash();
+ return 0;
+
+ /* n = elements, n2 = cycles */
+ n = (argc > 1) ? atoi(argv[1]) : 0;
+ if (n <= 0 || n > 1000000)
+ n = 100;
+ n2 = (argc > 2) ? atoi(argv[2]) : 0;
+ if (n2 <= 0)
+ n = 1000000;
+ n3 = (argc > 3) ? atoi(argv[3]) : 0;
+ bzero(&h, sizeof(h));
+ heap_init(&h, n, -1);
+ while (n2-- > 0) {
+ uint64_t prevk = 0;
+ for (i=0; i < n; i++)
+ heap_insert(&h, n3 ? n-i: random(), (void *)(100+i));
+
+ for (i=0; h.elements > 0; i++) {
+ uint64_t k = h.p[0].key;
+ if (k < prevk)
+ panic("wrong sequence\n");
+ prevk = k;
+ if (0)
+ printf("%d key %llu, val %p\n",
+ i, h.p[0].key, h.p[0].object);
+ heap_extract(&h, NULL);
+ }
+ }
+ return 0;
+}
diff --git a/sys/netinet/ipfw/test/test_dn_sched.c b/sys/netinet/ipfw/test/test_dn_sched.c
new file mode 100644
index 0000000..667c42e
--- /dev/null
+++ b/sys/netinet/ipfw/test/test_dn_sched.c
@@ -0,0 +1,76 @@
+/*
+ * $FreeBSD$
+ *
+ * library functions for userland testing of dummynet schedulers
+ */
+
+#include "dn_test.h"
+
+void
+m_freem(struct mbuf *m)
+{
+ printf("free %p\n", m);
+}
+
+int
+dn_sched_modevent(module_t mod, int cmd, void *arg)
+{
+ return 0;
+}
+
+void
+dn_free_pkts(struct mbuf *m)
+{
+ struct mbuf *x;
+ while ( (x = m) ) {
+ m = m->m_nextpkt;
+ m_freem(x);
+ }
+}
+
+int
+dn_delete_queue(void *_q, void *do_free)
+{
+ struct dn_queue *q = _q;
+ if (q->mq.head)
+ dn_free_pkts(q->mq.head);
+ free(q);
+ return 0;
+}
+
+/*
+ * This is a simplified function for testing purposes, which does
+ * not implement statistics or random loss.
+ * Enqueue a packet in q, subject to space and queue management policy
+ * (whose parameters are in q->fs).
+ * Update stats for the queue and the scheduler.
+ * Return 0 on success, 1 on drop. The packet is consumed anyways.
+ */
+int
+dn_enqueue(struct dn_queue *q, struct mbuf* m, int drop)
+{
+ if (drop)
+ goto drop;
+ if (q->ni.length >= 200)
+ goto drop;
+ mq_append(&q->mq, m);
+ q->ni.length++;
+ q->ni.tot_bytes += m->m_pkthdr.len;
+ return 0;
+
+drop:
+ q->ni.drops++;
+ return 1;
+}
+
+int
+ipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg)
+{
+ if (*v < lo) {
+ *v = dflt;
+ } else if (*v > hi) {
+ *v = hi;
+ }
+ return *v;
+}
+
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index d211e9a..ef18737 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -918,7 +918,8 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
static void
sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp,
- struct sctp_tcb *stcb, struct sctp_nets *net)
+ struct sctp_tcb *stcb,
+ struct sctp_nets *net)
{
struct sctp_association *asoc;
@@ -934,6 +935,13 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp,
asoc = &stcb->asoc;
/* process according to association state */
+ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) {
+ /* unexpected SHUTDOWN-ACK... do OOTB handling... */
+ sctp_send_shutdown_complete(stcb, net, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
/* unexpected SHUTDOWN-ACK... so ignore... */
@@ -975,7 +983,7 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp,
/* stop the timer */
sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_9);
/* send SHUTDOWN-COMPLETE */
- sctp_send_shutdown_complete(stcb, net);
+ sctp_send_shutdown_complete(stcb, net, 0);
/* notify upper layer protocol */
if (stcb->sctp_socket) {
sctp_ulp_notify(SCTP_NOTIFY_ASSOC_DOWN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED);
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 4afe009..be4c3a8 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -10622,27 +10622,37 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
void
sctp_send_shutdown_complete(struct sctp_tcb *stcb,
- struct sctp_nets *net)
+ struct sctp_nets *net,
+ int reflect_vtag)
{
/* formulate and SEND a SHUTDOWN-COMPLETE */
struct mbuf *m_shutdown_comp;
struct sctp_shutdown_complete_chunk *shutdown_complete;
+ uint32_t vtag;
+ uint8_t flags;
m_shutdown_comp = sctp_get_mbuf_for_msg(sizeof(struct sctp_chunkhdr), 0, M_DONTWAIT, 1, MT_HEADER);
if (m_shutdown_comp == NULL) {
/* no mbuf's */
return;
}
+ if (reflect_vtag) {
+ flags = SCTP_HAD_NO_TCB;
+ vtag = stcb->asoc.my_vtag;
+ } else {
+ flags = 0;
+ vtag = stcb->asoc.peer_vtag;
+ }
shutdown_complete = mtod(m_shutdown_comp, struct sctp_shutdown_complete_chunk *);
shutdown_complete->ch.chunk_type = SCTP_SHUTDOWN_COMPLETE;
- shutdown_complete->ch.chunk_flags = 0;
+ shutdown_complete->ch.chunk_flags = flags;
shutdown_complete->ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk));
SCTP_BUF_LEN(m_shutdown_comp) = sizeof(struct sctp_shutdown_complete_chunk);
(void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
m_shutdown_comp, 0, NULL, 0, 1, 0, NULL, 0,
stcb->sctp_ep->sctp_lport, stcb->rport,
- htonl(stcb->asoc.peer_vtag),
+ htonl(vtag),
net->port, SCTP_SO_NOT_LOCKED, NULL);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
return;
diff --git a/sys/netinet/sctp_output.h b/sys/netinet/sctp_output.h
index ce76feb..bd40a0b 100644
--- a/sys/netinet/sctp_output.h
+++ b/sys/netinet/sctp_output.h
@@ -111,7 +111,7 @@ void sctp_send_shutdown(struct sctp_tcb *, struct sctp_nets *);
void sctp_send_shutdown_ack(struct sctp_tcb *, struct sctp_nets *);
-void sctp_send_shutdown_complete(struct sctp_tcb *, struct sctp_nets *);
+void sctp_send_shutdown_complete(struct sctp_tcb *, struct sctp_nets *, int);
void
sctp_send_shutdown_complete2(struct mbuf *, int, struct sctphdr *,
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index 71f5f65..2851272 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -980,7 +980,9 @@ sctp_shutdown(struct socket *so)
/* For UDP model this is a invalid call */
if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
/* Restore the flags that the soshutdown took away. */
+ SOCKBUF_LOCK(&so->so_rcv);
so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
+ SOCKBUF_UNLOCK(&so->so_rcv);
/* This proc will wakeup for read and do nothing (I hope) */
SCTP_INP_RUNLOCK(inp);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
@@ -4465,6 +4467,15 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
/* Set the connected flag so we can queue data */
+ SOCKBUF_LOCK(&so->so_rcv);
+ so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
+ SOCKBUF_UNLOCK(&so->so_rcv);
+ SOCKBUF_LOCK(&so->so_snd);
+ so->so_snd.sb_state &= ~SBS_CANTSENDMORE;
+ SOCKBUF_UNLOCK(&so->so_snd);
+ SOCK_LOCK(so);
+ so->so_state &= ~SS_ISDISCONNECTING;
+ SOCK_UNLOCK(so);
soisconnecting(so);
}
SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index fc89b6d..658dc55 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -849,7 +849,7 @@ retry:
uint32_t
sctp_select_a_tag(struct sctp_inpcb *inp, uint16_t lport, uint16_t rport, int save_in_twait)
{
- u_long x, not_done;
+ uint32_t x, not_done;
struct timeval now;
(void)SCTP_GETTIME_TIMEVAL(&now);
@@ -2751,8 +2751,6 @@ sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf)
return (EFAULT);
}
-int sctp_asoc_change_wake = 0;
-
static void
sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
uint32_t error, void *data, int so_locked
@@ -2806,7 +2804,6 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
SCTP_SOCKET_UNLOCK(so, 1);
}
#endif
- sctp_asoc_change_wake++;
}
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
/* event not enabled */
diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c
index 16c4f67..4d9d487 100644
--- a/sys/netinet/tcp_syncache.c
+++ b/sys/netinet/tcp_syncache.c
@@ -278,11 +278,33 @@ syncache_init(void)
void
syncache_destroy(void)
{
+ struct syncache_head *sch;
+ struct syncache *sc, *nsc;
+ int i;
+
+ /* Cleanup hash buckets: stop timers, free entries, destroy locks. */
+ for (i = 0; i < V_tcp_syncache.hashsize; i++) {
+
+ sch = &V_tcp_syncache.hashbase[i];
+ callout_drain(&sch->sch_timer);
+
+ SCH_LOCK(sch);
+ TAILQ_FOREACH_SAFE(sc, &sch->sch_bucket, sc_hash, nsc)
+ syncache_drop(sc, sch);
+ SCH_UNLOCK(sch);
+ KASSERT(TAILQ_EMPTY(&sch->sch_bucket),
+ ("%s: sch->sch_bucket not empty", __func__));
+ KASSERT(sch->sch_length == 0, ("%s: sch->sch_length %d not 0",
+ __func__, sch->sch_length));
+ mtx_destroy(&sch->sch_mtx);
+ }
- /* XXX walk the cache, free remaining objects, stop timers */
+ KASSERT(V_tcp_syncache.cache_count == 0, ("%s: cache_count %d not 0",
+ __func__, V_tcp_syncache.cache_count));
+ /* Free the allocated global resources. */
uma_zdestroy(V_tcp_syncache.zone);
- FREE(V_tcp_syncache.hashbase, M_SYNCACHE);
+ free(V_tcp_syncache.hashbase, M_SYNCACHE);
}
#endif
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index 7995b43..6699ced 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -101,8 +101,6 @@ __FBSDID("$FreeBSD$");
#include <netinet6/in6_pcb.h>
#include <netinet6/scope6_var.h>
-#include <security/mac/mac_framework.h>
-
struct in6_addr zeroin6_addr;
int
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index d90520e..a32539b 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -764,22 +764,25 @@ regen_tmpaddr(struct in6_ifaddr *ia6)
*/
if (!IFA6_IS_DEPRECATED(it6))
public_ifa6 = it6;
+
+ if (public_ifa6 != NULL)
+ ifa_ref(&public_ifa6->ia_ifa);
}
+ IF_ADDR_UNLOCK(ifp);
if (public_ifa6 != NULL) {
int e;
if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) {
- IF_ADDR_UNLOCK(ifp);
+ ifa_free(&public_ifa6->ia_ifa);
log(LOG_NOTICE, "regen_tmpaddr: failed to create a new"
" tmp addr,errno=%d\n", e);
return (-1);
}
- IF_ADDR_UNLOCK(ifp);
+ ifa_free(&public_ifa6->ia_ifa);
return (0);
}
- IF_ADDR_UNLOCK(ifp);
return (-1);
}
diff --git a/sys/netipsec/keydb.h b/sys/netipsec/keydb.h
index 35a0122..07e1f60 100644
--- a/sys/netipsec/keydb.h
+++ b/sys/netipsec/keydb.h
@@ -52,7 +52,7 @@ union sockaddr_union {
/* Security Assocciation Index */
/* NOTE: Ensure to be same address family */
struct secasindex {
- union sockaddr_union src; /* srouce address for SA */
+ union sockaddr_union src; /* source address for SA */
union sockaddr_union dst; /* destination address for SA */
u_int16_t proto; /* IPPROTO_ESP or IPPROTO_AH */
u_int8_t mode; /* mode of protocol, see ipsec.h */
diff --git a/sys/nfsclient/nfs_kdtrace.c b/sys/nfsclient/nfs_kdtrace.c
index fc7e446..3a478e0 100644
--- a/sys/nfsclient/nfs_kdtrace.c
+++ b/sys/nfsclient/nfs_kdtrace.c
@@ -500,15 +500,11 @@ dtnfsclient_load(void *dummy)
static int
dtnfsclient_unload()
{
- int error = 0;
dtrace_nfsclient_nfs23_start_probe = NULL;
dtrace_nfsclient_nfs23_done_probe = NULL;
- if ((error = dtrace_unregister(dtnfsclient_id)) != 0)
- return (error);
-
- return (error);
+ return (dtrace_unregister(dtnfsclient_id));
}
static int
diff --git a/sys/pc98/pc98/machdep.c b/sys/pc98/pc98/machdep.c
index f07eb6b..f178748 100644
--- a/sys/pc98/pc98/machdep.c
+++ b/sys/pc98/pc98/machdep.c
@@ -129,7 +129,7 @@ __FBSDID("$FreeBSD$");
#endif
#ifdef DEV_ISA
-#include <i386/isa/icu.h>
+#include <x86/isa/icu.h>
#endif
/* Sanity check for __curthread() */
diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c
index b2e57b8..a9cf051 100644
--- a/sys/powerpc/aim/machdep.c
+++ b/sys/powerpc/aim/machdep.c
@@ -198,6 +198,11 @@ cpu_startup(void *dummy)
ptoa(physmem) / 1048576);
realmem = physmem;
+ if (bootverbose)
+ printf("available KVA = %zd (%zd MB)\n",
+ virtual_end - virtual_avail,
+ (virtual_end - virtual_avail) / 1048576);
+
/*
* Display any holes after the first chunk of extended memory.
*/
diff --git a/sys/powerpc/aim/mmu_oea.c b/sys/powerpc/aim/mmu_oea.c
index 4cd5f75..8357929 100644
--- a/sys/powerpc/aim/mmu_oea.c
+++ b/sys/powerpc/aim/mmu_oea.c
@@ -909,7 +909,7 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend)
* Set the start and end of kva.
*/
virtual_avail = VM_MIN_KERNEL_ADDRESS;
- virtual_end = VM_MAX_KERNEL_ADDRESS;
+ virtual_end = VM_MAX_SAFE_KERNEL_ADDRESS;
/*
* Allocate a kernel stack with a guard page for thread0 and map it
@@ -2413,7 +2413,7 @@ moea_unmapdev(mmu_t mmu, vm_offset_t va, vm_size_t size)
* If this is outside kernel virtual space, then it's a
* battable entry and doesn't require unmapping
*/
- if ((va >= VM_MIN_KERNEL_ADDRESS) && (va <= VM_MAX_KERNEL_ADDRESS)) {
+ if ((va >= VM_MIN_KERNEL_ADDRESS) && (va <= virtual_end)) {
base = trunc_page(va);
offset = va & PAGE_MASK;
size = roundup(offset + size, PAGE_SIZE);
diff --git a/sys/powerpc/aim/mmu_oea64.c b/sys/powerpc/aim/mmu_oea64.c
index db41275..6760fee 100644
--- a/sys/powerpc/aim/mmu_oea64.c
+++ b/sys/powerpc/aim/mmu_oea64.c
@@ -227,6 +227,7 @@ TLBIE(pmap_t pmap, vm_offset_t va) {
#define VSID_MAKE(sr, hash) ((sr) | (((hash) & 0xfffff) << 4))
#define VSID_TO_SR(vsid) ((vsid) & 0xf)
#define VSID_TO_HASH(vsid) (((vsid) >> 4) & 0xfffff)
+#define VSID_HASH_MASK 0x0000007fffffffffULL
#define PVO_PTEGIDX_MASK 0x007UL /* which PTEG slot */
#define PVO_PTEGIDX_VALID 0x008UL /* slot is valid */
@@ -297,9 +298,6 @@ struct pvo_head moea64_pvo_unmanaged =
uma_zone_t moea64_upvo_zone; /* zone for pvo entries for unmanaged pages */
uma_zone_t moea64_mpvo_zone; /* zone for pvo entries for managed pages */
-vm_offset_t pvo_allocator_start;
-vm_offset_t pvo_allocator_end;
-
#define BPVO_POOL_SIZE 327680
static struct pvo_entry *moea64_bpvo_pool;
static int moea64_bpvo_pool_index = 0;
@@ -461,9 +459,9 @@ MMU_DEF(oea64_bridge_mmu);
static __inline u_int
va_to_pteg(uint64_t vsid, vm_offset_t addr)
{
- u_int hash;
+ uint64_t hash;
- hash = vsid ^ (((uint64_t)addr & ADDR_PIDX) >>
+ hash = (vsid & VSID_HASH_MASK) ^ (((uint64_t)addr & ADDR_PIDX) >>
ADDR_PIDX_SHFT);
return (hash & moea64_pteg_mask);
}
@@ -699,6 +697,7 @@ moea64_add_ofw_mappings(mmu_t mmup, phandle_t mmu, size_t sz)
struct ofw_map translations[sz/sizeof(struct ofw_map)];
register_t msr;
vm_offset_t off;
+ vm_paddr_t pa_base;
int i, ofw_mappings;
bzero(translations, sz);
@@ -720,33 +719,18 @@ moea64_add_ofw_mappings(mmu_t mmup, phandle_t mmu, size_t sz)
if (translations[i].om_pa_hi)
panic("OFW translations above 32-bit boundary!");
+ pa_base = translations[i].om_pa_lo;
+
/* Now enter the pages for this mapping */
- /*
- * Lock the ofw pmap. pmap_kenter(), which we use for the
- * pages the kernel also needs, does its own locking.
- */
- PMAP_LOCK(&ofw_pmap);
DISABLE_TRANS(msr);
for (off = 0; off < translations[i].om_len; off += PAGE_SIZE) {
- struct vm_page m;
-
- /* Map low memory mappings into the kernel pmap, too.
- * These are typically mappings made by the loader,
- * so we need them if we want to keep executing. */
-
- if (translations[i].om_va + off < SEGMENT_LENGTH)
- moea64_kenter(mmup, translations[i].om_va + off,
- translations[i].om_va + off);
-
- m.phys_addr = translations[i].om_pa_lo + off;
- moea64_enter_locked(&ofw_pmap,
- translations[i].om_va + off, &m, VM_PROT_ALL, 1);
+ moea64_kenter(mmup, translations[i].om_va + off,
+ pa_base + off);
ofw_mappings++;
}
ENABLE_TRANS(msr);
- PMAP_UNLOCK(&ofw_pmap);
}
}
@@ -926,8 +910,8 @@ moea64_bridge_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernele
*/
moea64_pinit(mmup, &ofw_pmap);
- ofw_pmap.pm_sr[KERNEL_SR] = kernel_pmap->pm_sr[KERNEL_SR];
- ofw_pmap.pm_sr[KERNEL2_SR] = kernel_pmap->pm_sr[KERNEL2_SR];
+ for (i = 0; i < 16; i++)
+ ofw_pmap.pm_sr[i] = kernel_pmap->pm_sr[i];
if ((chosen = OF_finddevice("/chosen")) == -1)
panic("moea64_bootstrap: can't find /chosen");
@@ -965,15 +949,20 @@ moea64_bridge_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernele
* Set the start and end of kva.
*/
virtual_avail = VM_MIN_KERNEL_ADDRESS;
- virtual_end = VM_MAX_KERNEL_ADDRESS;
+ virtual_end = VM_MAX_SAFE_KERNEL_ADDRESS;
/*
- * Allocate some stupid buffer regions.
+ * Figure out how far we can extend virtual_end into segment 16
+ * without running into existing mappings. Segment 16 is guaranteed
+ * to contain neither RAM nor devices (at least on Apple hardware),
+ * but will generally contain some OFW mappings we should not
+ * step on.
*/
- pvo_allocator_start = virtual_avail;
- virtual_avail += SEGMENT_LENGTH/4;
- pvo_allocator_end = virtual_avail;
+ PMAP_LOCK(kernel_pmap);
+ while (moea64_pvo_find_va(kernel_pmap, virtual_end+1, NULL) == NULL)
+ virtual_end += PAGE_SIZE;
+ PMAP_UNLOCK(kernel_pmap);
/*
* Allocate some things for page zeroing
@@ -981,16 +970,17 @@ moea64_bridge_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernele
mtx_init(&moea64_scratchpage_mtx, "pvo zero page", NULL, MTX_DEF);
for (i = 0; i < 2; i++) {
- moea64_scratchpage_va[i] = virtual_avail;
- virtual_avail += PAGE_SIZE;
+ moea64_scratchpage_va[i] = (virtual_end+1) - PAGE_SIZE;
+ virtual_end -= PAGE_SIZE;
- moea64_kenter(mmup,moea64_scratchpage_va[i],kernelstart);
+ moea64_kenter(mmup,moea64_scratchpage_va[i],0);
LOCK_TABLE();
moea64_scratchpage_pvo[i] = moea64_pvo_find_va(kernel_pmap,
moea64_scratchpage_va[i],&j);
moea64_scratchpage_pte[i] = moea64_pvo_to_pte(
moea64_scratchpage_pvo[i],j);
+ moea64_scratchpage_pte[i]->pte_hi |= LPTE_LOCKED;
UNLOCK_TABLE();
}
@@ -1028,7 +1018,6 @@ moea64_bridge_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernele
*/
pa = moea64_bootstrap_alloc(DPCPU_SIZE, PAGE_SIZE);
dpcpu = (void *)virtual_avail;
- va = virtual_avail;
virtual_avail += DPCPU_SIZE;
while (va < virtual_avail) {
moea64_kenter(mmup, va, pa);
@@ -1091,15 +1080,6 @@ moea64_change_wiring(mmu_t mmu, pmap_t pm, vm_offset_t va, boolean_t wired)
}
/*
- * Zero a page of physical memory by temporarily mapping it into the tlb.
- */
-void
-moea64_zero_page(mmu_t mmu, vm_page_t m)
-{
- moea64_zero_page_area(mmu,m,0,PAGE_SIZE);
-}
-
-/*
* This goes through and sets the physical address of our
* special scratch PTE to the PA we want to zero or copy. Because
* of locking issues (this can get called in pvo_enter() by
@@ -1108,8 +1088,10 @@ moea64_zero_page(mmu_t mmu, vm_page_t m)
static __inline
void moea64_set_scratchpage_pa(int which, vm_offset_t pa) {
+ mtx_assert(&moea64_scratchpage_mtx, MA_OWNED);
+
moea64_scratchpage_pvo[which]->pvo_pte.lpte.pte_lo &=
- (~LPTE_WIMG & ~LPTE_RPGN);
+ ~(LPTE_WIMG | LPTE_RPGN);
moea64_scratchpage_pvo[which]->pvo_pte.lpte.pte_lo |=
moea64_calc_wimg(pa) | (uint64_t)pa;
@@ -1161,6 +1143,27 @@ moea64_zero_page_area(mmu_t mmu, vm_page_t m, int off, int size)
mtx_unlock(&moea64_scratchpage_mtx);
}
+/*
+ * Zero a page of physical memory by temporarily mapping it
+ */
+void
+moea64_zero_page(mmu_t mmu, vm_page_t m)
+{
+ vm_offset_t pa = VM_PAGE_TO_PHYS(m);
+ vm_offset_t off;
+
+ if (!moea64_initialized)
+ panic("moea64_zero_page: can't zero pa %#x", pa);
+
+ mtx_lock(&moea64_scratchpage_mtx);
+
+ moea64_set_scratchpage_pa(0,pa);
+ for (off = 0; off < PAGE_SIZE; off += cacheline_size)
+ __asm __volatile("dcbz 0,%0" ::
+ "r"(moea64_scratchpage_va[0] + off));
+ mtx_unlock(&moea64_scratchpage_mtx);
+}
+
void
moea64_zero_page_idle(mmu_t mmu, vm_page_t m)
{
@@ -1412,14 +1415,10 @@ moea64_uma_page_alloc(uma_zone_t zone, int bytes, u_int8_t *flags, int wait)
break;
}
- va = pvo_allocator_start;
- pvo_allocator_start += PAGE_SIZE;
-
- if (pvo_allocator_start >= pvo_allocator_end)
- panic("Ran out of PVO allocator buffer space!");
+ va = VM_PAGE_TO_PHYS(m);
moea64_pvo_enter(kernel_pmap, moea64_upvo_zone,
- &moea64_pvo_kunmanaged, va, VM_PAGE_TO_PHYS(m), LPTE_M,
+ &moea64_pvo_kunmanaged, va, VM_PAGE_TO_PHYS(m), LPTE_M,
PVO_WIRED | PVO_BOOTSTRAP);
if (needed_lock)
@@ -1557,10 +1556,12 @@ moea64_kenter(mmu_t mmu, vm_offset_t va, vm_offset_t pa)
uint64_t pte_lo;
int error;
+#if 0
if (!pmap_bootstrapped) {
- if (va >= VM_MIN_KERNEL_ADDRESS && va < VM_MAX_KERNEL_ADDRESS)
+ if (va >= VM_MIN_KERNEL_ADDRESS && va < virtual_end)
panic("Trying to enter an address in KVA -- %#x!\n",pa);
}
+#endif
pte_lo = moea64_calc_wimg(pa);
@@ -2171,18 +2172,16 @@ moea64_pvo_remove(struct pvo_entry *pvo, int pteidx)
static __inline int
moea64_pvo_pte_index(const struct pvo_entry *pvo, int ptegidx)
{
- int pteidx;
/*
* We can find the actual pte entry without searching by grabbing
- * the PTEG index from 3 unused bits in pte_lo[11:9] and by
+ * the PTEG index from 3 unused bits in pvo_vaddr and by
* noticing the HID bit.
*/
- pteidx = ptegidx * 8 + PVO_PTEGIDX_GET(pvo);
if (pvo->pvo_pte.lpte.pte_hi & LPTE_HID)
- pteidx ^= moea64_pteg_mask * 8;
+ ptegidx ^= moea64_pteg_mask;
- return (pteidx);
+ return ((ptegidx << 3) | PVO_PTEGIDX_GET(pvo));
}
static struct pvo_entry *
@@ -2279,7 +2278,8 @@ moea64_pte_insert(u_int ptegidx, struct lpte *pvo_pt)
* First try primary hash.
*/
for (pt = moea64_pteg_table[ptegidx].pt, i = 0; i < 8; i++, pt++) {
- if ((pt->pte_hi & LPTE_VALID) == 0) {
+ if ((pt->pte_hi & LPTE_VALID) == 0 &&
+ (pt->pte_hi & LPTE_LOCKED) == 0) {
pvo_pt->pte_hi &= ~LPTE_HID;
moea64_pte_set(pt, pvo_pt);
return (i);
@@ -2292,7 +2292,8 @@ moea64_pte_insert(u_int ptegidx, struct lpte *pvo_pt)
ptegidx ^= moea64_pteg_mask;
for (pt = moea64_pteg_table[ptegidx].pt, i = 0; i < 8; i++, pt++) {
- if ((pt->pte_hi & LPTE_VALID) == 0) {
+ if ((pt->pte_hi & LPTE_VALID) == 0 &&
+ (pt->pte_hi & LPTE_LOCKED) == 0) {
pvo_pt->pte_hi |= LPTE_HID;
moea64_pte_set(pt, pvo_pt);
return (i);
@@ -2414,7 +2415,22 @@ moea64_clear_bit(vm_page_t m, u_int64_t ptebit, u_int64_t *origbit)
boolean_t
moea64_dev_direct_mapped(mmu_t mmu, vm_offset_t pa, vm_size_t size)
{
- return (EFAULT);
+ struct pvo_entry *pvo;
+ vm_offset_t ppa;
+ int error = 0;
+
+ PMAP_LOCK(kernel_pmap);
+ for (ppa = pa & ~ADDR_POFF; ppa < pa + size; ppa += PAGE_SIZE) {
+ pvo = moea64_pvo_find_va(kernel_pmap, ppa, NULL);
+ if (pvo == NULL ||
+ (pvo->pvo_pte.lpte.pte_lo & LPTE_RPGN) != ppa) {
+ error = EFAULT;
+ break;
+ }
+ }
+ PMAP_UNLOCK(kernel_pmap);
+
+ return (error);
}
/*
diff --git a/sys/powerpc/aim/trap.c b/sys/powerpc/aim/trap.c
index 943e3c6..35f4147 100644
--- a/sys/powerpc/aim/trap.c
+++ b/sys/powerpc/aim/trap.c
@@ -82,6 +82,7 @@ static void printtrap(u_int vector, struct trapframe *frame, int isfatal,
int user);
static int trap_pfault(struct trapframe *frame, int user);
static int fix_unaligned(struct thread *td, struct trapframe *frame);
+static int ppc_instr_emulate(struct trapframe *frame);
static int handle_onfault(struct trapframe *frame);
static void syscall(struct trapframe *frame);
@@ -209,7 +210,9 @@ trap(struct trapframe *frame)
/* Identify the trap reason */
if (frame->srr1 & EXC_PGM_TRAP)
sig = SIGTRAP;
- else
+ else if (ppc_instr_emulate(frame) == 0)
+ frame->srr0 += 4;
+ else
sig = SIGILL;
break;
@@ -615,3 +618,21 @@ fix_unaligned(struct thread *td, struct trapframe *frame)
return -1;
}
+
+static int
+ppc_instr_emulate(struct trapframe *frame)
+{
+ uint32_t instr;
+ int reg;
+
+ instr = fuword32((void *)frame->srr0);
+
+ if ((instr & 0xfc1fffff) == 0x7c1f42a6) { /* mfpvr */
+ reg = (instr & ~0xfc1fffff) >> 21;
+ frame->fixreg[reg] = mfpvr();
+ return (0);
+ }
+
+ return (-1);
+}
+
diff --git a/sys/powerpc/aim/uma_machdep.c b/sys/powerpc/aim/uma_machdep.c
index dc03a26..6b28d67 100644
--- a/sys/powerpc/aim/uma_machdep.c
+++ b/sys/powerpc/aim/uma_machdep.c
@@ -56,13 +56,6 @@ uma_small_alloc(uma_zone_t zone, int bytes, u_int8_t *flags, int wait)
vm_page_t m;
int pflags;
- if (!hw_direct_map) {
- *flags = UMA_SLAB_KMEM;
- va = (void *)kmem_malloc(kmem_map, bytes, wait);
-
- return va;
- }
-
*flags = UMA_SLAB_PRIV;
if ((wait & (M_NOWAIT|M_USE_RESERVE)) == M_NOWAIT)
pflags = VM_ALLOC_INTERRUPT | VM_ALLOC_WIRED;
@@ -82,6 +75,10 @@ uma_small_alloc(uma_zone_t zone, int bytes, u_int8_t *flags, int wait)
}
va = (void *) VM_PAGE_TO_PHYS(m);
+
+ if (!hw_direct_map)
+ pmap_kenter((vm_offset_t)va, VM_PAGE_TO_PHYS(m));
+
if ((wait & M_ZERO) && (m->flags & PG_ZERO) == 0)
bzero(va, PAGE_SIZE);
atomic_add_int(&hw_uma_mdpages, 1);
@@ -94,13 +91,11 @@ uma_small_free(void *mem, int size, u_int8_t flags)
{
vm_page_t m;
- if (!hw_direct_map) {
- kmem_free(kmem_map, (vm_offset_t)mem, size);
-
- return;
- }
+ if (!hw_direct_map)
+ pmap_remove(kernel_pmap,(vm_offset_t)mem,
+ (vm_offset_t)mem + PAGE_SIZE);
- m = PHYS_TO_VM_PAGE((u_int32_t)mem);
+ m = PHYS_TO_VM_PAGE((vm_offset_t)mem);
m->wire_count--;
vm_page_free(m);
atomic_subtract_int(&cnt.v_wire_count, 1);
diff --git a/sys/powerpc/booke/copyinout.c b/sys/powerpc/booke/copyinout.c
index fd3bdf3..91195dd 100644
--- a/sys/powerpc/booke/copyinout.c
+++ b/sys/powerpc/booke/copyinout.c
@@ -295,8 +295,19 @@ casuword(volatile u_long *addr, u_long old, u_long new)
return (EFAULT);
}
- val = *addr;
- (void) atomic_cmpset_32((volatile uint32_t *)addr, old, new);
+ __asm __volatile (
+ "1:\tlwarx %0, 0, %2\n\t" /* load old value */
+ "cmplw %3, %0\n\t" /* compare */
+ "bne 2f\n\t" /* exit if not equal */
+ "stwcx. %4, 0, %2\n\t" /* attempt to store */
+ "bne- 1b\n\t" /* spin if failed */
+ "b 3f\n\t" /* we've succeeded */
+ "2:\n\t"
+ "stwcx. %0, 0, %2\n\t" /* clear reservation (74xx) */
+ "3:\n\t"
+ : "=&r" (val), "=m" (*addr)
+ : "r" (addr), "r" (old), "r" (new), "m" (*addr)
+ : "cc", "memory");
td->td_pcb->pcb_onfault = NULL;
diff --git a/sys/powerpc/include/pte.h b/sys/powerpc/include/pte.h
index f1e5319..b7f5fd9 100644
--- a/sys/powerpc/include/pte.h
+++ b/sys/powerpc/include/pte.h
@@ -95,6 +95,7 @@ struct lpteg {
/* High quadword: */
#define LPTE_VSID_SHIFT 12
#define LPTE_API 0x0000000000000F80ULL
+#define LPTE_LOCKED 0x0000000000000008ULL
#define LPTE_BIG 0x0000000000000004ULL /* 4kb/16Mb page */
#define LPTE_HID 0x0000000000000002ULL
#define LPTE_VALID 0x0000000000000001ULL
diff --git a/sys/powerpc/include/sr.h b/sys/powerpc/include/sr.h
index 2ef7b35..061195d 100644
--- a/sys/powerpc/include/sr.h
+++ b/sys/powerpc/include/sr.h
@@ -45,6 +45,7 @@
#define USER_SR 12
#define KERNEL_SR 13
#define KERNEL2_SR 14
+#define KERNEL3_SR 15
#define KERNEL_VSIDBITS 0xfffff
#define KERNEL_SEGMENT (0xfffff0 + KERNEL_SR)
#define KERNEL2_SEGMENT (0xfffff0 + KERNEL2_SR)
diff --git a/sys/powerpc/include/vmparam.h b/sys/powerpc/include/vmparam.h
index e778233..b7424f6c 100644
--- a/sys/powerpc/include/vmparam.h
+++ b/sys/powerpc/include/vmparam.h
@@ -98,7 +98,8 @@
#define KERNBASE 0x00100000 /* start of kernel virtual */
#define VM_MIN_KERNEL_ADDRESS ((vm_offset_t)(KERNEL_SR << ADDR_SR_SHFT))
-#define VM_MAX_KERNEL_ADDRESS (VM_MIN_KERNEL_ADDRESS + 2*SEGMENT_LENGTH - 1)
+#define VM_MAX_SAFE_KERNEL_ADDRESS (VM_MIN_KERNEL_ADDRESS + 2*SEGMENT_LENGTH -1)
+#define VM_MAX_KERNEL_ADDRESS (VM_MIN_KERNEL_ADDRESS + 3*SEGMENT_LENGTH - 1)
/*
* Use the direct-mapped BAT registers for UMA small allocs. This
@@ -106,13 +107,6 @@
*/
#define UMA_MD_SMALL_ALLOC
-/*
- * On 64-bit systems in bridge mode, we have no direct map, so we fake
- * the small_alloc() calls. But we need the VM to be in a reasonable
- * state first.
- */
-#define UMA_MD_SMALL_ALLOC_NEEDS_VM
-
#else
/*
diff --git a/sys/powerpc/powermac/smu.c b/sys/powerpc/powermac/smu.c
index 4d5e1c8..061ac1c 100644
--- a/sys/powerpc/powermac/smu.c
+++ b/sys/powerpc/powermac/smu.c
@@ -32,25 +32,51 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/systm.h>
#include <sys/module.h>
+#include <sys/callout.h>
#include <sys/conf.h>
#include <sys/cpu.h>
+#include <sys/ctype.h>
#include <sys/kernel.h>
+#include <sys/reboot.h>
#include <sys/rman.h>
#include <sys/sysctl.h>
#include <machine/bus.h>
#include <machine/md_var.h>
+#include <dev/led/led.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <powerpc/powermac/macgpiovar.h>
struct smu_cmd {
- uint8_t cmd;
+ volatile uint8_t cmd;
uint8_t len;
uint8_t data[254];
};
+struct smu_fan {
+ cell_t reg;
+ cell_t min_rpm;
+ cell_t max_rpm;
+ cell_t unmanaged_rpm;
+ char location[32];
+
+ int old_style;
+ int setpoint;
+};
+
+struct smu_sensor {
+ cell_t reg;
+ char location[32];
+ enum {
+ SMU_CURRENT_SENSOR,
+ SMU_VOLTAGE_SENSOR,
+ SMU_POWER_SENSOR,
+ SMU_TEMP_SENSOR
+ } type;
+};
+
struct smu_softc {
device_t sc_dev;
struct mtx sc_mtx;
@@ -65,6 +91,32 @@ struct smu_softc {
struct smu_cmd *sc_cmd;
bus_addr_t sc_cmd_phys;
bus_dmamap_t sc_cmd_dmamap;
+
+ struct smu_fan *sc_fans;
+ int sc_nfans;
+ struct smu_sensor *sc_sensors;
+ int sc_nsensors;
+
+ struct callout sc_fanmgt_callout;
+ time_t sc_lastuserchange;
+
+ /* Calibration data */
+ uint16_t sc_cpu_diode_scale;
+ int16_t sc_cpu_diode_offset;
+
+ uint16_t sc_cpu_volt_scale;
+ int16_t sc_cpu_volt_offset;
+ uint16_t sc_cpu_curr_scale;
+ int16_t sc_cpu_curr_offset;
+
+ uint16_t sc_slots_pow_scale;
+ int16_t sc_slots_pow_offset;
+
+ /* Thermal management parameters */
+ int sc_target_temp; /* Default 55 C */
+ int sc_critical_temp; /* Default 90 C */
+
+ struct cdev *sc_leddev;
};
/* regular bus attachment functions */
@@ -77,6 +129,16 @@ static int smu_attach(device_t);
static void smu_cpufreq_pre_change(device_t, const struct cf_level *level);
static void smu_cpufreq_post_change(device_t, const struct cf_level *level);
+/* utility functions */
+static int smu_run_cmd(device_t dev, struct smu_cmd *cmd);
+static int smu_get_datablock(device_t dev, int8_t id, uint8_t *buf,
+ size_t len);
+static void smu_attach_fans(device_t dev, phandle_t fanroot);
+static void smu_attach_sensors(device_t dev, phandle_t sensroot);
+static void smu_fanmgt_callout(void *xdev);
+static void smu_set_sleepled(void *xdev, int onoff);
+static int smu_server_mode(SYSCTL_HANDLER_ARGS);
+
/* where to find the doorbell GPIO */
static device_t smu_doorbell = NULL;
@@ -97,11 +159,43 @@ static driver_t smu_driver = {
static devclass_t smu_devclass;
DRIVER_MODULE(smu, nexus, smu_driver, smu_devclass, 0, 0);
+MALLOC_DEFINE(M_SMU, "smu", "SMU Sensor Information");
-#define SMU_MAILBOX 0x860c
+#define SMU_MAILBOX 0x8000860c
+#define SMU_FANMGT_INTERVAL 500 /* ms */
/* Command types */
-#define SMU_POWER 0xaa
+#define SMU_ADC 0xd8
+#define SMU_FAN 0x4a
+#define SMU_I2C 0x9a
+#define SMU_I2C_SIMPLE 0x00
+#define SMU_I2C_NORMAL 0x01
+#define SMU_I2C_COMBINED 0x02
+#define SMU_MISC 0xee
+#define SMU_MISC_GET_DATA 0x02
+#define SMU_MISC_LED_CTRL 0x04
+#define SMU_POWER 0xaa
+#define SMU_POWER_EVENTS 0x8f
+#define SMU_PWR_GET_POWERUP 0x00
+#define SMU_PWR_SET_POWERUP 0x01
+#define SMU_PWR_CLR_POWERUP 0x02
+
+/* Power event types */
+#define SMU_WAKEUP_KEYPRESS 0x01
+#define SMU_WAKEUP_AC_INSERT 0x02
+#define SMU_WAKEUP_AC_CHANGE 0x04
+#define SMU_WAKEUP_RING 0x10
+
+/* Data blocks */
+#define SMU_CPUTEMP_CAL 0x18
+#define SMU_CPUVOLT_CAL 0x21
+#define SMU_SLOTPW_CAL 0x78
+
+/* Partitions */
+#define SMU_PARTITION 0x3e
+#define SMU_PARTITION_LATEST 0x01
+#define SMU_PARTITION_BASE 0x02
+#define SMU_PARTITION_UPDATE 0x03
static int
smu_probe(device_t dev)
@@ -127,6 +221,8 @@ static int
smu_attach(device_t dev)
{
struct smu_softc *sc;
+ phandle_t node, child;
+ uint8_t data[12];
sc = device_get_softc(dev);
@@ -139,7 +235,7 @@ smu_attach(device_t dev)
bus_dma_tag_create(NULL, 16, 0, BUS_SPACE_MAXADDR_32BIT,
BUS_SPACE_MAXADDR, NULL, NULL, PAGE_SIZE, 1, PAGE_SIZE, 0, NULL,
NULL, &(sc->sc_dmatag));
- sc->sc_bt = &bs_be_tag;
+ sc->sc_bt = &bs_le_tag;
bus_space_map(sc->sc_bt, SMU_MAILBOX, 4, 0, &sc->sc_mailbox);
/*
@@ -159,6 +255,72 @@ smu_attach(device_t dev)
EVENTHANDLER_REGISTER(cpufreq_post_change, smu_cpufreq_post_change, dev,
EVENTHANDLER_PRI_ANY);
+ /*
+ * Detect and attach child devices.
+ */
+ node = ofw_bus_get_node(dev);
+ for (child = OF_child(node); child != 0; child = OF_peer(child)) {
+ char name[32];
+ memset(name, 0, sizeof(name));
+ OF_getprop(child, "name", name, sizeof(name));
+
+ if (strncmp(name, "rpm-fans", 9) == 0 ||
+ strncmp(name, "fans", 5) == 0)
+ smu_attach_fans(dev, child);
+
+ if (strncmp(name, "sensors", 8) == 0)
+ smu_attach_sensors(dev, child);
+ }
+
+ /*
+ * Collect calibration constants.
+ */
+ smu_get_datablock(dev, SMU_CPUTEMP_CAL, data, sizeof(data));
+ sc->sc_cpu_diode_scale = (data[4] << 8) + data[5];
+ sc->sc_cpu_diode_offset = (data[6] << 8) + data[7];
+
+ smu_get_datablock(dev, SMU_CPUVOLT_CAL, data, sizeof(data));
+ sc->sc_cpu_volt_scale = (data[4] << 8) + data[5];
+ sc->sc_cpu_volt_offset = (data[6] << 8) + data[7];
+ sc->sc_cpu_curr_scale = (data[8] << 8) + data[9];
+ sc->sc_cpu_curr_offset = (data[10] << 8) + data[11];
+
+ smu_get_datablock(dev, SMU_SLOTPW_CAL, data, sizeof(data));
+ sc->sc_slots_pow_scale = (data[4] << 8) + data[5];
+ sc->sc_slots_pow_offset = (data[6] << 8) + data[7];
+
+ /*
+ * Set up simple-minded thermal management.
+ */
+ sc->sc_target_temp = 55;
+ sc->sc_critical_temp = 90;
+
+ SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "target_temp", CTLTYPE_INT | CTLFLAG_RW, &sc->sc_target_temp,
+ sizeof(int), "Target temperature (C)");
+ SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "critical_temp", CTLTYPE_INT | CTLFLAG_RW,
+ &sc->sc_critical_temp, sizeof(int), "Critical temperature (C)");
+
+ callout_init(&sc->sc_fanmgt_callout, 1);
+ smu_fanmgt_callout(dev);
+
+ /*
+ * Set up LED interface
+ */
+ sc->sc_leddev = led_create(smu_set_sleepled, dev, "sleepled");
+
+ /*
+ * Reset on power loss behavior
+ */
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "server_mode", CTLTYPE_INT | CTLFLAG_RW, dev, 0,
+ smu_server_mode, "I", "Enable reboot after power failure");
+
return (0);
}
@@ -166,19 +328,22 @@ static int
smu_run_cmd(device_t dev, struct smu_cmd *cmd)
{
struct smu_softc *sc;
- int doorbell_ack, result;
+ int doorbell_ack, result, oldpow;
sc = device_get_softc(dev);
mtx_lock(&sc->sc_mtx);
+ oldpow = powerpc_pow_enabled;
+ powerpc_pow_enabled = 0;
+
/* Copy the command to the mailbox */
memcpy(sc->sc_cmd, cmd, sizeof(*cmd));
bus_dmamap_sync(sc->sc_dmatag, sc->sc_cmd_dmamap, BUS_DMASYNC_PREWRITE);
bus_space_write_4(sc->sc_bt, sc->sc_mailbox, 0, sc->sc_cmd_phys);
- /* Invalidate the cacheline it is in -- SMU bypasses the cache */
- __asm __volatile("dcbst 0,%0; sync" :: "r"(sc->sc_cmd): "memory");
+ /* Flush the cacheline it is in -- SMU bypasses the cache */
+ __asm __volatile("sync; dcbf 0,%0; sync" :: "r"(sc->sc_cmd): "memory");
/* Ring SMU doorbell */
macgpio_write(smu_doorbell, GPIO_DDR_OUTPUT);
@@ -188,7 +353,7 @@ smu_run_cmd(device_t dev, struct smu_cmd *cmd)
/* XXX: timeout */
DELAY(50);
doorbell_ack = macgpio_read(smu_doorbell);
- } while (!doorbell_ack);
+ } while (doorbell_ack != (GPIO_DDR_OUTPUT | GPIO_LEVEL_RO | GPIO_DATA));
/* Check result. First invalidate the cache again... */
__asm __volatile("dcbf 0,%0; sync" :: "r"(sc->sc_cmd) : "memory");
@@ -196,16 +361,50 @@ smu_run_cmd(device_t dev, struct smu_cmd *cmd)
bus_dmamap_sync(sc->sc_dmatag, sc->sc_cmd_dmamap, BUS_DMASYNC_POSTREAD);
/* SMU acks the command by inverting the command bits */
- if (sc->sc_cmd->cmd == ~cmd->cmd)
+ if (sc->sc_cmd->cmd == ((~cmd->cmd) & 0xff))
result = 0;
else
result = EIO;
+ powerpc_pow_enabled = oldpow;
+
+ memcpy(cmd->data, sc->sc_cmd->data, sizeof(cmd->data));
+ cmd->len = sc->sc_cmd->len;
+
mtx_unlock(&sc->sc_mtx);
return (result);
}
+static int
+smu_get_datablock(device_t dev, int8_t id, uint8_t *buf, size_t len)
+{
+ struct smu_cmd cmd;
+ uint8_t addr[4];
+
+ cmd.cmd = SMU_PARTITION;
+ cmd.len = 2;
+ cmd.data[0] = SMU_PARTITION_LATEST;
+ cmd.data[1] = id;
+
+ smu_run_cmd(dev, &cmd);
+
+ addr[0] = addr[1] = 0;
+ addr[2] = cmd.data[0];
+ addr[3] = cmd.data[1];
+
+ cmd.cmd = SMU_MISC;
+ cmd.len = 7;
+ cmd.data[0] = SMU_MISC_GET_DATA;
+ cmd.data[1] = sizeof(addr);
+ memcpy(&cmd.data[2], addr, sizeof(addr));
+ cmd.data[6] = len;
+
+ smu_run_cmd(dev, &cmd);
+ memcpy(buf, cmd.data, len);
+ return (0);
+}
+
static void
smu_slew_cpu_voltage(device_t dev, int to)
{
@@ -286,3 +485,453 @@ doorbell_attach(device_t dev)
smu_doorbell = dev;
return (0);
}
+
+/*
+ * Sensor and fan management
+ */
+
+static int
+smu_fan_set_rpm(device_t smu, struct smu_fan *fan, int rpm)
+{
+ struct smu_cmd cmd;
+ int error;
+
+ cmd.cmd = SMU_FAN;
+ error = EIO;
+
+ /* Clamp to allowed range */
+ rpm = max(fan->min_rpm, rpm);
+ rpm = min(fan->max_rpm, rpm);
+
+ /*
+ * Apple has two fan control mechanisms. We can't distinguish
+ * them except by seeing if the new one fails. If the new one
+ * fails, use the old one.
+ */
+
+ if (!fan->old_style) {
+ cmd.len = 4;
+ cmd.data[0] = 0x30;
+ cmd.data[1] = fan->reg;
+ cmd.data[2] = (rpm >> 8) & 0xff;
+ cmd.data[3] = rpm & 0xff;
+
+ error = smu_run_cmd(smu, &cmd);
+ if (error)
+ fan->old_style = 1;
+ }
+
+ if (fan->old_style) {
+ cmd.len = 14;
+ cmd.data[0] = 0;
+ cmd.data[1] = 1 << fan->reg;
+ cmd.data[2 + 2*fan->reg] = (rpm >> 8) & 0xff;
+ cmd.data[3 + 2*fan->reg] = rpm & 0xff;
+ error = smu_run_cmd(smu, &cmd);
+ }
+
+ if (error == 0)
+ fan->setpoint = rpm;
+
+ return (error);
+}
+
+static int
+smu_fan_read_rpm(device_t smu, struct smu_fan *fan)
+{
+ struct smu_cmd cmd;
+
+ cmd.cmd = SMU_FAN;
+ cmd.len = 1;
+ cmd.data[0] = 1;
+
+ smu_run_cmd(smu, &cmd);
+
+ return ((cmd.data[fan->reg*2+1] << 8) | cmd.data[fan->reg*2+2]);
+}
+
+static int
+smu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t smu;
+ struct smu_softc *sc;
+ struct smu_fan *fan;
+ int rpm, error;
+
+ smu = arg1;
+ sc = device_get_softc(smu);
+ fan = &sc->sc_fans[arg2];
+
+ rpm = smu_fan_read_rpm(smu, fan);
+ error = sysctl_handle_int(oidp, &rpm, 0, req);
+
+ if (error || !req->newptr)
+ return (error);
+
+ sc->sc_lastuserchange = time_uptime;
+
+ return (smu_fan_set_rpm(smu, fan, rpm));
+}
+
+static void
+smu_attach_fans(device_t dev, phandle_t fanroot)
+{
+ struct smu_fan *fan;
+ struct smu_softc *sc;
+ struct sysctl_oid *oid, *fanroot_oid;
+ struct sysctl_ctx_list *ctx;
+ phandle_t child;
+ char type[32], sysctl_name[32];
+ int i;
+
+ sc = device_get_softc(dev);
+ sc->sc_nfans = 0;
+
+ for (child = OF_child(fanroot); child != 0; child = OF_peer(child))
+ sc->sc_nfans++;
+
+ if (sc->sc_nfans == 0) {
+ device_printf(dev, "WARNING: No fans detected!\n");
+ return;
+ }
+
+ sc->sc_fans = malloc(sc->sc_nfans * sizeof(struct smu_fan), M_SMU,
+ M_WAITOK | M_ZERO);
+
+ fan = sc->sc_fans;
+ sc->sc_nfans = 0;
+
+ ctx = device_get_sysctl_ctx(dev);
+ fanroot_oid = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "fans",
+ CTLFLAG_RD, 0, "SMU Fan Information");
+
+ for (child = OF_child(fanroot); child != 0; child = OF_peer(child)) {
+ OF_getprop(child, "device_type", type, sizeof(type));
+ if (strcmp(type, "fan-rpm-control") != 0)
+ continue;
+
+ fan->old_style = 0;
+ OF_getprop(child, "reg", &fan->reg, sizeof(cell_t));
+ OF_getprop(child, "min-value", &fan->min_rpm, sizeof(cell_t));
+ OF_getprop(child, "max-value", &fan->max_rpm, sizeof(cell_t));
+
+ if (OF_getprop(child, "unmanaged-value", &fan->unmanaged_rpm,
+ sizeof(cell_t)) != sizeof(cell_t))
+ fan->unmanaged_rpm = fan->max_rpm;
+
+ fan->setpoint = smu_fan_read_rpm(dev, fan);
+
+ OF_getprop(child, "location", fan->location,
+ sizeof(fan->location));
+
+ /* Add sysctls */
+ for (i = 0; i < strlen(fan->location); i++) {
+ sysctl_name[i] = tolower(fan->location[i]);
+ if (isspace(sysctl_name[i]))
+ sysctl_name[i] = '_';
+ }
+ sysctl_name[i] = 0;
+
+ oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(fanroot_oid),
+ OID_AUTO, sysctl_name, CTLFLAG_RD, 0, "Fan Information");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "minrpm",
+ CTLTYPE_INT | CTLFLAG_RD, &fan->min_rpm, sizeof(cell_t),
+ "Minimum allowed RPM");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "maxrpm",
+ CTLTYPE_INT | CTLFLAG_RD, &fan->max_rpm, sizeof(cell_t),
+ "Maximum allowed RPM");
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "rpm",
+ CTLTYPE_INT | CTLFLAG_RW, dev, sc->sc_nfans,
+ smu_fanrpm_sysctl, "I", "Fan RPM");
+
+ fan++;
+ sc->sc_nfans++;
+ }
+}
+
+static int
+smu_sensor_read(device_t smu, struct smu_sensor *sens)
+{
+ struct smu_cmd cmd;
+ struct smu_softc *sc;
+ int64_t value;
+
+ cmd.cmd = SMU_ADC;
+ cmd.len = 1;
+ cmd.data[0] = sens->reg;
+
+ smu_run_cmd(smu, &cmd);
+
+ sc = device_get_softc(smu);
+ value = (cmd.data[0] << 8) | cmd.data[1];
+
+ switch (sens->type) {
+ case SMU_TEMP_SENSOR:
+ value *= sc->sc_cpu_diode_scale;
+ value >>= 3;
+ value += ((int64_t)sc->sc_cpu_diode_offset) << 9;
+ value <<= 1;
+
+ /* Convert from 16.16 fixed point degC into integer C. */
+ value *= 15625;
+ value /= 1024;
+ value /= 1000000;
+ break;
+ case SMU_VOLTAGE_SENSOR:
+ value *= sc->sc_cpu_volt_scale;
+ value += sc->sc_cpu_volt_offset;
+ value <<= 4;
+
+ /* Convert from 16.16 fixed point V into mV. */
+ value *= 15625;
+ value /= 1024;
+ value /= 1000;
+ break;
+ case SMU_CURRENT_SENSOR:
+ value *= sc->sc_cpu_curr_scale;
+ value += sc->sc_cpu_curr_offset;
+ value <<= 4;
+
+ /* Convert from 16.16 fixed point A into mA. */
+ value *= 15625;
+ value /= 1024;
+ value /= 1000;
+ break;
+ case SMU_POWER_SENSOR:
+ value *= sc->sc_slots_pow_scale;
+ value += sc->sc_slots_pow_offset;
+ value <<= 4;
+
+ /* Convert from 16.16 fixed point W into mW. */
+ value *= 15625;
+ value /= 1024;
+ value /= 1000;
+ break;
+ }
+
+ return (value);
+}
+
+static int
+smu_sensor_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t smu;
+ struct smu_softc *sc;
+ struct smu_sensor *sens;
+ int value, error;
+
+ smu = arg1;
+ sc = device_get_softc(smu);
+ sens = &sc->sc_sensors[arg2];
+
+ value = smu_sensor_read(smu, sens);
+ error = sysctl_handle_int(oidp, &value, 0, req);
+
+ return (error);
+}
+
+static void
+smu_attach_sensors(device_t dev, phandle_t sensroot)
+{
+ struct smu_sensor *sens;
+ struct smu_softc *sc;
+ struct sysctl_oid *sensroot_oid;
+ struct sysctl_ctx_list *ctx;
+ phandle_t child;
+ char type[32];
+ int i;
+
+ sc = device_get_softc(dev);
+ sc->sc_nsensors = 0;
+
+ for (child = OF_child(sensroot); child != 0; child = OF_peer(child))
+ sc->sc_nsensors++;
+
+ if (sc->sc_nsensors == 0) {
+ device_printf(dev, "WARNING: No sensors detected!\n");
+ return;
+ }
+
+ sc->sc_sensors = malloc(sc->sc_nsensors * sizeof(struct smu_sensor),
+ M_SMU, M_WAITOK | M_ZERO);
+
+ sens = sc->sc_sensors;
+ sc->sc_nsensors = 0;
+
+ ctx = device_get_sysctl_ctx(dev);
+ sensroot_oid = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensors",
+ CTLFLAG_RD, 0, "SMU Sensor Information");
+
+ for (child = OF_child(sensroot); child != 0; child = OF_peer(child)) {
+ char sysctl_name[40], sysctl_desc[40];
+ const char *units;
+
+ OF_getprop(child, "device_type", type, sizeof(type));
+
+ if (strcmp(type, "current-sensor") == 0) {
+ sens->type = SMU_CURRENT_SENSOR;
+ units = "mA";
+ } else if (strcmp(type, "temp-sensor") == 0) {
+ sens->type = SMU_TEMP_SENSOR;
+ units = "C";
+ } else if (strcmp(type, "voltage-sensor") == 0) {
+ sens->type = SMU_VOLTAGE_SENSOR;
+ units = "mV";
+ } else if (strcmp(type, "power-sensor") == 0) {
+ sens->type = SMU_POWER_SENSOR;
+ units = "mW";
+ } else {
+ continue;
+ }
+
+ OF_getprop(child, "reg", &sens->reg, sizeof(cell_t));
+ OF_getprop(child, "location", sens->location,
+ sizeof(sens->location));
+
+ for (i = 0; i < strlen(sens->location); i++) {
+ sysctl_name[i] = tolower(sens->location[i]);
+ if (isspace(sysctl_name[i]))
+ sysctl_name[i] = '_';
+ }
+ sysctl_name[i] = 0;
+
+ sprintf(sysctl_desc,"%s (%s)", sens->location, units);
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensroot_oid), OID_AUTO,
+ sysctl_name, CTLTYPE_INT | CTLFLAG_RD, dev, sc->sc_nsensors,
+ smu_sensor_sysctl, "I", sysctl_desc);
+
+ sens++;
+ sc->sc_nsensors++;
+ }
+}
+
+static int
+ms_to_ticks(int ms)
+{
+ if (hz > 1000)
+ return ms*(hz/1000);
+
+ return ms/(1000/hz);
+}
+
+static void
+smu_fanmgt_callout(void *xdev) {
+ device_t smu = xdev;
+ struct smu_softc *sc;
+ int i, maxtemp, temp, factor;
+
+ sc = device_get_softc(smu);
+
+ if (time_uptime - sc->sc_lastuserchange < 3) {
+ /*
+ * If we have heard from a user process in the last 3 seconds,
+ * go away.
+ */
+
+ callout_reset(&sc->sc_fanmgt_callout,
+ ms_to_ticks(SMU_FANMGT_INTERVAL), smu_fanmgt_callout, smu);
+ return;
+ }
+
+ maxtemp = 0;
+ for (i = 0; i < sc->sc_nsensors; i++) {
+ if (sc->sc_sensors[i].type != SMU_TEMP_SENSOR)
+ continue;
+
+ temp = smu_sensor_read(smu, &sc->sc_sensors[i]);
+ if (temp > maxtemp)
+ maxtemp = temp;
+ }
+
+ if (maxtemp < 10) { /* Bail if no good sensors */
+ for (i = 0; i < sc->sc_nfans; i++)
+ smu_fan_set_rpm(smu, &sc->sc_fans[i],
+ sc->sc_fans[i].unmanaged_rpm);
+ return;
+ }
+
+ if (maxtemp > sc->sc_critical_temp) {
+ device_printf(smu, "WARNING: Current system temperature (%d C) "
+ "exceeds critical temperature (%d C)! Shutting down!\n",
+ maxtemp, sc->sc_critical_temp);
+ shutdown_nice(RB_POWEROFF);
+ }
+
+ if (maxtemp - sc->sc_target_temp > 20)
+ device_printf(smu, "WARNING: Current system temperature (%d C) "
+ "more than 20 degrees over target temperature (%d C)!\n",
+ maxtemp, sc->sc_target_temp);
+
+ if (maxtemp > sc->sc_target_temp)
+ factor = 110;
+ else if (sc->sc_target_temp - maxtemp > 4)
+ factor = 90;
+ else if (sc->sc_target_temp - maxtemp > 1)
+ factor = 95;
+ else
+ factor = 100;
+
+ for (i = 0; i < sc->sc_nfans; i++)
+ smu_fan_set_rpm(smu, &sc->sc_fans[i],
+ (sc->sc_fans[i].setpoint * factor) / 100);
+
+ callout_reset(&sc->sc_fanmgt_callout,
+ ms_to_ticks(SMU_FANMGT_INTERVAL), smu_fanmgt_callout, smu);
+}
+
+static void
+smu_set_sleepled(void *xdev, int onoff)
+{
+ struct smu_cmd cmd;
+ device_t smu = xdev;
+
+ cmd.cmd = SMU_MISC;
+ cmd.len = 3;
+ cmd.data[0] = SMU_MISC_LED_CTRL;
+ cmd.data[1] = 0;
+ cmd.data[2] = onoff;
+
+ smu_run_cmd(smu, &cmd);
+}
+
+static int
+smu_server_mode(SYSCTL_HANDLER_ARGS)
+{
+ struct smu_cmd cmd;
+ u_int server_mode;
+ device_t smu = arg1;
+ int error;
+
+ cmd.cmd = SMU_POWER_EVENTS;
+ cmd.len = 1;
+ cmd.data[0] = SMU_PWR_GET_POWERUP;
+
+ error = smu_run_cmd(smu, &cmd);
+
+ if (error)
+ return (error);
+
+ server_mode = (cmd.data[1] & SMU_WAKEUP_AC_INSERT) ? 1 : 0;
+
+ error = sysctl_handle_int(oidp, &server_mode, 0, req);
+
+ if (error || !req->newptr)
+ return (error);
+
+ if (server_mode == 1)
+ cmd.data[0] = SMU_PWR_SET_POWERUP;
+ else if (server_mode == 0)
+ cmd.data[0] = SMU_PWR_CLR_POWERUP;
+ else
+ return (EINVAL);
+
+ cmd.len = 3;
+ cmd.data[1] = 0;
+ cmd.data[2] = SMU_WAKEUP_AC_INSERT;
+
+ return (smu_run_cmd(smu, &cmd));
+}
+
diff --git a/sys/powerpc/powerpc/cpu.c b/sys/powerpc/powerpc/cpu.c
index ebf36ee..d02c156 100644
--- a/sys/powerpc/powerpc/cpu.c
+++ b/sys/powerpc/powerpc/cpu.c
@@ -446,8 +446,16 @@ cpu_970_setup(int cpuid, uint16_t vers)
: "=r" (hid0_hi), "=r" (hid0_lo) : "K" (SPR_HID0));
/* Configure power-saving mode */
- hid0_hi |= (HID0_NAP | HID0_DPM);
- hid0_hi &= ~(HID0_DOZE | HID0_DEEPNAP);
+ switch (vers) {
+ case IBM970MP:
+ hid0_hi |= (HID0_DEEPNAP | HID0_DPM);
+ hid0_hi &= ~(HID0_DOZE | HID0_NAP);
+ break;
+ default:
+ hid0_hi |= (HID0_NAP | HID0_DPM);
+ hid0_hi &= ~(HID0_DOZE | HID0_DEEPNAP);
+ break;
+ }
powerpc_pow_enabled = 1;
__asm __volatile (" \
diff --git a/sys/powerpc/powerpc/mem.c b/sys/powerpc/powerpc/mem.c
index d56d634..e4b70c6 100644
--- a/sys/powerpc/powerpc/mem.c
+++ b/sys/powerpc/powerpc/mem.c
@@ -121,8 +121,7 @@ kmem_direct_mapped: v = uio->uio_offset;
else if (dev2unit(dev) == CDEV_MINOR_KMEM) {
va = uio->uio_offset;
- if ((va < VM_MIN_KERNEL_ADDRESS)
- || (va > VM_MAX_KERNEL_ADDRESS))
+ if ((va < VM_MIN_KERNEL_ADDRESS) || (va > virtual_end))
goto kmem_direct_mapped;
va = trunc_page(uio->uio_offset);
@@ -135,8 +134,7 @@ kmem_direct_mapped: v = uio->uio_offset;
*/
for (; va < eva; va += PAGE_SIZE)
- if (pmap_extract(kernel_pmap, va)
- == 0)
+ if (pmap_extract(kernel_pmap, va) == 0)
return (EFAULT);
prot = (uio->uio_rw == UIO_READ)
diff --git a/sys/security/mac_biba/mac_biba.c b/sys/security/mac_biba/mac_biba.c
index e66e089..fcede07 100644
--- a/sys/security/mac_biba/mac_biba.c
+++ b/sys/security/mac_biba/mac_biba.c
@@ -955,6 +955,7 @@ biba_devfs_create_device(struct ucred *cred, struct mount *mp,
biba_type = MAC_BIBA_TYPE_EQUAL;
else if (ptys_equal &&
(strncmp(dev->si_name, "ttyp", strlen("ttyp")) == 0 ||
+ strncmp(dev->si_name, "pts/", strlen("pts/")) == 0 ||
strncmp(dev->si_name, "ptyp", strlen("ptyp")) == 0))
biba_type = MAC_BIBA_TYPE_EQUAL;
else
diff --git a/sys/security/mac_lomac/mac_lomac.c b/sys/security/mac_lomac/mac_lomac.c
index af9539c..5cdfc67 100644
--- a/sys/security/mac_lomac/mac_lomac.c
+++ b/sys/security/mac_lomac/mac_lomac.c
@@ -1043,6 +1043,7 @@ lomac_devfs_create_device(struct ucred *cred, struct mount *mp,
lomac_type = MAC_LOMAC_TYPE_EQUAL;
else if (ptys_equal &&
(strncmp(dev->si_name, "ttyp", strlen("ttyp")) == 0 ||
+ strncmp(dev->si_name, "pts/", strlen("pts/")) == 0 ||
strncmp(dev->si_name, "ptyp", strlen("ptyp")) == 0))
lomac_type = MAC_LOMAC_TYPE_EQUAL;
else
diff --git a/sys/security/mac_mls/mac_mls.c b/sys/security/mac_mls/mac_mls.c
index a0669c7..d41799d 100644
--- a/sys/security/mac_mls/mac_mls.c
+++ b/sys/security/mac_mls/mac_mls.c
@@ -918,6 +918,7 @@ mls_devfs_create_device(struct ucred *cred, struct mount *mp,
mls_type = MAC_MLS_TYPE_HIGH;
else if (ptys_equal &&
(strncmp(dev->si_name, "ttyp", strlen("ttyp")) == 0 ||
+ strncmp(dev->si_name, "pts/", strlen("pts/")) == 0 ||
strncmp(dev->si_name, "ptyp", strlen("ptyp")) == 0))
mls_type = MAC_MLS_TYPE_EQUAL;
else
diff --git a/sys/sparc64/include/cache.h b/sys/sparc64/include/cache.h
index 9dd7191..9c4804b 100644
--- a/sys/sparc64/include/cache.h
+++ b/sys/sparc64/include/cache.h
@@ -91,7 +91,7 @@ struct cacheinfo {
struct pcpu;
-typedef void cache_enable_t(void);
+typedef void cache_enable_t(u_int cpu_impl);
typedef void cache_flush_t(void);
typedef void dcache_page_inval_t(vm_paddr_t pa);
typedef void icache_page_inval_t(vm_paddr_t pa);
diff --git a/sys/sparc64/include/cpu.h b/sys/sparc64/include/cpu.h
index b593f13..c0845a0 100644
--- a/sys/sparc64/include/cpu.h
+++ b/sys/sparc64/include/cpu.h
@@ -52,7 +52,7 @@
extern char btext[];
extern char etext[];
-void cheetah_init(void);
+void cheetah_init(u_int cpu_impl);
void cpu_halt(void);
void cpu_reset(void);
void fork_trampoline(void);
diff --git a/sys/sparc64/include/md_var.h b/sys/sparc64/include/md_var.h
index 592d980..a1f3980 100644
--- a/sys/sparc64/include/md_var.h
+++ b/sys/sparc64/include/md_var.h
@@ -47,8 +47,8 @@ extern vm_paddr_t kstack0_phys;
struct pcpu;
struct md_utrap;
-const char *cpu_cpuid_prop(void);
-uint32_t cpu_get_mid(void);
+const char *cpu_cpuid_prop(u_int cpu_impl);
+uint32_t cpu_get_mid(u_int cpu_impl);
void cpu_identify(u_long vers, u_int clock, u_int id);
void cpu_setregs(struct pcpu *pc);
int is_physical_memory(vm_paddr_t addr);
diff --git a/sys/sparc64/include/pcpu.h b/sys/sparc64/include/pcpu.h
index 7d2f5a0..f5735bf 100644
--- a/sys/sparc64/include/pcpu.h
+++ b/sys/sparc64/include/pcpu.h
@@ -54,6 +54,7 @@ struct pmap;
u_long pc_tickref; \
u_long pc_tickadj; \
u_int pc_clock; \
+ u_int pc_impl; \
u_int pc_mid; \
u_int pc_node; \
u_int pc_tlb_ctx; \
diff --git a/sys/sparc64/include/pmap.h b/sys/sparc64/include/pmap.h
index 91c2a51..83c8190 100644
--- a/sys/sparc64/include/pmap.h
+++ b/sys/sparc64/include/pmap.h
@@ -80,7 +80,7 @@ struct pmap {
#define pmap_page_get_memattr(m) VM_MEMATTR_DEFAULT
#define pmap_page_set_memattr(m, ma) (void)0
-void pmap_bootstrap(void);
+void pmap_bootstrap(u_int cpu_impl);
vm_paddr_t pmap_kextract(vm_offset_t va);
void pmap_kenter(vm_offset_t va, vm_page_t m);
void pmap_kremove(vm_offset_t);
diff --git a/sys/sparc64/include/smp.h b/sys/sparc64/include/smp.h
index 8735543..467c6b6 100644
--- a/sys/sparc64/include/smp.h
+++ b/sys/sparc64/include/smp.h
@@ -94,7 +94,7 @@ void cpu_mp_shutdown(void);
typedef void cpu_ipi_selected_t(u_int, u_long, u_long, u_long);
extern cpu_ipi_selected_t *cpu_ipi_selected;
-void mp_init(void);
+void mp_init(u_int cpu_impl);
extern struct mtx ipi_mtx;
extern struct ipi_cache_args ipi_cache_args;
diff --git a/sys/sparc64/include/tick.h b/sys/sparc64/include/tick.h
index 9182cb4..ae80d53 100644
--- a/sys/sparc64/include/tick.h
+++ b/sys/sparc64/include/tick.h
@@ -31,8 +31,8 @@
extern u_int hardclock_use_stick;
-void tick_clear(void);
+void tick_clear(u_int cpu_impl);
void tick_start(void);
-void tick_stop(void);
+void tick_stop(u_int cpu_impl);
#endif
diff --git a/sys/sparc64/include/ver.h b/sys/sparc64/include/ver.h
index 0fb7933..ad6841b 100644
--- a/sys/sparc64/include/ver.h
+++ b/sys/sparc64/include/ver.h
@@ -43,24 +43,28 @@
#ifndef LOCORE
-#define VER_MANUF_MASK (((1L<<VER_MANUF_SIZE)-1)<<VER_MANUF_SHIFT)
-#define VER_IMPL_MASK (((1L<<VER_IMPL_SIZE)-1)<<VER_IMPL_SHIFT)
-#define VER_MASK_MASK (((1L<<VER_MASK_SIZE)-1)<<VER_MASK_SHIFT)
-#define VER_MAXTL_MASK (((1L<<VER_MAXTL_SIZE)-1)<<VER_MAXTL_SHIFT)
-#define VER_MAXWIN_MASK (((1L<<VER_MAXWIN_SIZE)-1)<<VER_MAXWIN_SHIFT)
+#define VER_MANUF_MASK \
+ (((1UL << VER_MANUF_SIZE) - 1) << VER_MANUF_SHIFT)
+#define VER_IMPL_MASK \
+ (((1UL << VER_IMPL_SIZE) - 1) << VER_IMPL_SHIFT)
+#define VER_MASK_MASK \
+ (((1UL << VER_MASK_SIZE) - 1) << VER_MASK_SHIFT)
+#define VER_MAXTL_MASK \
+ (((1UL << VER_MAXTL_SIZE) - 1) << VER_MAXTL_SHIFT)
+#define VER_MAXWIN_MASK \
+ (((1UL << VER_MAXWIN_SIZE) - 1) << VER_MAXWIN_SHIFT)
-#define VER_MANUF(ver) \
+#define VER_MANUF(ver) \
(((ver) & VER_MANUF_MASK) >> VER_MANUF_SHIFT)
-#define VER_IMPL(ver) \
+#define VER_IMPL(ver) \
(((ver) & VER_IMPL_MASK) >> VER_IMPL_SHIFT)
-#define VER_MASK(ver) \
+#define VER_MASK(ver) \
(((ver) & VER_MASK_MASK) >> VER_MASK_SHIFT)
-#define VER_MAXTL(ver) \
+#define VER_MAXTL(ver) \
(((ver) & VER_MAXTL_MASK) >> VER_MAXTL_SHIFT)
-#define VER_MAXWIN(ver) \
+#define VER_MAXWIN(ver) \
(((ver) & VER_MAXWIN_MASK) >> VER_MAXWIN_SHIFT)
-extern int cpu_impl;
extern char sparc64_model[];
#endif /* !LOCORE */
diff --git a/sys/sparc64/sparc64/cache.c b/sys/sparc64/sparc64/cache.c
index 8dd933e..8cb8dee 100644
--- a/sys/sparc64/sparc64/cache.c
+++ b/sys/sparc64/sparc64/cache.c
@@ -43,6 +43,7 @@
*/
/*-
* Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>.
+ * Copyright (c) 2008, 2010 Marius Strobl <marius@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -89,32 +90,49 @@ icache_page_inval_t *icache_page_inval;
#define OF_GET(h, n, v) OF_getprop((h), (n), &(v), sizeof(v))
+static u_int cache_new_prop(u_int cpu_impl);
+
+static u_int
+cache_new_prop(u_int cpu_impl)
+{
+
+ switch (cpu_impl) {
+ case CPU_IMPL_ULTRASPARCIV:
+ case CPU_IMPL_ULTRASPARCIVp:
+ return (1);
+ default:
+ return (0);
+ }
+}
+
/*
- * Fill in the cache parameters using the cpu node.
+ * Fill in the cache parameters using the CPU node.
*/
void
cache_init(struct pcpu *pcpu)
{
u_long set;
+ u_int use_new_prop;
- if (OF_GET(pcpu->pc_node, "icache-size",
- pcpu->pc_cache.ic_size) == -1 ||
- OF_GET(pcpu->pc_node, "icache-line-size",
- pcpu->pc_cache.ic_linesize) == -1 ||
- OF_GET(pcpu->pc_node, "icache-associativity",
- pcpu->pc_cache.ic_assoc) == -1 ||
- OF_GET(pcpu->pc_node, "dcache-size",
- pcpu->pc_cache.dc_size) == -1 ||
- OF_GET(pcpu->pc_node, "dcache-line-size",
- pcpu->pc_cache.dc_linesize) == -1 ||
- OF_GET(pcpu->pc_node, "dcache-associativity",
- pcpu->pc_cache.dc_assoc) == -1 ||
- OF_GET(pcpu->pc_node, "ecache-size",
- pcpu->pc_cache.ec_size) == -1 ||
- OF_GET(pcpu->pc_node, "ecache-line-size",
- pcpu->pc_cache.ec_linesize) == -1 ||
- OF_GET(pcpu->pc_node, "ecache-associativity",
- pcpu->pc_cache.ec_assoc) == -1)
+ use_new_prop = cache_new_prop(pcpu->pc_impl);
+ if (OF_GET(pcpu->pc_node, !use_new_prop ? "icache-size" :
+ "l1-icache-size", pcpu->pc_cache.ic_size) == -1 ||
+ OF_GET(pcpu->pc_node, !use_new_prop ? "icache-line-size" :
+ "l1-icache-line-size", pcpu->pc_cache.ic_linesize) == -1 ||
+ OF_GET(pcpu->pc_node, !use_new_prop ? "icache-associativity" :
+ "l1-icache-associativity", pcpu->pc_cache.ic_assoc) == -1 ||
+ OF_GET(pcpu->pc_node, !use_new_prop ? "dcache-size" :
+ "l1-dcache-size", pcpu->pc_cache.dc_size) == -1 ||
+ OF_GET(pcpu->pc_node, !use_new_prop ? "dcache-line-size" :
+ "l1-dcache-line-size", pcpu->pc_cache.dc_linesize) == -1 ||
+ OF_GET(pcpu->pc_node, !use_new_prop ? "dcache-associativity" :
+ "l1-dcache-associativity", pcpu->pc_cache.dc_assoc) == -1 ||
+ OF_GET(pcpu->pc_node, !use_new_prop ? "ecache-size" :
+ "l2-cache-size", pcpu->pc_cache.ec_size) == -1 ||
+ OF_GET(pcpu->pc_node, !use_new_prop ? "ecache-line-size" :
+ "l2-cache-line-size", pcpu->pc_cache.ec_linesize) == -1 ||
+ OF_GET(pcpu->pc_node, !use_new_prop ? "ecache-associativity" :
+ "l2-cache-associativity", pcpu->pc_cache.ec_assoc) == -1)
panic("cache_init: could not retrieve cache parameters");
set = pcpu->pc_cache.ic_size / pcpu->pc_cache.ic_assoc;
@@ -130,7 +148,7 @@ cache_init(struct pcpu *pcpu)
if ((set & ~(1UL << (ffs(set) - 1))) != 0)
panic("cache_init: E$ set size not a power of 2");
- if (cpu_impl >= CPU_IMPL_ULTRASPARCIII) {
+ if (pcpu->pc_impl >= CPU_IMPL_ULTRASPARCIII) {
cache_enable = cheetah_cache_enable;
cache_flush = cheetah_cache_flush;
dcache_page_inval = cheetah_dcache_page_inval;
diff --git a/sys/sparc64/sparc64/cheetah.c b/sys/sparc64/sparc64/cheetah.c
index e2dc714..ae24744 100644
--- a/sys/sparc64/sparc64/cheetah.c
+++ b/sys/sparc64/sparc64/cheetah.c
@@ -58,7 +58,7 @@ __FBSDID("$FreeBSD$");
* CPU-specific initialization
*/
void
-cheetah_init(void)
+cheetah_init(u_int cpu_impl)
{
register_t s;
@@ -119,7 +119,7 @@ cheetah_init(void)
* Enable level 1 caches.
*/
void
-cheetah_cache_enable(void)
+cheetah_cache_enable(u_int cpu_impl)
{
u_long lsu;
diff --git a/sys/sparc64/sparc64/identcpu.c b/sys/sparc64/sparc64/identcpu.c
index cdb09e6..0b73151 100644
--- a/sys/sparc64/sparc64/identcpu.c
+++ b/sys/sparc64/sparc64/identcpu.c
@@ -15,7 +15,6 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/sysctl.h>
-#include <machine/cpufunc.h>
#include <machine/md_var.h>
#include <machine/ver.h>
@@ -34,8 +33,6 @@ static u_int cpu_freq;
SYSCTL_UINT(_hw_freq, OID_AUTO, cpu, CTLFLAG_RD, &cpu_freq, 0,
"CPU clock frequency");
-int cpu_impl;
-
void
cpu_identify(u_long vers, u_int freq, u_int id)
{
diff --git a/sys/sparc64/sparc64/iommu.c b/sys/sparc64/sparc64/iommu.c
index b5f24db..9d31303 100644
--- a/sys/sparc64/sparc64/iommu.c
+++ b/sys/sparc64/sparc64/iommu.c
@@ -130,6 +130,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/mutex.h>
+#include <sys/pcpu.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/uio.h>
@@ -377,7 +378,7 @@ iommu_init(const char *name, struct iommu_state *is, u_int tsbsize,
printf("%s: PROM IOTSB size: %d (%d entries)\n", name,
obptsbsize, obptsbentries);
if ((is->is_flags & IOMMU_PRESERVE_PROM) != 0 &&
- !(cpu_impl == CPU_IMPL_ULTRASPARCIIi && obptsbsize == 7)) {
+ !(PCPU_GET(impl) == CPU_IMPL_ULTRASPARCIIi && obptsbsize == 7)) {
if (obptsbentries > tsbentries)
panic("%s: PROM IOTSB entries exceed kernel",
__func__);
diff --git a/sys/sparc64/sparc64/machdep.c b/sys/sparc64/sparc64/machdep.c
index eed7db8..c5b08ee 100644
--- a/sys/sparc64/sparc64/machdep.c
+++ b/sys/sparc64/sparc64/machdep.c
@@ -146,7 +146,7 @@ static int cpu_use_vis = 1;
cpu_block_copy_t *cpu_block_copy;
cpu_block_zero_t *cpu_block_zero;
-static phandle_t find_bsp(phandle_t node, uint32_t bspid);
+static phandle_t find_bsp(phandle_t node, uint32_t bspid, u_int cpu_impl);
void sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3,
ofw_vec_t *vec);
static void sparc64_shutdown_final(void *dummy, int howto);
@@ -241,7 +241,7 @@ spinlock_exit(void)
}
static phandle_t
-find_bsp(phandle_t node, uint32_t bspid)
+find_bsp(phandle_t node, uint32_t bspid, u_int cpu_impl)
{
char type[sizeof("cpu")];
phandle_t child;
@@ -250,7 +250,7 @@ find_bsp(phandle_t node, uint32_t bspid)
for (; node != 0; node = OF_peer(node)) {
child = OF_child(node);
if (child > 0) {
- child = find_bsp(child, bspid);
+ child = find_bsp(child, bspid, cpu_impl);
if (child > 0)
return (child);
} else {
@@ -259,7 +259,7 @@ find_bsp(phandle_t node, uint32_t bspid)
continue;
if (strcmp(type, "cpu") != 0)
continue;
- if (OF_getprop(node, cpu_cpuid_prop(), &cpuid,
+ if (OF_getprop(node, cpu_cpuid_prop(cpu_impl), &cpuid,
sizeof(cpuid)) <= 0)
continue;
if (cpuid == bspid)
@@ -270,7 +270,7 @@ find_bsp(phandle_t node, uint32_t bspid)
}
const char *
-cpu_cpuid_prop(void)
+cpu_cpuid_prop(u_int cpu_impl)
{
switch (cpu_impl) {
@@ -294,7 +294,7 @@ cpu_cpuid_prop(void)
}
uint32_t
-cpu_get_mid(void)
+cpu_get_mid(u_int cpu_impl)
{
switch (cpu_impl) {
@@ -328,6 +328,7 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec)
vm_offset_t va;
caddr_t kmdp;
phandle_t root;
+ u_int cpu_impl;
end = 0;
kmdp = NULL;
@@ -342,12 +343,12 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec)
* Do CPU-specific Initialization.
*/
if (cpu_impl >= CPU_IMPL_ULTRASPARCIII)
- cheetah_init();
+ cheetah_init(cpu_impl);
/*
* Clear (S)TICK timer (including NPT).
*/
- tick_clear();
+ tick_clear(cpu_impl);
/*
* UltraSparc II[e,i] based systems come up with the tick interrupt
@@ -357,7 +358,7 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec)
* enabled, causing an interrupt storm on startup since they are not
* handled.
*/
- tick_stop();
+ tick_stop(cpu_impl);
/*
* Set up Open Firmware entry points.
@@ -399,7 +400,8 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec)
pc = (struct pcpu *)(pcpu0 + (PCPU_PAGES * PAGE_SIZE)) - 1;
pcpu_init(pc, 0, sizeof(struct pcpu));
pc->pc_addr = (vm_offset_t)pcpu0;
- pc->pc_mid = cpu_get_mid();
+ pc->pc_impl = cpu_impl;
+ pc->pc_mid = cpu_get_mid(cpu_impl);
pc->pc_tlb_ctx = TLB_CTX_USER_MIN;
pc->pc_tlb_ctx_min = TLB_CTX_USER_MIN;
pc->pc_tlb_ctx_max = TLB_CTX_USER_MAX;
@@ -409,7 +411,7 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec)
* BSP is in the device tree in the first place).
*/
root = OF_peer(0);
- pc->pc_node = find_bsp(root, pc->pc_mid);
+ pc->pc_node = find_bsp(root, pc->pc_mid, cpu_impl);
if (pc->pc_node == 0)
OF_exit();
if (OF_getprop(pc->pc_node, "clock-frequency", &pc->pc_clock,
@@ -475,7 +477,7 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec)
panic("sparc64_init: cannot determine number of iTLB slots");
cache_init(pc);
- cache_enable();
+ cache_enable(cpu_impl);
uma_set_align(pc->pc_cache.dc_linesize - 1);
cpu_block_copy = bcopy;
@@ -501,13 +503,13 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec)
}
#ifdef SMP
- mp_init();
+ mp_init(cpu_impl);
#endif
/*
* Initialize virtual memory and calculate physmem.
*/
- pmap_bootstrap();
+ pmap_bootstrap(cpu_impl);
/*
* Initialize tunables.
diff --git a/sys/sparc64/sparc64/mp_locore.S b/sys/sparc64/sparc64/mp_locore.S
index 96239d5..17dc444 100644
--- a/sys/sparc64/sparc64/mp_locore.S
+++ b/sys/sparc64/sparc64/mp_locore.S
@@ -202,17 +202,17 @@ ENTRY(mp_startup)
cmp %l1, CPU_IMPL_ULTRASPARCIII
bl %icc, 3f
nop
- mov CPU_STICKSYNC, %l1
+ mov CPU_STICKSYNC, %l2
membar #StoreLoad
- stw %l1, [%l0 + CSA_STATE]
+ stw %l2, [%l0 + CSA_STATE]
-2: ldx [%l0 + CSA_STICK], %l1
- brz %l1, 2b
+2: ldx [%l0 + CSA_STICK], %l2
+ brz %l2, 2b
nop
- wr %l1, 0, %asr24
+ wr %l2, 0, %asr24
3: call cpu_get_mid
- nop
+ mov %l1, %o0
/*
* Inform the boot processor we have inited.
diff --git a/sys/sparc64/sparc64/mp_machdep.c b/sys/sparc64/sparc64/mp_machdep.c
index 8e9f9e1..8ea72f3 100644
--- a/sys/sparc64/sparc64/mp_machdep.c
+++ b/sys/sparc64/sparc64/mp_machdep.c
@@ -119,11 +119,11 @@ static u_int cpuid_to_mid[MAXCPU];
static int isjbus;
static volatile u_int shutdown_cpus;
-static void ap_count(phandle_t node, u_int mid);
-static void ap_start(phandle_t node, u_int mid);
+static void ap_count(phandle_t node, u_int mid, u_int cpu_impl);
+static void ap_start(phandle_t node, u_int mid, u_int cpu_impl);
static void cpu_mp_unleash(void *v);
static void foreach_ap(phandle_t node, void (*func)(phandle_t node,
- u_int mid));
+ u_int mid, u_int cpu_impl));
static void spitfire_ipi_send(u_int mid, u_long d0, u_long d1, u_long d2);
static void sun4u_startcpu(phandle_t cpu, void *func, u_long arg);
@@ -137,7 +137,7 @@ CTASSERT(MAXCPU <= sizeof(u_int) * NBBY);
CTASSERT(MAXCPU <= sizeof(int) * NBBY);
void
-mp_init(void)
+mp_init(u_int cpu_impl)
{
struct tte *tp;
int i;
@@ -171,11 +171,13 @@ mp_init(void)
}
static void
-foreach_ap(phandle_t node, void (*func)(phandle_t node, u_int mid))
+foreach_ap(phandle_t node, void (*func)(phandle_t node, u_int mid,
+ u_int cpu_impl))
{
char type[sizeof("cpu")];
phandle_t child;
u_int cpuid;
+ uint32_t cpu_impl;
/* There's no need to traverse the whole OFW tree twice. */
if (mp_maxid > 0 && mp_ncpus >= mp_maxid + 1)
@@ -191,12 +193,17 @@ foreach_ap(phandle_t node, void (*func)(phandle_t node, u_int mid))
continue;
if (strcmp(type, "cpu") != 0)
continue;
- if (OF_getprop(node, cpu_cpuid_prop(), &cpuid,
- sizeof(cpuid)) <= 0)
- panic("%s: can't get module ID", __func__);
+ if (OF_getprop(node, "implementation#", &cpu_impl,
+ sizeof(cpu_impl)) <= 0)
+ panic("%s: couldn't determine CPU "
+ "implementation", __func__);
+ if (OF_getprop(node, cpu_cpuid_prop(cpu_impl), &cpuid,
+ sizeof(cpuid)) <= 0)
+ panic("%s: couldn't determine CPU module ID",
+ __func__);
if (cpuid == PCPU_GET(mid))
continue;
- (*func)(node, cpuid);
+ (*func)(node, cpuid, cpu_impl);
}
}
}
@@ -216,7 +223,7 @@ cpu_mp_setmaxid()
}
static void
-ap_count(phandle_t node __unused, u_int mid __unused)
+ap_count(phandle_t node __unused, u_int mid __unused, u_int cpu_impl __unused)
{
mp_maxid++;
@@ -283,20 +290,20 @@ cpu_mp_start(void)
}
static void
-ap_start(phandle_t node, u_int mid)
+ap_start(phandle_t node, u_int mid, u_int cpu_impl)
{
volatile struct cpu_start_args *csa;
struct pcpu *pc;
register_t s;
vm_offset_t va;
- u_int clock;
u_int cpuid;
+ uint32_t clock;
if (mp_ncpus > MAXCPU)
return;
if (OF_getprop(node, "clock-frequency", &clock, sizeof(clock)) <= 0)
- panic("%s: can't get clock", __func__);
+ panic("%s: couldn't determine CPU frequency", __func__);
if (clock != PCPU_GET(clock))
hardclock_use_stick = 1;
@@ -329,6 +336,7 @@ ap_start(phandle_t node, u_int mid)
dpcpu_init((void *)kmem_alloc(kernel_map, DPCPU_SIZE), cpuid);
pc->pc_addr = va;
pc->pc_clock = clock;
+ pc->pc_impl = cpu_impl;
pc->pc_mid = mid;
pc->pc_node = node;
@@ -401,9 +409,9 @@ cpu_mp_bootstrap(struct pcpu *pc)
volatile struct cpu_start_args *csa;
csa = &cpu_start_args;
- if (cpu_impl >= CPU_IMPL_ULTRASPARCIII)
- cheetah_init();
- cache_enable();
+ if (pc->pc_impl >= CPU_IMPL_ULTRASPARCIII)
+ cheetah_init(pc->pc_impl);
+ cache_enable(pc->pc_impl);
pmap_map_tsb();
/*
* Flush all non-locked TLB entries possibly left over by the
diff --git a/sys/sparc64/sparc64/nexus.c b/sys/sparc64/sparc64/nexus.c
index 6a88fa6..ee01aa8 100644
--- a/sys/sparc64/sparc64/nexus.c
+++ b/sys/sparc64/sparc64/nexus.c
@@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
+#include <sys/pcpu.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
@@ -522,7 +523,7 @@ nexus_setup_dinfo(device_t dev, phandle_t node)
nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr),
(void **)&intr);
if (nintr > 0) {
- if (OF_getprop(node, cpu_impl < CPU_IMPL_ULTRASPARCIII ?
+ if (OF_getprop(node, PCPU_GET(impl) < CPU_IMPL_ULTRASPARCIII ?
"upa-portid" : "portid", &ign, sizeof(ign)) <= 0) {
device_printf(dev, "<%s>: could not determine portid\n",
ndi->ndi_obdinfo.obd_name);
diff --git a/sys/sparc64/sparc64/pmap.c b/sys/sparc64/sparc64/pmap.c
index cd04178..5ebc6ff 100644
--- a/sys/sparc64/sparc64/pmap.c
+++ b/sys/sparc64/sparc64/pmap.c
@@ -278,7 +278,7 @@ om_cmp(const void *a, const void *b)
* Bootstrap the system enough to run with virtual memory.
*/
void
-pmap_bootstrap(void)
+pmap_bootstrap(u_int cpu_impl)
{
struct pmap *pm;
struct tte *tp;
@@ -1543,7 +1543,7 @@ pmap_copy_tte(pmap_t src_pmap, pmap_t dst_pmap, struct tte *tp,
void
pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr,
- vm_size_t len, vm_offset_t src_addr)
+ vm_size_t len, vm_offset_t src_addr)
{
struct tte *tp;
vm_offset_t va;
diff --git a/sys/sparc64/sparc64/spitfire.c b/sys/sparc64/sparc64/spitfire.c
index 5a8c4ec..d6e25b9 100644
--- a/sys/sparc64/sparc64/spitfire.c
+++ b/sys/sparc64/sparc64/spitfire.c
@@ -56,7 +56,7 @@ PMAP_STATS_VAR(spitfire_icache_npage_inval_match);
* Enable the level 1 caches.
*/
void
-spitfire_cache_enable(void)
+spitfire_cache_enable(u_int cpu_impl __unused)
{
u_long lsu;
diff --git a/sys/sparc64/sparc64/tick.c b/sys/sparc64/sparc64/tick.c
index 9747228..1a38013 100644
--- a/sys/sparc64/sparc64/tick.c
+++ b/sys/sparc64/sparc64/tick.c
@@ -120,7 +120,7 @@ cpu_initclocks(void)
*/
} else {
clock = PCPU_GET(clock);
- intr_setup(PIL_TICK, cpu_impl < CPU_IMPL_ULTRASPARCIII ?
+ intr_setup(PIL_TICK, PCPU_GET(impl) < CPU_IMPL_ULTRASPARCIII ?
tick_hardclock_bbwar : tick_hardclock, -1, NULL, NULL);
set_cputicker(tick_cputicks, clock, 0);
}
@@ -322,7 +322,7 @@ tick_start(void)
}
void
-tick_clear(void)
+tick_clear(u_int cpu_impl)
{
if (cpu_impl >= CPU_IMPL_ULTRASPARCIII)
@@ -331,7 +331,7 @@ tick_clear(void)
}
void
-tick_stop(void)
+tick_stop(u_int cpu_impl)
{
if (cpu_impl >= CPU_IMPL_ULTRASPARCIII)
diff --git a/sys/sparc64/sparc64/trap.c b/sys/sparc64/sparc64/trap.c
index 56935c5..3df335b 100644
--- a/sys/sparc64/sparc64/trap.c
+++ b/sys/sparc64/sparc64/trap.c
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/systm.h>
+#include <sys/pcpu.h>
#include <sys/pioctl.h>
#include <sys/ptrace.h>
#include <sys/proc.h>
@@ -391,7 +392,7 @@ trap(struct trapframe *tf)
if (tf->tf_tpc > (u_long)fas_nofault_begin &&
tf->tf_tpc < (u_long)fas_nofault_end) {
cache_flush();
- cache_enable();
+ cache_enable(PCPU_GET(impl));
tf->tf_tpc = (u_long)fas_fault;
tf->tf_tnpc = tf->tf_tpc + 4;
error = 0;
diff --git a/sys/sys/ata.h b/sys/sys/ata.h
index e8a04db..cacb1ea0 100644
--- a/sys/sys/ata.h
+++ b/sys/sys/ata.h
@@ -51,7 +51,7 @@ struct ata_params {
#define ATA_RESP_INCOMPLETE 0x0004
/*001*/ u_int16_t cylinders; /* # of cylinders */
- u_int16_t reserved2;
+/*002*/ u_int16_t specconf; /* specific configuration */
/*003*/ u_int16_t heads; /* # heads */
u_int16_t obsolete4;
u_int16_t obsolete5;
diff --git a/sys/sys/eventhandler.h b/sys/sys/eventhandler.h
index 1f26d48..6715efc 100644
--- a/sys/sys/eventhandler.h
+++ b/sys/sys/eventhandler.h
@@ -211,7 +211,20 @@ EVENTHANDLER_DECLARE(process_exit, exitlist_fn);
EVENTHANDLER_DECLARE(process_fork, forklist_fn);
EVENTHANDLER_DECLARE(process_exec, execlist_fn);
+/*
+ * application dump event
+ */
struct thread;
+typedef void (*app_coredump_start_fn)(void *, struct thread *, char *name);
+typedef void (*app_coredump_progress_fn)(void *, struct thread *td, int byte_count);
+typedef void (*app_coredump_finish_fn)(void *, struct thread *td);
+typedef void (*app_coredump_error_fn)(void *, struct thread *td, char *msg, ...);
+
+EVENTHANDLER_DECLARE(app_coredump_start, app_coredump_start_fn);
+EVENTHANDLER_DECLARE(app_coredump_progress, app_coredump_progress_fn);
+EVENTHANDLER_DECLARE(app_coredump_finish, app_coredump_finish_fn);
+EVENTHANDLER_DECLARE(app_coredump_error, app_coredump_error_fn);
+
typedef void (*thread_ctor_fn)(void *, struct thread *);
typedef void (*thread_dtor_fn)(void *, struct thread *);
typedef void (*thread_fini_fn)(void *, struct thread *);
diff --git a/sys/sys/fbio.h b/sys/sys/fbio.h
index 415ad96..5745182 100644
--- a/sys/sys/fbio.h
+++ b/sys/sys/fbio.h
@@ -332,6 +332,7 @@ struct video_adapter {
#define V_ADP_INITIALIZED (1 << 17)
#define V_ADP_REGISTERED (1 << 18)
#define V_ADP_ATTACHED (1 << 19)
+#define V_ADP_DAC8 (1 << 20)
vm_offset_t va_io_base;
int va_io_size;
vm_offset_t va_crtc_addr;
diff --git a/sys/sys/imgact.h b/sys/sys/imgact.h
index e6acc00..79b389e 100644
--- a/sys/sys/imgact.h
+++ b/sys/sys/imgact.h
@@ -75,6 +75,8 @@ struct image_params {
struct sysentvec;
struct thread;
+#define IMGACT_CORE_COMPRESS 0x01
+
int exec_check_permissions(struct image_params *);
register_t *exec_copyout_strings(struct image_params *);
int exec_new_vmspace(struct image_params *, struct sysentvec *);
diff --git a/sys/sys/imgact_aout.h b/sys/sys/imgact_aout.h
index c386c1b..ca67cab 100644
--- a/sys/sys/imgact_aout.h
+++ b/sys/sys/imgact_aout.h
@@ -150,7 +150,8 @@ struct exec {
struct thread;
struct vnode;
-int aout_coredump(struct thread *td, struct vnode *vp, off_t limit);
+int aout_coredump(struct thread *td, struct vnode *vp, off_t limit,
+ int flags);
#endif
#endif /* !_IMGACT_AOUT_H_ */
diff --git a/sys/sys/imgact_elf.h b/sys/sys/imgact_elf.h
index 4ccee5d..1cc2a61 100644
--- a/sys/sys/imgact_elf.h
+++ b/sys/sys/imgact_elf.h
@@ -88,7 +88,7 @@ int __elfN(brand_inuse)(Elf_Brandinfo *entry);
int __elfN(insert_brand_entry)(Elf_Brandinfo *entry);
int __elfN(remove_brand_entry)(Elf_Brandinfo *entry);
int __elfN(freebsd_fixup)(register_t **, struct image_params *);
-int __elfN(coredump)(struct thread *, struct vnode *, off_t);
+int __elfN(coredump)(struct thread *, struct vnode *, off_t, int);
/* Machine specific function to dump per-thread information. */
void __elfN(dump_thread)(struct thread *, void *, size_t *);
diff --git a/sys/sys/queue.h b/sys/sys/queue.h
index f1f35c8..257679b 100644
--- a/sys/sys/queue.h
+++ b/sys/sys/queue.h
@@ -112,6 +112,7 @@ struct qm_trace {
#define TRACEBUF struct qm_trace trace;
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
+#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
#define QMD_TRACE_HEAD(head) do { \
(head)->trace.prevline = (head)->trace.lastline; \
@@ -130,6 +131,7 @@ struct qm_trace {
#else
#define QMD_TRACE_ELEM(elem)
#define QMD_TRACE_HEAD(head)
+#define QMD_SAVELINK(name, link)
#define TRACEBUF
#define TRASHIT(x)
#endif /* QUEUE_MACRO_DEBUG */
@@ -189,6 +191,7 @@ struct { \
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_REMOVE(head, elm, type, field) do { \
+ QMD_SAVELINK(oldnext, (elm)->field.sle_next); \
if (SLIST_FIRST((head)) == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} \
@@ -198,7 +201,7 @@ struct { \
curelm = SLIST_NEXT(curelm, field); \
SLIST_REMOVE_AFTER(curelm, field); \
} \
- TRASHIT((elm)->field.sle_next); \
+ TRASHIT(*oldnext); \
} while (0)
#define SLIST_REMOVE_AFTER(elm, field) do { \
@@ -285,6 +288,7 @@ struct { \
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_REMOVE(head, elm, type, field) do { \
+ QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \
if (STAILQ_FIRST((head)) == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
} \
@@ -294,7 +298,7 @@ struct { \
curelm = STAILQ_NEXT(curelm, field); \
STAILQ_REMOVE_AFTER(head, curelm, field); \
} \
- TRASHIT((elm)->field.stqe_next); \
+ TRASHIT(*oldnext); \
} while (0)
#define STAILQ_REMOVE_HEAD(head, field) do { \
@@ -415,14 +419,16 @@ struct { \
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_REMOVE(elm, field) do { \
+ QMD_SAVELINK(oldnext, (elm)->field.le_next); \
+ QMD_SAVELINK(oldprev, (elm)->field.le_prev); \
QMD_LIST_CHECK_NEXT(elm, field); \
QMD_LIST_CHECK_PREV(elm, field); \
if (LIST_NEXT((elm), field) != NULL) \
LIST_NEXT((elm), field)->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
- TRASHIT((elm)->field.le_next); \
- TRASHIT((elm)->field.le_prev); \
+ TRASHIT(*oldnext); \
+ TRASHIT(*oldprev); \
} while (0)
#define LIST_SWAP(head1, head2, type, field) do { \
@@ -587,6 +593,8 @@ struct { \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_REMOVE(head, elm, field) do { \
+ QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \
+ QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \
QMD_TAILQ_CHECK_NEXT(elm, field); \
QMD_TAILQ_CHECK_PREV(elm, field); \
if ((TAILQ_NEXT((elm), field)) != NULL) \
@@ -597,8 +605,8 @@ struct { \
QMD_TRACE_HEAD(head); \
} \
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
- TRASHIT((elm)->field.tqe_next); \
- TRASHIT((elm)->field.tqe_prev); \
+ TRASHIT(*oldnext); \
+ TRASHIT(*oldprev); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h
index e1ce718..aa7b8df 100644
--- a/sys/sys/sysctl.h
+++ b/sys/sys/sysctl.h
@@ -714,8 +714,8 @@ int sysctl_wire_old_buffer(struct sysctl_req *req, size_t len);
#include <sys/cdefs.h>
__BEGIN_DECLS
-int sysctl(int *, u_int, void *, size_t *, void *, size_t);
-int sysctlbyname(const char *, void *, size_t *, void *, size_t);
+int sysctl(const int *, u_int, void *, size_t *, const void *, size_t);
+int sysctlbyname(const char *, void *, size_t *, const void *, size_t);
int sysctlnametomib(const char *, int *, size_t *);
__END_DECLS
#endif /* _KERNEL */
diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h
index f17f4f03..a7a2907 100644
--- a/sys/sys/sysent.h
+++ b/sys/sys/sysent.h
@@ -87,7 +87,7 @@ struct sysentvec {
void (*sv_prepsyscall)(struct trapframe *, int *, u_int *,
caddr_t *);
char *sv_name; /* name of binary type */
- int (*sv_coredump)(struct thread *, struct vnode *, off_t);
+ int (*sv_coredump)(struct thread *, struct vnode *, off_t, int);
/* function to dump core, or NULL */
int (*sv_imgact_try)(struct image_params *);
int sv_minsigstksz; /* minimum signal stack size */
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
index 07d43d9..3868c9a 100644
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -52,8 +52,6 @@ extern char version[]; /* system version */
extern char copyright[]; /* system copyright */
extern int kstack_pages; /* number of kernel stack pages */
-extern int nswap; /* size of swap space */
-
extern u_long pagesizes[]; /* supported page sizes */
extern long physmem; /* physical memory */
extern long realmem; /* 'real' memory */
@@ -65,6 +63,9 @@ extern int bootverbose; /* nonzero to print verbose messages */
extern int maxusers; /* system tune hint */
extern int ngroups_max; /* max # of supplemental groups */
+extern int vm_guest; /* Running as virtual machine guest? */
+
+enum VM_GUEST { VM_GUEST_NO = 0, VM_GUEST_VM, VM_GUEST_XEN };
#ifdef INVARIANTS /* The option is always available */
#define KASSERT(exp,msg) do { \
diff --git a/sys/sys/user.h b/sys/sys/user.h
index b135034..d5e46fe 100644
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -100,8 +100,12 @@
#define KINFO_PROC_SIZE 768
#endif
#ifdef __mips__
+#ifdef __mips_n64
+#define KINFO_PROC_SIZE 1088
+#else
#define KINFO_PROC_SIZE 816
#endif
+#endif
#ifdef __powerpc__
#define KINFO_PROC_SIZE 768
#endif
diff --git a/sys/vm/vm_init.c b/sys/vm/vm_init.c
index e9baf09..fdffb46 100644
--- a/sys/vm/vm_init.c
+++ b/sys/vm/vm_init.c
@@ -186,7 +186,7 @@ again:
panic("startup: table size inconsistency");
clean_map = kmem_suballoc(kernel_map, &kmi->clean_sva, &kmi->clean_eva,
- (long)nbuf * BKVASIZE + (long)nswbuf * MAXPHYS, FALSE);
+ (long)nbuf * BKVASIZE + (long)nswbuf * MAXPHYS, TRUE);
buffer_map = kmem_suballoc(clean_map, &kmi->buffer_sva,
&kmi->buffer_eva, (long)nbuf * BKVASIZE, FALSE);
buffer_map->system_map = 1;
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
index c6bcfa0..665baa9 100644
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -1020,8 +1020,13 @@ vm_page_cache_transfer(vm_object_t orig_object, vm_pindex_t offidxstart,
* VM_ALLOC_SYSTEM system *really* needs a page
* VM_ALLOC_INTERRUPT interrupt time request
* VM_ALLOC_ZERO zero page
+ * VM_ALLOC_WIRED wire the allocated page
+ * VM_ALLOC_NOOBJ page is not associated with a vm object
+ * VM_ALLOC_NOBUSY do not set the page busy
+ * VM_ALLOC_IFNOTCACHED return NULL, do not reactivate if the page
+ * is cached
*
- * This routine may not block.
+ * This routine may not sleep.
*/
vm_page_t
vm_page_alloc(vm_object_t object, vm_pindex_t pindex, int req)
diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c
index 179afbf..aedc794 100644
--- a/sys/vm/vnode_pager.c
+++ b/sys/vm/vnode_pager.c
@@ -1016,7 +1016,6 @@ vnode_pager_putpages(object, m, count, sync, rtvals)
{
int rtval;
struct vnode *vp;
- struct mount *mp;
int bytes = count * PAGE_SIZE;
/*
@@ -1039,8 +1038,6 @@ vnode_pager_putpages(object, m, count, sync, rtvals)
*/
vp = object->handle;
VM_OBJECT_UNLOCK(object);
- if (vp->v_type != VREG)
- mp = NULL;
rtval = VOP_PUTPAGES(vp, m, bytes, sync, rtvals, 0);
KASSERT(rtval != EOPNOTSUPP,
("vnode_pager: stale FS putpages\n"));
diff --git a/sys/i386/bios/smbios.c b/sys/x86/bios/smbios.c
index f38d985..f38d985 100644
--- a/sys/i386/bios/smbios.c
+++ b/sys/x86/bios/smbios.c
diff --git a/sys/i386/bios/vpd.c b/sys/x86/bios/vpd.c
index 246b76d..246b76d 100644
--- a/sys/i386/bios/vpd.c
+++ b/sys/x86/bios/vpd.c
diff --git a/sys/i386/cpufreq/est.c b/sys/x86/cpufreq/est.c
index 6a7b514..6a7b514 100644
--- a/sys/i386/cpufreq/est.c
+++ b/sys/x86/cpufreq/est.c
diff --git a/sys/i386/cpufreq/hwpstate.c b/sys/x86/cpufreq/hwpstate.c
index 3790b76..3790b76 100644
--- a/sys/i386/cpufreq/hwpstate.c
+++ b/sys/x86/cpufreq/hwpstate.c
diff --git a/sys/i386/cpufreq/p4tcc.c b/sys/x86/cpufreq/p4tcc.c
index 29279e3..29279e3 100644
--- a/sys/i386/cpufreq/p4tcc.c
+++ b/sys/x86/cpufreq/p4tcc.c
diff --git a/sys/i386/cpufreq/powernow.c b/sys/x86/cpufreq/powernow.c
index b248cc8..b248cc8 100644
--- a/sys/i386/cpufreq/powernow.c
+++ b/sys/x86/cpufreq/powernow.c
diff --git a/sys/i386/cpufreq/smist.c b/sys/x86/cpufreq/smist.c
index 5cfd72b..5cfd72b 100644
--- a/sys/i386/cpufreq/smist.c
+++ b/sys/x86/cpufreq/smist.c
diff --git a/sys/i386/isa/atpic.c b/sys/x86/isa/atpic.c
index 37a1285..d17153c 100644
--- a/sys/i386/isa/atpic.c
+++ b/sys/x86/isa/atpic.c
@@ -53,14 +53,22 @@ __FBSDID("$FreeBSD$");
#include <machine/segments.h>
#include <dev/ic/i8259.h>
-#include <i386/isa/icu.h>
+#include <x86/isa/icu.h>
#ifdef PC98
#include <pc98/cbus/cbus.h>
#else
-#include <i386/isa/isa.h>
+#include <x86/isa/isa.h>
#endif
#include <isa/isavar.h>
+#ifdef __amd64__
+#define SDT_ATPIC SDT_SYSIGT
+#define GSEL_ATPIC 0
+#else
+#define SDT_ATPIC SDT_SYS386IGT
+#define GSEL_ATPIC GSEL(GCODE_SEL, SEL_KPL)
+#endif
+
#define MASTER 0
#define SLAVE 1
@@ -468,8 +476,7 @@ atpic_startup(void)
ai->at_intsrc.is_count = &ai->at_count;
ai->at_intsrc.is_straycount = &ai->at_straycount;
setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
- ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL,
- GSEL(GCODE_SEL, SEL_KPL));
+ ai->at_irq, ai->at_intr, SDT_ATPIC, SEL_KPL, GSEL_ATPIC);
}
#ifdef DEV_MCA
diff --git a/sys/isa/atrtc.c b/sys/x86/isa/atrtc.c
index 777c720..777c720 100644
--- a/sys/isa/atrtc.c
+++ b/sys/x86/isa/atrtc.c
diff --git a/sys/i386/isa/clock.c b/sys/x86/isa/clock.c
index e999b56..6ced537 100644
--- a/sys/i386/isa/clock.c
+++ b/sys/x86/isa/clock.c
@@ -39,12 +39,13 @@ __FBSDID("$FreeBSD$");
* Routines to handle clock hardware.
*/
+#ifndef __amd64__
#include "opt_apic.h"
+#endif
#include "opt_clock.h"
#include "opt_kdtrace.h"
#include "opt_isa.h"
#include "opt_mca.h"
-#include "opt_xbox.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -62,7 +63,6 @@ __FBSDID("$FreeBSD$");
#include <machine/clock.h>
#include <machine/cpu.h>
-#include <machine/frame.h>
#include <machine/intr_machdep.h>
#include <machine/md_var.h>
#include <machine/apicvar.h>
@@ -480,12 +480,15 @@ i8254_restore(void)
mtx_unlock_spin(&clock_lock);
}
+#ifndef __amd64__
/*
* Restore all the timers non-atomically (XXX: should be atomically).
*
* This function is called from pmtimer_resume() to restore all the timers.
* This should not be necessary, but there are broken laptops that do not
* restore all the timers on resume.
+ * As long as pmtimer is not part of amd64 suport, skip this for the amd64
+ * case.
*/
void
timer_restore(void)
@@ -494,6 +497,7 @@ timer_restore(void)
i8254_restore(); /* restore i8254_freq and hz */
atrtc_restore(); /* reenable RTC interrupts */
}
+#endif
/* This is separate from startrtclock() so that it can be called early. */
void
@@ -523,7 +527,7 @@ void
cpu_initclocks()
{
-#ifdef DEV_APIC
+#if defined(__amd64__) || defined(DEV_APIC)
using_lapic_timer = lapic_setup_clock();
#endif
/*
@@ -625,11 +629,15 @@ i8254_simple_get_timecount(struct timecounter *tc)
static unsigned
i8254_get_timecount(struct timecounter *tc)
{
+ register_t flags;
u_int count;
u_int high, low;
- u_int eflags;
- eflags = read_eflags();
+#ifdef __amd64__
+ flags = read_rflags();
+#else
+ flags = read_eflags();
+#endif
mtx_lock_spin(&clock_lock);
/* Select timer0 and latch counter value. */
@@ -640,7 +648,7 @@ i8254_get_timecount(struct timecounter *tc)
count = i8254_max_count - ((high << 8) | low);
if (count < i8254_lastcount ||
(!i8254_ticked && (clkintr_pending ||
- ((count < 20 || (!(eflags & PSL_I) &&
+ ((count < 20 || (!(flags & PSL_I) &&
count < i8254_max_count / 2u)) &&
i8254_pending != NULL && i8254_pending(i8254_intsrc))))) {
i8254_ticked = 1;
@@ -678,6 +686,14 @@ attimer_attach(device_t dev)
return(0);
}
+static int
+attimer_resume(device_t dev)
+{
+
+ i8254_restore();
+ return (0);
+}
+
static device_method_t attimer_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, attimer_probe),
@@ -685,7 +701,7 @@ static device_method_t attimer_methods[] = {
DEVMETHOD(device_detach, bus_generic_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
- DEVMETHOD(device_resume, bus_generic_resume),
+ DEVMETHOD(device_resume, attimer_resume),
{ 0, 0 }
};
diff --git a/sys/amd64/isa/elcr.c b/sys/x86/isa/elcr.c
index 266d783..266d783 100644
--- a/sys/amd64/isa/elcr.c
+++ b/sys/x86/isa/elcr.c
diff --git a/sys/i386/isa/icu.h b/sys/x86/isa/icu.h
index bd9df08..d7cd87a 100644
--- a/sys/i386/isa/icu.h
+++ b/sys/x86/isa/icu.h
@@ -38,8 +38,8 @@
* W. Jolitz 8/89
*/
-#ifndef _I386_ISA_ICU_H_
-#define _I386_ISA_ICU_H_
+#ifndef _X86_ISA_ICU_H_
+#define _X86_ISA_ICU_H_
#ifdef PC98
#define ICU_IMR_OFFSET 2
@@ -50,4 +50,4 @@
void atpic_handle_intr(u_int vector, struct trapframe *frame);
void atpic_startup(void);
-#endif /* !_I386_ISA_ICU_H_ */
+#endif /* !_X86_ISA_ICU_H_ */
diff --git a/sys/i386/isa/isa.c b/sys/x86/isa/isa.c
index 786de1a..7b2982a 100644
--- a/sys/i386/isa/isa.c
+++ b/sys/x86/isa/isa.c
@@ -245,7 +245,7 @@ isa_release_resource(device_t bus, device_t child, int type, int rid,
*/
int
isa_setup_intr(device_t bus, device_t child, struct resource *r, int flags,
- driver_filter_t filter, void (*ihand)(void *), void *arg,
+ driver_filter_t *filter, void (*ihand)(void *), void *arg,
void **cookiep)
{
return (BUS_SETUP_INTR(device_get_parent(bus), child, r, flags,
diff --git a/sys/i386/isa/isa.h b/sys/x86/isa/isa.h
index ac493b2..78bd956 100644
--- a/sys/i386/isa/isa.h
+++ b/sys/x86/isa/isa.h
@@ -37,8 +37,8 @@
#error isa.h is included from PC-9801 source
#endif
-#ifndef _I386_ISA_ISA_H_
-#define _I386_ISA_ISA_H_
+#ifndef _X86_ISA_ISA_H_
+#define _X86_ISA_ISA_H_
/* BEWARE: Included in both assembler and C code */
@@ -99,4 +99,4 @@
#define RAM_SIZE (RAM_END - RAM_BEGIN)
#endif /* !RAM_BEGIN */
-#endif /* !_I386_ISA_ISA_H_ */
+#endif /* !_X86_ISA_ISA_H_ */
diff --git a/sys/amd64/isa/isa_dma.c b/sys/x86/isa/isa_dma.c
index 0e99778..cbc9959 100644
--- a/sys/amd64/isa/isa_dma.c
+++ b/sys/x86/isa/isa_dma.c
@@ -61,7 +61,7 @@ __FBSDID("$FreeBSD$");
#include <isa/isavar.h>
#include <isa/isa_dmareg.h>
-#define ISARAM_END 0x1000000
+#define ISARAM_END RAM_END
static int isa_dmarangecheck(caddr_t va, u_int length, int chan);
diff --git a/sys/i386/isa/nmi.c b/sys/x86/isa/nmi.c
index db5550c..db5550c 100644
--- a/sys/i386/isa/nmi.c
+++ b/sys/x86/isa/nmi.c
diff --git a/sys/isa/orm.c b/sys/x86/isa/orm.c
index f25312f..f25312f 100644
--- a/sys/isa/orm.c
+++ b/sys/x86/isa/orm.c
diff --git a/sys/xen/evtchn/evtchn_dev.c b/sys/xen/evtchn/evtchn_dev.c
index 4253d8a..7e21d7a 100644
--- a/sys/xen/evtchn/evtchn_dev.c
+++ b/sys/xen/evtchn/evtchn_dev.c
@@ -302,11 +302,11 @@ evtchn_close(struct cdev *dev, int flag, int otyp, struct thread *td __unused)
{
int i;
- mtx_lock_spin(&lock);
if (ring != NULL) {
free(ring, M_DEVBUF);
ring = NULL;
}
+ mtx_lock_spin(&lock);
for ( i = 0; i < NR_EVENT_CHANNELS; i++ )
if ( synch_test_and_clear_bit(i, &bound_ports[0]) )
mask_evtchn(i);
diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc
index 2912bbf..dd5497e 100644
--- a/tools/build/mk/OptionalObsoleteFiles.inc
+++ b/tools/build/mk/OptionalObsoleteFiles.inc
@@ -1510,6 +1510,8 @@ OLD_FILES+=usr/share/man/man8/verify_krb5_conf.8.gz
#.endif
.if ${MK_LPR} == no
+OLD_FILES+=etc/hosts.lpd
+OLD_FILES+=etc/printcap
OLD_FILES+=usr/bin/lp
OLD_FILES+=usr/bin/lpq
OLD_FILES+=usr/bin/lpr
@@ -1524,6 +1526,8 @@ OLD_FILES+=usr/sbin/lpd
OLD_FILES+=usr/sbin/lptest
OLD_FILES+=usr/sbin/pac
OLD_FILES+=usr/share/doc/smm/07.lpd/paper.ascii.gz
+OLD_FILES+=usr/share/examples/etc/hosts.lpd
+OLD_FILES+=usr/share/examples/etc/printcap
OLD_FILES+=usr/share/man/man1/lp.1.gz
OLD_FILES+=usr/share/man/man1/lpq.1.gz
OLD_FILES+=usr/share/man/man1/lpr.1.gz
@@ -1547,7 +1551,6 @@ OLD_FILES+=usr/libexec/comsat
OLD_FILES+=usr/share/examples/etc/mail.rc
OLD_FILES+=usr/share/man/man1/Mail.1.gz
OLD_FILES+=usr/share/man/man1/biff.1.gz
-OLD_FILES+=usr/share/man/man1/fmt.1.gz
OLD_FILES+=usr/share/man/man1/from.1.gz
OLD_FILES+=usr/share/man/man1/mail.1.gz
OLD_FILES+=usr/share/man/man1/mailx.1.gz
@@ -1596,12 +1599,12 @@ OLD_FILES+=usr/include/netncp/nwerror.h
#OLD_DIRS+=usr/include/netncp
OLD_FILES+=usr/lib/libncp.a
OLD_FILES+=usr/lib/libncp.so
-OLD_LIBS+=usr/lib/libncp.so.3
+OLD_LIBS+=usr/lib/libncp.so.4
OLD_FILES+=usr/lib/libncp_p.a
.if ${TARGET_ARCH} == "amd64"
OLD_FILES+=usr/lib32/libncp.a
OLD_FILES+=usr/lib32/libncp.so
-OLD_LIBS+=usr/lib32/libncp.so.3
+OLD_LIBS+=usr/lib32/libncp.so.4
OLD_FILES+=usr/lib32/libncp_p.a
.endif
OLD_FILES+=usr/sbin/mount_nwfs
@@ -1611,6 +1614,14 @@ OLD_FILES+=usr/share/man/man1/ncplogout.1.gz
OLD_FILES+=usr/share/man/man8/mount_nwfs.8.gz
.endif
+.if ${MK_NDIS} == no
+OLD_FILES+=usr/sbin/ndiscvt
+OLD_FILES+=usr/sbin/ndisgen
+OLD_FILES+=usr/share/man/man8/ndiscvt.8.gz
+OLD_FILES+=usr/share/man/man8/ndisgen.8.gz
+OLD_FILES+=usr/share/misc/windrv_stub.c
+.endif
+
.if ${MK_NETCAT} == no
OLD_FILES+=usr/bin/nc
OLD_FILES+=usr/share/man/man1/nc.1.gz
@@ -1624,6 +1635,93 @@ OLD_FILES+=usr/share/man/man1/nc.1.gz
# to be filled in
#.endif
+.if ${MK_NTP} == no
+OLD_FILES+=etc/ntp.conf
+OLD_FILES+=etc/periodic/daily/480.status-ntpd
+OLD_FILES+=usr/bin/ntpq
+OLD_FILES+=usr/sbin/ntp-keygen
+OLD_FILES+=usr/sbin/ntpd
+OLD_FILES+=usr/sbin/ntpdate
+OLD_FILES+=usr/sbin/ntpdc
+OLD_FILES+=usr/sbin/ntptime
+OLD_FILES+=usr/sbin/sntp
+OLD_FILES+=usr/share/doc/ntp/accopt.html
+OLD_FILES+=usr/share/doc/ntp/assoc.html
+OLD_FILES+=usr/share/doc/ntp/audio.html
+OLD_FILES+=usr/share/doc/ntp/authopt.html
+OLD_FILES+=usr/share/doc/ntp/build.html
+OLD_FILES+=usr/share/doc/ntp/clockopt.html
+OLD_FILES+=usr/share/doc/ntp/config.html
+OLD_FILES+=usr/share/doc/ntp/confopt.html
+OLD_FILES+=usr/share/doc/ntp/copyright.html
+OLD_FILES+=usr/share/doc/ntp/debug.html
+OLD_FILES+=usr/share/doc/ntp/driver1.html
+OLD_FILES+=usr/share/doc/ntp/driver10.html
+OLD_FILES+=usr/share/doc/ntp/driver11.html
+OLD_FILES+=usr/share/doc/ntp/driver12.html
+OLD_FILES+=usr/share/doc/ntp/driver16.html
+OLD_FILES+=usr/share/doc/ntp/driver18.html
+OLD_FILES+=usr/share/doc/ntp/driver19.html
+OLD_FILES+=usr/share/doc/ntp/driver2.html
+OLD_FILES+=usr/share/doc/ntp/driver20.html
+OLD_FILES+=usr/share/doc/ntp/driver22.html
+OLD_FILES+=usr/share/doc/ntp/driver26.html
+OLD_FILES+=usr/share/doc/ntp/driver27.html
+OLD_FILES+=usr/share/doc/ntp/driver28.html
+OLD_FILES+=usr/share/doc/ntp/driver29.html
+OLD_FILES+=usr/share/doc/ntp/driver3.html
+OLD_FILES+=usr/share/doc/ntp/driver30.html
+OLD_FILES+=usr/share/doc/ntp/driver32.html
+OLD_FILES+=usr/share/doc/ntp/driver33.html
+OLD_FILES+=usr/share/doc/ntp/driver34.html
+OLD_FILES+=usr/share/doc/ntp/driver35.html
+OLD_FILES+=usr/share/doc/ntp/driver36.html
+OLD_FILES+=usr/share/doc/ntp/driver37.html
+OLD_FILES+=usr/share/doc/ntp/driver4.html
+OLD_FILES+=usr/share/doc/ntp/driver5.html
+OLD_FILES+=usr/share/doc/ntp/driver6.html
+OLD_FILES+=usr/share/doc/ntp/driver7.html
+OLD_FILES+=usr/share/doc/ntp/driver8.html
+OLD_FILES+=usr/share/doc/ntp/driver9.html
+OLD_FILES+=usr/share/doc/ntp/extern.html
+OLD_FILES+=usr/share/doc/ntp/hints.html
+OLD_FILES+=usr/share/doc/ntp/howto.html
+OLD_FILES+=usr/share/doc/ntp/index.html
+OLD_FILES+=usr/share/doc/ntp/kern.html
+OLD_FILES+=usr/share/doc/ntp/ldisc.html
+OLD_FILES+=usr/share/doc/ntp/measure.html
+OLD_FILES+=usr/share/doc/ntp/miscopt.html
+OLD_FILES+=usr/share/doc/ntp/monopt.html
+OLD_FILES+=usr/share/doc/ntp/mx4200data.html
+OLD_FILES+=usr/share/doc/ntp/notes.html
+OLD_FILES+=usr/share/doc/ntp/ntpd.html
+OLD_FILES+=usr/share/doc/ntp/ntpdate.html
+OLD_FILES+=usr/share/doc/ntp/ntpdc.html
+OLD_FILES+=usr/share/doc/ntp/ntpq.html
+OLD_FILES+=usr/share/doc/ntp/ntptime.html
+OLD_FILES+=usr/share/doc/ntp/ntptrace.html
+OLD_FILES+=usr/share/doc/ntp/parsedata.html
+OLD_FILES+=usr/share/doc/ntp/parsenew.html
+OLD_FILES+=usr/share/doc/ntp/patches.html
+OLD_FILES+=usr/share/doc/ntp/porting.html
+OLD_FILES+=usr/share/doc/ntp/pps.html
+OLD_FILES+=usr/share/doc/ntp/prefer.html
+OLD_FILES+=usr/share/doc/ntp/quick.html
+OLD_FILES+=usr/share/doc/ntp/rdebug.html
+OLD_FILES+=usr/share/doc/ntp/refclock.html
+OLD_FILES+=usr/share/doc/ntp/release.html
+OLD_FILES+=usr/share/doc/ntp/tickadj.html
+OLD_FILES+=usr/share/examples/etc/ntp.conf
+OLD_FILES+=usr/share/man/man5/ntp.conf.5.gz
+OLD_FILES+=usr/share/man/man5/ntp.keys.5.gz
+OLD_FILES+=usr/share/man/man8/ntp-keygen.8.gz
+OLD_FILES+=usr/share/man/man8/ntpd.8.gz
+OLD_FILES+=usr/share/man/man8/ntpdate.8.gz
+OLD_FILES+=usr/share/man/man8/ntpdc.8.gz
+OLD_FILES+=usr/share/man/man8/ntpq.8.gz
+OLD_FILES+=usr/share/man/man8/ntptime.8.gz
+.endif
+
#.if ${MK_OBJC} == no
# to be filled in
#.endif
@@ -1636,9 +1734,67 @@ OLD_FILES+=usr/share/man/man1/nc.1.gz
# to be filled in
#.endif
-#.if ${MK_PCVT} == no
-# to be filled in
-#.endif
+.if ${MK_PF} == no
+OLD_FILES+=etc/periodic/security/520.pfdenied
+OLD_FILES+=etc/pf.os
+OLD_FILES+=sbin/pfctl
+OLD_FILES+=sbin/pflogd
+OLD_FILES+=usr/libexec/tftp-proxy
+OLD_FILES+=usr/sbin/ftp-proxy
+OLD_FILES+=usr/share/examples/etc/pf.os
+OLD_FILES+=usr/share/examples/pf/ackpri
+OLD_FILES+=usr/share/examples/pf/faq-example1
+OLD_FILES+=usr/share/examples/pf/faq-example2
+OLD_FILES+=usr/share/examples/pf/faq-example3
+OLD_FILES+=usr/share/examples/pf/pf.conf
+OLD_FILES+=usr/share/examples/pf/queue1
+OLD_FILES+=usr/share/examples/pf/queue2
+OLD_FILES+=usr/share/examples/pf/queue3
+OLD_FILES+=usr/share/examples/pf/queue4
+OLD_FILES+=usr/share/examples/pf/spamd
+OLD_FILES+=usr/share/man/man4/pf.4.gz
+OLD_FILES+=usr/share/man/man4/pflog.4.gz
+OLD_FILES+=usr/share/man/man4/pfsync.4.gz
+OLD_FILES+=usr/share/man/man5/pf.conf.5.gz
+OLD_FILES+=usr/share/man/man5/pf.os.5.gz
+OLD_FILES+=usr/share/man/man8/ftp-proxy.8.gz
+OLD_FILES+=usr/share/man/man8/pfctl.8.gz
+OLD_FILES+=usr/share/man/man8/pflogd.8.gz
+OLD_FILES+=usr/share/man/man8/tftp-proxy.8.gz
+.endif
+
+.if ${MK_PKGTOOLS} == no
+OLD_FILES+=etc/periodic/weekly/400.status-pkg
+OLD_FILES+=usr/sbin/pkg_add
+OLD_FILES+=usr/sbin/pkg_create
+OLD_FILES+=usr/sbin/pkg_delete
+OLD_FILES+=usr/sbin/pkg_info
+OLD_FILES+=usr/sbin/pkg_updating
+OLD_FILES+=usr/sbin/pkg_version
+OLD_FILES+=usr/share/man/man1/pkg_add.1.gz
+OLD_FILES+=usr/share/man/man1/pkg_create.1.gz
+OLD_FILES+=usr/share/man/man1/pkg_delete.1.gz
+OLD_FILES+=usr/share/man/man1/pkg_info.1.gz
+OLD_FILES+=usr/share/man/man1/pkg_updating.1.gz
+OLD_FILES+=usr/share/man/man1/pkg_version.1.gz
+.endif
+
+.if ${MK_PORTSNAP} == no
+OLD_FILES+=etc/portsnap.conf
+OLD_FILES+=usr/libexec/make_index
+OLD_FILES+=usr/libexec/phttpget
+OLD_FILES+=usr/sbin/portsnap
+OLD_FILES+=usr/share/examples/etc/portsnap.conf
+OLD_FILES+=usr/share/man/man8/portsnap.8.gz
+.endif
+
+.if ${MK_PPP} == no
+OLD_FILES+=etc/ppp/ppp.conf
+OLD_FILES+=usr/sbin/ppp
+OLD_FILES+=usr/sbin/pppctl
+OLD_FILES+=usr/share/man/man8/ppp.8.gz
+OLD_FILES+=usr/share/man/man8/pppctl.8.gz
+.endif
.if ${MK_PROFILE} == no
OLD_FILES+=usr/lib/libalias_cuseeme_p.a
@@ -1755,26 +1911,62 @@ OLD_FILES+=usr/lib/libz_p.a
.if ${MK_RCMDS} == no
OLD_FILES+=bin/rcp
+OLD_FILES+=etc/periodic/daily/140.clean-rwho
+OLD_FILES+=etc/periodic/daily/430.status-rwho
OLD_FILES+=rescue/rcp
OLD_FILES+=usr/bin/rlogin
OLD_FILES+=usr/bin/rsh
+OLD_FILES+=usr/bin/ruptime
+OLD_FILES+=usr/bin/rwho
OLD_FILES+=usr/libexec/rlogind
OLD_FILES+=usr/libexec/rshd
+OLD_FILES+=usr/sbin/rwhod
OLD_FILES+=usr/share/man/man1/rcp.1.gz
OLD_FILES+=usr/share/man/man1/rlogin.1.gz
OLD_FILES+=usr/share/man/man1/rsh.1.gz
+OLD_FILES+=usr/share/man/man1/ruptime.1.gz
+OLD_FILES+=usr/share/man/man1/rwho.1.gz
OLD_FILES+=usr/share/man/man8/rlogind.8.gz
OLD_FILES+=usr/share/man/man8/rshd.8.gz
+OLD_FILES+=usr/share/man/man8/rwhod.8.gz
.endif
-#.if ${MK_RCS} == no
-# to be filled in
-#.endif
+.if ${MK_RCS} == no
+OLD_FILES+=usr/bin/ci
+OLD_FILES+=usr/bin/co
+OLD_FILES+=usr/bin/ident
+OLD_FILES+=usr/bin/merge
+OLD_FILES+=usr/bin/rcs
+OLD_FILES+=usr/bin/rcsclean
+OLD_FILES+=usr/bin/rcsdiff
+OLD_FILES+=usr/bin/rcsfreeze
+OLD_FILES+=usr/bin/rcsmerge
+OLD_FILES+=usr/bin/rlog
+OLD_FILES+=usr/share/man/man1/ci.1.gz
+OLD_FILES+=usr/share/man/man1/co.1.gz
+OLD_FILES+=usr/share/man/man1/ident.1.gz
+OLD_FILES+=usr/share/man/man1/merge.1.gz
+OLD_FILES+=usr/share/man/man1/rcs.1.gz
+OLD_FILES+=usr/share/man/man1/rcsclean.1.gz
+OLD_FILES+=usr/share/man/man1/rcsdiff.1.gz
+OLD_FILES+=usr/share/man/man1/rcsfreeze.1.gz
+OLD_FILES+=usr/share/man/man1/rcsintro.1.gz
+OLD_FILES+=usr/share/man/man1/rcsmerge.1.gz
+OLD_FILES+=usr/share/man/man1/rlog.1.gz
+OLD_FILES+=usr/share/man/man5/rcsfile.5.gz
+.endif
#.if ${MK_RESCUE} == no
# to be filled in or replaced with a special target
#.endif
+.if ${MK_ROUTED} == no
+OLD_FILES+=sbin/routed
+OLD_FILES+=sbin/rtquery
+OLD_FILES+=usr/share/man/man8/routed.8.gz
+OLD_FILES+=usr/share/man/man8/rtquery.8.gz
+.endif
+
.if ${MK_SENDMAIL} == no
OLD_FILES+=bin/rmail
OLD_FILES+=usr/bin/vacation
@@ -2036,6 +2228,13 @@ OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/tcsh.cat
OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/tcsh.cat
.endif
+.if ${MK_TELNET} == no
+OLD_FILES+=usr/bin/telnet
+OLD_FILES+=usr/libexec/telnetd
+OLD_FILES+=usr/share/man/man1/telnet.1.gz
+OLD_FILES+=usr/share/man/man8/telnetd.8.gz
+.endif
+
#.if ${MK_TOOLCHAIN} == no
# to be filled in
#.endif
@@ -2043,3 +2242,32 @@ OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/tcsh.cat
#.if ${MK_USB} == no
# to be filled in
#.endif
+
+.if ${MK_WIRELESS} == no
+OLD_FILES+=etc/regdomain.xml
+OLD_FILES+=usr/sbin/ancontrol
+OLD_FILES+=usr/sbin/hostapd
+OLD_FILES+=usr/sbin/hostapd_cli
+OLD_FILES+=usr/sbin/ndis_events
+OLD_FILES+=usr/sbin/wlandebug
+OLD_FILES+=usr/sbin/wlconfig
+OLD_FILES+=usr/sbin/wpa_cli
+OLD_FILES+=usr/sbin/wpa_passphrase
+OLD_FILES+=usr/sbin/wpa_supplicant
+OLD_FILES+=usr/share/examples/etc/regdomain.xml
+OLD_FILES+=usr/share/examples/etc/wpa_supplicant.conf
+OLD_FILES+=usr/share/examples/hostapd/hostapd.conf
+OLD_FILES+=usr/share/examples/hostapd/hostapd.eap_user
+OLD_FILES+=usr/share/examples/hostapd/hostapd.wpa_psk
+OLD_FILES+=usr/share/man/man5/hostapd.conf.5.gz
+OLD_FILES+=usr/share/man/man5/wpa_supplicant.conf.5.gz
+OLD_FILES+=usr/share/man/man8/ancontrol.8.gz
+OLD_FILES+=usr/share/man/man8/hostapd.8.gz
+OLD_FILES+=usr/share/man/man8/hostapd_cli.8.gz
+OLD_FILES+=usr/share/man/man8/i386/wlconfig.8.gz
+OLD_FILES+=usr/share/man/man8/ndis_events.8.gz
+OLD_FILES+=usr/share/man/man8/wlandebug.8.gz
+OLD_FILES+=usr/share/man/man8/wpa_cli.8.gz
+OLD_FILES+=usr/share/man/man8/wpa_passphrase.8.gz
+OLD_FILES+=usr/share/man/man8/wpa_supplicant.8.gz
+.endif
diff --git a/tools/regression/file/closefrom/Makefile b/tools/regression/file/closefrom/Makefile
index 7ff2df8..4b8829c 100644
--- a/tools/regression/file/closefrom/Makefile
+++ b/tools/regression/file/closefrom/Makefile
@@ -3,7 +3,7 @@
PROG= closefrom
MAN=
WARNS?= 6
-
+DPADD= ${LIBUTIL}
LDADD= -lutil
.include <bsd.prog.mk>
diff --git a/tools/regression/file/flock/Makefile b/tools/regression/file/flock/Makefile
index f3522a5..1c9e6cc 100644
--- a/tools/regression/file/flock/Makefile
+++ b/tools/regression/file/flock/Makefile
@@ -3,7 +3,7 @@
PROG= flock
NO_MAN=
WARNS?= 6
-
-LDADD+= -lpthread
+DPADD= ${LIBPTHREAD}
+LDADD= -lpthread
.include <bsd.prog.mk>
diff --git a/tools/regression/gaithrstress/Makefile b/tools/regression/gaithrstress/Makefile
index 2506e01..f3b8b00 100644
--- a/tools/regression/gaithrstress/Makefile
+++ b/tools/regression/gaithrstress/Makefile
@@ -1,7 +1,8 @@
# $FreeBSD$
PROG= gaithrstress
-LDADD+= -pthread
+DPADD= ${LIBPTHREAD}
+LDADD= -lpthread
NO_MAN=
.include <bsd.prog.mk>
diff --git a/tools/regression/kgssapi/Makefile b/tools/regression/kgssapi/Makefile
index 49059fa..e033e28 100644
--- a/tools/regression/kgssapi/Makefile
+++ b/tools/regression/kgssapi/Makefile
@@ -3,6 +3,7 @@
PROG= gsstest
NO_MAN=
WARNS?= 2
+DPADD= ${LIBGSSAPI} ${LIBGSSAPI_KRB5}
LDADD= -lgssapi -lgssapi_krb5
DEBUG_FLAGS= -g -O0
diff --git a/tools/regression/kqueue/Makefile b/tools/regression/kqueue/Makefile
index b25a17b..4537249 100644
--- a/tools/regression/kqueue/Makefile
+++ b/tools/regression/kqueue/Makefile
@@ -16,6 +16,6 @@ SRCS= \
signal.c \
user.c
NO_MAN=
-WARNS=2
+WARNS?= 2
.include "bsd.prog.mk"
diff --git a/tools/regression/kthread/kld/Makefile b/tools/regression/kthread/kld/Makefile
new file mode 100644
index 0000000..df1f763
--- /dev/null
+++ b/tools/regression/kthread/kld/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}
+
+KMOD= kthrdlk
+NO_MAN=
+SRCS= kthrdlk.c
+WARNS?= 2
+
+.include <bsd.kmod.mk>
diff --git a/tools/regression/kthread/kld/kthrdlk.c b/tools/regression/kthread/kld/kthrdlk.c
new file mode 100644
index 0000000..6485c11
--- /dev/null
+++ b/tools/regression/kthread/kld/kthrdlk.c
@@ -0,0 +1,204 @@
+/*-
+ * Copyright (c) 2010 Giovanni Trematerra <giovanni.trematerra@gmail.com>
+ * 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.
+ */
+
+/*
+ * PURPOSE:
+ *
+ * This kernel module helped to identify a deadlock in kthread
+ * interface, also pointed out a race in kthread_exit function.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+
+#ifdef TESTPAUSE_DEBUG
+#define DPRINTF(x) do { \
+ printf (x); \
+} while (0)
+#else
+#define DPRINTF(x)
+#endif
+
+static struct mtx test_global_lock;
+static int global_condvar;
+static int test_thrcnt;
+volatile int QUIT;
+
+static void
+thr_suspender(void *arg)
+{
+ struct thread *td = (struct thread *) arg;
+ int error;
+
+ for (;;) {
+ if (QUIT == 1)
+ break;
+ error = kthread_suspend(td, 10*hz);
+ if (error != 0 && QUIT == 0) {
+ if (error == EWOULDBLOCK)
+ panic("Ooops: kthread deadlock\n");
+ else
+ panic("kthread_suspend error: %d\n", error);
+ break;
+ }
+ }
+
+ mtx_lock(&test_global_lock);
+ test_thrcnt--;
+ wakeup(&global_condvar);
+ mtx_unlock(&test_global_lock);
+
+ kthread_exit();
+}
+
+static void
+thr_resumer(void *arg)
+{
+ struct thread *td = (struct thread *) arg;
+ int error;
+
+ for (;;) {
+ /* must be the last thread to exit */
+ if (QUIT == 1 && test_thrcnt == 1)
+ break;
+ error = kthread_resume(td);
+ if (error != 0)
+ panic("%s: error on kthread_resume. error: %d\n",
+ __func__, error);
+ }
+
+ mtx_lock(&test_global_lock);
+ test_thrcnt--;
+ wakeup(&global_condvar);
+ mtx_unlock(&test_global_lock);
+
+ kthread_exit();
+}
+
+static void
+thr_getsuspended(void *arg)
+{
+ for (;;) {
+ if (QUIT == 1)
+ break;
+ kthread_suspend_check();
+ }
+
+ mtx_lock(&test_global_lock);
+ test_thrcnt--;
+ wakeup(&global_condvar);
+ mtx_unlock(&test_global_lock);
+
+ kthread_exit();
+}
+
+static void
+kthrdlk_init(void)
+{
+ struct proc *testproc;
+ struct thread *newthr;
+ int error;
+
+ QUIT = 0;
+ test_thrcnt = 3;
+ mtx_init(&test_global_lock, "kthrdlk_lock", NULL, MTX_DEF);
+ testproc = NULL;
+ error = kproc_kthread_add(thr_getsuspended, NULL, &testproc, &newthr,
+ 0, 0, "kthrdlk", "thr_getsuspended");
+ if (error != 0)
+ panic("cannot start thr_getsuspended error: %d\n", error);
+
+ error = kproc_kthread_add(thr_resumer, newthr, &testproc, NULL, 0, 0,
+ "kthrdlk", "thr_resumer");
+ if (error != 0)
+ panic("cannot start thr_resumer error: %d\n", error);
+
+ error = kproc_kthread_add(thr_suspender, newthr, &testproc, NULL, 0, 0,
+ "kthrdlk", "thr_suspender");
+ if (error != 0)
+ panic("cannot start thr_suspender error: %d\n", error);
+}
+
+static void
+kthrdlk_done(void)
+{
+ int ret;
+ DPRINTF(("sending QUIT signal to the thrdlk threads\n"));
+
+ /* wait kernel threads end */
+ mtx_lock(&test_global_lock);
+ QUIT = 1;
+ while (test_thrcnt != 0) {
+ ret = mtx_sleep(&global_condvar, &test_global_lock, 0, "waiting thrs end", 30 * hz);
+ if (ret == EWOULDBLOCK) {
+ panic("some threads not die! remaing: %d", test_thrcnt);
+ break;
+ }
+ }
+ if (test_thrcnt == 0)
+ DPRINTF(("All test_pause threads die\n"));
+
+ mtx_destroy(&test_global_lock);
+}
+
+static int
+kthrdlk_handler(module_t mod, int /*modeventtype_t*/ what,
+ void *arg)
+{
+ switch (what) {
+ case MOD_LOAD:
+ kthrdlk_init();
+ uprintf("kthrdlk loaded!\n");
+ return (0);
+ case MOD_UNLOAD:
+ kthrdlk_done();
+ uprintf("Bye Bye! kthrdlk unloaded!\n");
+ return (0);
+ }
+
+ return (EOPNOTSUPP);
+}
+
+static moduledata_t mod_data= {
+ "kthrdlk",
+ kthrdlk_handler,
+ 0
+ };
+
+MODULE_VERSION(kthrdlk, 1);
+
+DECLARE_MODULE(kthrdlk, mod_data, SI_SUB_EXEC, SI_ORDER_ANY);
+
diff --git a/tools/regression/mqueue/mqtest1/Makefile b/tools/regression/mqueue/mqtest1/Makefile
index 4e04d1d..370b5c9 100644
--- a/tools/regression/mqueue/mqtest1/Makefile
+++ b/tools/regression/mqueue/mqtest1/Makefile
@@ -1,7 +1,8 @@
# $FreeBSD$
PROG=mqtest1
-LDADD+=-lrt
+DPADD= ${LIBRT}
+LDADD= -lrt
NO_MAN=
DEBUG_FLAGS=-g
diff --git a/tools/regression/mqueue/mqtest2/Makefile b/tools/regression/mqueue/mqtest2/Makefile
index 9d1b92c..07a5577 100644
--- a/tools/regression/mqueue/mqtest2/Makefile
+++ b/tools/regression/mqueue/mqtest2/Makefile
@@ -1,7 +1,8 @@
# $FreeBSD$
PROG=mqtest2
-LDADD+=-lrt
+DPADD= ${LIBRT}
+LDADD= -lrt
NO_MAN=
DEBUG_FLAGS=-g
diff --git a/tools/regression/mqueue/mqtest3/Makefile b/tools/regression/mqueue/mqtest3/Makefile
index d4ea9fa..5439480 100644
--- a/tools/regression/mqueue/mqtest3/Makefile
+++ b/tools/regression/mqueue/mqtest3/Makefile
@@ -1,7 +1,8 @@
# $FreeBSD$
PROG=mqtest3
-LDADD+=-lrt
+DPADD= ${LIBRT}
+LDADD= -lrt
NO_MAN=
DEBUG_FLAGS=-g
diff --git a/tools/regression/mqueue/mqtest4/Makefile b/tools/regression/mqueue/mqtest4/Makefile
index 3dfec4d..d0476b2 100644
--- a/tools/regression/mqueue/mqtest4/Makefile
+++ b/tools/regression/mqueue/mqtest4/Makefile
@@ -1,7 +1,8 @@
# $FreeBSD$
PROG=mqtest4
-LDADD+=-lrt
+DPADD= ${LIBRT}
+LDADD= -lrt
NO_MAN=
DEBUG_FLAGS=-g
diff --git a/tools/regression/mqueue/mqtest5/Makefile b/tools/regression/mqueue/mqtest5/Makefile
index 25f46ad..b2f3aad 100644
--- a/tools/regression/mqueue/mqtest5/Makefile
+++ b/tools/regression/mqueue/mqtest5/Makefile
@@ -1,7 +1,8 @@
# $FreeBSD$
PROG=mqtest5
-LDADD+=-lrt
+DPADD= ${LIBRT}
+LDADD= -lrt
NO_MAN=
DEBUG_FLAGS=-g
diff --git a/tools/regression/netipx/ipxdgramloopback/Makefile b/tools/regression/netipx/ipxdgramloopback/Makefile
index 364d787..78b3e45 100644
--- a/tools/regression/netipx/ipxdgramloopback/Makefile
+++ b/tools/regression/netipx/ipxdgramloopback/Makefile
@@ -5,7 +5,7 @@
PROG= ipxdgramloopback
NO_MAN=
-DPADD= ${LIBIPX};
+DPADD= ${LIBIPX}
LDADD= -lipx
WARNS?= 3
diff --git a/tools/regression/netipx/spxabort/Makefile b/tools/regression/netipx/spxabort/Makefile
index b9498a0..ec3ef5b 100644
--- a/tools/regression/netipx/spxabort/Makefile
+++ b/tools/regression/netipx/spxabort/Makefile
@@ -5,7 +5,7 @@
PROG= spxabort
NO_MAN=
-DPADD= ${LIBIPX};
+DPADD= ${LIBIPX}
LDADD= -lipx
WARNS?= 3
diff --git a/tools/regression/netipx/spxloopback/Makefile b/tools/regression/netipx/spxloopback/Makefile
index edbfbbc..4245217 100644
--- a/tools/regression/netipx/spxloopback/Makefile
+++ b/tools/regression/netipx/spxloopback/Makefile
@@ -5,7 +5,7 @@
PROG= spxloopback
NO_MAN=
-DPADD= ${LIBIPX};
+DPADD= ${LIBIPX}
LDADD= -lipx
WARNS?= 3
diff --git a/tools/regression/priv/Makefile b/tools/regression/priv/Makefile
index 814f5c3..663d68d 100644
--- a/tools/regression/priv/Makefile
+++ b/tools/regression/priv/Makefile
@@ -46,7 +46,7 @@ SRCS= main.c \
priv_vm_munlock.c
NO_MAN=
-WARNS= 3
+WARNS?= 3
DPADD+= ${LIBIPSEC}
LDADD+= -lipsec
diff --git a/tools/regression/pthread/cv_cancel1/Makefile b/tools/regression/pthread/cv_cancel1/Makefile
index 6fe38c7..bb23825 100644
--- a/tools/regression/pthread/cv_cancel1/Makefile
+++ b/tools/regression/pthread/cv_cancel1/Makefile
@@ -2,7 +2,7 @@
PROG= cv_cancel1
NO_MAN=
-
+DPADD= ${LIBPTHREAD}
LDADD= -lpthread
.include <bsd.prog.mk>
diff --git a/tools/regression/pthread/mutex_isowned_np/Makefile b/tools/regression/pthread/mutex_isowned_np/Makefile
index d7d3ac4..a234fbc 100644
--- a/tools/regression/pthread/mutex_isowned_np/Makefile
+++ b/tools/regression/pthread/mutex_isowned_np/Makefile
@@ -2,7 +2,7 @@
PROG= mutex_isowned_np
NO_MAN=
-
+DPADD= ${LIBPTHREAD}
LDADD= -lpthread
.include <bsd.prog.mk>
diff --git a/tools/regression/rpcsec_gss/Makefile b/tools/regression/rpcsec_gss/Makefile
index 29b14d6..d1f894b 100644
--- a/tools/regression/rpcsec_gss/Makefile
+++ b/tools/regression/rpcsec_gss/Makefile
@@ -3,6 +3,7 @@
PROG= rpctest
NO_MAN=
WARNS?= 6
+DPADD= ${LIBRPCSEC_GSS}
LDADD= -lrpcsec_gss
DEBUG_FLAGS= -g -O0
diff --git a/tools/regression/sigqueue/sigqtest1/Makefile b/tools/regression/sigqueue/sigqtest1/Makefile
index 08a140c..86f7206 100644
--- a/tools/regression/sigqueue/sigqtest1/Makefile
+++ b/tools/regression/sigqueue/sigqtest1/Makefile
@@ -1,7 +1,6 @@
# $FreeBSD$
PROG=sigqtest1
-LDADD+=
NO_MAN=
DEBUG_FLAGS=-g
diff --git a/tools/regression/sigqueue/sigqtest2/Makefile b/tools/regression/sigqueue/sigqtest2/Makefile
index b3899ad..e7033f7 100644
--- a/tools/regression/sigqueue/sigqtest2/Makefile
+++ b/tools/regression/sigqueue/sigqtest2/Makefile
@@ -1,7 +1,6 @@
# $FreeBSD$
PROG=sigqtest2
-LDADD+=
NO_MAN=
DEBUG_FLAGS=-g
diff --git a/tools/regression/sockets/sendfile/Makefile b/tools/regression/sockets/sendfile/Makefile
index e1a43cb..2930363 100644
--- a/tools/regression/sockets/sendfile/Makefile
+++ b/tools/regression/sockets/sendfile/Makefile
@@ -5,5 +5,7 @@
PROG= sendfile
NO_MAN=
WARNS?= 6
+DPADD= ${LIBMD}
+LDADD= -lmd
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/sendfile/sendfile.c b/tools/regression/sockets/sendfile/sendfile.c
index fbeaac1..c815824 100644
--- a/tools/regression/sockets/sendfile/sendfile.c
+++ b/tools/regression/sockets/sendfile/sendfile.c
@@ -29,11 +29,14 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/wait.h>
#include <netinet/in.h>
#include <err.h>
+#include <errno.h>
#include <limits.h>
+#include <md5.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
@@ -47,113 +50,192 @@
* of cases and performing limited validation.
*/
+#define FAIL(msg) {printf("# %s\n", msg); \
+ return (-1);}
+
+#define FAIL_ERR(msg) {printf("# %s: %s\n", msg, strerror(errno)); \
+ return (-1);}
+
#define TEST_PORT 5678
#define TEST_MAGIC 0x4440f7bb
#define TEST_PAGES 4
#define TEST_SECONDS 30
struct test_header {
- u_int32_t th_magic;
- u_int32_t th_header_length;
- u_int32_t th_offset;
- u_int32_t th_length;
+ uint32_t th_magic;
+ uint32_t th_header_length;
+ uint32_t th_offset;
+ uint32_t th_length;
+ char th_md5[33];
+};
+
+struct sendfile_test {
+ uint32_t hdr_length;
+ uint32_t offset;
+ uint32_t length;
};
-pid_t child_pid, parent_pid;
-int listen_socket;
int file_fd;
+char path[PATH_MAX];
+int listen_socket;
+int accept_socket;
+
+static int test_th(struct test_header *th, uint32_t *header_length,
+ uint32_t *offset, uint32_t *length);
+static void signal_alarm(int signum);
+static void setup_alarm(int seconds);
+static void cancel_alarm(void);
+static int receive_test(void);
+static void run_child(void);
+static int new_test_socket(int *connect_socket);
+static void init_th(struct test_header *th, uint32_t header_length,
+ uint32_t offset, uint32_t length);
+static int send_test(int connect_socket, struct sendfile_test);
+static void run_parent(void);
+static void cleanup(void);
+
static int
-test_th(struct test_header *th, u_int32_t *header_length, u_int32_t *offset,
- u_int32_t *length)
+test_th(struct test_header *th, uint32_t *header_length, uint32_t *offset,
+ uint32_t *length)
{
if (th->th_magic != htonl(TEST_MAGIC))
- return (0);
+ FAIL("magic number not found in header")
*header_length = ntohl(th->th_header_length);
*offset = ntohl(th->th_offset);
*length = ntohl(th->th_length);
- return (1);
+ return (0);
}
static void
signal_alarm(int signum)
{
-
(void)signum;
+
+ printf("# test timeout\n");
+
+ if (accept_socket > 0)
+ close(accept_socket);
+ if (listen_socket > 0)
+ close(listen_socket);
+
+ _exit(-1);
}
static void
setup_alarm(int seconds)
{
+ struct itimerval itv;
+ bzero(&itv, sizeof(itv));
+ (void)seconds;
+ itv.it_value.tv_sec = seconds;
signal(SIGALRM, signal_alarm);
- alarm(seconds);
+ setitimer(ITIMER_REAL, &itv, NULL);
}
static void
cancel_alarm(void)
{
-
- alarm(0);
- signal(SIGALRM, SIG_DFL);
+ struct itimerval itv;
+ bzero(&itv, sizeof(itv));
+ setitimer(ITIMER_REAL, &itv, NULL);
}
-static void
-receive_test(int accept_socket)
+static int
+receive_test(void)
{
- u_int32_t header_length, offset, length, counter;
+ uint32_t header_length, offset, length, counter;
struct test_header th;
ssize_t len;
- char ch;
+ char buf[10240];
+ MD5_CTX md5ctx;
+ char *rxmd5;
len = read(accept_socket, &th, sizeof(th));
- if (len < 0)
- err(1, "read");
- if ((size_t)len < sizeof(th))
- errx(1, "read: %zd", len);
+ if (len < 0 || (size_t)len < sizeof(th))
+ FAIL_ERR("read")
- if (test_th(&th, &header_length, &offset, &length) == 0)
- errx(1, "test_th: bad");
+ if (test_th(&th, &header_length, &offset, &length) != 0)
+ return (-1);
+
+ MD5Init(&md5ctx);
counter = 0;
while (1) {
- len = read(accept_socket, &ch, sizeof(ch));
- if (len < 0)
- err(1, "read");
- if (len == 0)
+ len = read(accept_socket, buf, sizeof(buf));
+ if (len < 0 || len == 0)
break;
- counter++;
- /* XXXRW: Validate byte here. */
+ counter += len;
+ MD5Update(&md5ctx, buf, len);
}
- if (counter != header_length + length)
- errx(1, "receive_test: expected (%d, %d) received %d",
- header_length, length, counter);
+
+ rxmd5 = MD5End(&md5ctx, NULL);
+
+ if ((counter != header_length+length) ||
+ memcmp(th.th_md5, rxmd5, 33) != 0)
+ FAIL("receive length mismatch")
+
+ free(rxmd5);
+ return (0);
}
static void
run_child(void)
{
- int accept_socket;
+ struct sockaddr_in sin;
+ int rc = 0;
- while (1) {
+ listen_socket = socket(PF_INET, SOCK_STREAM, 0);
+ if (listen_socket < 0) {
+ printf("# socket: %s\n", strerror(errno));
+ rc = -1;
+ }
+
+ if (!rc) {
+ bzero(&sin, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ sin.sin_port = htons(TEST_PORT);
+
+ if (bind(listen_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ printf("# bind: %s\n", strerror(errno));
+ rc = -1;
+ }
+ }
+
+ if (!rc && listen(listen_socket, -1) < 0) {
+ printf("# listen: %s\n", strerror(errno));
+ rc = -1;
+ }
+
+ if (!rc) {
accept_socket = accept(listen_socket, NULL, NULL);
setup_alarm(TEST_SECONDS);
- receive_test(accept_socket);
- cancel_alarm();
- close(accept_socket);
+ if (receive_test() != 0)
+ rc = -1;
}
+
+ cancel_alarm();
+ if (accept_socket > 0)
+ close(accept_socket);
+ if (listen_socket > 0)
+ close(listen_socket);
+
+ _exit(rc);
}
static int
-new_test_socket(void)
+new_test_socket(int *connect_socket)
{
struct sockaddr_in sin;
- int connect_socket;
+ int rc = 0;
- connect_socket = socket(PF_INET, SOCK_STREAM, 0);
- if (connect_socket < 0)
- err(1, "socket");
+ *connect_socket = socket(PF_INET, SOCK_STREAM, 0);
+ if (*connect_socket < 0)
+ FAIL_ERR("socket")
bzero(&sin, sizeof(sin));
sin.sin_len = sizeof(sin);
@@ -161,57 +243,65 @@ new_test_socket(void)
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sin.sin_port = htons(TEST_PORT);
- if (connect(connect_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0)
- err(1, "connect");
+ if (connect(*connect_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0)
+ FAIL_ERR("connect")
- return (connect_socket);
+ return (rc);
}
static void
-init_th(struct test_header *th, u_int32_t header_length, u_int32_t offset,
- u_int32_t length)
+init_th(struct test_header *th, uint32_t header_length, uint32_t offset,
+ uint32_t length)
{
-
bzero(th, sizeof(*th));
th->th_magic = htonl(TEST_MAGIC);
th->th_header_length = htonl(header_length);
th->th_offset = htonl(offset);
th->th_length = htonl(length);
+
+ MD5FileChunk(path, th->th_md5, offset, length);
}
-static void
-send_test(int connect_socket, u_int32_t header_length, u_int32_t offset,
- u_int32_t length)
+static int
+send_test(int connect_socket, struct sendfile_test test)
{
struct test_header th;
struct sf_hdtr hdtr, *hdtrp;
struct iovec headers;
char *header;
ssize_t len;
+ int length;
off_t off;
len = lseek(file_fd, 0, SEEK_SET);
- if (len < 0)
- err(1, "lseek");
if (len != 0)
- errx(1, "lseek: %zd", len);
+ FAIL_ERR("lseek")
- init_th(&th, header_length, offset, length);
+ if (test.length == 0) {
+ struct stat st;
+ if (fstat(file_fd, &st) < 0)
+ FAIL_ERR("fstat")
+ length = st.st_size - test.offset;
+ }
+ else {
+ length = test.length;
+ }
+
+ init_th(&th, test.hdr_length, test.offset, length);
len = write(connect_socket, &th, sizeof(th));
- if (len < 0)
- err(1, "send");
if (len != sizeof(th))
- err(1, "send: %zd", len);
+ return (-1);
- if (header_length != 0) {
- header = malloc(header_length);
+ if (test.hdr_length != 0) {
+ header = malloc(test.hdr_length);
if (header == NULL)
- err(1, "malloc");
+ FAIL_ERR("malloc")
+
hdtrp = &hdtr;
bzero(&headers, sizeof(headers));
headers.iov_base = header;
- headers.iov_len = header_length;
+ headers.iov_len = test.hdr_length;
bzero(&hdtr, sizeof(hdtr));
hdtr.headers = &headers;
hdtr.hdr_cnt = 1;
@@ -222,148 +312,130 @@ send_test(int connect_socket, u_int32_t header_length, u_int32_t offset,
header = NULL;
}
- if (sendfile(file_fd, connect_socket, offset, length, hdtrp, &off,
- 0) < 0)
- err(1, "sendfile");
+ if (sendfile(file_fd, connect_socket, test.offset, test.length,
+ hdtrp, &off, 0) < 0) {
+ if (header != NULL)
+ free(header);
+ FAIL_ERR("sendfile")
+ }
if (length == 0) {
struct stat sb;
- if (fstat(file_fd, &sb) < 0)
- err(1, "fstat");
- length = sb.st_size - offset;
- }
-
- if (off != length) {
- errx(1, "sendfile: off(%ju) != length(%ju)",
- (uintmax_t)off, (uintmax_t)length);
+ if (fstat(file_fd, &sb) == 0)
+ length = sb.st_size - test.offset;
}
if (header != NULL)
free(header);
+
+ if (off != length)
+ FAIL("offset != length")
+
+ return (0);
}
static void
run_parent(void)
{
int connect_socket;
+ int status;
+ int test_num;
+ int pid;
+
+ const int pagesize = getpagesize();
+
+ struct sendfile_test tests[10] = {
+ { .hdr_length = 0, .offset = 0, .length = 1 },
+ { .hdr_length = 0, .offset = 0, .length = pagesize },
+ { .hdr_length = 0, .offset = 1, .length = 1 },
+ { .hdr_length = 0, .offset = 1, .length = pagesize },
+ { .hdr_length = 0, .offset = pagesize, .length = pagesize },
+ { .hdr_length = 0, .offset = 0, .length = 2*pagesize },
+ { .hdr_length = 0, .offset = 0, .length = 0 },
+ { .hdr_length = 0, .offset = pagesize, .length = 0 },
+ { .hdr_length = 0, .offset = 2*pagesize, .length = 0 },
+ { .hdr_length = 0, .offset = TEST_PAGES*pagesize, .length = 0 }
+ };
+
+ printf("1..10\n");
+
+ for (test_num = 1; test_num <= 10; test_num++) {
+
+ pid = fork();
+ if (pid == -1) {
+ printf("not ok %d\n", test_num);
+ continue;
+ }
+
+ if (pid == 0)
+ run_child();
+
+ usleep(250000);
+
+ if (new_test_socket(&connect_socket) != 0) {
+ printf("not ok %d\n", test_num);
+ kill(pid, SIGALRM);
+ close(connect_socket);
+ continue;
+ }
+
+ if (send_test(connect_socket, tests[test_num-1]) != 0) {
+ printf("not ok %d\n", test_num);
+ kill(pid, SIGALRM);
+ close(connect_socket);
+ continue;
+ }
+
+ close(connect_socket);
+ if (waitpid(pid, &status, 0) == pid) {
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
+ printf("%s %d\n", "ok", test_num);
+ else
+ printf("%s %d\n", "not ok", test_num);
+ }
+ else {
+ printf("not ok %d\n", test_num);
+ }
+ }
+}
- connect_socket = new_test_socket();
- send_test(connect_socket, 0, 0, 1);
- close(connect_socket);
-
- sleep(1);
-
- connect_socket = new_test_socket();
- send_test(connect_socket, 0, 0, getpagesize());
- close(connect_socket);
-
- sleep(1);
-
- connect_socket = new_test_socket();
- send_test(connect_socket, 0, 1, 1);
- close(connect_socket);
-
- sleep(1);
-
- connect_socket = new_test_socket();
- send_test(connect_socket, 0, 1, getpagesize());
- close(connect_socket);
-
- sleep(1);
-
- connect_socket = new_test_socket();
- send_test(connect_socket, 0, getpagesize(), getpagesize());
- close(connect_socket);
-
- sleep(1);
-
- connect_socket = new_test_socket();
- send_test(connect_socket, 0, 0, 2 * getpagesize());
- close(connect_socket);
-
- sleep(1);
-
- connect_socket = new_test_socket();
- send_test(connect_socket, 0, 0, 0);
- close(connect_socket);
-
- sleep(1);
-
- connect_socket = new_test_socket();
- send_test(connect_socket, 0, getpagesize(), 0);
- close(connect_socket);
-
- sleep(1);
-
- connect_socket = new_test_socket();
- send_test(connect_socket, 0, 2 * getpagesize(), 0);
- close(connect_socket);
-
- sleep(1);
-
- connect_socket = new_test_socket();
- send_test(connect_socket, 0, TEST_PAGES * getpagesize(), 0);
- close(connect_socket);
-
- sleep(1);
-
- (void)kill(child_pid, SIGKILL);
+static void
+cleanup(void)
+{
+ if (*path != '\0')
+ unlink(path);
}
int
main(void)
{
- char path[PATH_MAX], *page_buffer;
- struct sockaddr_in sin;
+ char *page_buffer;
int pagesize;
ssize_t len;
+ *path = '\0';
+
pagesize = getpagesize();
page_buffer = malloc(TEST_PAGES * pagesize);
if (page_buffer == NULL)
- err(1, "malloc");
+ FAIL_ERR("malloc")
bzero(page_buffer, TEST_PAGES * pagesize);
- listen_socket = socket(PF_INET, SOCK_STREAM, 0);
- if (listen_socket < 0)
- err(1, "socket");
-
- bzero(&sin, sizeof(sin));
- sin.sin_len = sizeof(sin);
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- sin.sin_port = htons(TEST_PORT);
-
snprintf(path, PATH_MAX, "/tmp/sendfile.XXXXXXXXXXXX");
file_fd = mkstemp(path);
- (void)unlink(path);
+ atexit(cleanup);
len = write(file_fd, page_buffer, TEST_PAGES * pagesize);
if (len < 0)
- err(1, "write");
+ FAIL_ERR("write")
len = lseek(file_fd, 0, SEEK_SET);
if (len < 0)
- err(1, "lseek");
+ FAIL_ERR("lseek")
if (len != 0)
- errx(1, "lseek: %zd", len);
-
- if (bind(listen_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0)
- err(1, "bind");
-
- if (listen(listen_socket, -1) < 0)
- err(1, "listen");
-
- parent_pid = getpid();
- child_pid = fork();
- if (child_pid < 0)
- err(1, "fork");
- if (child_pid == 0) {
- child_pid = getpid();
- run_child();
- } else
- run_parent();
+ FAIL("len != 0")
+ run_parent();
return (0);
}
diff --git a/tools/regression/sockets/unix_gc/Makefile b/tools/regression/sockets/unix_gc/Makefile
index 1e2fd56..d791494 100644
--- a/tools/regression/sockets/unix_gc/Makefile
+++ b/tools/regression/sockets/unix_gc/Makefile
@@ -1,7 +1,7 @@
# $FreeBSD$
PROG= unix_gc
-WARNS= 3
NO_MAN=
+WARNS?= 3
.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/unix_sorflush/Makefile b/tools/regression/sockets/unix_sorflush/Makefile
index 7f0b9f1..96e48cf 100644
--- a/tools/regression/sockets/unix_sorflush/Makefile
+++ b/tools/regression/sockets/unix_sorflush/Makefile
@@ -2,6 +2,6 @@
PROG= unix_sorflush
NO_MAN=
-WARNS= 3
+WARNS?= 3
.include <bsd.prog.mk>
diff --git a/tools/regression/sysvsem/semtest.c b/tools/regression/sysvsem/semtest.c
index 83f73e9..b6859bf 100644
--- a/tools/regression/sysvsem/semtest.c
+++ b/tools/regression/sysvsem/semtest.c
@@ -14,13 +14,6 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/tools/regression/tls/libxx/Makefile b/tools/regression/tls/libxx/Makefile
index bc9393b..cf4e680 100644
--- a/tools/regression/tls/libxx/Makefile
+++ b/tools/regression/tls/libxx/Makefile
@@ -1,7 +1,6 @@
# $FreeBSD$
-LIB= xx
-SHLIB_MAJOR= 1
+SHLIB_NAME= libxx.so
SRCS= xx.c
#CFLAGS+=-mtls-dialect=sun
diff --git a/tools/regression/tls/libyy/Makefile b/tools/regression/tls/libyy/Makefile
index 8b45b99..b7a7198 100644
--- a/tools/regression/tls/libyy/Makefile
+++ b/tools/regression/tls/libyy/Makefile
@@ -1,7 +1,6 @@
# $FreeBSD$
-LIB= yy
-SHLIB_MAJOR= 1
+SHLIB_NAME= libyy.so
SRCS= yy.c
CFLAGS+=-fpic
diff --git a/tools/regression/tls/ttls1/Makefile b/tools/regression/tls/ttls1/Makefile
index d3b6e65..f4da549 100644
--- a/tools/regression/tls/ttls1/Makefile
+++ b/tools/regression/tls/ttls1/Makefile
@@ -1,8 +1,8 @@
# $FreeBSD$
PROG= ttls1
-LDADD+= -L../libxx -lxx -Wl,--rpath=${.OBJDIR}/../libxx
-LDADD+= -L../libyy -lyy -Wl,--rpath=${.OBJDIR}/../libyy
+LDFLAGS+= -L../libxx -lxx -Wl,--rpath=${.OBJDIR}/../libxx
+LDFLAGS+= -L../libyy -lyy -Wl,--rpath=${.OBJDIR}/../libyy
NO_MAN=
DEBUG_FLAGS= -g
diff --git a/tools/regression/tls/ttls2/Makefile b/tools/regression/tls/ttls2/Makefile
index 0a3bc95..043b9ca 100644
--- a/tools/regression/tls/ttls2/Makefile
+++ b/tools/regression/tls/ttls2/Makefile
@@ -1,7 +1,8 @@
# $FreeBSD$
PROG= ttls2
-LDADD+= -lpthread
+DPADD= ${LIBPTHREAD}
+LDADD= -lpthread
NO_MAN=
DEBUG_FLAGS= -g
diff --git a/tools/regression/tls/ttls4/Makefile b/tools/regression/tls/ttls4/Makefile
index 5fb37df..9a38a58 100644
--- a/tools/regression/tls/ttls4/Makefile
+++ b/tools/regression/tls/ttls4/Makefile
@@ -1,7 +1,8 @@
# $FreeBSD$
PROG= ttls4
-LDADD+= -lpthread
+DPADD= ${LIBPTHREAD}
+LDADD= -lpthread
NO_MAN=
DEBUG_FLAGS= -g
diff --git a/tools/regression/tmpfs/Makefile b/tools/regression/tmpfs/Makefile
index 91e1392..f96ba18 100644
--- a/tools/regression/tmpfs/Makefile
+++ b/tools/regression/tmpfs/Makefile
@@ -31,7 +31,7 @@ regress: ${tests}
PROG= h_tools
NO_MAN= # defined
-WARNS= 4
+WARNS?= 4
t_sizes t_sockets t_statvfs: h_tools
diff --git a/tools/tools/ether_reflect/Makefile b/tools/tools/ether_reflect/Makefile
index e3cf266..822643b 100644
--- a/tools/tools/ether_reflect/Makefile
+++ b/tools/tools/ether_reflect/Makefile
@@ -4,7 +4,7 @@
# A Makefile that builds both the ether_reflect program and its manual page.
PROG= ether_reflect
-
-LDADD+= -lpcap
+DPADD= ${LIBPCAP}
+LDADD= -lpcap
.include <bsd.prog.mk>
diff --git a/tools/tools/mcgrab/Makefile b/tools/tools/mcgrab/Makefile
new file mode 100644
index 0000000..a470227
--- /dev/null
+++ b/tools/tools/mcgrab/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+PROG_CXX= mcgrab
+CFLAGS+= -I${.CURDIR}/../mctest
+
+.include <bsd.prog.mk>
diff --git a/tools/tools/mctest/mcgrab.1 b/tools/tools/mcgrab/mcgrab.1
index f2b8b34..1b83f50 100644
--- a/tools/tools/mctest/mcgrab.1
+++ b/tools/tools/mcgrab/mcgrab.1
@@ -25,7 +25,7 @@
.\" $FreeBSD$
.\"
.Dd July 9, 2008
-.Dt mcgrab 1
+.Dt MCGRAB 1
.Os
.Sh NAME
.Nm mcgrab
@@ -36,23 +36,27 @@
.Op Fl g Ar group
.Op Fl n Ar number
.Sh DESCRIPTION
-The
+The
.Nm
command implements a multicast test which grabs and holds
-N multicast addresses. The purpose of the test is to see what
+N multicast addresses.
+The purpose of the test is to see what
happens when a network interface is no longer able to filter
-multicasts in hardware and has to switch to promiscious or
-multicast promiscious mode. A successful test does not have any
+multicasts in hardware and has to switch to promiscuous or
+multicast promiscuous mode.
+A successful test does not have any
result, but an unsuccessful test will have deleterious side effects.
Packet size in bytes.
The options are as follows:
-.Bl -tag -width ".Fl d Ar argument"
+.Bl -tag -width ".Fl i Ar interface"
.It Fl i Ar interface
-Network interface, which can be found with ifconfig(1).
-.It Fl i Ar group
-Multicast group
+Network interface, which can be found with
+.Xr ifconfig 8 .
+.It Fl g Ar group
+Multicast group.
.It Fl n Ar number
Number of groups to join.
+.El
.Sh EXAMPLES
The following is an example of a typical usage
of the
@@ -62,9 +66,9 @@ command:
.Dl "mcgrab -i em0 -g 239.255.255.1 -n 1024"
.Sh SEE ALSO
.Xr mctest 1 ,
-.Xr ifconfig 8 ,
.Xr netstat 1 ,
-.Xr nanosleep 2 .
+.Xr nanosleep 2 ,
+.Xr ifconfig 8
.Sh HISTORY
The
.Nm
@@ -75,4 +79,5 @@ This
manual page was written by
.An George V. Neville-Neil Aq gnn@FreeBSD.org .
.Sh BUGS
-Should be reported to the author or to net@freebsd.org.
+Should be reported to the author or to
+.Aq net@FreeBSD.org .
diff --git a/tools/tools/mctest/mcgrab.cc b/tools/tools/mcgrab/mcgrab.cc
index 5522f30..5522f30 100644
--- a/tools/tools/mctest/mcgrab.cc
+++ b/tools/tools/mcgrab/mcgrab.cc
diff --git a/tools/tools/mctest/Makefile b/tools/tools/mctest/Makefile
index 4de93c3..6edaf89 100644
--- a/tools/tools/mctest/Makefile
+++ b/tools/tools/mctest/Makefile
@@ -1,11 +1,7 @@
-#
# $FreeBSD$
-#
-# A Makefile that builds both the mctest program and its manual page.
PROG_CXX= mctest
-PROG_CXX= mcgrab
-
-LDADD+= -lpthread
+DPADD= ${LIBPTHREAD}
+LDADD= -lpthread
.include <bsd.prog.mk>
diff --git a/tools/tools/mctest/mctest.1 b/tools/tools/mctest/mctest.1
index 5eb7e5b..c64a5f8 100644
--- a/tools/tools/mctest/mctest.1
+++ b/tools/tools/mctest/mctest.1
@@ -25,7 +25,7 @@
.\" $FreeBSD$
.\"
.Dd April 3, 2008
-.Dt mctest 1
+.Dt MCTEST 1
.Os
.Sh NAME
.Nm mctest
@@ -40,29 +40,34 @@
.Op Fl t Ar inter-packet gap
.Op Fl M Ar number of clients (source only)
.Op Fl m Ar my client number (sink only)
-.Op Fl r
+.Op Fl r
.Sh DESCRIPTION
-The
+The
.Nm
-command implements a multicast test which involved a source
-and a sink. The source sends packets to a pre-configured
-multicast address over the interface given as a command line
-argument. The sink listens for multicast packets, records
-the time at which they're received and then reflects them back
-over unicast to the source. When the source has captured all
+command implements a multicast test which involves a source
+and a sink.
+The source sends packets to a pre-configured
+multicast address over the interface given as a command line
+argument.
+The sink listens for multicast packets, records
+the time at which they are received and then reflects them back
+over unicast to the source.
+When the source has captured all
the reflected packets it prints out the round trip time of each.
.Pp
The source prints out the round trip time of packets sent to the
-sinks. The sink prints out the time between the packets received.
+sinks.
+The sink prints out the time between the packets received.
.Pp
The options are as follows:
-.Bl -tag -width ".Fl d Ar argument"
+.Bl -tag -width ".Fl i Ar interface"
.It Fl i Ar interface
-Network interface, which can be found with ifconfig(1).
+Network interface, which can be found with
+.Xr ifconfig 8 .
.It Fl g Ar group
-Multicast group
+Multicast group.
.It Fl b Ar base port
-Port on which to listen
+Port on which to listen.
.It Fl s Ar size
Packet size in bytes.
.It Fl n Ar number
@@ -70,14 +75,15 @@ Number of packets.
.It Fl t Ar gap
Inter-packet gap in nanoseconds.
.It Fl M Ar clients
-The number of clients that are listening
+The number of clients that are listening.
.It Fl m Ar my number
The client's number 0, 1, etc.
.It Fl r
This version of
.Nm
-is the receiver aka the sink. This option MUST
-only be used with one copy of the program at a time.
+is the receiver aka the sink.
+This option MUST
+only be used with one copy of the program at a time.
.El
.Sh EXAMPLES
The following is an example of a typical usage
@@ -92,14 +98,15 @@ Sink
.Pp
Send 100 packets of 1024 bytes, with an inter-packet gap of 1 nanosecond.
.Pp
-Gaps are measured with
+Gaps are measured with
.Xr nanosleep 2 ,
and so are not accurate down to nanoseconds
-but depend on the setting of kern.hz.
+but depend on the setting of
+.Va kern.hz .
.Sh SEE ALSO
-.Xr ifconfig 8 ,
.Xr netstat 1 ,
-.Xr nanosleep 2 .
+.Xr nanosleep 2 ,
+.Xr ifconfig 8
.Sh HISTORY
The
.Nm
@@ -110,4 +117,5 @@ This
manual page was written by
.An George V. Neville-Neil Aq gnn@FreeBSD.org .
.Sh BUGS
-Should be reported to the author or to net@freebsd.org.
+Should be reported to the author or to
+.Aq net@FreeBSD.org .
diff --git a/tools/tools/net80211/stumbler/Makefile b/tools/tools/net80211/stumbler/Makefile
index 69abea7..d7236af 100644
--- a/tools/tools/net80211/stumbler/Makefile
+++ b/tools/tools/net80211/stumbler/Makefile
@@ -2,7 +2,7 @@
PROG= stumbler
BINDIR= /usr/local/bin
-DPADD= ${LIBPCAP}
+DPADD= ${LIBPCAP} ${LIBNCURSES}
LDADD= -lpcap -lncurses
CFLAGS=-g
NO_MAN=
diff --git a/tools/tools/net80211/w00t/Makefile.inc b/tools/tools/net80211/w00t/Makefile.inc
index 0670300..ecf5517 100644
--- a/tools/tools/net80211/w00t/Makefile.inc
+++ b/tools/tools/net80211/w00t/Makefile.inc
@@ -3,7 +3,8 @@
W00T= ../libw00t
# NB: we get crc32 from -lz
DPADD= ${W00T}/libw00t.a ${LIBCRYPTO} ${LIBZ}
-LDADD= -L${W00T} -lw00t -lcrypto -lz
+LDFLAGS= -L${W00T}
+LDADD= -lw00t -lcrypto -lz
BINDIR= /usr/local/bin
CFLAGS= -g -I${W00T}
diff --git a/tools/tools/netrate/http/Makefile b/tools/tools/netrate/http/Makefile
index 789e7d0..fb8960b 100644
--- a/tools/tools/netrate/http/Makefile
+++ b/tools/tools/netrate/http/Makefile
@@ -1,8 +1,8 @@
# $FreeBSD$
PROG= http
-WARNS= 3
NO_MAN=
+WARNS?= 3
DPADD= ${LIBPTHREAD}
LDADD= -lpthread
diff --git a/tools/tools/netrate/httpd/Makefile b/tools/tools/netrate/httpd/Makefile
index 74067f2..b66ad19 100644
--- a/tools/tools/netrate/httpd/Makefile
+++ b/tools/tools/netrate/httpd/Makefile
@@ -1,8 +1,8 @@
# $FreeBSD$
PROG= httpd
-WARNS= 3
NO_MAN=
+WARNS?= 3
DPADD= ${LIBPTHREAD}
LDADD= -lpthread
diff --git a/tools/tools/netrate/juggle/Makefile b/tools/tools/netrate/juggle/Makefile
index 67d6263..cd64a07 100644
--- a/tools/tools/netrate/juggle/Makefile
+++ b/tools/tools/netrate/juggle/Makefile
@@ -2,9 +2,8 @@
PROG= juggle
NO_MAN=
-WARNS= 3
-
-LDADD= -lpthread
+WARNS?= 3
DPADD= ${LIBPTHREAD}
+LDADD= -lpthread
.include <bsd.prog.mk>
diff --git a/tools/tools/netrate/tcpconnect/Makefile b/tools/tools/netrate/tcpconnect/Makefile
index 4a3f5ad..624c94a 100644
--- a/tools/tools/netrate/tcpconnect/Makefile
+++ b/tools/tools/netrate/tcpconnect/Makefile
@@ -1,7 +1,7 @@
# $FreeBSD$
PROG= tcpconnect
-WARNS= 3
NO_MAN=
+WARNS?= 3
.include <bsd.prog.mk>
diff --git a/tools/tools/netrate/tcpp/Makefile b/tools/tools/netrate/tcpp/Makefile
index 31f8fc2..a0b2715 100644
--- a/tools/tools/netrate/tcpp/Makefile
+++ b/tools/tools/netrate/tcpp/Makefile
@@ -4,6 +4,6 @@ PROG= tcpp
INCS= tcpp.h
NO_MAN=
SRCS= tcpp.c tcpp_client.c tcpp_server.c tcpp_util.c
-WARNS= 3
+WARNS?= 3
.include <bsd.prog.mk>
diff --git a/tools/tools/netrate/tcpreceive/Makefile b/tools/tools/netrate/tcpreceive/Makefile
index 06d58ce..f04ea5f 100644
--- a/tools/tools/netrate/tcpreceive/Makefile
+++ b/tools/tools/netrate/tcpreceive/Makefile
@@ -1,7 +1,7 @@
# $FreeBSD$
PROG= tcpreceive
-WARNS= 3
NO_MAN=
+WARNS?= 3
.include <bsd.prog.mk>
diff --git a/tools/tools/umastat/Makefile b/tools/tools/umastat/Makefile
index 9461173..2335673 100644
--- a/tools/tools/umastat/Makefile
+++ b/tools/tools/umastat/Makefile
@@ -2,10 +2,9 @@
PROG= umastat
NO_MAN=
+WARNS?= 3
DPADD= ${LIBKVM}
LDADD= -lkvm
-WARNS= 3
-
.include <bsd.prog.mk>
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index 03b17c0..60eed85 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -172,6 +172,7 @@ SUBDIR= alias \
${_rwho} \
script \
sed \
+ seq \
shar \
showmount \
${_smbutil} \
diff --git a/usr.bin/cpio/Makefile b/usr.bin/cpio/Makefile
index d609780..bfcbe97 100644
--- a/usr.bin/cpio/Makefile
+++ b/usr.bin/cpio/Makefile
@@ -5,7 +5,6 @@
PROG= bsdcpio
BSDCPIO_VERSION_STRING=2.7.0
SRCS= cpio.c cmdline.c err.c matching.c pathmatch.c
-DPADD= ${LIBARCHIVE} ${LIBZ} ${LIBBZ2}
CFLAGS+= -DBSDCPIO_VERSION_STRING=\"${BSDCPIO_VERSION_STRING}\"
CFLAGS+= -DPLATFORM_CONFIG_H=\"config_freebsd.h\"
.ifdef RELEASE_CRUNCH
@@ -13,8 +12,10 @@ CFLAGS+= -DPLATFORM_CONFIG_H=\"config_freebsd.h\"
# statically linked, cannot use -lcrypto, and are size sensitive.
CFLAGS+= -DSMALLER
.endif
-LDADD+= -larchive -lz -lbz2 -lmd
+DPADD= ${LIBARCHIVE} ${LIBZ} ${LIBBZ2} ${LIBMD}
+LDADD= -larchive -lz -lbz2 -lmd
.if ${MK_OPENSSL} != "no"
+DPADD+= ${LIBCRYPTO}
LDADD+= -lcrypto
.endif
diff --git a/usr.bin/cpio/bsdcpio.1 b/usr.bin/cpio/bsdcpio.1
index 81b3462..6017bc5 100644
--- a/usr.bin/cpio/bsdcpio.1
+++ b/usr.bin/cpio/bsdcpio.1
@@ -266,7 +266,7 @@ for more information.
.Sh EXAMPLES
The
.Nm
-command is traditionally used to copy file heirarchies in conjunction
+command is traditionally used to copy file hierarchies in conjunction
with the
.Xr find 1
command.
diff --git a/usr.bin/csup/Makefile b/usr.bin/csup/Makefile
index 417de54..af1815c 100644
--- a/usr.bin/csup/Makefile
+++ b/usr.bin/csup/Makefile
@@ -1,42 +1,22 @@
# $FreeBSD$
-.PATH: ${.CURDIR}/../../contrib/csup
+PREFIX?= /usr/local
+BINDIR?= ${PREFIX}/bin
+MANDIR?= ${PREFIX}/man/man
+
+UNAME!= /usr/bin/uname -s
PROG= csup
-SRCS= attrstack.c \
- auth.c \
- config.c \
- detailer.c \
- diff.c \
- fattr.c \
- fixups.c \
- fnmatch.c \
- globtree.c \
- idcache.c \
- keyword.c \
- lex.rcs.c \
- lister.c \
- main.c \
- misc.c \
- mux.c \
- parse.y \
- pathcomp.c \
- proto.c \
- rcsfile.c \
- rcsparse.c \
- rsyncfile.c \
- status.c \
- stream.c \
- threads.c \
- token.l \
- updater.c
+SRCS= attrstack.c auth.c config.c detailer.c diff.c fattr.c fixups.c fnmatch.c \
+ globtree.c idcache.c keyword.c lister.c main.c misc.c mux.c parse.y \
+ pathcomp.c proto.c status.c stream.c threads.c token.l updater.c \
+ rcsfile.c rcsparse.c lex.rcs.c rsyncfile.c
-CFLAGS+= -I. -I${.CURDIR}/../../contrib/csup
-CFLAGS+= -DHAVE_FFLAGS -DNDEBUG
-WARNS?= 1
+CFLAGS+= -I. -I${.CURDIR} -g -pthread -DHAVE_FFLAGS -DNDEBUG
+WARNS?= 1
-DPADD= ${LIBCRYPTO} ${LIBZ} ${LIBPTHREAD}
-LDADD= -lcrypto -lz -lpthread
+DPADD= ${LIBCRYPTO} ${LIBZ}
+LDADD= -lcrypto -lz
SCRIPTS= cpasswd.sh
MAN= csup.1 cpasswd.1
diff --git a/contrib/csup/README b/usr.bin/csup/README
index 879c481..879c481 100644
--- a/contrib/csup/README
+++ b/usr.bin/csup/README
diff --git a/contrib/csup/TODO b/usr.bin/csup/TODO
index f4f0b31..9854d35 100644
--- a/contrib/csup/TODO
+++ b/usr.bin/csup/TODO
@@ -18,9 +18,8 @@ BUGS:
MISSING FEATURES:
- Add support for shell commands sent by the server.
-- Add missing support for various CVSup options : -D, -a (requires
- authentication support), -e and -E (requires shell commands support)
- and the destDir parameter.
+- Add missing support for various CVSup options : -D, -e and -E (requires
+ shell commands support) and the destDir parameter.
- For now, this code should build fine on FreeBSD, NetBSD, OpenBSD,
Linux and Darwin. Solaris support would also be nice at some point.
- Implement some new useful options : the ability to generate CVS
diff --git a/contrib/csup/attrstack.c b/usr.bin/csup/attrstack.c
index f5f56b3..f5f56b3 100644
--- a/contrib/csup/attrstack.c
+++ b/usr.bin/csup/attrstack.c
diff --git a/contrib/csup/attrstack.h b/usr.bin/csup/attrstack.h
index 721313c..721313c 100644
--- a/contrib/csup/attrstack.h
+++ b/usr.bin/csup/attrstack.h
diff --git a/contrib/csup/auth.c b/usr.bin/csup/auth.c
index 4e79bc5..4e79bc5 100644
--- a/contrib/csup/auth.c
+++ b/usr.bin/csup/auth.c
diff --git a/contrib/csup/auth.h b/usr.bin/csup/auth.h
index 61052e3..61052e3 100644
--- a/contrib/csup/auth.h
+++ b/usr.bin/csup/auth.h
diff --git a/contrib/csup/config.c b/usr.bin/csup/config.c
index 46ae6cd..46ae6cd 100644
--- a/contrib/csup/config.c
+++ b/usr.bin/csup/config.c
diff --git a/contrib/csup/config.h b/usr.bin/csup/config.h
index 859013c..859013c 100644
--- a/contrib/csup/config.h
+++ b/usr.bin/csup/config.h
diff --git a/contrib/csup/cpasswd.1 b/usr.bin/csup/cpasswd.1
index 946783f..946783f 100644
--- a/contrib/csup/cpasswd.1
+++ b/usr.bin/csup/cpasswd.1
diff --git a/contrib/csup/cpasswd.sh b/usr.bin/csup/cpasswd.sh
index 71e17c5..71e17c5 100755
--- a/contrib/csup/cpasswd.sh
+++ b/usr.bin/csup/cpasswd.sh
diff --git a/contrib/csup/csup.1 b/usr.bin/csup/csup.1
index 2690863..2690863 100644
--- a/contrib/csup/csup.1
+++ b/usr.bin/csup/csup.1
diff --git a/contrib/csup/detailer.c b/usr.bin/csup/detailer.c
index 5592655..5592655 100644
--- a/contrib/csup/detailer.c
+++ b/usr.bin/csup/detailer.c
diff --git a/contrib/csup/detailer.h b/usr.bin/csup/detailer.h
index fe82b27..fe82b27 100644
--- a/contrib/csup/detailer.h
+++ b/usr.bin/csup/detailer.h
diff --git a/contrib/csup/diff.c b/usr.bin/csup/diff.c
index 8059676..8059676 100644
--- a/contrib/csup/diff.c
+++ b/usr.bin/csup/diff.c
diff --git a/contrib/csup/diff.h b/usr.bin/csup/diff.h
index b0c8c97..b0c8c97 100644
--- a/contrib/csup/diff.h
+++ b/usr.bin/csup/diff.h
diff --git a/contrib/csup/fattr.c b/usr.bin/csup/fattr.c
index b141c2c..b141c2c 100644
--- a/contrib/csup/fattr.c
+++ b/usr.bin/csup/fattr.c
diff --git a/contrib/csup/fattr.h b/usr.bin/csup/fattr.h
index bd4e649..bd4e649 100644
--- a/contrib/csup/fattr.h
+++ b/usr.bin/csup/fattr.h
diff --git a/contrib/csup/fattr_bsd.h b/usr.bin/csup/fattr_bsd.h
index 112a824..112a824 100644
--- a/contrib/csup/fattr_bsd.h
+++ b/usr.bin/csup/fattr_bsd.h
diff --git a/contrib/csup/fattr_posix.h b/usr.bin/csup/fattr_posix.h
index c4650e4..c4650e4 100644
--- a/contrib/csup/fattr_posix.h
+++ b/usr.bin/csup/fattr_posix.h
diff --git a/contrib/csup/fixups.c b/usr.bin/csup/fixups.c
index b105a8f..b105a8f 100644
--- a/contrib/csup/fixups.c
+++ b/usr.bin/csup/fixups.c
diff --git a/contrib/csup/fixups.h b/usr.bin/csup/fixups.h
index 0dddc90..0dddc90 100644
--- a/contrib/csup/fixups.h
+++ b/usr.bin/csup/fixups.h
diff --git a/contrib/csup/fnmatch.c b/usr.bin/csup/fnmatch.c
index a63f016..a63f016 100644
--- a/contrib/csup/fnmatch.c
+++ b/usr.bin/csup/fnmatch.c
diff --git a/contrib/csup/fnmatch.h b/usr.bin/csup/fnmatch.h
index 21d2f64..21d2f64 100644
--- a/contrib/csup/fnmatch.h
+++ b/usr.bin/csup/fnmatch.h
diff --git a/contrib/csup/globtree.c b/usr.bin/csup/globtree.c
index 74ac2c1..74ac2c1 100644
--- a/contrib/csup/globtree.c
+++ b/usr.bin/csup/globtree.c
diff --git a/contrib/csup/globtree.h b/usr.bin/csup/globtree.h
index 43882e3..43882e3 100644
--- a/contrib/csup/globtree.h
+++ b/usr.bin/csup/globtree.h
diff --git a/contrib/csup/idcache.c b/usr.bin/csup/idcache.c
index 47a3e71..47a3e71 100644
--- a/contrib/csup/idcache.c
+++ b/usr.bin/csup/idcache.c
diff --git a/contrib/csup/idcache.h b/usr.bin/csup/idcache.h
index 558af0c..558af0c 100644
--- a/contrib/csup/idcache.h
+++ b/usr.bin/csup/idcache.h
diff --git a/contrib/csup/keyword.c b/usr.bin/csup/keyword.c
index 049a011..049a011 100644
--- a/contrib/csup/keyword.c
+++ b/usr.bin/csup/keyword.c
diff --git a/contrib/csup/keyword.h b/usr.bin/csup/keyword.h
index 033cb0a..033cb0a 100644
--- a/contrib/csup/keyword.h
+++ b/usr.bin/csup/keyword.h
diff --git a/contrib/csup/lex.rcs.c b/usr.bin/csup/lex.rcs.c
index 5db7a7b..5db7a7b 100644
--- a/contrib/csup/lex.rcs.c
+++ b/usr.bin/csup/lex.rcs.c
diff --git a/contrib/csup/lister.c b/usr.bin/csup/lister.c
index b10dbd3..b10dbd3 100644
--- a/contrib/csup/lister.c
+++ b/usr.bin/csup/lister.c
diff --git a/contrib/csup/lister.h b/usr.bin/csup/lister.h
index a0a9bbe..a0a9bbe 100644
--- a/contrib/csup/lister.h
+++ b/usr.bin/csup/lister.h
diff --git a/contrib/csup/main.c b/usr.bin/csup/main.c
index e7711b3..e7711b3 100644
--- a/contrib/csup/main.c
+++ b/usr.bin/csup/main.c
diff --git a/contrib/csup/main.h b/usr.bin/csup/main.h
index 217c7eb..217c7eb 100644
--- a/contrib/csup/main.h
+++ b/usr.bin/csup/main.h
diff --git a/contrib/csup/misc.c b/usr.bin/csup/misc.c
index ae16b59..ae16b59 100644
--- a/contrib/csup/misc.c
+++ b/usr.bin/csup/misc.c
diff --git a/contrib/csup/misc.h b/usr.bin/csup/misc.h
index a7ca3a6..a7ca3a6 100644
--- a/contrib/csup/misc.h
+++ b/usr.bin/csup/misc.h
diff --git a/contrib/csup/mux.c b/usr.bin/csup/mux.c
index b344be1..b344be1 100644
--- a/contrib/csup/mux.c
+++ b/usr.bin/csup/mux.c
diff --git a/contrib/csup/mux.h b/usr.bin/csup/mux.h
index ff36083..ff36083 100644
--- a/contrib/csup/mux.h
+++ b/usr.bin/csup/mux.h
diff --git a/contrib/csup/parse.y b/usr.bin/csup/parse.y
index 3dcd617..3dcd617 100644
--- a/contrib/csup/parse.y
+++ b/usr.bin/csup/parse.y
diff --git a/contrib/csup/pathcomp.c b/usr.bin/csup/pathcomp.c
index 380d042..380d042 100644
--- a/contrib/csup/pathcomp.c
+++ b/usr.bin/csup/pathcomp.c
diff --git a/contrib/csup/pathcomp.h b/usr.bin/csup/pathcomp.h
index 3cea410..3cea410 100644
--- a/contrib/csup/pathcomp.h
+++ b/usr.bin/csup/pathcomp.h
diff --git a/contrib/csup/proto.c b/usr.bin/csup/proto.c
index 166a134..166a134 100644
--- a/contrib/csup/proto.c
+++ b/usr.bin/csup/proto.c
diff --git a/contrib/csup/proto.h b/usr.bin/csup/proto.h
index 0c4a782..0c4a782 100644
--- a/contrib/csup/proto.h
+++ b/usr.bin/csup/proto.h
diff --git a/contrib/csup/queue.h b/usr.bin/csup/queue.h
index aa9cac1..aa9cac1 100644
--- a/contrib/csup/queue.h
+++ b/usr.bin/csup/queue.h
diff --git a/contrib/csup/rcsfile.c b/usr.bin/csup/rcsfile.c
index 1f3ede1..1f3ede1 100644
--- a/contrib/csup/rcsfile.c
+++ b/usr.bin/csup/rcsfile.c
diff --git a/contrib/csup/rcsfile.h b/usr.bin/csup/rcsfile.h
index 5fa9f31..5fa9f31 100644
--- a/contrib/csup/rcsfile.h
+++ b/usr.bin/csup/rcsfile.h
diff --git a/contrib/csup/rcsparse.c b/usr.bin/csup/rcsparse.c
index 5ea690c..5ea690c 100644
--- a/contrib/csup/rcsparse.c
+++ b/usr.bin/csup/rcsparse.c
diff --git a/contrib/csup/rcsparse.h b/usr.bin/csup/rcsparse.h
index 01b0156..01b0156 100644
--- a/contrib/csup/rcsparse.h
+++ b/usr.bin/csup/rcsparse.h
diff --git a/contrib/csup/rcstokenizer.h b/usr.bin/csup/rcstokenizer.h
index 66ea724..66ea724 100644
--- a/contrib/csup/rcstokenizer.h
+++ b/usr.bin/csup/rcstokenizer.h
diff --git a/contrib/csup/rcstokenizer.l b/usr.bin/csup/rcstokenizer.l
index 56f0f41..56f0f41 100644
--- a/contrib/csup/rcstokenizer.l
+++ b/usr.bin/csup/rcstokenizer.l
diff --git a/contrib/csup/rsyncfile.c b/usr.bin/csup/rsyncfile.c
index 7680bcc..7680bcc 100644
--- a/contrib/csup/rsyncfile.c
+++ b/usr.bin/csup/rsyncfile.c
diff --git a/contrib/csup/rsyncfile.h b/usr.bin/csup/rsyncfile.h
index 2c41a28..2c41a28 100644
--- a/contrib/csup/rsyncfile.h
+++ b/usr.bin/csup/rsyncfile.h
diff --git a/contrib/csup/status.c b/usr.bin/csup/status.c
index 3482e8e..3482e8e 100644
--- a/contrib/csup/status.c
+++ b/usr.bin/csup/status.c
diff --git a/contrib/csup/status.h b/usr.bin/csup/status.h
index 86efdda..86efdda 100644
--- a/contrib/csup/status.h
+++ b/usr.bin/csup/status.h
diff --git a/contrib/csup/stream.c b/usr.bin/csup/stream.c
index aa229b4..aa229b4 100644
--- a/contrib/csup/stream.c
+++ b/usr.bin/csup/stream.c
diff --git a/contrib/csup/stream.h b/usr.bin/csup/stream.h
index 2128635..2128635 100644
--- a/contrib/csup/stream.h
+++ b/usr.bin/csup/stream.h
diff --git a/contrib/csup/threads.c b/usr.bin/csup/threads.c
index 46a9860..46a9860 100644
--- a/contrib/csup/threads.c
+++ b/usr.bin/csup/threads.c
diff --git a/contrib/csup/threads.h b/usr.bin/csup/threads.h
index 66153ce..66153ce 100644
--- a/contrib/csup/threads.h
+++ b/usr.bin/csup/threads.h
diff --git a/contrib/csup/token.h b/usr.bin/csup/token.h
index 0dc3ec0..0dc3ec0 100644
--- a/contrib/csup/token.h
+++ b/usr.bin/csup/token.h
diff --git a/contrib/csup/token.l b/usr.bin/csup/token.l
index 267e61f..267e61f 100644
--- a/contrib/csup/token.l
+++ b/usr.bin/csup/token.l
diff --git a/contrib/csup/updater.c b/usr.bin/csup/updater.c
index d9f4210..d9f4210 100644
--- a/contrib/csup/updater.c
+++ b/usr.bin/csup/updater.c
diff --git a/contrib/csup/updater.h b/usr.bin/csup/updater.h
index 9ec9ed7..9ec9ed7 100644
--- a/contrib/csup/updater.h
+++ b/usr.bin/csup/updater.h
diff --git a/usr.bin/fetch/Makefile b/usr.bin/fetch/Makefile
index 5686fc6..6f0db80 100644
--- a/usr.bin/fetch/Makefile
+++ b/usr.bin/fetch/Makefile
@@ -4,8 +4,8 @@
PROG= fetch
CSTD?= c99
-DPADD= ${LIBFETCH}
-LDADD= -lfetch
+DPADD= ${LIBFETCH} ${LIBMD}
+LDADD= -lfetch -lmd
.if ${MK_OPENSSL} != "no"
DPADD+= ${LIBSSL} ${LIBCRYPTO}
LDADD+= -lssl -lcrypto
diff --git a/usr.bin/gcore/Makefile b/usr.bin/gcore/Makefile
index 358c747..e83a48f 100644
--- a/usr.bin/gcore/Makefile
+++ b/usr.bin/gcore/Makefile
@@ -1,9 +1,10 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
# $FreeBSD$
-LDADD+= -lutil
PROG= gcore
SRCS= elfcore.c gcore.c
+DPADD= ${LIBUTIL}
+LDADD= -lutil
WARNS?= 1
diff --git a/usr.bin/hexdump/hexdump.1 b/usr.bin/hexdump/hexdump.1
index 4d8c2da..baf9d46 100644
--- a/usr.bin/hexdump/hexdump.1
+++ b/usr.bin/hexdump/hexdump.1
@@ -32,7 +32,7 @@
.\" @(#)hexdump.1 8.2 (Berkeley) 4/18/94
.\" $FreeBSD$
.\"
-.Dd July 10, 2004
+.Dd February 18, 2010
.Dt HEXDUMP 1
.Os
.Sh NAME
@@ -258,7 +258,7 @@ strings.
.It "\&00C\ FF\t00D\ CR\t00E\ SO\t00F\ SI\t010\ DLE\t011\ DC1
.It "\&012\ DC2\t013\ DC3\t014\ DC4\t015\ NAK\t016\ SYN\t017\ ETB
.It "\&018\ CAN\t019\ EM\t01A\ SUB\t01B\ ESC\t01C\ FS\t01D\ GS
-.It "\&01E\ RS\t01F\ US\t0FF\ DEL
+.It "\&01E\ RS\t01F\ US\t07F\ DEL
.El
.El
.Pp
diff --git a/usr.bin/hexdump/od.1 b/usr.bin/hexdump/od.1
index 9bf7967..dd67ff5 100644
--- a/usr.bin/hexdump/od.1
+++ b/usr.bin/hexdump/od.1
@@ -32,7 +32,7 @@
.\" @(#)od.1 8.1 (Berkeley) 6/6/93
.\" $FreeBSD$
.\"
-.Dd December 24, 2006
+.Dd February 18, 2010
.Os
.Dt OD 1
.Sh NAME
@@ -155,7 +155,7 @@ Control characters are displayed using the following names:
.It "00c FF 00d CR 00e SO 00f SI 010 DLE 011 DC1"
.It "012 DC2 013 DC3 014 DC4 015 NAK 016 SYN 017 ETB"
.It "018 CAN 019 EM 01a SUB 01b ESC 01c FS 01d GS"
-.It "01e RS 01f US 020 SP 0ff DEL"
+.It "01e RS 01f US 020 SP 07f DEL"
.El
.It Cm c
Characters in the default character set.
diff --git a/usr.bin/jot/jot.1 b/usr.bin/jot/jot.1
index 77cebb4..3e198a34 100644
--- a/usr.bin/jot/jot.1
+++ b/usr.bin/jot/jot.1
@@ -32,7 +32,7 @@
.\" @(#)jot.1 8.1 (Berkeley) 6/6/93
.\" $FreeBSD$
.\"
-.Dd November 6, 2006
+.Dd February 19, 2010
.Dt JOT 1
.Os
.Sh NAME
@@ -239,6 +239,7 @@ but only one is allowed.
.Xr ed 1 ,
.Xr expand 1 ,
.Xr rs 1 ,
+.Xr seq 1 ,
.Xr yes 1 ,
.Xr arc4random 3 ,
.Xr printf 3 ,
diff --git a/usr.bin/locale/Makefile b/usr.bin/locale/Makefile
index 5b8932c..96c18bc 100644
--- a/usr.bin/locale/Makefile
+++ b/usr.bin/locale/Makefile
@@ -1,7 +1,7 @@
# $FreeBSD$
-PROG = locale
-CFLAGS += -I${.CURDIR}/../../lib/libc/locale
-WARNS ?= 3
+PROG= locale
+WARNS?= 3
+CFLAGS+= -I${.CURDIR}/../../lib/libc/locale
.include <bsd.prog.mk>
diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile
index df31aec..8f00901 100644
--- a/usr.bin/netstat/Makefile
+++ b/usr.bin/netstat/Makefile
@@ -4,7 +4,7 @@
.include <bsd.own.mk>
PROG= netstat
-SRCS= if.c inet.c main.c mbuf.c mroute.c route.c \
+SRCS= if.c inet.c main.c mbuf.c mroute.c netisr.c route.c \
unix.c atalk.c mroute6.c ipsec.c bpf.c pfkey.c sctp.c
WARNS?= 3
diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c
index cd701df..f54db4e 100644
--- a/usr.bin/netstat/main.c
+++ b/usr.bin/netstat/main.c
@@ -338,6 +338,7 @@ int noutputs = 0; /* how much outputs before we exit */
int numeric_addr; /* show addresses numerically */
int numeric_port; /* show ports numerically */
static int pflag; /* show given protocol */
+int Qflag; /* show netisr information */
int rflag; /* show routing tables (or routing stats) */
int sflag; /* show protocol statistics */
int Wflag; /* wide display */
@@ -360,7 +361,8 @@ main(int argc, char *argv[])
af = AF_UNSPEC;
- while ((ch = getopt(argc, argv, "AaBbdf:ghI:iLlM:mN:np:q:rSsuWw:xz")) != -1)
+ while ((ch = getopt(argc, argv, "AaBbdf:ghI:iLlM:mN:np:Qq:rSsuWw:xz"))
+ != -1)
switch(ch) {
case 'A':
Aflag = 1;
@@ -446,6 +448,9 @@ main(int argc, char *argv[])
}
pflag = 1;
break;
+ case 'Q':
+ Qflag = 1;
+ break;
case 'q':
noutputs = atoi(optarg);
if (noutputs != 0)
@@ -524,6 +529,14 @@ main(int argc, char *argv[])
mbpr(NULL, 0);
exit(0);
}
+ if (Qflag) {
+ if (!live) {
+ if (kread(0, NULL, 0) == 0)
+ netisr_stats(kvmd);
+ } else
+ netisr_stats(NULL);
+ exit(0);
+ }
#if 0
/*
* Keep file descriptors open to avoid overhead
@@ -780,7 +793,7 @@ name2protox(const char *name)
static void
usage(void)
{
- (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+ (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
"usage: netstat [-AaLnSWx] [-f protocol_family | -p protocol]\n"
" [-M core] [-N system]",
" netstat -i | -I interface [-abdhnW] [-f address_family]\n"
@@ -795,6 +808,7 @@ usage(void)
" netstat -r [-AanW] [-f address_family] [-M core] [-N system]",
" netstat -rs [-s] [-M core] [-N system]",
" netstat -g [-W] [-f address_family] [-M core] [-N system]",
-" netstat -gs [-s] [-f address_family] [-M core] [-N system]");
+" netstat -gs [-s] [-f address_family] [-M core] [-N system]",
+" netstat -Q");
exit(1);
}
diff --git a/usr.bin/netstat/netisr.c b/usr.bin/netstat/netisr.c
new file mode 100644
index 0000000..733a847
--- /dev/null
+++ b/usr.bin/netstat/netisr.c
@@ -0,0 +1,518 @@
+/*-
+ * Copyright (c) 2010 Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert N. M. Watson under contract
+ * to Juniper Networks, Inc.
+ *
+ * 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/sysctl.h>
+
+#include <sys/_lock.h>
+#include <sys/_mutex.h>
+
+#define _WANT_NETISR_INTERNAL
+#include <net/netisr.h>
+#include <net/netisr_internal.h>
+
+#include <err.h>
+#include <kvm.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "netstat.h"
+
+/*
+ * Print statistics for the kernel netisr subsystem.
+ */
+static u_int bindthreads;
+static u_int maxthreads;
+static u_int numthreads;
+
+static u_int defaultqlimit;
+static u_int maxqlimit;
+
+static u_int direct;
+static u_int direct_force;
+
+static struct sysctl_netisr_proto *proto_array;
+static u_int proto_array_len;
+
+static struct sysctl_netisr_workstream *workstream_array;
+static u_int workstream_array_len;
+
+static struct sysctl_netisr_work *work_array;
+static u_int work_array_len;
+
+static u_int *nws_array;
+
+static u_int maxprot;
+
+static void
+netisr_load_kvm_uint(kvm_t *kd, char *name, u_int *p)
+{
+ struct nlist nl[] = {
+ { .n_name = name },
+ { .n_name = NULL },
+ };
+ int ret;
+
+ ret = kvm_nlist(kd, nl);
+ if (ret < 0)
+ errx(-1, "%s: kvm_nlist(%s): %s", __func__, name,
+ kvm_geterr(kd));
+ if (ret != 0)
+ errx(-1, "%s: kvm_nlist(%s): unresolved symbol", __func__,
+ name);
+ if (kvm_read(kd, nl[0].n_value, p, sizeof(*p)) != sizeof(*p))
+ errx(-1, "%s: kvm_read(%s): %s", __func__, name,
+ kvm_geterr(kd));
+}
+
+/*
+ * Load a nul-terminated string from KVM up to 'limit', guarantee that the
+ * string in local memory is nul-terminated.
+ */
+static void
+netisr_load_kvm_string(kvm_t *kd, uintptr_t addr, char *dest, u_int limit)
+{
+ u_int i;
+
+ for (i = 0; i < limit; i++) {
+ if (kvm_read(kd, addr + i, &dest[i], sizeof(dest[i])) !=
+ sizeof(dest[i]))
+ err(-1, "%s: kvm_read: %s", __func__,
+ kvm_geterr(kd));
+ if (dest[i] == '\0')
+ break;
+ }
+ dest[limit - 1] = '\0';
+}
+
+static const char *
+netisr_proto2name(u_int proto)
+{
+ u_int i;
+
+ for (i = 0; i < proto_array_len; i++) {
+ if (proto_array[i].snp_proto == proto)
+ return (proto_array[i].snp_name);
+ }
+ return ("unknown");
+}
+
+static int
+netisr_protoispresent(u_int proto)
+{
+ u_int i;
+
+ for (i = 0; i < proto_array_len; i++) {
+ if (proto_array[i].snp_proto == proto)
+ return (1);
+ }
+ return (0);
+}
+
+static void
+netisr_load_kvm_config(kvm_t *kd)
+{
+
+ netisr_load_kvm_uint(kd, "_netisr_bindthreads", &bindthreads);
+ netisr_load_kvm_uint(kd, "_netisr_maxthreads", &maxthreads);
+ netisr_load_kvm_uint(kd, "_nws_count", &numthreads);
+
+ netisr_load_kvm_uint(kd, "_netisr_defaultqlimit", &defaultqlimit);
+ netisr_load_kvm_uint(kd, "_netisr_maxqlimit", &maxqlimit);
+
+ netisr_load_kvm_uint(kd, "_netisr_direct", &direct);
+ netisr_load_kvm_uint(kd, "_netisr_direct_force", &direct_force);
+}
+
+static void
+netisr_load_sysctl_uint(const char *name, u_int *p)
+{
+ size_t retlen;
+
+ retlen = sizeof(u_int);
+ if (sysctlbyname(name, p, &retlen, NULL, 0) < 0)
+ err(-1, "%s", name);
+ if (retlen != sizeof(u_int))
+ errx(-1, "%s: invalid len %ju", name, (uintmax_t)retlen);
+}
+
+static void
+netisr_load_sysctl_config(void)
+{
+
+ netisr_load_sysctl_uint("net.isr.bindthreads", &bindthreads);
+ netisr_load_sysctl_uint("net.isr.maxthreads", &maxthreads);
+ netisr_load_sysctl_uint("net.isr.numthreads", &numthreads);
+
+ netisr_load_sysctl_uint("net.isr.defaultqlimit", &defaultqlimit);
+ netisr_load_sysctl_uint("net.isr.maxqlimit", &maxqlimit);
+
+ netisr_load_sysctl_uint("net.isr.direct", &direct);
+ netisr_load_sysctl_uint("net.isr.direct_force", &direct_force);
+}
+
+static void
+netisr_load_kvm_proto(kvm_t *kd)
+{
+ struct nlist nl[] = {
+#define NLIST_NETISR_PROTO 0
+ { .n_name = "_netisr_proto" },
+ { .n_name = NULL },
+ };
+ struct netisr_proto *np_array, *npp;
+ u_int i, protocount;
+ struct sysctl_netisr_proto *snpp;
+ size_t len;
+ int ret;
+
+ /*
+ * Kernel compile-time and user compile-time definitions of
+ * NETISR_MAXPROT must match, as we use that to size work arrays.
+ */
+ netisr_load_kvm_uint(kd, "_netisr_maxprot", &maxprot);
+ if (maxprot != NETISR_MAXPROT)
+ errx(-1, "%s: NETISR_MAXPROT mismatch", __func__);
+ len = maxprot * sizeof(*np_array);
+ np_array = malloc(len);
+ if (np_array == NULL)
+ err(-1, "%s: malloc", __func__);
+ ret = kvm_nlist(kd, nl);
+ if (ret < 0)
+ errx(-1, "%s: kvm_nlist(_netisr_proto): %s", __func__,
+ kvm_geterr(kd));
+ if (ret != 0)
+ errx(-1, "%s: kvm_nlist(_netisr_proto): unresolved symbol",
+ __func__);
+ if (kvm_read(kd, nl[NLIST_NETISR_PROTO].n_value, np_array, len) !=
+ (ssize_t)len)
+ errx(-1, "%s: kvm_read(_netisr_proto): %s", __func__,
+ kvm_geterr(kd));
+
+ /*
+ * Size and allocate memory to hold only live protocols.
+ */
+ protocount = 0;
+ for (i = 0; i < maxprot; i++) {
+ if (np_array[i].np_name == NULL)
+ continue;
+ protocount++;
+ }
+ proto_array = calloc(protocount, sizeof(*proto_array));
+ if (proto_array == NULL)
+ err(-1, "malloc");
+ protocount = 0;
+ for (i = 0; i < maxprot; i++) {
+ npp = &np_array[i];
+ if (npp->np_name == NULL)
+ continue;
+ snpp = &proto_array[protocount];
+ snpp->snp_version = sizeof(*snpp);
+ netisr_load_kvm_string(kd, (uintptr_t)npp->np_name,
+ snpp->snp_name, sizeof(snpp->snp_name));
+ snpp->snp_proto = i;
+ snpp->snp_qlimit = npp->np_qlimit;
+ snpp->snp_policy = npp->np_policy;
+ if (npp->np_m2flow != NULL)
+ snpp->snp_flags |= NETISR_SNP_FLAGS_M2FLOW;
+ if (npp->np_m2cpuid != NULL)
+ snpp->snp_flags |= NETISR_SNP_FLAGS_M2CPUID;
+ if (npp->np_drainedcpu != NULL)
+ snpp->snp_flags |= NETISR_SNP_FLAGS_DRAINEDCPU;
+ protocount++;
+ }
+ proto_array_len = protocount;
+ free(np_array);
+}
+
+static void
+netisr_load_sysctl_proto(void)
+{
+ size_t len;
+
+ if (sysctlbyname("net.isr.proto", NULL, &len, NULL, 0) < 0)
+ err(-1, "net.isr.proto: query len");
+ if (len % sizeof(*proto_array) != 0)
+ errx(-1, "net.isr.proto: invalid len");
+ proto_array = malloc(len);
+ if (proto_array == NULL)
+ err(-1, "malloc");
+ if (sysctlbyname("net.isr.proto", proto_array, &len, NULL, 0) < 0)
+ err(-1, "net.isr.proto: query data");
+ if (len % sizeof(*proto_array) != 0)
+ errx(-1, "net.isr.proto: invalid len");
+ proto_array_len = len / sizeof(*proto_array);
+ if (proto_array_len < 1)
+ errx(-1, "net.isr.proto: no data");
+ if (proto_array[0].snp_version != sizeof(proto_array[0]))
+ errx(-1, "net.isr.proto: invalid version");
+}
+
+static void
+netisr_load_kvm_workstream(kvm_t *kd)
+{
+ struct nlist nl[] = {
+#define NLIST_NWS_ARRAY 0
+ { .n_name = "_nws_array" },
+ { .n_name = NULL },
+ };
+ struct netisr_workstream nws;
+ struct sysctl_netisr_workstream *snwsp;
+ struct sysctl_netisr_work *snwp;
+ struct netisr_work *nwp;
+ struct nlist nl_nws[2];
+ u_int counter, cpuid, proto, wsid;
+ size_t len;
+ int ret;
+
+ len = numthreads * sizeof(*nws_array);
+ nws_array = malloc(len);
+ if (nws_array == NULL)
+ err(-1, "malloc");
+ ret = kvm_nlist(kd, nl);
+ if (ret < 0)
+ errx(-1, "%s: kvm_nlist: %s", __func__, kvm_geterr(kd));
+ if (ret != 0)
+ errx(-1, "%s: kvm_nlist: unresolved symbol", __func__);
+ if (kvm_read(kd, nl[NLIST_NWS_ARRAY].n_value, nws_array, len) !=
+ (ssize_t)len)
+ errx(-1, "%s: kvm_read(_nws_array): %s", __func__,
+ kvm_geterr(kd));
+ workstream_array = calloc(numthreads, sizeof(*workstream_array));
+ if (workstream_array == NULL)
+ err(-1, "calloc");
+ workstream_array_len = numthreads;
+ work_array = calloc(numthreads * proto_array_len, sizeof(*work_array));
+ if (work_array == NULL)
+ err(-1, "calloc");
+ counter = 0;
+ for (wsid = 0; wsid < numthreads; wsid++) {
+ cpuid = nws_array[wsid];
+ if (kvm_dpcpu_setcpu(kd, cpuid) < 0)
+ errx(-1, "%s: kvm_dpcpu_setcpu(%u): %s", __func__,
+ cpuid, kvm_geterr(kd));
+ bzero(nl_nws, sizeof(nl_nws));
+ nl_nws[0].n_name = "_nws";
+ ret = kvm_nlist(kd, nl_nws);
+ if (ret < 0)
+ errx(-1, "%s: kvm_nlist looking up nws on CPU %u: %s",
+ __func__, cpuid, kvm_geterr(kd));
+ if (ret != 0)
+ errx(-1, "%s: kvm_nlist(nws): unresolved symbol on "
+ "CPU %u", __func__, cpuid);
+ if (kvm_read(kd, nl_nws[0].n_value, &nws, sizeof(nws)) !=
+ sizeof(nws))
+ errx(-1, "%s: kvm_read(nw): %s", __func__,
+ kvm_geterr(kd));
+ snwsp = &workstream_array[wsid];
+ snwsp->snws_version = sizeof(*snwsp);
+ snwsp->snws_wsid = cpuid;
+ snwsp->snws_cpu = cpuid;
+ if (nws.nws_intr_event != NULL)
+ snwsp->snws_flags |= NETISR_SNWS_FLAGS_INTR;
+
+ /*
+ * Extract the CPU's per-protocol work information.
+ */
+ printf("counting to maxprot: %u\n", maxprot);
+ for (proto = 0; proto < maxprot; proto++) {
+ if (!netisr_protoispresent(proto))
+ continue;
+ nwp = &nws.nws_work[proto];
+ snwp = &work_array[counter];
+ snwp->snw_version = sizeof(*snwp);
+ snwp->snw_wsid = cpuid;
+ snwp->snw_proto = proto;
+ snwp->snw_len = nwp->nw_len;
+ snwp->snw_watermark = nwp->nw_watermark;
+ snwp->snw_dispatched = nwp->nw_dispatched;
+ snwp->snw_hybrid_dispatched =
+ nwp->nw_hybrid_dispatched;
+ snwp->snw_qdrops = nwp->nw_qdrops;
+ snwp->snw_queued = nwp->nw_queued;
+ snwp->snw_handled = nwp->nw_handled;
+ counter++;
+ }
+ }
+ work_array_len = counter;
+}
+
+static void
+netisr_load_sysctl_workstream(void)
+{
+ size_t len;
+
+ if (sysctlbyname("net.isr.workstream", NULL, &len, NULL, 0) < 0)
+ err(-1, "net.isr.workstream: query len");
+ if (len % sizeof(*workstream_array) != 0)
+ errx(-1, "net.isr.workstream: invalid len");
+ workstream_array = malloc(len);
+ if (workstream_array == NULL)
+ err(-1, "malloc");
+ if (sysctlbyname("net.isr.workstream", workstream_array, &len, NULL,
+ 0) < 0)
+ err(-1, "net.isr.workstream: query data");
+ if (len % sizeof(*workstream_array) != 0)
+ errx(-1, "net.isr.workstream: invalid len");
+ workstream_array_len = len / sizeof(*workstream_array);
+ if (workstream_array_len < 1)
+ errx(-1, "net.isr.workstream: no data");
+ if (workstream_array[0].snws_version != sizeof(workstream_array[0]))
+ errx(-1, "net.isr.workstream: invalid version");
+}
+
+static void
+netisr_load_sysctl_work(void)
+{
+ size_t len;
+
+ if (sysctlbyname("net.isr.work", NULL, &len, NULL, 0) < 0)
+ err(-1, "net.isr.work: query len");
+ if (len % sizeof(*work_array) != 0)
+ errx(-1, "net.isr.work: invalid len");
+ work_array = malloc(len);
+ if (work_array == NULL)
+ err(-1, "malloc");
+ if (sysctlbyname("net.isr.work", work_array, &len, NULL, 0) < 0)
+ err(-1, "net.isr.work: query data");
+ if (len % sizeof(*work_array) != 0)
+ errx(-1, "net.isr.work: invalid len");
+ work_array_len = len / sizeof(*work_array);
+ if (work_array_len < 1)
+ errx(-1, "net.isr.work: no data");
+ if (work_array[0].snw_version != sizeof(work_array[0]))
+ errx(-1, "net.isr.work: invalid version");
+}
+
+static void
+netisr_print_proto(struct sysctl_netisr_proto *snpp)
+{
+
+ printf("%-6s", snpp->snp_name);
+ printf(" %5u", snpp->snp_proto);
+ printf(" %6u", snpp->snp_qlimit);
+ printf(" %6s",
+ (snpp->snp_policy == NETISR_POLICY_SOURCE) ? "source" :
+ (snpp->snp_policy == NETISR_POLICY_FLOW) ? "flow" :
+ (snpp->snp_policy == NETISR_POLICY_CPU) ? "cpu" : "-");
+ printf(" %s%s%s\n",
+ (snpp->snp_flags & NETISR_SNP_FLAGS_M2CPUID) ? "C" : "-",
+ (snpp->snp_flags & NETISR_SNP_FLAGS_DRAINEDCPU) ? "D" : "-",
+ (snpp->snp_flags & NETISR_SNP_FLAGS_M2FLOW) ? "F" : "-");
+}
+
+static void
+netisr_print_workstream(struct sysctl_netisr_workstream *snwsp)
+{
+ struct sysctl_netisr_work *snwp;
+ int first;
+ u_int i;
+
+ first = 1;
+ for (i = 0; i < work_array_len; i++) {
+ snwp = &work_array[i];
+ if (snwp->snw_wsid != snwsp->snws_wsid)
+ continue;
+ if (first) {
+ printf("%4u", snwsp->snws_wsid);
+ printf(" %3u", snwsp->snws_cpu);
+ first = 0;
+ } else
+ printf("%4s %3s", "", "");
+ printf("%2s", "");
+ printf("%-6s", netisr_proto2name(snwp->snw_proto));
+ printf(" %5u", snwp->snw_len);
+ printf(" %5u", snwp->snw_watermark);
+ printf(" %8ju", snwp->snw_dispatched);
+ printf(" %8ju", snwp->snw_hybrid_dispatched);
+ printf(" %8ju", snwp->snw_qdrops);
+ printf(" %8ju", snwp->snw_queued);
+ printf(" %8ju", snwp->snw_handled);
+ printf("\n");
+ }
+}
+
+void
+netisr_stats(void *kvmd)
+{
+ struct sysctl_netisr_workstream *snwsp;
+ struct sysctl_netisr_proto *snpp;
+ kvm_t *kd = kvmd;
+ u_int i;
+
+ if (live) {
+ netisr_load_sysctl_config();
+ netisr_load_sysctl_proto();
+ netisr_load_sysctl_workstream();
+ netisr_load_sysctl_work();
+ } else {
+ if (kd == NULL)
+ errx(-1, "netisr_stats: !live but !kd");
+ netisr_load_kvm_config(kd);
+ netisr_load_kvm_proto(kd);
+ netisr_load_kvm_workstream(kd); /* Also does work. */
+ }
+
+ printf("Configuration:\n");
+ printf("%-25s %12s %12s\n", "Setting", "Current", "Limit");
+ printf("%-25s %12u %12u\n", "Thread count", numthreads, maxthreads);
+ printf("%-25s %12u %12u\n", "Default queue limit", defaultqlimit,
+ maxqlimit);
+ printf("%-25s %12s %12s\n", "Direct dispatch",
+ direct ? "enabled" : "disabled", "n/a");
+ printf("%-25s %12s %12s\n", "Forced direct dispatch",
+ direct_force ? "enabled" : "disabled", "n/a");
+ printf("%-25s %12s %12s\n", "Threads bound to CPUs",
+ bindthreads ? "enabled" : "disabled", "n/a");
+ printf("\n");
+
+ printf("Protocols:\n");
+ printf("%-6s %5s %6s %-6s %-5s\n", "Name", "Proto", "QLimit",
+ "Policy", "Flags");
+ for (i = 0; i < proto_array_len; i++) {
+ snpp = &proto_array[i];
+ netisr_print_proto(snpp);
+ }
+ printf("\n");
+
+ printf("Workstreams:\n");
+ printf("%4s %3s ", "WSID", "CPU");
+ printf("%2s", "");
+ printf("%-6s %5s %5s %8s %8s %8s %8s %8s\n", "Name", "Len", "WMark",
+ "Disp'd", "HDisp'd", "QDrops", "Queued", "Handled");
+ for (i = 0; i < workstream_array_len; i++) {
+ snwsp = &workstream_array[i];
+ netisr_print_workstream(snwsp);
+ }
+}
diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1
index 7767847..6cf895b 100644
--- a/usr.bin/netstat/netstat.1
+++ b/usr.bin/netstat/netstat.1
@@ -32,7 +32,7 @@
.\" @(#)netstat.1 8.8 (Berkeley) 4/18/94
.\" $FreeBSD$
.\"
-.Dd January 10, 2010
+.Dd February 22, 2010
.Dt NETSTAT 1
.Os
.Sh NAME
@@ -292,6 +292,15 @@ Show multicast routing statistics.
If
.Fl s
is repeated, counters with a value of zero are suppressed.
+.It Xo
+.Bk -words
+.Nm
+.Fl Q
+.Ek
+.Xc
+Show
+.Xr netisr 9
+statistics.
.El
.Pp
Some options have the general meaning:
diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h
index 485901d..da3f8f3 100644
--- a/usr.bin/netstat/netstat.h
+++ b/usr.bin/netstat/netstat.h
@@ -67,6 +67,9 @@ const char *plural(uintmax_t);
const char *plurales(uintmax_t);
const char *pluralies(uintmax_t);
+struct sockaddr;
+struct socket;
+struct xsocket;
int sotoxsocket(struct socket *, struct xsocket *);
void protopr(u_long, const char *, int, int);
void tcp_stats(u_long, const char *, int, int);
@@ -112,6 +115,8 @@ void pfkey_stats(u_long, const char *, int, int);
void mbpr(void *, u_long);
+void netisr_stats(void *);
+
void hostpr(u_long, u_long);
void impstats(u_long, u_long);
diff --git a/usr.bin/pr/Makefile b/usr.bin/pr/Makefile
index 88ec7b4..15652dc 100644
--- a/usr.bin/pr/Makefile
+++ b/usr.bin/pr/Makefile
@@ -4,6 +4,4 @@
PROG= pr
SRCS= pr.c egetopt.c
-WARNS?= 2
-
.include <bsd.prog.mk>
diff --git a/usr.bin/pr/egetopt.c b/usr.bin/pr/egetopt.c
index cf42d7c..4b41b4a 100644
--- a/usr.bin/pr/egetopt.c
+++ b/usr.bin/pr/egetopt.c
@@ -48,6 +48,8 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <string.h>
+#include "extern.h"
+
/*
* egetopt: get option letter from argument vector (an extended
* version of getopt).
diff --git a/usr.bin/pr/pr.c b/usr.bin/pr/pr.c
index fed27f2..ae7ae07 100644
--- a/usr.bin/pr/pr.c
+++ b/usr.bin/pr/pr.c
@@ -1265,9 +1265,7 @@ FILE *
nxtfile(int argc, char **argv, const char **fname, char *buf, int dt)
{
FILE *inf = NULL;
- struct timeval tv;
time_t tv_sec;
- struct timezone tz;
struct tm *timeptr = NULL;
struct stat statbuf;
static int twice = -1;
@@ -1287,14 +1285,13 @@ nxtfile(int argc, char **argv, const char **fname, char *buf, int dt)
*fname = fnamedefault;
if (nohead)
return(inf);
- if (gettimeofday(&tv, &tz) < 0) {
+ if ((tv_sec = time(NULL)) == -1) {
++errcnt;
(void)fprintf(err, "pr: cannot get time of day, %s\n",
strerror(errno));
eoptind = argc - 1;
return(NULL);
}
- tv_sec = tv.tv_sec;
timeptr = localtime(&tv_sec);
}
for (; eoptind < argc; ++eoptind) {
@@ -1311,14 +1308,13 @@ nxtfile(int argc, char **argv, const char **fname, char *buf, int dt)
++eoptind;
if (nohead || (dt && twice))
return(inf);
- if (gettimeofday(&tv, &tz) < 0) {
+ if ((tv_sec = time(NULL)) == -1) {
++errcnt;
(void)fprintf(err,
"pr: cannot get time of day, %s\n",
strerror(errno));
return(NULL);
}
- tv_sec = tv.tv_sec;
timeptr = localtime(&tv_sec);
} else {
/*
@@ -1343,14 +1339,13 @@ nxtfile(int argc, char **argv, const char **fname, char *buf, int dt)
return(inf);
if (dt) {
- if (gettimeofday(&tv, &tz) < 0) {
+ if ((tv_sec = time(NULL)) == -1) {
++errcnt;
(void)fprintf(err,
"pr: cannot get time of day, %s\n",
strerror(errno));
return(NULL);
}
- tv_sec = tv.tv_sec;
timeptr = localtime(&tv_sec);
} else {
if (fstat(fileno(inf), &statbuf) < 0) {
diff --git a/usr.bin/seq/Makefile b/usr.bin/seq/Makefile
new file mode 100644
index 0000000..58b16ae
--- /dev/null
+++ b/usr.bin/seq/Makefile
@@ -0,0 +1,8 @@
+# $NetBSD: Makefile,v 1.3 2009/04/14 22:15:26 lukem Exp $
+# $FreeBSD$
+
+PROG= seq
+DPADD= ${LIBM}
+LDADD= -lm
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/seq/seq.1 b/usr.bin/seq/seq.1
new file mode 100644
index 0000000..e3bccee
--- /dev/null
+++ b/usr.bin/seq/seq.1
@@ -0,0 +1,187 @@
+.\" $NetBSD: seq.1,v 1.6 2008/11/26 15:03:47 ginsbach Exp $
+.\"
+.\" Copyright (c) 2005 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Brian Ginsbach.
+.\"
+.\" 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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$
+.\"
+.Dd February 19, 2010
+.Dt SEQ 1
+.Os
+.Sh NAME
+.Nm seq
+.Nd print sequences of numbers
+.Sh SYNOPSIS
+.Nm
+.Op Fl w
+.Op Fl f Ar format
+.Op Fl s Ar string
+.Op Fl t Ar string
+.Op Ar first Op Ar incr
+.Ar last
+.Sh DESCRIPTION
+The
+.Nm
+utility prints a sequence of numbers, one per line
+.Pq default ,
+from
+.Ar first
+.Pq default 1 ,
+to near
+.Ar last
+as possible, in increments of
+.Ar incr
+.Pq default 1 .
+When
+.Ar first
+is larger than
+.Ar last
+the default
+.Ar incr
+is -1.
+.Pp
+All numbers are interpreted as floating point.
+.Pp
+Normally integer values are printed as decimal integers.
+.Pp
+The
+.Nm
+utility accepts the following options:
+.Bl -tag -width Ar
+.It Fl f Ar format
+Use a
+.Xr printf 3
+style
+.Ar format
+to print each number.
+Only the
+.Cm E ,
+.Cm e ,
+.Cm f ,
+.Cm G ,
+.Cm g ,
+and
+.Cm %
+conversion characters are valid, along with any optional
+flags and an optional numeric minimum field width or precision.
+The
+.Ar format
+can contain character escape sequences in backslash notation as
+defined in
+.St -ansiC .
+The default is
+.Cm %g .
+.It Fl s Ar string
+Use
+.Ar string
+to separate numbers.
+The
+.Ar string
+can contain character escape sequences in backslash notation as
+defined in
+.St -ansiC .
+The default is
+.Cm \en .
+.It Fl t Ar string
+Use
+.Ar string
+to terminate sequence of numbers.
+The
+.Ar string
+can contain character escape sequences in backslash notation as
+defined in
+.St -ansiC .
+This option is useful when the default separator
+does not contain a
+.Cm \en .
+.It Fl w
+Equalize the widths of all numbers by padding with zeros as necessary.
+This option has no effect with the
+.Fl f
+option.
+If any sequence numbers will be printed in exponential notation,
+the default conversion is changed to
+.Cm %e .
+.El
+.Pp
+The
+.Nm
+utility exits 0 on success and non-zero if an error occurs.
+.Sh EXAMPLES
+.Bd -literal -offset indent
+# seq 1 3
+1
+2
+3
+
+# seq 3 1
+3
+2
+1
+
+# seq -w 0 .05 .1
+0.00
+0.05
+0.10
+.Ed
+.Sh SEE ALSO
+.Xr jot 1 ,
+.Xr printf 1 ,
+.Xr printf 3
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Tn "Plan 9 from Bell Labs" .
+A
+.Nm
+command appeared in
+.Nx 3.0 ,
+and ported to
+.Fx 9.0 .
+This command was based on the command of the same name in
+.Tn "Plan 9 from Bell Labs"
+and the
+.Tn GNU
+core utilities.
+The
+.Tn GNU
+.Nm
+command first appeared in the 1.13 shell utilities release.
+.Sh BUGS
+The
+.Fl w
+option does not handle the transition from pure floating point
+to exponent representation very well.
+The
+.Nm
+command is not bug for bug compatible with the
+.Tn "Plan 9 from Bell Labs"
+or
+.Tn GNU
+versions of
+.Nm .
diff --git a/usr.bin/seq/seq.c b/usr.bin/seq/seq.c
new file mode 100644
index 0000000..f94ca00
--- /dev/null
+++ b/usr.bin/seq/seq.c
@@ -0,0 +1,453 @@
+/* $NetBSD: seq.c,v 1.5 2008/07/21 14:19:26 lukem Exp $ */
+/*
+ * Copyright (c) 2005 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Brian Ginsbach.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <math.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ZERO '0'
+#define SPACE ' '
+
+#define MAX(a, b) (((a) < (b))? (b) : (a))
+#define ISSIGN(c) ((int)(c) == '-' || (int)(c) == '+')
+#define ISEXP(c) ((int)(c) == 'e' || (int)(c) == 'E')
+#define ISODIGIT(c) ((int)(c) >= '0' && (int)(c) <= '7')
+
+/* Globals */
+
+const char *decimal_point = "."; /* default */
+char default_format[] = { "%g" }; /* default */
+
+/* Prototypes */
+
+double e_atof(const char *);
+
+int decimal_places(const char *);
+int main(int, char *[]);
+int numeric(const char *);
+int valid_format(const char *);
+
+char *generate_format(double, double, double, int, char);
+char *unescape(char *);
+
+/*
+ * The seq command will print out a numeric sequence from 1, the default,
+ * to a user specified upper limit by 1. The lower bound and increment
+ * maybe indicated by the user on the command line. The sequence can
+ * be either whole, the default, or decimal numbers.
+ */
+int
+main(int argc, char *argv[])
+{
+ int c = 0, errflg = 0;
+ int equalize = 0;
+ double first = 1.0;
+ double last = 0.0;
+ double incr = 0.0;
+ struct lconv *locale;
+ char *fmt = NULL;
+ const char *sep = "\n";
+ const char *term = NULL;
+ char pad = ZERO;
+
+ /* Determine the locale's decimal point. */
+ locale = localeconv();
+ if (locale && locale->decimal_point && locale->decimal_point[0] != '\0')
+ decimal_point = locale->decimal_point;
+
+ /*
+ * Process options, but handle negative numbers separately
+ * least they trip up getopt(3).
+ */
+ while ((optind < argc) && !numeric(argv[optind]) &&
+ (c = getopt(argc, argv, "f:hs:t:w")) != -1) {
+
+ switch (c) {
+ case 'f': /* format (plan9) */
+ fmt = optarg;
+ equalize = 0;
+ break;
+ case 's': /* separator (GNU) */
+ sep = unescape(optarg);
+ break;
+ case 't': /* terminator (new) */
+ term = unescape(optarg);
+ break;
+ case 'w': /* equal width (plan9) */
+ if (!fmt)
+ if (equalize++)
+ pad = SPACE;
+ break;
+ case 'h': /* help (GNU) */
+ default:
+ errflg++;
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argc < 1 || argc > 3)
+ errflg++;
+
+ if (errflg) {
+ fprintf(stderr,
+ "usage: %s [-w] [-f format] [-s string] [-t string] [first [incr]] last\n",
+ getprogname());
+ exit(1);
+ }
+
+ last = e_atof(argv[argc - 1]);
+
+ if (argc > 1)
+ first = e_atof(argv[0]);
+
+ if (argc > 2) {
+ incr = e_atof(argv[1]);
+ /* Plan 9/GNU don't do zero */
+ if (incr == 0.0)
+ errx(1, "zero %screment", (first < last)? "in" : "de");
+ }
+
+ /* default is one for Plan 9/GNU work alike */
+ if (incr == 0.0)
+ incr = (first < last) ? 1.0 : -1.0;
+
+ if (incr <= 0.0 && first < last)
+ errx(1, "needs positive increment");
+
+ if (incr >= 0.0 && first > last)
+ errx(1, "needs negative decrement");
+
+ if (fmt != NULL) {
+ if (!valid_format(fmt))
+ errx(1, "invalid format string: `%s'", fmt);
+ fmt = unescape(fmt);
+ /*
+ * XXX to be bug for bug compatible with Plan 9 add a
+ * newline if none found at the end of the format string.
+ */
+ } else
+ fmt = generate_format(first, incr, last, equalize, pad);
+
+ if (incr > 0) {
+ for (; first <= last; first += incr) {
+ printf(fmt, first);
+ fputs(sep, stdout);
+ }
+ } else {
+ for (; first >= last; first += incr) {
+ printf(fmt, first);
+ fputs(sep, stdout);
+ }
+ }
+ if (term != NULL)
+ fputs(term, stdout);
+
+ return (0);
+}
+
+/*
+ * numeric - verify that string is numeric
+ */
+int
+numeric(const char *s)
+{
+ int seen_decimal_pt, decimal_pt_len;
+
+ /* skip any sign */
+ if (ISSIGN((unsigned char)*s))
+ s++;
+
+ seen_decimal_pt = 0;
+ decimal_pt_len = strlen(decimal_point);
+ while (*s) {
+ if (!isdigit((unsigned char)*s)) {
+ if (!seen_decimal_pt &&
+ strncmp(s, decimal_point, decimal_pt_len) == 0) {
+ s += decimal_pt_len;
+ seen_decimal_pt = 1;
+ continue;
+ }
+ if (ISEXP((unsigned char)*s)) {
+ s++;
+ if (ISSIGN((unsigned char)*s) ||
+ isdigit((unsigned char)*s)) {
+ s++;
+ continue;
+ }
+ }
+ break;
+ }
+ s++;
+ }
+ return (*s == '\0');
+}
+
+/*
+ * valid_format - validate user specified format string
+ */
+int
+valid_format(const char *fmt)
+{
+ int conversions = 0;
+
+ while (*fmt != '\0') {
+ /* scan for conversions */
+ if (*fmt != '\0' && *fmt != '%') {
+ do {
+ fmt++;
+ } while (*fmt != '\0' && *fmt != '%');
+ }
+ /* scan a conversion */
+ if (*fmt != '\0') {
+ do {
+ fmt++;
+
+ /* ok %% */
+ if (*fmt == '%') {
+ fmt++;
+ break;
+ }
+ /* valid conversions */
+ if (strchr("eEfgG", *fmt) &&
+ conversions++ < 1) {
+ fmt++;
+ break;
+ }
+ /* flags, width and precsision */
+ if (isdigit((unsigned char)*fmt) ||
+ strchr("+- 0#.", *fmt))
+ continue;
+
+ /* oops! bad conversion format! */
+ return (0);
+ } while (*fmt != '\0');
+ }
+ }
+
+ return (conversions <= 1);
+}
+
+/*
+ * unescape - handle C escapes in a string
+ */
+char *
+unescape(char *orig)
+{
+ char c, *cp, *new = orig;
+ int i;
+
+ for (cp = orig; (*orig = *cp); cp++, orig++) {
+ if (*cp != '\\')
+ continue;
+
+ switch (*++cp) {
+ case 'a': /* alert (bell) */
+ *orig = '\a';
+ continue;
+ case 'b': /* backspace */
+ *orig = '\b';
+ continue;
+ case 'e': /* escape */
+ *orig = '\e';
+ continue;
+ case 'f': /* formfeed */
+ *orig = '\f';
+ continue;
+ case 'n': /* newline */
+ *orig = '\n';
+ continue;
+ case 'r': /* carriage return */
+ *orig = '\r';
+ continue;
+ case 't': /* horizontal tab */
+ *orig = '\t';
+ continue;
+ case 'v': /* vertical tab */
+ *orig = '\v';
+ continue;
+ case '\\': /* backslash */
+ *orig = '\\';
+ continue;
+ case '\'': /* single quote */
+ *orig = '\'';
+ continue;
+ case '\"': /* double quote */
+ *orig = '"';
+ continue;
+ case '0':
+ case '1':
+ case '2':
+ case '3': /* octal */
+ case '4':
+ case '5':
+ case '6':
+ case '7': /* number */
+ for (i = 0, c = 0;
+ ISODIGIT((unsigned char)*cp) && i < 3;
+ i++, cp++) {
+ c <<= 3;
+ c |= (*cp - '0');
+ }
+ *orig = c;
+ --cp;
+ continue;
+ case 'x': /* hexidecimal number */
+ cp++; /* skip 'x' */
+ for (i = 0, c = 0;
+ isxdigit((unsigned char)*cp) && i < 2;
+ i++, cp++) {
+ c <<= 4;
+ if (isdigit((unsigned char)*cp))
+ c |= (*cp - '0');
+ else
+ c |= ((toupper((unsigned char)*cp) -
+ 'A') + 10);
+ }
+ *orig = c;
+ --cp;
+ continue;
+ default:
+ --cp;
+ break;
+ }
+ }
+
+ return (new);
+}
+
+/*
+ * e_atof - convert an ASCII string to a double
+ * exit if string is not a valid double, or if converted value would
+ * cause overflow or underflow
+ */
+double
+e_atof(const char *num)
+{
+ char *endp;
+ double dbl;
+
+ errno = 0;
+ dbl = strtod(num, &endp);
+
+ if (errno == ERANGE)
+ /* under or overflow */
+ err(2, "%s", num);
+ else if (*endp != '\0')
+ /* "junk" left in number */
+ errx(2, "invalid floating point argument: %s", num);
+
+ /* zero shall have no sign */
+ if (dbl == -0.0)
+ dbl = 0;
+ return (dbl);
+}
+
+/*
+ * decimal_places - count decimal places in a number (string)
+ */
+int
+decimal_places(const char *number)
+{
+ int places = 0;
+ char *dp;
+
+ /* look for a decimal point */
+ if ((dp = strstr(number, decimal_point))) {
+ dp += strlen(decimal_point);
+
+ while (isdigit((unsigned char)*dp++))
+ places++;
+ }
+ return (places);
+}
+
+/*
+ * generate_format - create a format string
+ *
+ * XXX to be bug for bug compatable with Plan9 and GNU return "%g"
+ * when "%g" prints as "%e" (this way no width adjustments are made)
+ */
+char *
+generate_format(double first, double incr, double last, int equalize, char pad)
+{
+ static char buf[256];
+ char cc = '\0';
+ int precision, width1, width2, places;
+
+ if (equalize == 0)
+ return (default_format);
+
+ /* figure out "last" value printed */
+ if (first > last)
+ last = first - incr * floor((first - last) / incr);
+ else
+ last = first + incr * floor((last - first) / incr);
+
+ sprintf(buf, "%g", incr);
+ if (strchr(buf, 'e'))
+ cc = 'e';
+ precision = decimal_places(buf);
+
+ width1 = sprintf(buf, "%g", first);
+ if (strchr(buf, 'e'))
+ cc = 'e';
+ if ((places = decimal_places(buf)))
+ width1 -= (places + strlen(decimal_point));
+
+ precision = MAX(places, precision);
+
+ width2 = sprintf(buf, "%g", last);
+ if (strchr(buf, 'e'))
+ cc = 'e';
+ if ((places = decimal_places(buf)))
+ width2 -= (places + strlen(decimal_point));
+
+ if (precision) {
+ sprintf(buf, "%%%c%d.%d%c", pad,
+ MAX(width1, width2) + (int) strlen(decimal_point) +
+ precision, precision, (cc) ? cc : 'f');
+ } else {
+ sprintf(buf, "%%%c%d%c", pad, MAX(width1, width2),
+ (cc) ? cc : 'g');
+ }
+
+ return (buf);
+}
diff --git a/usr.bin/systat/Makefile b/usr.bin/systat/Makefile
index bdd41c6..6a7e53d 100644
--- a/usr.bin/systat/Makefile
+++ b/usr.bin/systat/Makefile
@@ -16,7 +16,7 @@ CFLAGS+= -DINET6
WARNS?= 0
-DPADD= ${LIBCURSES} ${LIBM} ${LIBDEVSTAT} ${LIBKVM}
-LDADD= -lcursesw -lm -ldevstat -lkvm
+DPADD= ${LIBNCURSESW} ${LIBM} ${LIBDEVSTAT} ${LIBKVM}
+LDADD= -lncursesw -lm -ldevstat -lkvm
.include <bsd.prog.mk>
diff --git a/usr.bin/tar/Makefile b/usr.bin/tar/Makefile
index 29abcc5..1828952 100644
--- a/usr.bin/tar/Makefile
+++ b/usr.bin/tar/Makefile
@@ -15,9 +15,10 @@ SRCS= bsdtar.c \
tree.c \
util.c \
write.c
-DPADD= ${LIBARCHIVE} ${LIBBZ2} ${LIBZ}
+DPADD= ${LIBARCHIVE} ${LIBBZ2} ${LIBZ} ${LIBMD}
LDADD= -larchive -lbz2 -lz -lmd
.if ${MK_OPENSSL} != "no"
+DPADD+= ${LIBCRYPTO}
LDADD+= -lcrypto
.endif
CFLAGS+= -DBSDTAR_VERSION_STRING=\"${BSDTAR_VERSION_STRING}\"
diff --git a/usr.bin/tar/test/test_option_T.c b/usr.bin/tar/test/test_option_T.c
index 9f4a2b3..72dcd54 100644
--- a/usr.bin/tar/test/test_option_T.c
+++ b/usr.bin/tar/test/test_option_T.c
@@ -43,7 +43,7 @@ DEFINE_TEST(test_option_T)
int r;
struct stat st;
- /* Create a simple dir heirarchy; bail if anything fails. */
+ /* Create a simple dir hierarchy; bail if anything fails. */
if (!assertEqualInt(0, mkdir("d1", 0755))) return;
if (!assertEqualInt(0, mkdir("d1/d2", 0755))) return;
if (!touch("d1/f1")) return;
diff --git a/usr.bin/tar/test/test_option_s.c b/usr.bin/tar/test/test_option_s.c
index 1059066..c9a6899 100644
--- a/usr.bin/tar/test/test_option_s.c
+++ b/usr.bin/tar/test/test_option_s.c
@@ -44,7 +44,7 @@ DEFINE_TEST(test_option_s)
{
struct stat st;
- /* Create a sample file heirarchy. */
+ /* Create a sample file hierarchy. */
assertEqualInt(0, mkdir("in", 0755));
assertEqualInt(0, mkdir("in/d1", 0755));
assertEqualInt(0, mkfile("in/d1/foo", "foo"));
diff --git a/usr.bin/tar/tree.c b/usr.bin/tar/tree.c
index f70b6d5..58e9feb 100644
--- a/usr.bin/tar/tree.c
+++ b/usr.bin/tar/tree.c
@@ -313,7 +313,7 @@ tree_next(struct tree *t)
* violation. Just crash now. */
if (t->visit_type == TREE_ERROR_FATAL) {
const char *msg = "Unable to continue traversing"
- " directory heirarchy after a fatal error.";
+ " directory hierarchy after a fatal error.";
write(2, msg, strlen(msg));
*(int *)0 = 1; /* Deliberate SEGV; NULL pointer dereference. */
exit(1); /* In case the SEGV didn't work. */
diff --git a/usr.bin/unifdef/unifdef.1 b/usr.bin/unifdef/unifdef.1
index 2e75f0a..da7cde8 100644
--- a/usr.bin/unifdef/unifdef.1
+++ b/usr.bin/unifdef/unifdef.1
@@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)unifdef.1 8.2 (Berkeley) 4/1/94
-.\" $dotat: unifdef/unifdef.1,v 1.62 2010/01/19 17:33:53 fanf2 Exp $
+.\" $dotat: unifdef/unifdef.1,v 1.63 2010/02/19 16:41:15 fanf2 Exp $
.\" $FreeBSD$
.\"
.Dd January 19, 2010
@@ -168,14 +168,16 @@ with appropriate arguments to process the file.
.Sh OPTIONS
.Pp
.Bl -tag -width indent -compact
-.It Fl D Ns Ar sym Ns Op = Ns Ar val
-Specify that a symbol is defined,
-and optionally specify what value to give it
-for the purpose of handling
+.It Fl D Ns Ar sym Ns = Ns Ar val
+Specify that a symbol is defined to a given value
+which is used when evaluating
.Ic #if
and
.Ic #elif
-directives.
+control expressions.
+.Pp
+.It Fl D Ns Ar sym
+Specify that a symbol is defined to the value 1.
.Pp
.It Fl U Ns Ar sym
Specify that a symbol is undefined.
diff --git a/usr.bin/unifdef/unifdef.c b/usr.bin/unifdef/unifdef.c
index f50e600..cdcc403 100644
--- a/usr.bin/unifdef/unifdef.c
+++ b/usr.bin/unifdef/unifdef.c
@@ -39,8 +39,8 @@
* #else's and #endif's to see that they match their
* corresponding #ifdef or #ifndef
*
- * The first two items above require better buffer handling, which would
- * also make it possible to handle all "dodgy" directives correctly.
+ * These require better buffer handling, which would also make
+ * it possible to handle all "dodgy" directives correctly.
*/
#include <sys/types.h>
@@ -57,7 +57,7 @@
#include <unistd.h>
#ifdef __IDSTRING
-__IDSTRING(dotat, "$dotat: unifdef/unifdef.c,v 1.193 2010/01/19 18:03:02 fanf2 Exp $");
+__IDSTRING(dotat, "$dotat: unifdef/unifdef.c,v 1.198 2010/02/19 16:37:05 fanf2 Exp $");
#endif
#ifdef __FBSDID
__FBSDID("$FreeBSD$");
@@ -190,6 +190,10 @@ static char tempname[FILENAME_MAX]; /* used when overwriting */
static char tline[MAXLINE+EDITSLOP];/* input buffer plus space */
static char *keyword; /* used for editing #elif's */
+static const char *newline; /* input file format */
+static const char newline_unix[] = "\n";
+static const char newline_crlf[] = "\r\n";
+
static Comment_state incomment; /* comment parser state */
static Line_state linestate; /* #if line parser state */
static Ifstate ifstate[MAXDEPTH]; /* #if processor state */
@@ -313,6 +317,7 @@ main(int argc, char *argv[])
input = stdin;
}
if (ofilename == NULL) {
+ ofilename = "[stdout]";
output = stdout;
} else {
struct stat ist, ost;
@@ -336,7 +341,8 @@ main(int argc, char *argv[])
"%.*s/" TEMPLATE,
(int)(dirsep - ofilename), ofilename);
else
- strlcpy(tempname, TEMPLATE, sizeof(tempname));
+ snprintf(tempname, sizeof(tempname),
+ TEMPLATE);
ofd = mkstemp(tempname);
if (ofd != -1)
output = fdopen(ofd, "w+");
@@ -429,9 +435,9 @@ static void Itrue (void) { Ftrue(); ignoreon(); }
static void Ifalse(void) { Ffalse(); ignoreon(); }
/* edit this line */
static void Mpass (void) { strncpy(keyword, "if ", 4); Pelif(); }
-static void Mtrue (void) { keywordedit("else\n"); state(IS_TRUE_MIDDLE); }
-static void Melif (void) { keywordedit("endif\n"); state(IS_FALSE_TRAILER); }
-static void Melse (void) { keywordedit("endif\n"); state(IS_FALSE_ELSE); }
+static void Mtrue (void) { keywordedit("else"); state(IS_TRUE_MIDDLE); }
+static void Melif (void) { keywordedit("endif"); state(IS_FALSE_TRAILER); }
+static void Melse (void) { keywordedit("endif"); state(IS_FALSE_ELSE); }
static state_fn * const trans_table[IS_COUNT][LT_COUNT] = {
/* IS_OUTSIDE */
@@ -497,7 +503,8 @@ ignoreon(void)
static void
keywordedit(const char *replacement)
{
- strlcpy(keyword, replacement, tline + sizeof(tline) - keyword);
+ snprintf(keyword, tline + sizeof(tline) - keyword,
+ "%s%s", replacement, newline);
print();
}
static void
@@ -532,20 +539,20 @@ flushline(bool keep)
if (symlist)
return;
if (keep ^ complement) {
- bool blankline = tline[strspn(tline, " \t\n")] == '\0';
+ bool blankline = tline[strspn(tline, " \t\r\n")] == '\0';
if (blankline && compblank && blankcount != blankmax) {
delcount += 1;
blankcount += 1;
} else {
if (lnnum && delcount > 0)
- printf("#line %d\n", linenum);
+ printf("#line %d%s", linenum, newline);
fputs(tline, output);
delcount = 0;
blankmax = blankcount = blankline ? blankcount + 1 : 0;
}
} else {
if (lnblank)
- putc('\n', output);
+ fputs(newline, output);
exitstat = 1;
delcount += 1;
blankcount = 0;
@@ -580,7 +587,7 @@ static void
closeout(void)
{
if (fclose(output) == EOF) {
- warn("couldn't write to output");
+ warn("couldn't write to %s", ofilename);
if (overwriting) {
unlink(tempname);
errx(2, "%s unchanged", filename);
@@ -623,6 +630,12 @@ parseline(void)
if (fgets(tline, MAXLINE, input) == NULL)
return (LT_EOF);
+ if (newline == NULL) {
+ if (strrchr(tline, '\n') == strrchr(tline, '\r') + 1)
+ newline = newline_crlf;
+ else
+ newline = newline_unix;
+ }
retval = LT_PLAIN;
wascomment = incomment;
cp = skipcomment(tline);
@@ -638,7 +651,8 @@ parseline(void)
cp = skipsym(cp);
kwlen = cp - keyword;
/* no way can we deal with a continuation inside a keyword */
- if (strncmp(cp, "\\\n", 2) == 0)
+ if (strncmp(cp, "\\\r\n", 3) == 0 ||
+ strncmp(cp, "\\\n", 2) == 0)
Eioccc();
if (strlcmp("ifdef", keyword, kwlen) == 0 ||
strlcmp("ifndef", keyword, kwlen) == 0) {
@@ -689,9 +703,8 @@ parseline(void)
size_t len = cp - tline;
if (fgets(tline + len, MAXLINE - len, input) == NULL) {
/* append the missing newline */
- tline[len+0] = '\n';
- tline[len+1] = '\0';
- cp++;
+ strcpy(tline + len, newline);
+ cp += strlen(newline);
linestate = LS_START;
} else {
linestate = LS_DIRTY;
@@ -947,11 +960,16 @@ skipcomment(const char *cp)
}
while (*cp != '\0')
/* don't reset to LS_START after a line continuation */
- if (strncmp(cp, "\\\n", 2) == 0)
+ if (strncmp(cp, "\\\r\n", 3) == 0)
+ cp += 3;
+ else if (strncmp(cp, "\\\n", 2) == 0)
cp += 2;
else switch (incomment) {
case NO_COMMENT:
- if (strncmp(cp, "/\\\n", 3) == 0) {
+ if (strncmp(cp, "/\\\r\n", 4) == 0) {
+ incomment = STARTING_COMMENT;
+ cp += 4;
+ } else if (strncmp(cp, "/\\\n", 3) == 0) {
incomment = STARTING_COMMENT;
cp += 3;
} else if (strncmp(cp, "/*", 2) == 0) {
@@ -971,7 +989,7 @@ skipcomment(const char *cp)
} else if (strncmp(cp, "\n", 1) == 0) {
linestate = LS_START;
cp += 1;
- } else if (strchr(" \t", *cp) != NULL) {
+ } else if (strchr(" \r\t", *cp) != NULL) {
cp += 1;
} else
return (cp);
@@ -1003,7 +1021,10 @@ skipcomment(const char *cp)
cp += 1;
continue;
case C_COMMENT:
- if (strncmp(cp, "*\\\n", 3) == 0) {
+ if (strncmp(cp, "*\\\r\n", 4) == 0) {
+ incomment = FINISHING_COMMENT;
+ cp += 4;
+ } else if (strncmp(cp, "*\\\n", 3) == 0) {
incomment = FINISHING_COMMENT;
cp += 3;
} else if (strncmp(cp, "*/", 2) == 0) {
@@ -1124,7 +1145,7 @@ addsym(bool ignorethis, bool definethis, char *sym)
value[symind] = val+1;
*val = '\0';
} else if (*val == '\0')
- value[symind] = "";
+ value[symind] = "1";
else
usage();
} else {
diff --git a/usr.bin/unzip/Makefile b/usr.bin/unzip/Makefile
index 5f235bb..ef8a690 100644
--- a/usr.bin/unzip/Makefile
+++ b/usr.bin/unzip/Makefile
@@ -2,7 +2,7 @@
PROG = unzip
CSTD = c99
-DPADD = ${LIBARCHIVE}
-LDADD = -larchive
+DPADD = ${LIBARCHIVE} ${LIBZ}
+LDADD = -larchive -lz
.include <bsd.prog.mk>
diff --git a/usr.bin/xinstall/xinstall.c b/usr.bin/xinstall/xinstall.c
index 1466645..449dea3 100644
--- a/usr.bin/xinstall/xinstall.c
+++ b/usr.bin/xinstall/xinstall.c
@@ -733,7 +733,7 @@ strip(const char *to_name)
/*
* install_dir --
- * build directory heirarchy
+ * build directory hierarchy
*/
static void
install_dir(char *path)
diff --git a/usr.sbin/auditd/Makefile b/usr.sbin/auditd/Makefile
index 201f961..47ffd0b 100644
--- a/usr.sbin/auditd/Makefile
+++ b/usr.sbin/auditd/Makefile
@@ -11,8 +11,8 @@ PROG= auditd
SRCS= auditd.c audit_warn.c auditd_fbsd.c
MAN= auditd.8
-DPADD= ${LIBBSM} ${LIBAUDITD}
-LDADD= -lbsm -lauditd
+DPADD= ${LIBAUDITD} ${LIBBSM}
+LDADD= -lauditd -lbsm
WARNS?= 3
diff --git a/usr.sbin/bluetooth/bthidd/Makefile b/usr.sbin/bluetooth/bthidd/Makefile
index 128bd20..dd0754d 100644
--- a/usr.sbin/bluetooth/bthidd/Makefile
+++ b/usr.sbin/bluetooth/bthidd/Makefile
@@ -8,7 +8,6 @@ SRCS= bthidd.c client.c hid.c kbd.c lexer.l parser.y server.c \
session.c
CFLAGS+= -I${.CURDIR}
-WARNS?= 6
DEBUG_FLAGS= -g
DPADD= ${LIBBLUETOOTH} ${LIBUSBHID}
diff --git a/usr.sbin/boot0cfg/Makefile b/usr.sbin/boot0cfg/Makefile
index 79e7cd2..9b46701 100644
--- a/usr.sbin/boot0cfg/Makefile
+++ b/usr.sbin/boot0cfg/Makefile
@@ -3,7 +3,7 @@
PROG= boot0cfg
MAN= boot0cfg.8
-DPADD= ${LIBGEOM}
-LDADD= -lgeom
+DPADD= ${LIBGEOM} ${LIBBSDXML} ${LIBSBUF}
+LDADD= -lgeom -lbsdxml -lsbuf
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsnmpd/modules/Makefile.inc b/usr.sbin/bsnmpd/modules/Makefile.inc
index adf6d72..b5dad56 100644
--- a/usr.sbin/bsnmpd/modules/Makefile.inc
+++ b/usr.sbin/bsnmpd/modules/Makefile.inc
@@ -1,8 +1,9 @@
# $FreeBSD$
SHLIB_MAJOR= 6
-WARNS?= 6
MANFILTER= sed -e 's%@MODPATH@%${LIBDIR}/%g' \
-e 's%@DEFPATH@%${DEFSDIR}/%g' \
-e 's%@MIBSPATH@%${BMIBSDIR}/%g'
+
+.include "../Makefile.inc"
diff --git a/usr.sbin/chown/chgrp.1 b/usr.sbin/chown/chgrp.1
index 71b6806..8a4c271 100644
--- a/usr.sbin/chown/chgrp.1
+++ b/usr.sbin/chown/chgrp.1
@@ -31,7 +31,7 @@
.\" @(#)chgrp.1 8.3 (Berkeley) 3/31/94
.\" $FreeBSD$
.\"
-.Dd April 25, 2003
+.Dd February 21, 2010
.Dt CHGRP 1
.Os
.Sh NAME
@@ -39,7 +39,7 @@
.Nd change group
.Sh SYNOPSIS
.Nm
-.Op Fl fhv
+.Op Fl fhvx
.Oo
.Fl R
.Op Fl H | Fl L | Fl P
@@ -89,6 +89,8 @@ If the
flag is specified more than once,
.Nm
will print the filename, followed by the old and new numeric group ID.
+.It Fl x
+File system mount points are not traversed.
.El
.Pp
The
@@ -125,7 +127,9 @@ In previous versions of this system, symbolic links did not have groups.
.Pp
The
.Fl v
-option is non-standard and its use in scripts is not recommended.
+and
+.Fl x
+options are non-standard and their use in scripts is not recommended.
.Sh SEE ALSO
.Xr chown 2 ,
.Xr fts 3 ,
diff --git a/usr.sbin/chown/chown.8 b/usr.sbin/chown/chown.8
index f617f73..b5882a3 100644
--- a/usr.sbin/chown/chown.8
+++ b/usr.sbin/chown/chown.8
@@ -28,7 +28,7 @@
.\" @(#)chown.8 8.3 (Berkeley) 3/31/94
.\" $FreeBSD$
.\"
-.Dd April 25, 2003
+.Dd February 21, 2010
.Dt CHOWN 8
.Os
.Sh NAME
@@ -36,7 +36,7 @@
.Nd change file owner and group
.Sh SYNOPSIS
.Nm
-.Op Fl fhv
+.Op Fl fhvx
.Oo
.Fl R
.Op Fl H | Fl L | Fl P
@@ -44,7 +44,7 @@
.Ar owner Ns Op : Ns Ar group
.Ar
.Nm
-.Op Fl fhv
+.Op Fl fhvx
.Oo
.Fl R
.Op Fl H | Fl L | Fl P
@@ -97,6 +97,8 @@ If the
flag is specified more than once,
.Nm
will print the filename, followed by the old and new numeric user/group ID.
+.It Fl x
+File system mount points are not traversed.
.El
.Pp
The
@@ -146,7 +148,9 @@ owners.
.Pp
The
.Fl v
-option is non-standard and its use in scripts is not recommended.
+and
+.Fl x
+options are non-standard and their use in scripts is not recommended.
.Sh SEE ALSO
.Xr chgrp 1 ,
.Xr find 1 ,
diff --git a/usr.sbin/chown/chown.c b/usr.sbin/chown/chown.c
index b79deca..7a22292 100644
--- a/usr.sbin/chown/chown.c
+++ b/usr.sbin/chown/chown.c
@@ -73,14 +73,14 @@ main(int argc, char **argv)
{
FTS *ftsp;
FTSENT *p;
- int Hflag, Lflag, Rflag, fflag, hflag, vflag;
+ int Hflag, Lflag, Rflag, fflag, hflag, vflag, xflag;
int ch, fts_options, rval;
char *cp;
ischown = (strcmp(basename(argv[0]), "chown") == 0);
- Hflag = Lflag = Rflag = fflag = hflag = vflag = 0;
- while ((ch = getopt(argc, argv, "HLPRfhv")) != -1)
+ Hflag = Lflag = Rflag = fflag = hflag = vflag = xflag = 0;
+ while ((ch = getopt(argc, argv, "HLPRfhvx")) != -1)
switch (ch) {
case 'H':
Hflag = 1;
@@ -105,6 +105,9 @@ main(int argc, char **argv)
case 'v':
vflag++;
break;
+ case 'x':
+ xflag = 1;
+ break;
case '?':
default:
usage();
@@ -128,6 +131,8 @@ main(int argc, char **argv)
}
} else
fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
+ if (xflag)
+ fts_options |= FTS_XDEV;
uid = (uid_t)-1;
gid = (gid_t)-1;
@@ -301,11 +306,11 @@ usage(void)
if (ischown)
(void)fprintf(stderr, "%s\n%s\n",
- "usage: chown [-fhv] [-R [-H | -L | -P]] owner[:group]"
+ "usage: chown [-fhvx] [-R [-H | -L | -P]] owner[:group]"
" file ...",
- " chown [-fhv] [-R [-H | -L | -P]] :group file ...");
+ " chown [-fhvx] [-R [-H | -L | -P]] :group file ...");
else
(void)fprintf(stderr, "%s\n",
- "usage: chgrp [-fhv] [-R [-H | -L | -P]] group file ...");
+ "usage: chgrp [-fhvx] [-R [-H | -L | -P]] group file ...");
exit(1);
}
diff --git a/usr.sbin/cxgbtool/cxgbtool.c b/usr.sbin/cxgbtool/cxgbtool.c
index 8d7e677..28d91f9 100644
--- a/usr.sbin/cxgbtool/cxgbtool.c
+++ b/usr.sbin/cxgbtool/cxgbtool.c
@@ -85,7 +85,8 @@ struct reg_info {
static const char *progname;
-static void __attribute__((noreturn)) usage(FILE *fp)
+static void
+usage(FILE *fp)
{
fprintf(fp, "Usage: %s <interface> [operation]\n", progname);
fprintf(fp,
@@ -136,7 +137,8 @@ doit(const char *iff_name, unsigned long cmd, void *data)
return ioctl(fd, cmd, data) < 0 ? -1 : 0;
}
-static int get_int_arg(const char *s, uint32_t *valp)
+static int
+get_int_arg(const char *s, uint32_t *valp)
{
char *p;
@@ -172,11 +174,12 @@ write_reg(const char *iff_name, uint32_t addr, uint32_t val)
err(1, "register write");
}
-static int register_io(int argc, char *argv[], int start_arg,
+static int
+register_io(int argc, char *argv[], int start_arg,
const char *iff_name)
{
char *p;
- uint32_t addr, val = 0, write = 0;
+ uint32_t addr, val = 0, w = 0;
if (argc != start_arg + 1) return -1;
@@ -184,14 +187,14 @@ static int register_io(int argc, char *argv[], int start_arg,
if (p == argv[start_arg]) return -1;
if (*p == '=' && p[1]) {
val = strtoul(p + 1, &p, 0);
- write = 1;
+ w = 1;
}
if (*p) {
warnx("bad parameter \"%s\"", argv[start_arg]);
return -1;
}
- if (write)
+ if (w)
write_reg(iff_name, addr, val);
else {
val = read_reg(iff_name, addr);
@@ -200,9 +203,9 @@ static int register_io(int argc, char *argv[], int start_arg,
return 0;
}
-static int mdio_io(int argc, char *argv[], int start_arg, const char *iff_name)
+static int
+mdio_io(int argc, char *argv[], int start_arg, const char *iff_name)
{
- struct ifreq ifr;
struct ch_mii_data p;
unsigned int cmd, phy_addr, reg, mmd, val;
@@ -230,12 +233,14 @@ static int mdio_io(int argc, char *argv[], int start_arg, const char *iff_name)
return 0;
}
-static inline uint32_t xtract(uint32_t val, int shift, int len)
+static inline
+uint32_t xtract(uint32_t val, int shift, int len)
{
return (val >> shift) & ((1 << len) - 1);
}
-static int dump_block_regs(const struct reg_info *reg_array, uint32_t *regs)
+static int
+dump_block_regs(const struct reg_info *reg_array, uint32_t *regs)
{
uint32_t reg_val = 0; // silence compiler warning
@@ -254,7 +259,8 @@ static int dump_block_regs(const struct reg_info *reg_array, uint32_t *regs)
return 1;
}
-static int dump_regs_t2(int argc, char *argv[], int start_arg, uint32_t *regs)
+static int
+dump_regs_t2(int argc, char *argv[], int start_arg, uint32_t *regs)
{
int match = 0;
char *block_name = NULL;
@@ -292,8 +298,8 @@ static int dump_regs_t2(int argc, char *argv[], int start_arg, uint32_t *regs)
}
#if defined(CONFIG_T3_REGS)
-static int dump_regs_t3(int argc, char *argv[], int start_arg, uint32_t *regs,
- int is_pcie)
+static int
+dump_regs_t3(int argc, char *argv[], int start_arg, uint32_t *regs, int is_pcie)
{
int match = 0;
char *block_name = NULL;
@@ -353,8 +359,9 @@ static int dump_regs_t3(int argc, char *argv[], int start_arg, uint32_t *regs,
return 0;
}
-static int dump_regs_t3b(int argc, char *argv[], int start_arg, uint32_t *regs,
- int is_pcie)
+static int
+dump_regs_t3b(int argc, char *argv[], int start_arg, uint32_t *regs,
+ int is_pcie)
{
int match = 0;
char *block_name = NULL;
@@ -414,8 +421,9 @@ static int dump_regs_t3b(int argc, char *argv[], int start_arg, uint32_t *regs,
return 0;
}
-static int dump_regs_t3c(int argc, char *argv[], int start_arg, uint32_t *regs,
- int is_pcie)
+static int
+dump_regs_t3c(int argc, char *argv[], int start_arg, uint32_t *regs,
+ int is_pcie)
{
int match = 0;
char *block_name = NULL;
@@ -479,7 +487,7 @@ static int dump_regs_t3c(int argc, char *argv[], int start_arg, uint32_t *regs,
static int
dump_regs(int argc, char *argv[], int start_arg, const char *iff_name)
{
- int i, vers, revision, is_pcie;
+ int vers, revision, is_pcie;
struct ch_ifconf_regs regs;
regs.len = REGDUMP_SIZE;
@@ -514,7 +522,8 @@ dump_regs(int argc, char *argv[], int start_arg, const char *iff_name)
return 0;
}
-static int t3_meminfo(const uint32_t *regs)
+static int
+t3_meminfo(const uint32_t *regs)
{
enum {
SG_EGR_CNTX_BADDR = 0x58,
@@ -592,11 +601,16 @@ static int t3_meminfo(const uint32_t *regs)
return 0;
}
-static int meminfo(int argc, char *argv[], int start_arg, const char *iff_name)
+static int
+meminfo(int argc, char *argv[], int start_arg, const char *iff_name)
{
int vers;
struct ch_ifconf_regs regs;
+ (void) argc;
+ (void) argv;
+ (void) start_arg;
+
regs.len = REGDUMP_SIZE;
if ((regs.data = malloc(regs.len)) == NULL)
err(1, "can't malloc");
@@ -612,11 +626,11 @@ static int meminfo(int argc, char *argv[], int start_arg, const char *iff_name)
return 0;
}
-static int mtu_tab_op(int argc, char *argv[], int start_arg,
- const char *iff_name)
+static int
+mtu_tab_op(int argc, char *argv[], int start_arg, const char *iff_name)
{
struct ch_mtus m;
- int i;
+ unsigned int i;
if (argc == start_arg) {
if (doit(iff_name, CHELSIO_GETMTUTAB, &m) < 0)
@@ -649,13 +663,14 @@ static int mtu_tab_op(int argc, char *argv[], int start_arg,
}
#ifdef CHELSIO_INTERNAL
-static void show_egress_cntxt(uint32_t data[])
+static void
+show_egress_cntxt(uint32_t data[])
{
printf("credits: %u\n", data[0] & 0x7fff);
printf("GTS: %u\n", (data[0] >> 15) & 1);
printf("index: %u\n", data[0] >> 16);
printf("queue size: %u\n", data[1] & 0xffff);
- printf("base address: 0x%llx\n",
+ printf("base address: 0x%" PRIx64 "\n",
((data[1] >> 16) | ((uint64_t)data[2] << 16) |
(((uint64_t)data[3] & 0xf) << 48)) << 12);
printf("rsp queue #: %u\n", (data[3] >> 4) & 7);
@@ -667,9 +682,10 @@ static void show_egress_cntxt(uint32_t data[])
printf("valid: %u\n", (data[3] >> 31) & 1);
}
-static void show_fl_cntxt(uint32_t data[])
+static void
+show_fl_cntxt(uint32_t data[])
{
- printf("base address: 0x%llx\n",
+ printf("base address: 0x%" PRIx64 "\n",
((uint64_t)data[0] | ((uint64_t)data[1] & 0xfffff) << 32) << 12);
printf("index: %u\n", (data[1] >> 20) | ((data[2] & 0xf) << 12));
printf("queue size: %u\n", (data[2] >> 4) & 0xffff);
@@ -680,11 +696,12 @@ static void show_fl_cntxt(uint32_t data[])
printf("GTS: %u\n", (data[3] >> 31) & 1);
}
-static void show_response_cntxt(uint32_t data[])
+static void
+show_response_cntxt(uint32_t data[])
{
printf("index: %u\n", data[0] & 0xffff);
printf("size: %u\n", data[0] >> 16);
- printf("base address: 0x%llx\n",
+ printf("base address: 0x%" PRIx64 "\n",
((uint64_t)data[1] | ((uint64_t)data[2] & 0xfffff) << 32) << 12);
printf("MSI-X/RspQ: %u\n", (data[2] >> 20) & 0x3f);
printf("intr enable: %u\n", (data[2] >> 26) & 1);
@@ -694,11 +711,12 @@ static void show_response_cntxt(uint32_t data[])
printf("FL threshold: %u\n", data[3]);
}
-static void show_cq_cntxt(uint32_t data[])
+static void
+show_cq_cntxt(uint32_t data[])
{
printf("index: %u\n", data[0] & 0xffff);
printf("size: %u\n", data[0] >> 16);
- printf("base address: 0x%llx\n",
+ printf("base address: 0x%" PRIx64 "\n",
((uint64_t)data[1] | ((uint64_t)data[2] & 0xfffff) << 32) << 12);
printf("rsp queue #: %u\n", (data[2] >> 20) & 0x3f);
printf("AN: %u\n", (data[2] >> 26) & 1);
@@ -710,8 +728,8 @@ static void show_cq_cntxt(uint32_t data[])
printf("credit threshold: %u\n", data[3] >> 16);
}
-static int get_sge_context(int argc, char *argv[], int start_arg,
- const char *iff_name)
+static int
+get_sge_context(int argc, char *argv[], int start_arg, const char *iff_name)
{
struct ch_cntxt ctx;
@@ -750,8 +768,8 @@ static int get_sge_context(int argc, char *argv[], int start_arg,
#define ntohll(x) be64toh((x))
-static int get_sge_desc(int argc, char *argv[], int start_arg,
- const char *iff_name)
+static int
+get_sge_desc(int argc, char *argv[], int start_arg, const char *iff_name)
{
uint64_t *p, wr_hdr;
unsigned int n = 1, qset, qnum;
@@ -796,7 +814,8 @@ static int get_sge_desc(int argc, char *argv[], int start_arg,
}
#endif
-static int get_tcb2(int argc, char *argv[], int start_arg, const char *iff_name)
+static int
+get_tcb2(int argc, char *argv[], int start_arg, const char *iff_name)
{
uint64_t *d;
unsigned int i;
@@ -835,8 +854,9 @@ static int get_tcb2(int argc, char *argv[], int start_arg, const char *iff_name)
return 0;
}
-static int get_pm_page_spec(const char *s, unsigned int *page_size,
- unsigned int *num_pages)
+static int
+get_pm_page_spec(const char *s, unsigned int *page_size,
+ unsigned int *num_pages)
{
char *p;
unsigned long val;
@@ -854,7 +874,8 @@ static int get_pm_page_spec(const char *s, unsigned int *page_size,
return *p;
}
-static int conf_pm(int argc, char *argv[], int start_arg, const char *iff_name)
+static int
+conf_pm(int argc, char *argv[], int start_arg, const char *iff_name)
{
struct ch_pm pm;
@@ -884,8 +905,8 @@ static int conf_pm(int argc, char *argv[], int start_arg, const char *iff_name)
}
#ifdef CHELSIO_INTERNAL
-static int dump_tcam(int argc, char *argv[], int start_arg,
- const char *iff_name)
+static int
+dump_tcam(int argc, char *argv[], int start_arg, const char *iff_name)
{
unsigned int nwords;
struct ch_tcam_word op;
@@ -907,7 +928,8 @@ static int dump_tcam(int argc, char *argv[], int start_arg,
return 0;
}
-static void hexdump_8b(unsigned int start, uint64_t *data, unsigned int len)
+static void
+hexdump_8b(unsigned int start, uint64_t *data, unsigned int len)
{
int i;
@@ -920,8 +942,8 @@ static void hexdump_8b(unsigned int start, uint64_t *data, unsigned int len)
}
}
-static int dump_mc7(int argc, char *argv[], int start_arg,
- const char *iff_name)
+static int
+dump_mc7(int argc, char *argv[], int start_arg, const char *iff_name)
{
struct ch_mem_range mem;
unsigned int mem_id, addr, len;
@@ -959,10 +981,11 @@ static int dump_mc7(int argc, char *argv[], int start_arg,
}
#endif
-/* Max FW size is 32K including version, +4 bytes for the checksum. */
+/* Max FW size is 64K including version, +4 bytes for the checksum. */
#define MAX_FW_IMAGE_SIZE (64 * 1024)
-static int load_fw(int argc, char *argv[], int start_arg, const char *iff_name)
+static int
+load_fw(int argc, char *argv[], int start_arg, const char *iff_name)
{
int fd, len;
struct ch_mem_range op;
@@ -979,12 +1002,13 @@ static int load_fw(int argc, char *argv[], int start_arg, const char *iff_name)
if (!op.buf)
err(1, "load firmware");
- op.len = read(fd, op.buf, MAX_FW_IMAGE_SIZE + 1);
- if (op.len < 0)
+ len = read(fd, op.buf, MAX_FW_IMAGE_SIZE + 1);
+ if (len < 0)
err(1, "load firmware");
- if (op.len > MAX_FW_IMAGE_SIZE)
+ if (len > MAX_FW_IMAGE_SIZE)
errx(1, "FW image too large");
+ op.len = len;
if (doit(iff_name, CHELSIO_LOAD_FW, &op) < 0)
err(1, "load firmware");
return 0;
@@ -993,8 +1017,8 @@ static int load_fw(int argc, char *argv[], int start_arg, const char *iff_name)
/* Max BOOT size is 255*512 bytes including the BIOS boot ROM basic header */
#define MAX_BOOT_IMAGE_SIZE (0xff * 512)
-static int load_boot(int argc, char *argv[],
- int start_arg, const char *iff_name)
+static int
+load_boot(int argc, char *argv[], int start_arg, const char *iff_name)
{
int fd, len;
struct ch_mem_range op;
@@ -1024,7 +1048,8 @@ static int load_boot(int argc, char *argv[],
return 0;
}
-static int dump_proto_sram(const char *iff_name)
+static int
+dump_proto_sram(const char *iff_name)
{
int i, j;
uint8_t buf[PROTO_SRAM_SIZE];
@@ -1054,15 +1079,20 @@ static int dump_proto_sram(const char *iff_name)
return 0;
}
-static int proto_sram_op(int argc, char *argv[], int start_arg,
+static int
+proto_sram_op(int argc, char *argv[], int start_arg,
const char *iff_name)
{
+ (void) argv;
+ (void) start_arg;
+
if (argc == start_arg)
return dump_proto_sram(iff_name);
return -1;
}
-static int dump_qset_params(const char *iff_name)
+static int
+dump_qset_params(const char *iff_name)
{
struct ch_qset_params qp;
@@ -1084,10 +1114,10 @@ static int dump_qset_params(const char *iff_name)
return 0;
}
-static int qset_config(int argc, char *argv[], int start_arg,
- const char *iff_name)
+static int
+qset_config(int argc, char *argv[], int start_arg, const char *iff_name)
{
- struct ch_qset_params qp;
+ (void) argv;
if (argc == start_arg)
return dump_qset_params(iff_name);
@@ -1095,11 +1125,13 @@ static int qset_config(int argc, char *argv[], int start_arg,
return -1;
}
-static int qset_num_config(int argc, char *argv[], int start_arg,
- const char *iff_name)
+static int
+qset_num_config(int argc, char *argv[], int start_arg, const char *iff_name)
{
struct ch_reg reg;
+ (void) argv;
+
if (argc == start_arg) {
if (doit(iff_name, CHELSIO_GET_QSET_NUM, &reg) < 0)
err(1, "get qsets");
@@ -1113,7 +1145,8 @@ static int qset_num_config(int argc, char *argv[], int start_arg,
/*
* Parse a string containing an IP address with an optional network prefix.
*/
-static int parse_ipaddr(const char *s, uint32_t *addr, uint32_t *mask)
+static int
+parse_ipaddr(const char *s, uint32_t *addr, uint32_t *mask)
{
char *p, *slash;
struct in_addr ia;
@@ -1143,7 +1176,8 @@ static int parse_ipaddr(const char *s, uint32_t *addr, uint32_t *mask)
/*
* Parse a string containing a value and an optional colon separated mask.
*/
-static int parse_val_mask_param(const char *s, uint32_t *val, uint32_t *mask)
+static int
+parse_val_mask_param(const char *s, uint32_t *val, uint32_t *mask)
{
char *p;
@@ -1156,14 +1190,15 @@ static int parse_val_mask_param(const char *s, uint32_t *val, uint32_t *mask)
return *p ? -1 : 0;
}
-static int parse_trace_param(const char *s, uint32_t *val, uint32_t *mask)
+static int
+parse_trace_param(const char *s, uint32_t *val, uint32_t *mask)
{
return strchr(s, '.') ? parse_ipaddr(s, val, mask) :
parse_val_mask_param(s, val, mask);
}
-static int trace_config(int argc, char *argv[], int start_arg,
- const char *iff_name)
+static int
+trace_config(int argc, char *argv[], int start_arg, const char *iff_name)
{
uint32_t val, mask;
struct ch_trace trace;
@@ -1238,7 +1273,8 @@ static int trace_config(int argc, char *argv[], int start_arg,
return 0;
}
-static int get_sched_param(int argc, char *argv[], int pos, unsigned int *valp)
+static int
+get_sched_param(int argc, char *argv[], int pos, unsigned int *valp)
{
if (pos + 1 >= argc)
errx(1, "missing value for %s", argv[pos]);
@@ -1247,7 +1283,8 @@ static int get_sched_param(int argc, char *argv[], int pos, unsigned int *valp)
return 0;
}
-static int tx_sched(int argc, char *argv[], int start_arg, const char *iff_name)
+static int
+tx_sched(int argc, char *argv[], int start_arg, const char *iff_name)
{
struct ch_hw_sched op;
unsigned int idx, val;
@@ -1293,7 +1330,8 @@ static int tx_sched(int argc, char *argv[], int start_arg, const char *iff_name)
return 0;
}
-static int pktsched(int argc, char *argv[], int start_arg, const char *iff_name)
+static int
+pktsched(int argc, char *argv[], int start_arg, const char *iff_name)
{
struct ch_pktsched_params op;
unsigned int idx, min = -1, max, binding = -1;
@@ -1333,20 +1371,29 @@ static int pktsched(int argc, char *argv[], int start_arg, const char *iff_name)
return 0;
}
-static int clear_stats(int argc, char *argv[], int start_arg,
- const char *iff_name)
+static int
+clear_stats(int argc, char *argv[], int start_arg, const char *iff_name)
{
+ (void) argc;
+ (void) argv;
+ (void) start_arg;
+
if (doit(iff_name, CHELSIO_CLEAR_STATS, NULL) < 0)
err(1, "clearstats");
return 0;
}
-static int get_up_la(int argc, char *argv[], int start_arg, const char *iff_name)
+static int
+get_up_la(int argc, char *argv[], int start_arg, const char *iff_name)
{
struct ch_up_la la;
int i, idx, max_idx, entries;
+ (void) argc;
+ (void) argv;
+ (void) start_arg;
+
la.stopped = 0;
la.idx = -1;
la.bufsize = LA_BUFSIZE;
@@ -1372,11 +1419,16 @@ static int get_up_la(int argc, char *argv[], int start_arg, const char *iff_name
return 0;
}
-static int get_up_ioqs(int argc, char *argv[], int start_arg, const char *iff_name)
+static int
+get_up_ioqs(int argc, char *argv[], int start_arg, const char *iff_name)
{
struct ch_up_ioqs ioqs;
int i, entries;
+ (void) argc;
+ (void) argv;
+ (void) start_arg;
+
bzero(&ioqs, sizeof(ioqs));
ioqs.bufsize = IOQS_BUFSIZE;
ioqs.data = malloc(IOQS_BUFSIZE);
@@ -1465,10 +1517,12 @@ run_cmd(int argc, char *argv[], const char *iff_name)
static int
run_cmd_loop(int argc, char *argv[], const char *iff_name)
{
- int n, i;
+ int n;
+ unsigned int i;
char buf[64];
char *args[8], *s;
+ (void) argc;
args[0] = argv[0];
args[1] = argv[1];
@@ -1481,11 +1535,8 @@ run_cmd_loop(int argc, char *argv[], const char *iff_name)
for (;;) {
fprintf(stdout, "> ");
fflush(stdout);
- n = read(STDIN_FILENO, buf, sizeof(buf));
- if (n > sizeof(buf) - 1) {
- fprintf(stdout, "too much input.\n");
- return (0);
- } else if (n <= 0)
+ n = read(STDIN_FILENO, buf, sizeof(buf) - 1);
+ if (n <= 0)
return (0);
if (buf[--n] != '\n')
diff --git a/usr.sbin/cxgbtool/reg_defs.c b/usr.sbin/cxgbtool/reg_defs.c
index 734061f..687bb75 100644
--- a/usr.sbin/cxgbtool/reg_defs.c
+++ b/usr.sbin/cxgbtool/reg_defs.c
@@ -106,7 +106,7 @@ struct reg_info sge_regs[] = {
{ "Packet_Too_Big", 3, 1 },
{ "Packet_Mismatch", 4, 1 },
{ "SG_RESPACCUTIMER", 0xc0, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info mc3_regs[] = {
@@ -196,7 +196,7 @@ struct reg_info mc3_regs[] = {
{ "MC3_Uncorr_Err", 1, 1 },
{ "MC3_Parity_Err", 2, 8 },
{ "MC3_Addr_Err", 10, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info mc4_regs[] = {
@@ -276,7 +276,7 @@ struct reg_info mc4_regs[] = {
{ "MC4_Corr_Err", 0, 1 },
{ "MC4_Uncorr_Err", 1, 1 },
{ "MC4_Addr_Err", 2, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info tpi_regs[] = {
@@ -290,7 +290,7 @@ struct reg_info tpi_regs[] = {
{ "INT_DIR", 31, 1 },
{ "TPI_PAR", 0x29c, 0 },
{ "TPIPAR", 0, 7 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info tp_regs[] = {
@@ -509,7 +509,7 @@ struct reg_info tp_regs[] = {
{ "DROP_TICKS_CNT", 4, 26 },
{ "NUM_PKTS_DROPPED", 0, 4 },
{ "TP_TX_DROP_COUNT", 0x4bc, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info rat_regs[] = {
@@ -532,7 +532,7 @@ struct reg_info rat_regs[] = {
{ "CspiFramingError", 1, 1 },
{ "SgeFramingError", 2, 1 },
{ "TpFramingError", 3, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info cspi_regs[] = {
@@ -560,7 +560,7 @@ struct reg_info cspi_regs[] = {
{ "TXDrop", 2, 1 },
{ "RXOverflow", 3, 1 },
{ "RAMParityErr", 4, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info espi_regs[] = {
@@ -660,7 +660,7 @@ struct reg_info espi_regs[] = {
{ "Error_Ack", 9, 1 },
{ "Unmapped_Err", 10, 1 },
{ "Transaction_Timer", 16, 8 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info ulp_regs[] = {
@@ -682,7 +682,7 @@ struct reg_info ulp_regs[] = {
{ "Pm_E2C_Wrt_Full", 24, 1 },
{ "Pm_C2E_Wrt_Full", 25, 1 },
{ "ULP_PIO_CTRL", 0x998, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info pl_regs[] = {
@@ -712,7 +712,7 @@ struct reg_info pl_regs[] = {
{ "PL_Intr_CSPI", 9, 1 },
{ "PL_Intr_PCIX", 10, 1 },
{ "PL_Intr_EXT", 11, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info mc5_regs[] = {
@@ -833,5 +833,5 @@ struct reg_info mc5_regs[] = {
{ "MC5_DATA_WRITE_CMD", 0xcf4, 0 },
{ "MC5_DATA_READ_CMD", 0xcf8, 0 },
{ "MC5_MASK_WRITE_CMD", 0xcfc, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
diff --git a/usr.sbin/cxgbtool/reg_defs_t3.c b/usr.sbin/cxgbtool/reg_defs_t3.c
index ffa4aef..6e9b8b1 100644
--- a/usr.sbin/cxgbtool/reg_defs_t3.c
+++ b/usr.sbin/cxgbtool/reg_defs_t3.c
@@ -140,7 +140,7 @@ struct reg_info sge3_regs[] = {
{ "DrbPriThrsh", 0, 16 },
{ "SG_DEBUG_INDEX", 0x78, 0 },
{ "SG_DEBUG_DATA", 0x7c, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info pcix1_regs[] = {
@@ -212,7 +212,7 @@ struct reg_info pcix1_regs[] = {
{ "WakeUp0", 2, 1 },
{ "SleepMode1", 1, 1 },
{ "SleepMode0", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info pcie0_regs[] = {
@@ -411,7 +411,7 @@ struct reg_info pcie0_regs[] = {
{ "BISTDone", 24, 8 },
{ "BISTCycleThresh", 3, 16 },
{ "BISTMode", 0, 3 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3dbg_regs[] = {
@@ -557,7 +557,7 @@ struct reg_info t3dbg_regs[] = {
{ "PMON_CDEL_MANUAL", 4, 1 },
{ "PMON_MANUAL", 1, 1 },
{ "PMON_AUTO", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info mc7_pmrx_regs[] = {
@@ -674,7 +674,7 @@ struct reg_info mc7_pmrx_regs[] = {
{ "PE", 2, 15 },
{ "UE", 1, 1 },
{ "CE", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info mc7_pmtx_regs[] = {
@@ -791,7 +791,7 @@ struct reg_info mc7_pmtx_regs[] = {
{ "PE", 2, 15 },
{ "UE", 1, 1 },
{ "CE", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info mc7_cm_regs[] = {
@@ -908,7 +908,7 @@ struct reg_info mc7_cm_regs[] = {
{ "PE", 2, 15 },
{ "UE", 1, 1 },
{ "CE", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info cim_regs[] = {
@@ -1024,7 +1024,7 @@ struct reg_info cim_regs[] = {
{ "CIM_CDEBUGDATA", 0x2d0, 0 },
{ "CDebugDataH", 16, 16 },
{ "CDebugDataL", 0, 16 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info tp1_regs[] = {
@@ -1384,7 +1384,7 @@ struct reg_info tp1_regs[] = {
{ "TP_EMBED_OP_FIELD3", 0x4f4, 0 },
{ "TP_EMBED_OP_FIELD4", 0x4f8, 0 },
{ "TP_EMBED_OP_FIELD5", 0x4fc, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info ulp2_rx_regs[] = {
@@ -1428,7 +1428,7 @@ struct reg_info ulp2_rx_regs[] = {
{ "ULPRX_RQ_ULIMIT", 0x538, 0 },
{ "ULPRX_PBL_LLIMIT", 0x53c, 0 },
{ "ULPRX_PBL_ULIMIT", 0x540, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info ulp2_tx_regs[] = {
@@ -1456,7 +1456,7 @@ struct reg_info ulp2_tx_regs[] = {
{ "ULPTX_DMA_WEIGHT", 0x5ac, 0 },
{ "D1_WEIGHT", 16, 16 },
{ "D0_WEIGHT", 0, 16 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info pm1_rx_regs[] = {
@@ -1500,7 +1500,7 @@ struct reg_info pm1_rx_regs[] = {
{ "ocspi1_ofifo2x_Tx_framing_error", 6, 1 },
{ "iespi_par_error", 3, 3 },
{ "ocspi_par_error", 0, 3 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info pm1_tx_regs[] = {
@@ -1544,7 +1544,7 @@ struct reg_info pm1_tx_regs[] = {
{ "oespi1_ofifo2x_Tx_framing_error", 6, 1 },
{ "icspi_par_error", 3, 3 },
{ "oespi_par_error", 0, 3 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info mps0_regs[] = {
@@ -1585,7 +1585,7 @@ struct reg_info mps0_regs[] = {
{ "RXTpParErr", 4, 2 },
{ "TX1TpParErr", 2, 2 },
{ "TX0TpParErr", 0, 2 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info cpl_switch_regs[] = {
@@ -1616,7 +1616,7 @@ struct reg_info cpl_switch_regs[] = {
{ "cpl_map_tbl_idx", 0, 8 },
{ "CPL_MAP_TBL_DATA", 0x65c, 0 },
{ "cpl_map_tbl_data", 0, 8 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info smb0_regs[] = {
@@ -1682,7 +1682,7 @@ struct reg_info smb0_regs[] = {
{ "DebugDataL", 0, 16 },
{ "SMB_DEBUG_LA", 0x69c, 0 },
{ "DebugLAReqAddr", 0, 10 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info i2cm0_regs[] = {
@@ -1695,7 +1695,7 @@ struct reg_info i2cm0_regs[] = {
{ "Ack", 30, 1 },
{ "Cont", 1, 1 },
{ "Op", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info mi1_regs[] = {
@@ -1714,7 +1714,7 @@ struct reg_info mi1_regs[] = {
{ "Busy", 31, 1 },
{ "Inc", 2, 1 },
{ "Op", 0, 2 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info jm1_regs[] = {
@@ -1727,7 +1727,7 @@ struct reg_info jm1_regs[] = {
{ "JM_OP", 0x6cc, 0 },
{ "Busy", 31, 1 },
{ "Cnt", 0, 5 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info sf1_regs[] = {
@@ -1737,7 +1737,7 @@ struct reg_info sf1_regs[] = {
{ "Cont", 3, 1 },
{ "ByteCnt", 1, 2 },
{ "Op", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info pl3_regs[] = {
@@ -1839,7 +1839,7 @@ struct reg_info pl3_regs[] = {
{ "PL_REV", 0x6f4, 0 },
{ "Rev", 0, 4 },
{ "PL_CLI", 0x6f8, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info mc5a_regs[] = {
@@ -2010,7 +2010,7 @@ struct reg_info mc5a_regs[] = {
{ "ReadCmd", 0, 20 },
{ "MC5_DB_MASK_WRITE_CMD", 0x7fc, 0 },
{ "MaskWr", 0, 16 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info xgmac0_0_regs[] = {
@@ -2341,7 +2341,7 @@ struct reg_info xgmac0_0_regs[] = {
{ "XGM_RX_SPI4_SOP_EOP_CNT", 0x9ac, 0 },
{ "RxSPI4SopCnt", 16, 16 },
{ "RxSPI4EopCnt", 0, 16 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info xgmac0_1_regs[] = {
@@ -2672,5 +2672,5 @@ struct reg_info xgmac0_1_regs[] = {
{ "XGM_RX_SPI4_SOP_EOP_CNT", 0xbac, 0 },
{ "RxSPI4SopCnt", 16, 16 },
{ "RxSPI4EopCnt", 0, 16 },
- { NULL }
+ { NULL, 0, 0 }
};
diff --git a/usr.sbin/cxgbtool/reg_defs_t3b.c b/usr.sbin/cxgbtool/reg_defs_t3b.c
index 539742c..cd85d84 100644
--- a/usr.sbin/cxgbtool/reg_defs_t3b.c
+++ b/usr.sbin/cxgbtool/reg_defs_t3b.c
@@ -150,7 +150,7 @@ struct reg_info t3b_sge3_regs[] = {
{ "DrbPriThrsh", 0, 16 },
{ "SG_DEBUG_INDEX", 0x78, 0 },
{ "SG_DEBUG_DATA", 0x7c, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_pcix1_regs[] = {
@@ -222,7 +222,7 @@ struct reg_info t3b_pcix1_regs[] = {
{ "WakeUp0", 2, 1 },
{ "SleepMode1", 1, 1 },
{ "SleepMode0", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_pcie0_regs[] = {
@@ -376,7 +376,7 @@ struct reg_info t3b_pcie0_regs[] = {
{ "BeaconDetect", 2, 1 },
{ "RxDetect", 1, 1 },
{ "TxIdleDetect", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_t3dbg_regs[] = {
@@ -557,7 +557,7 @@ struct reg_info t3b_t3dbg_regs[] = {
{ "BSEnLane1", 4, 1 },
{ "BSInSelLane0", 1, 2 },
{ "BSEnLane0", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_mc7_pmrx_regs[] = {
@@ -678,7 +678,7 @@ struct reg_info t3b_mc7_pmrx_regs[] = {
{ "PE", 2, 15 },
{ "UE", 1, 1 },
{ "CE", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_mc7_pmtx_regs[] = {
@@ -799,7 +799,7 @@ struct reg_info t3b_mc7_pmtx_regs[] = {
{ "PE", 2, 15 },
{ "UE", 1, 1 },
{ "CE", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_mc7_cm_regs[] = {
@@ -920,7 +920,7 @@ struct reg_info t3b_mc7_cm_regs[] = {
{ "PE", 2, 15 },
{ "UE", 1, 1 },
{ "CE", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_cim_regs[] = {
@@ -1047,7 +1047,7 @@ struct reg_info t3b_cim_regs[] = {
{ "PILADbgWrPtr", 0, 9 },
{ "CIM_PO_LA_DEBUGDATA", 0x2e8, 0 },
{ "CIM_PI_LA_DEBUGDATA", 0x2ec, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_tp1_regs[] = {
@@ -1453,7 +1453,7 @@ struct reg_info t3b_tp1_regs[] = {
{ "TP_EMBED_OP_FIELD3", 0x4f4, 0 },
{ "TP_EMBED_OP_FIELD4", 0x4f8, 0 },
{ "TP_EMBED_OP_FIELD5", 0x4fc, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_ulp2_rx_regs[] = {
@@ -1497,7 +1497,7 @@ struct reg_info t3b_ulp2_rx_regs[] = {
{ "ULPRX_RQ_ULIMIT", 0x538, 0 },
{ "ULPRX_PBL_LLIMIT", 0x53c, 0 },
{ "ULPRX_PBL_ULIMIT", 0x540, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_ulp2_tx_regs[] = {
@@ -1525,7 +1525,7 @@ struct reg_info t3b_ulp2_tx_regs[] = {
{ "ULPTX_DMA_WEIGHT", 0x5ac, 0 },
{ "D1_WEIGHT", 16, 16 },
{ "D0_WEIGHT", 0, 16 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_pm1_rx_regs[] = {
@@ -1569,7 +1569,7 @@ struct reg_info t3b_pm1_rx_regs[] = {
{ "ocspi1_ofifo2x_Tx_framing_error", 6, 1 },
{ "iespi_par_error", 3, 3 },
{ "ocspi_par_error", 0, 3 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_pm1_tx_regs[] = {
@@ -1613,7 +1613,7 @@ struct reg_info t3b_pm1_tx_regs[] = {
{ "oespi1_ofifo2x_Tx_framing_error", 6, 1 },
{ "icspi_par_error", 3, 3 },
{ "oespi_par_error", 0, 3 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_mps0_regs[] = {
@@ -1655,7 +1655,7 @@ struct reg_info t3b_mps0_regs[] = {
{ "RXTpParErr", 4, 2 },
{ "TX1TpParErr", 2, 2 },
{ "TX0TpParErr", 0, 2 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_cpl_switch_regs[] = {
@@ -1686,7 +1686,7 @@ struct reg_info t3b_cpl_switch_regs[] = {
{ "cpl_map_tbl_idx", 0, 8 },
{ "CPL_MAP_TBL_DATA", 0x65c, 0 },
{ "cpl_map_tbl_data", 0, 8 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_smb0_regs[] = {
@@ -1752,7 +1752,7 @@ struct reg_info t3b_smb0_regs[] = {
{ "DebugDataL", 0, 16 },
{ "SMB_DEBUG_LA", 0x69c, 0 },
{ "DebugLAReqAddr", 0, 10 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_i2cm0_regs[] = {
@@ -1765,7 +1765,7 @@ struct reg_info t3b_i2cm0_regs[] = {
{ "Ack", 30, 1 },
{ "Cont", 1, 1 },
{ "Op", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_mi1_regs[] = {
@@ -1784,7 +1784,7 @@ struct reg_info t3b_mi1_regs[] = {
{ "Busy", 31, 1 },
{ "Inc", 2, 1 },
{ "Op", 0, 2 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_jm1_regs[] = {
@@ -1797,7 +1797,7 @@ struct reg_info t3b_jm1_regs[] = {
{ "JM_OP", 0x6cc, 0 },
{ "Busy", 31, 1 },
{ "Cnt", 0, 5 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_sf1_regs[] = {
@@ -1807,7 +1807,7 @@ struct reg_info t3b_sf1_regs[] = {
{ "Cont", 3, 1 },
{ "ByteCnt", 1, 2 },
{ "Op", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_pl3_regs[] = {
@@ -1917,7 +1917,7 @@ struct reg_info t3b_pl3_regs[] = {
{ "PL_CLI", 0x6f8, 0 },
{ "PL_LCK", 0x6fc, 0 },
{ "Lck", 0, 2 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_mc5a_regs[] = {
@@ -2100,7 +2100,7 @@ struct reg_info t3b_mc5a_regs[] = {
{ "ReadCmd", 0, 20 },
{ "MC5_DB_MASK_WRITE_CMD", 0x7fc, 0 },
{ "MaskWr", 0, 16 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_xgmac0_0_regs[] = {
@@ -2464,7 +2464,7 @@ struct reg_info t3b_xgmac0_0_regs[] = {
{ "XGM_RX_SPI4_SOP_EOP_CNT", 0x9ac, 0 },
{ "RxSPI4SopCnt", 16, 16 },
{ "RxSPI4EopCnt", 0, 16 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3b_xgmac0_1_regs[] = {
@@ -2828,5 +2828,5 @@ struct reg_info t3b_xgmac0_1_regs[] = {
{ "XGM_RX_SPI4_SOP_EOP_CNT", 0xbac, 0 },
{ "RxSPI4SopCnt", 16, 16 },
{ "RxSPI4EopCnt", 0, 16 },
- { NULL }
+ { NULL, 0, 0 }
};
diff --git a/usr.sbin/cxgbtool/reg_defs_t3c.c b/usr.sbin/cxgbtool/reg_defs_t3c.c
index 6127fa4..b9181b6 100644
--- a/usr.sbin/cxgbtool/reg_defs_t3c.c
+++ b/usr.sbin/cxgbtool/reg_defs_t3c.c
@@ -177,7 +177,7 @@ struct reg_info t3c_sge3_regs[] = {
{ "DrbPriThrsh", 0, 16 },
{ "SG_DEBUG_INDEX", 0x78, 0 },
{ "SG_DEBUG_DATA", 0x7c, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_pcix1_regs[] = {
@@ -282,7 +282,7 @@ struct reg_info t3c_pcix1_regs[] = {
{ "IntSt", 4, 3 },
{ "PIOSt", 2, 2 },
{ "RFReqRdSt", 0, 2 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_pcie0_regs[] = {
@@ -475,7 +475,7 @@ struct reg_info t3c_pcie0_regs[] = {
{ "P_WMark", 18, 11 },
{ "NP_WMark", 11, 7 },
{ "CPL_WMark", 0, 11 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_t3dbg_regs[] = {
@@ -656,7 +656,7 @@ struct reg_info t3c_t3dbg_regs[] = {
{ "BSEnLane1", 4, 1 },
{ "BSInSelLane0", 1, 2 },
{ "BSEnLane0", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_mc7_pmrx_regs[] = {
@@ -777,7 +777,7 @@ struct reg_info t3c_mc7_pmrx_regs[] = {
{ "PE", 2, 15 },
{ "UE", 1, 1 },
{ "CE", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_mc7_pmtx_regs[] = {
@@ -898,7 +898,7 @@ struct reg_info t3c_mc7_pmtx_regs[] = {
{ "PE", 2, 15 },
{ "UE", 1, 1 },
{ "CE", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_mc7_cm_regs[] = {
@@ -1019,7 +1019,7 @@ struct reg_info t3c_mc7_cm_regs[] = {
{ "PE", 2, 15 },
{ "UE", 1, 1 },
{ "CE", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_cim_regs[] = {
@@ -1194,7 +1194,7 @@ struct reg_info t3c_cim_regs[] = {
{ "PILADbgWrPtr", 0, 9 },
{ "CIM_PO_LA_DEBUGDATA", 0x2e8, 0 },
{ "CIM_PI_LA_DEBUGDATA", 0x2ec, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_tp1_regs[] = {
@@ -1667,7 +1667,7 @@ struct reg_info t3c_tp1_regs[] = {
{ "TP_EMBED_OP_FIELD3", 0x4f4, 0 },
{ "TP_EMBED_OP_FIELD4", 0x4f8, 0 },
{ "TP_EMBED_OP_FIELD5", 0x4fc, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_ulp2_rx_regs[] = {
@@ -1725,7 +1725,7 @@ struct reg_info t3c_ulp2_rx_regs[] = {
{ "ULPRX_RQ_ULIMIT", 0x538, 0 },
{ "ULPRX_PBL_LLIMIT", 0x53c, 0 },
{ "ULPRX_PBL_ULIMIT", 0x540, 0 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_ulp2_tx_regs[] = {
@@ -1766,7 +1766,7 @@ struct reg_info t3c_ulp2_tx_regs[] = {
{ "ULPTX_DMA_WEIGHT", 0x5ac, 0 },
{ "D1_WEIGHT", 16, 16 },
{ "D0_WEIGHT", 0, 16 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_pm1_rx_regs[] = {
@@ -1810,7 +1810,7 @@ struct reg_info t3c_pm1_rx_regs[] = {
{ "ocspi1_ofifo2x_Tx_framing_error", 6, 1 },
{ "iespi_par_error", 3, 3 },
{ "ocspi_par_error", 0, 3 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_pm1_tx_regs[] = {
@@ -1854,7 +1854,7 @@ struct reg_info t3c_pm1_tx_regs[] = {
{ "oespi1_ofifo2x_Tx_framing_error", 6, 1 },
{ "icspi_par_error", 3, 3 },
{ "oespi_par_error", 0, 3 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_mps0_regs[] = {
@@ -1896,7 +1896,7 @@ struct reg_info t3c_mps0_regs[] = {
{ "RXTpParErr", 4, 2 },
{ "TX1TpParErr", 2, 2 },
{ "TX0TpParErr", 0, 2 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_cpl_switch_regs[] = {
@@ -1930,7 +1930,7 @@ struct reg_info t3c_cpl_switch_regs[] = {
{ "cpl_map_tbl_idx", 0, 8 },
{ "CPL_MAP_TBL_DATA", 0x65c, 0 },
{ "cpl_map_tbl_data", 0, 8 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_smb0_regs[] = {
@@ -1996,7 +1996,7 @@ struct reg_info t3c_smb0_regs[] = {
{ "DebugDataL", 0, 16 },
{ "SMB_DEBUG_LA", 0x69c, 0 },
{ "DebugLAReqAddr", 0, 10 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_i2cm0_regs[] = {
@@ -2009,7 +2009,7 @@ struct reg_info t3c_i2cm0_regs[] = {
{ "Ack", 30, 1 },
{ "Cont", 1, 1 },
{ "Op", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_mi1_regs[] = {
@@ -2028,7 +2028,7 @@ struct reg_info t3c_mi1_regs[] = {
{ "Busy", 31, 1 },
{ "Inc", 2, 1 },
{ "Op", 0, 2 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_jm1_regs[] = {
@@ -2041,7 +2041,7 @@ struct reg_info t3c_jm1_regs[] = {
{ "JM_OP", 0x6cc, 0 },
{ "Busy", 31, 1 },
{ "Cnt", 0, 5 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_sf1_regs[] = {
@@ -2051,7 +2051,7 @@ struct reg_info t3c_sf1_regs[] = {
{ "Cont", 3, 1 },
{ "ByteCnt", 1, 2 },
{ "Op", 0, 1 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_pl3_regs[] = {
@@ -2162,7 +2162,7 @@ struct reg_info t3c_pl3_regs[] = {
{ "PL_CLI", 0x6f8, 0 },
{ "PL_LCK", 0x6fc, 0 },
{ "Lck", 0, 2 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_mc5a_regs[] = {
@@ -2346,7 +2346,7 @@ struct reg_info t3c_mc5a_regs[] = {
{ "ReadCmd", 0, 20 },
{ "MC5_DB_MASK_WRITE_CMD", 0x7fc, 0 },
{ "MaskWr", 0, 16 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_xgmac0_0_regs[] = {
@@ -2730,7 +2730,7 @@ struct reg_info t3c_xgmac0_0_regs[] = {
{ "XGM_RX_SPI4_SOP_EOP_CNT", 0x9ac, 0 },
{ "RxSPI4SopCnt", 16, 16 },
{ "RxSPI4EopCnt", 0, 16 },
- { NULL }
+ { NULL, 0, 0 }
};
struct reg_info t3c_xgmac0_1_regs[] = {
@@ -3114,6 +3114,6 @@ struct reg_info t3c_xgmac0_1_regs[] = {
{ "XGM_RX_SPI4_SOP_EOP_CNT", 0xbac, 0 },
{ "RxSPI4SopCnt", 16, 16 },
{ "RxSPI4EopCnt", 0, 16 },
- { NULL }
+ { NULL, 0, 0 }
};
diff --git a/usr.sbin/fwcontrol/Makefile b/usr.sbin/fwcontrol/Makefile
index 9694d5e..10320d2 100644
--- a/usr.sbin/fwcontrol/Makefile
+++ b/usr.sbin/fwcontrol/Makefile
@@ -3,7 +3,7 @@
PROG= fwcontrol
SRCS= fwcontrol.c fwcrom.c fwdv.c fwmpegts.c
MAN= fwcontrol.8
-WARNS= 3
+WARNS?= 3
.PATH: ${.CURDIR}/../../sys/dev/firewire
diff --git a/usr.sbin/mfiutil/Makefile b/usr.sbin/mfiutil/Makefile
index 03ded03..dbf158d 100644
--- a/usr.sbin/mfiutil/Makefile
+++ b/usr.sbin/mfiutil/Makefile
@@ -8,6 +8,7 @@ MAN8= mfiutil.8
CFLAGS+= -fno-builtin-strftime
WARNS?=3
+DPADD= ${LIBUTIL}
LDADD= -lutil
# Here be dragons
diff --git a/usr.sbin/mptable/mptable.c b/usr.sbin/mptable/mptable.c
index 1ca6dfe..a16a1b9 100644
--- a/usr.sbin/mptable/mptable.c
+++ b/usr.sbin/mptable/mptable.c
@@ -147,7 +147,7 @@ tableEntry basetableEntryTypes[] =
tableEntry extendedtableEntryTypes[] =
{
{ 128, 20, "System Address Space" },
- { 129, 8, "Bus Heirarchy" },
+ { 129, 8, "Bus Hierarchy" },
{ 130, 8, "Compatibility Bus Address" }
};
diff --git a/usr.sbin/mptutil/Makefile b/usr.sbin/mptutil/Makefile
index 4abf66e..53d75b3 100644
--- a/usr.sbin/mptutil/Makefile
+++ b/usr.sbin/mptutil/Makefile
@@ -8,8 +8,8 @@ MAN= mptutil.8
WARNS?= 3
-DPADD+= ${LIBCAM} ${LIBUTIL}
-LDADD+= -lcam -lutil
+DPADD= ${LIBCAM} ${LIBSBUF} ${LIBUTIL}
+LDADD= -lcam -lsbuf -lutil
# Here be dragons
.ifdef DEBUG
diff --git a/usr.sbin/mptutil/mpt_cam.c b/usr.sbin/mptutil/mpt_cam.c
index 0d20c7d..b14451a 100644
--- a/usr.sbin/mptutil/mpt_cam.c
+++ b/usr.sbin/mptutil/mpt_cam.c
@@ -56,15 +56,75 @@ xpt_open(void)
return (xptfd);
}
+/* Fetch the path id of bus 0 for the opened mpt controller. */
+static int
+fetch_path_id(path_id_t *path_id)
+{
+ struct bus_match_pattern *b;
+ union ccb ccb;
+ size_t bufsize;
+
+ if (xpt_open() < 0)
+ return (ENXIO);
+
+ /* First, find the path id of bus 0 for this mpt controller. */
+ bzero(&ccb, sizeof(ccb));
+
+ ccb.ccb_h.func_code = XPT_DEV_MATCH;
+
+ bufsize = sizeof(struct dev_match_result) * 1;
+ ccb.cdm.num_matches = 0;
+ ccb.cdm.match_buf_len = bufsize;
+ ccb.cdm.matches = calloc(1, bufsize);
+
+ bufsize = sizeof(struct dev_match_pattern) * 1;
+ ccb.cdm.num_patterns = 1;
+ ccb.cdm.pattern_buf_len = bufsize;
+ ccb.cdm.patterns = calloc(1, bufsize);
+
+ /* Match mptX bus 0. */
+ ccb.cdm.patterns[0].type = DEV_MATCH_BUS;
+ b = &ccb.cdm.patterns[0].pattern.bus_pattern;
+ snprintf(b->dev_name, sizeof(b->dev_name), "mpt");
+ b->unit_number = mpt_unit;
+ b->bus_id = 0;
+ b->flags = BUS_MATCH_NAME | BUS_MATCH_UNIT | BUS_MATCH_BUS_ID;
+
+ if (ioctl(xptfd, CAMIOCOMMAND, &ccb) < 0) {
+ free(ccb.cdm.matches);
+ free(ccb.cdm.patterns);
+ return (errno);
+ }
+ free(ccb.cdm.patterns);
+
+ if (((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) ||
+ (ccb.cdm.status != CAM_DEV_MATCH_LAST)) {
+ warnx("fetch_path_id got CAM error %#x, CDM error %d\n",
+ ccb.ccb_h.status, ccb.cdm.status);
+ free(ccb.cdm.matches);
+ return (EIO);
+ }
+
+ /* We should have exactly 1 match for the bus. */
+ if (ccb.cdm.num_matches != 1 ||
+ ccb.cdm.matches[0].type != DEV_MATCH_BUS) {
+ free(ccb.cdm.matches);
+ return (ENOENT);
+ }
+ *path_id = ccb.cdm.matches[0].result.bus_result.path_id;
+ free(ccb.cdm.matches);
+ return (0);
+}
+
int
mpt_query_disk(U8 VolumeBus, U8 VolumeID, struct mpt_query_disk *qd)
{
- struct bus_match_pattern *b;
struct periph_match_pattern *p;
struct periph_match_result *r;
union ccb ccb;
+ path_id_t path_id;
size_t bufsize;
- int i;
+ int error, i;
/* mpt(4) only handles devices on bus 0. */
if (VolumeBus != 0)
@@ -73,6 +133,11 @@ mpt_query_disk(U8 VolumeBus, U8 VolumeID, struct mpt_query_disk *qd)
if (xpt_open() < 0)
return (ENXIO);
+ /* Find the path ID of bus 0. */
+ error = fetch_path_id(&path_id);
+ if (error)
+ return (error);
+
bzero(&ccb, sizeof(ccb));
ccb.ccb_h.func_code = XPT_DEV_MATCH;
@@ -85,25 +150,18 @@ mpt_query_disk(U8 VolumeBus, U8 VolumeID, struct mpt_query_disk *qd)
ccb.cdm.match_buf_len = bufsize;
ccb.cdm.matches = calloc(1, bufsize);
- bufsize = sizeof(struct dev_match_pattern) * 2;
- ccb.cdm.num_patterns = 2;
+ bufsize = sizeof(struct dev_match_pattern) * 1;
+ ccb.cdm.num_patterns = 1;
ccb.cdm.pattern_buf_len = bufsize;
ccb.cdm.patterns = calloc(1, bufsize);
- /* Match mptX bus 0. */
- ccb.cdm.patterns[0].type = DEV_MATCH_BUS;
- b = &ccb.cdm.patterns[0].pattern.bus_pattern;
- snprintf(b->dev_name, sizeof(b->dev_name), "mpt");
- b->unit_number = mpt_unit;
- b->bus_id = 0;
- b->flags = BUS_MATCH_NAME | BUS_MATCH_UNIT | BUS_MATCH_BUS_ID;
-
/* Look for a "da" device at the specified target and lun. */
- ccb.cdm.patterns[1].type = DEV_MATCH_PERIPH;
- p = &ccb.cdm.patterns[1].pattern.periph_pattern;
+ ccb.cdm.patterns[0].type = DEV_MATCH_PERIPH;
+ p = &ccb.cdm.patterns[0].pattern.periph_pattern;
+ p->path_id = path_id;
snprintf(p->periph_name, sizeof(p->periph_name), "da");
p->target_id = VolumeID;
- p->flags = PERIPH_MATCH_NAME | PERIPH_MATCH_TARGET;
+ p->flags = PERIPH_MATCH_PATH | PERIPH_MATCH_NAME | PERIPH_MATCH_TARGET;
if (ioctl(xptfd, CAMIOCOMMAND, &ccb) < 0) {
i = errno;
@@ -122,25 +180,22 @@ mpt_query_disk(U8 VolumeBus, U8 VolumeID, struct mpt_query_disk *qd)
}
/*
- * We should have exactly 2 matches, 1 for the bus and 1 for
- * the peripheral. However, if we only have 1 match and it is
- * for the bus, don't print an error message and return
- * ENOENT.
+ * We should have exactly 1 match for the peripheral.
+ * However, if we don't get a match, don't print an error
+ * message and return ENOENT.
*/
- if (ccb.cdm.num_matches == 1 &&
- ccb.cdm.matches[0].type == DEV_MATCH_BUS) {
+ if (ccb.cdm.num_matches == 0) {
free(ccb.cdm.matches);
return (ENOENT);
}
- if (ccb.cdm.num_matches != 2) {
- warnx("mpt_query_disk got %d matches, expected 2",
+ if (ccb.cdm.num_matches != 1) {
+ warnx("mpt_query_disk got %d matches, expected 1",
ccb.cdm.num_matches);
free(ccb.cdm.matches);
return (EIO);
}
- if (ccb.cdm.matches[0].type != DEV_MATCH_BUS ||
- ccb.cdm.matches[1].type != DEV_MATCH_PERIPH) {
- warnx("mpt_query_disk got wrong CAM matches");
+ if (ccb.cdm.matches[0].type != DEV_MATCH_PERIPH) {
+ warnx("mpt_query_disk got wrong CAM match");
free(ccb.cdm.matches);
return (EIO);
}
@@ -336,47 +391,44 @@ mpt_fetch_disks(int fd, int *ndisks, struct mpt_standalone_disk **disksp)
{
CONFIG_PAGE_IOC_2 *ioc2;
struct mpt_standalone_disk *disks;
- struct bus_match_pattern *b;
struct periph_match_pattern *p;
struct periph_match_result *r;
struct cam_device *dev;
union ccb ccb;
+ path_id_t path_id;
size_t bufsize;
u_int i;
- int count;
+ int count, error;
if (xpt_open() < 0)
return (ENXIO);
+ error = fetch_path_id(&path_id);
+ if (error)
+ return (error);
+
for (count = 100;; count+= 100) {
/* Try to fetch 'count' disks in one go. */
bzero(&ccb, sizeof(ccb));
ccb.ccb_h.func_code = XPT_DEV_MATCH;
- bufsize = sizeof(struct dev_match_result) * (count + 2);
+ bufsize = sizeof(struct dev_match_result) * (count + 1);
ccb.cdm.num_matches = 0;
ccb.cdm.match_buf_len = bufsize;
ccb.cdm.matches = calloc(1, bufsize);
- bufsize = sizeof(struct dev_match_pattern) * 2;
- ccb.cdm.num_patterns = 2;
+ bufsize = sizeof(struct dev_match_pattern) * 1;
+ ccb.cdm.num_patterns = 1;
ccb.cdm.pattern_buf_len = bufsize;
ccb.cdm.patterns = calloc(1, bufsize);
- /* Match mptX bus 0. */
- ccb.cdm.patterns[0].type = DEV_MATCH_BUS;
- b = &ccb.cdm.patterns[0].pattern.bus_pattern;
- snprintf(b->dev_name, sizeof(b->dev_name), "mpt");
- b->unit_number = mpt_unit;
- b->bus_id = 0;
- b->flags = BUS_MATCH_NAME | BUS_MATCH_UNIT | BUS_MATCH_BUS_ID;
-
/* Match any "da" peripherals. */
- ccb.cdm.patterns[1].type = DEV_MATCH_PERIPH;
- p = &ccb.cdm.patterns[1].pattern.periph_pattern;
+ ccb.cdm.patterns[0].type = DEV_MATCH_PERIPH;
+ p = &ccb.cdm.patterns[0].pattern.periph_pattern;
+ p->path_id = path_id;
snprintf(p->periph_name, sizeof(p->periph_name), "da");
- p->flags = PERIPH_MATCH_NAME;
+ p->flags = PERIPH_MATCH_PATH | PERIPH_MATCH_NAME;
if (ioctl(xptfd, CAMIOCOMMAND, &ccb) < 0) {
i = errno;
@@ -406,21 +458,16 @@ mpt_fetch_disks(int fd, int *ndisks, struct mpt_standalone_disk **disksp)
break;
}
- /*
- * We should have N + 1 matches, 1 for the bus and 1 for each
- * "da" device.
- */
- if (ccb.cdm.num_matches < 1) {
- warnx("mpt_fetch_disks didn't get any matches");
- free(ccb.cdm.matches);
- return (EIO);
- }
- if (ccb.cdm.matches[0].type != DEV_MATCH_BUS) {
- warnx("mpt_fetch_disks got wrong CAM matches");
+ /* Shortcut if we don't have any "da" devices. */
+ if (ccb.cdm.num_matches == 0) {
free(ccb.cdm.matches);
- return (EIO);
+ *ndisks = 0;
+ *disksp = NULL;
+ return (0);
}
- for (i = 1; i < ccb.cdm.num_matches; i++) {
+
+ /* We should have N matches, 1 for each "da" device. */
+ for (i = 0; i < ccb.cdm.num_matches; i++) {
if (ccb.cdm.matches[i].type != DEV_MATCH_PERIPH) {
warnx("mpt_fetch_disks got wrong CAM matches");
free(ccb.cdm.matches);
@@ -428,14 +475,6 @@ mpt_fetch_disks(int fd, int *ndisks, struct mpt_standalone_disk **disksp)
}
}
- /* Shortcut if we don't have any "da" devices. */
- if (ccb.cdm.num_matches == 1) {
- free(ccb.cdm.matches);
- *ndisks = 0;
- *disksp = NULL;
- return (0);
- }
-
/*
* Some of the "da" peripherals may be for RAID volumes, so
* fetch the IOC 2 page (list of RAID volumes) so we can
@@ -444,7 +483,7 @@ mpt_fetch_disks(int fd, int *ndisks, struct mpt_standalone_disk **disksp)
ioc2 = mpt_read_ioc_page(fd, 2, NULL);
disks = calloc(ccb.cdm.num_matches, sizeof(*disks));
count = 0;
- for (i = 1; i < ccb.cdm.num_matches; i++) {
+ for (i = 0; i < ccb.cdm.num_matches; i++) {
r = &ccb.cdm.matches[i].result.periph_result;
if (periph_is_volume(ioc2, r))
continue;
@@ -480,10 +519,9 @@ mpt_fetch_disks(int fd, int *ndisks, struct mpt_standalone_disk **disksp)
int
mpt_rescan_bus(int bus, int id)
{
- struct bus_match_pattern *b;
union ccb ccb;
path_id_t path_id;
- size_t bufsize;
+ int error;
/* mpt(4) only handles devices on bus 0. */
if (bus != -1 && bus != 0)
@@ -492,54 +530,12 @@ mpt_rescan_bus(int bus, int id)
if (xpt_open() < 0)
return (ENXIO);
- /* First, find the path id of bus 0 for this mpt controller. */
- bzero(&ccb, sizeof(ccb));
-
- ccb.ccb_h.func_code = XPT_DEV_MATCH;
-
- bufsize = sizeof(struct dev_match_result) * 1;
- ccb.cdm.num_matches = 0;
- ccb.cdm.match_buf_len = bufsize;
- ccb.cdm.matches = calloc(1, bufsize);
-
- bufsize = sizeof(struct dev_match_pattern) * 1;
- ccb.cdm.num_patterns = 1;
- ccb.cdm.pattern_buf_len = bufsize;
- ccb.cdm.patterns = calloc(1, bufsize);
-
- /* Match mptX bus 0. */
- ccb.cdm.patterns[0].type = DEV_MATCH_BUS;
- b = &ccb.cdm.patterns[0].pattern.bus_pattern;
- snprintf(b->dev_name, sizeof(b->dev_name), "mpt");
- b->unit_number = mpt_unit;
- b->bus_id = 0;
- b->flags = BUS_MATCH_NAME | BUS_MATCH_UNIT | BUS_MATCH_BUS_ID;
-
- if (ioctl(xptfd, CAMIOCOMMAND, &ccb) < 0) {
- free(ccb.cdm.matches);
- free(ccb.cdm.patterns);
- return (errno);
- }
- free(ccb.cdm.patterns);
-
- if (((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) ||
- (ccb.cdm.status != CAM_DEV_MATCH_LAST)) {
- warnx("mpt_rescan_bus got CAM error %#x, CDM error %d\n",
- ccb.ccb_h.status, ccb.cdm.status);
- free(ccb.cdm.matches);
- return (EIO);
- }
-
- /* We should have exactly 1 match for the bus. */
- if (ccb.cdm.num_matches != 1 ||
- ccb.cdm.matches[0].type != DEV_MATCH_BUS) {
- free(ccb.cdm.matches);
- return (ENOENT);
- }
- path_id = ccb.cdm.matches[0].result.bus_result.path_id;
- free(ccb.cdm.matches);
+ error = fetch_path_id(&path_id);
+ if (error)
+ return (error);
- /* Now perform the actual rescan. */
+ /* Perform the actual rescan. */
+ bzero(&ccb, sizeof(ccb));
ccb.ccb_h.path_id = path_id;
if (id == -1) {
ccb.ccb_h.func_code = XPT_SCAN_BUS;
diff --git a/usr.sbin/mptutil/mpt_show.c b/usr.sbin/mptutil/mpt_show.c
index e0b6b74..5a2a946 100644
--- a/usr.sbin/mptutil/mpt_show.c
+++ b/usr.sbin/mptutil/mpt_show.c
@@ -78,6 +78,7 @@ show_adapter(int ac, char **av)
CONFIG_PAGE_MANUFACTURING_0 *man0;
CONFIG_PAGE_IOC_2 *ioc2;
CONFIG_PAGE_IOC_6 *ioc6;
+ U16 IOCStatus;
int fd, comma;
if (ac != 1) {
@@ -108,7 +109,7 @@ show_adapter(int ac, char **av)
free(man0);
- ioc2 = mpt_read_ioc_page(fd, 2, NULL);
+ ioc2 = mpt_read_ioc_page(fd, 2, &IOCStatus);
if (ioc2 != NULL) {
printf(" RAID Levels:");
comma = 0;
@@ -151,9 +152,11 @@ show_adapter(int ac, char **av)
printf(" none");
printf("\n");
free(ioc2);
- }
+ } else if ((IOCStatus & MPI_IOCSTATUS_MASK) !=
+ MPI_IOCSTATUS_CONFIG_INVALID_PAGE)
+ warnx("mpt_read_ioc_page(2): %s", mpt_ioc_status(IOCStatus));
- ioc6 = mpt_read_ioc_page(fd, 6, NULL);
+ ioc6 = mpt_read_ioc_page(fd, 6, &IOCStatus);
if (ioc6 != NULL) {
display_stripe_map(" RAID0 Stripes",
ioc6->SupportedStripeSizeMapIS);
@@ -172,7 +175,9 @@ show_adapter(int ac, char **av)
printf("-%u", ioc6->MaxDrivesIME);
printf("\n");
free(ioc6);
- }
+ } else if ((IOCStatus & MPI_IOCSTATUS_MASK) !=
+ MPI_IOCSTATUS_CONFIG_INVALID_PAGE)
+ warnx("mpt_read_ioc_page(6): %s", mpt_ioc_status(IOCStatus));
/* TODO: Add an ioctl to fetch IOC_FACTS and print firmware version. */
@@ -541,7 +546,8 @@ show_physdisks(int ac, char **av)
for (i = 0; i <= 0xff; i++) {
pinfo = mpt_pd_info(fd, i, &IOCStatus);
if (pinfo == NULL) {
- if (IOCStatus != MPI_IOCSTATUS_CONFIG_INVALID_PAGE)
+ if ((IOCStatus & MPI_IOCSTATUS_MASK) !=
+ MPI_IOCSTATUS_CONFIG_INVALID_PAGE)
warnx("mpt_pd_info(%d): %s", i,
mpt_ioc_status(IOCStatus));
continue;
diff --git a/usr.sbin/mtree/mtree.5 b/usr.sbin/mtree/mtree.5
index 375cc78..8f17d90 100644
--- a/usr.sbin/mtree/mtree.5
+++ b/usr.sbin/mtree/mtree.5
@@ -33,12 +33,12 @@
.Os
.Sh NAME
.Nm mtree
-.Nd format of mtree dir heirarchy files
+.Nd format of mtree dir hierarchy files
.Sh DESCRIPTION
The
.Nm
format is a textual format that describes a collection of filesystem objects.
-Such files are typically used to create or verify directory heirarchies.
+Such files are typically used to create or verify directory hierarchies.
.Ss General Format
An
.Nm
diff --git a/usr.sbin/pmcstat/Makefile b/usr.sbin/pmcstat/Makefile
index a29b016..c27e56d 100644
--- a/usr.sbin/pmcstat/Makefile
+++ b/usr.sbin/pmcstat/Makefile
@@ -5,7 +5,7 @@
PROG= pmcstat
MAN= pmcstat.8
-DPADD= ${LIBELF} ${LIBKVM} ${LIBPMC} ${LIBM}
+DPADD= ${LIBELF} ${LIBKVM} ${LIBPMC} ${LIBM} ${LIBNCURSES}
LDADD= -lelf -lkvm -lpmc -lm -lncurses
SRCS= pmcstat.c pmcstat.h pmcstat_log.c \
diff --git a/usr.sbin/rtsold/Makefile b/usr.sbin/rtsold/Makefile
index ad4059a..efc322c 100644
--- a/usr.sbin/rtsold/Makefile
+++ b/usr.sbin/rtsold/Makefile
@@ -19,10 +19,8 @@ MAN= rtsold.8
MLINKS= rtsold.8 rtsol.8
SRCS= rtsold.c rtsol.c if.c probe.c dump.c rtsock.c
+WARNS?= 3
CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H
-
-WARNS?= 1
-
DPADD= ${LIBKVM}
LDADD= -lkvm
diff --git a/usr.sbin/rtsold/dump.c b/usr.sbin/rtsold/dump.c
index 62056ae..2756b87 100644
--- a/usr.sbin/rtsold/dump.c
+++ b/usr.sbin/rtsold/dump.c
@@ -52,8 +52,8 @@ static FILE *fp;
extern struct ifinfo *iflist;
static void dump_interface_status(void);
-static char *sec2str(time_t);
-char *ifstatstr[] = {"IDLE", "DELAY", "PROBE", "DOWN", "TENTATIVE"};
+static const char *sec2str(time_t);
+static const char * const ifstatstr[] = {"IDLE", "DELAY", "PROBE", "DOWN", "TENTATIVE"};
static void
dump_interface_status(void)
@@ -97,7 +97,7 @@ dump_interface_status(void)
}
void
-rtsold_dump_file(char *dumpfile)
+rtsold_dump_file(const char *dumpfile)
{
if ((fp = fopen(dumpfile, "w")) == NULL) {
warnmsg(LOG_WARNING, __func__, "open a dump file(%s): %s",
@@ -108,7 +108,7 @@ rtsold_dump_file(char *dumpfile)
fclose(fp);
}
-static char *
+static const char *
sec2str(time_t total)
{
static char result[256];
diff --git a/usr.sbin/rtsold/if.c b/usr.sbin/rtsold/if.c
index e8786ff..c555d2a 100644
--- a/usr.sbin/rtsold/if.c
+++ b/usr.sbin/rtsold/if.c
@@ -82,7 +82,6 @@ interface_up(char *name)
struct in6_ndireq nd;
int llflag;
int s;
- int error;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
diff --git a/usr.sbin/rtsold/rtsock.c b/usr.sbin/rtsold/rtsock.c
index 0de6e85..726c1e6 100644
--- a/usr.sbin/rtsold/rtsock.c
+++ b/usr.sbin/rtsold/rtsock.c
@@ -94,9 +94,9 @@ rtsock_input(int s)
char *lim, *next;
struct rt_msghdr *rtm;
int idx;
- size_t len;
+ ssize_t len;
int ret = 0;
- const size_t lenlim =
+ const ssize_t lenlim =
offsetof(struct rt_msghdr, rtm_msglen) + sizeof(rtm->rtm_msglen);
n = read(s, msg, sizeof(msg));
@@ -135,7 +135,7 @@ rtsock_input(int s)
#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/
static int
-rtsock_input_ifannounce(int s, struct rt_msghdr *rtm, char *lim)
+rtsock_input_ifannounce(int s __unused, struct rt_msghdr *rtm, char *lim)
{
struct if_announcemsghdr *ifan;
struct ifinfo *ifinfo;
diff --git a/usr.sbin/rtsold/rtsol.c b/usr.sbin/rtsold/rtsol.c
index 3420f2f..be2a9b8 100644
--- a/usr.sbin/rtsold/rtsol.c
+++ b/usr.sbin/rtsold/rtsol.c
@@ -72,8 +72,10 @@ static int rcvcmsglen;
int rssock;
-static struct sockaddr_in6 sin6_allrouters =
-{sizeof(sin6_allrouters), AF_INET6};
+static struct sockaddr_in6 sin6_allrouters = {
+ .sin6_len = sizeof(sin6_allrouters),
+ .sin6_family = AF_INET6,
+};
static void call_script(char *, char *);
static int safefile(const char *);
@@ -183,7 +185,7 @@ sendpacket(struct ifinfo *ifinfo)
struct in6_pktinfo *pi;
struct cmsghdr *cm;
int hoplimit = 255;
- int i;
+ ssize_t i;
struct sockaddr_in6 dst;
dst = sin6_allrouters;
@@ -213,7 +215,7 @@ sendpacket(struct ifinfo *ifinfo)
"send RS on %s, whose state is %d",
ifinfo->ifname, ifinfo->state);
i = sendmsg(rssock, &sndmhdr, 0);
- if (i < 0 || i != ifinfo->rs_datalen) {
+ if (i < 0 || (size_t)i != ifinfo->rs_datalen) {
/*
* ENETDOWN is not so serious, especially when using several
* network cards on a mobile node. We ignore it.
@@ -231,7 +233,8 @@ void
rtsol_input(int s)
{
u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
- int ifindex = 0, i, *hlimp = NULL;
+ int ifindex = 0, *hlimp = NULL;
+ ssize_t i;
struct in6_pktinfo *pi = NULL;
struct ifinfo *ifi = NULL;
struct icmp6_hdr *icp;
@@ -272,9 +275,9 @@ rtsol_input(int s)
return;
}
- if (i < sizeof(struct nd_router_advert)) {
+ if ((size_t)i < sizeof(struct nd_router_advert)) {
warnmsg(LOG_INFO, __func__,
- "packet size(%d) is too short", i);
+ "packet size(%zd) is too short", i);
return;
}
diff --git a/usr.sbin/rtsold/rtsold.c b/usr.sbin/rtsold/rtsold.c
index 12c0836..0db050c 100644
--- a/usr.sbin/rtsold/rtsold.c
+++ b/usr.sbin/rtsold/rtsold.c
@@ -91,10 +91,10 @@ int main(int, char **);
static int mobile_node = 0;
#ifndef SMALL
static int do_dump;
-static char *dumpfilename = "/var/run/rtsold.dump"; /* XXX: should be configurable */
+static const char *dumpfilename = "/var/run/rtsold.dump"; /* XXX: should be configurable */
#endif
#if 1
-static char *pidfilename = "/var/run/rtsold.pid"; /* should be configurable */
+static const char *pidfilename = "/var/run/rtsold.pid"; /* should be configurable */
#endif
#if 0
@@ -113,7 +113,8 @@ main(int argc, char **argv)
{
int s, ch, once = 0;
struct timeval *timeout;
- char *argv0, *opts;
+ char *argv0;
+ const char *opts;
#ifdef HAVE_POLL_H
struct pollfd set[2];
#else
@@ -734,7 +735,7 @@ rtsol_timer_update(struct ifinfo *ifinfo)
#ifndef SMALL
static void
-rtsold_set_dump_file(int sig)
+rtsold_set_dump_file(int sig __unused)
{
do_dump = 1;
}
@@ -790,7 +791,7 @@ autoifprobe(void)
static char **argv = NULL;
static int n = 0;
char **a;
- int s, i, found;
+ int s = 0, i, found;
struct ifaddrs *ifap, *ifa, *target;
struct in6_ndireq nd;
diff --git a/usr.sbin/rtsold/rtsold.h b/usr.sbin/rtsold/rtsold.h
index 8a3cfa6..8aef490 100644
--- a/usr.sbin/rtsold/rtsold.h
+++ b/usr.sbin/rtsold/rtsold.h
@@ -97,7 +97,7 @@ extern int probe_init(void);
extern void defrouter_probe(struct ifinfo *);
/* dump.c */
-extern void rtsold_dump_file(char *);
+extern void rtsold_dump_file(const char *);
/* rtsock.c */
extern int rtsock_open(void);
diff --git a/usr.sbin/sysinstall/devices.c b/usr.sbin/sysinstall/devices.c
index b95fdc5..a2b7939 100644
--- a/usr.sbin/sysinstall/devices.c
+++ b/usr.sbin/sysinstall/devices.c
@@ -105,6 +105,7 @@ static struct _devname {
NETWORK("bfe", "Broadcom BCM440x PCI Ethernet card"),
NETWORK("bge", "Broadcom BCM570x PCI Gigabit Ethernet card"),
NETWORK("bm", "Apple BMAC Built-in Ethernet"),
+ NETWORK("bwn", "Broadcom BCM43xx IEEE 802.11 wireless adapter"),
NETWORK("cas", "Sun Cassini/Cassini+ or NS DP83065 Saturn Ethernet"),
NETWORK("cue", "CATC USB Ethernet adapter"),
NETWORK("cxgb", "Chelsio T3 10Gb Ethernet card"),
diff --git a/usr.sbin/uhsoctl/Makefile b/usr.sbin/uhsoctl/Makefile
index 9704923..565b2e6 100644
--- a/usr.sbin/uhsoctl/Makefile
+++ b/usr.sbin/uhsoctl/Makefile
@@ -2,7 +2,7 @@
PROG= uhsoctl
MAN= uhsoctl.1
-WARNS= 1
+WARNS?= 1
DPADD= ${LIBUTIL}
LDADD= -lutil
diff --git a/usr.sbin/zic/zdump/Makefile b/usr.sbin/zic/zdump/Makefile
index 7ee8db3..d654dee 100644
--- a/usr.sbin/zic/zdump/Makefile
+++ b/usr.sbin/zic/zdump/Makefile
@@ -1,6 +1,6 @@
# $FreeBSD$
-.PATH: ${.CURDIR}/..
+.PATH: ${.CURDIR}/../../../contrib/tzcode/zic
PROG= zdump
MAN= zdump.8
@@ -8,7 +8,7 @@ SRCS= zdump.c ialloc.c scheck.c
CFLAGS+= -DTM_GMTOFF=tm_gmtoff -DTM_ZONE=tm_zone -DSTD_INSPIRED -DPCTS
CFLAGS+= -DHAVE_LONG_DOUBLE -DTZDIR=\"/usr/share/zoneinfo\" -Demkdir=mkdir
-CFLAGS+= -I${.CURDIR}/.. -I${.CURDIR}/../../../lib/libc/stdtime
+CFLAGS+= -I${.CURDIR}/.. -I${.CURDIR}/../../../contrib/tzcode/stdtime
WARNS?= 2
diff --git a/usr.sbin/zic/zic/Makefile b/usr.sbin/zic/zic/Makefile
index 02dc6e2..f473da5 100644
--- a/usr.sbin/zic/zic/Makefile
+++ b/usr.sbin/zic/zic/Makefile
@@ -1,6 +1,6 @@
# $FreeBSD$
-.PATH: ${.CURDIR}/..
+.PATH: ${.CURDIR}/../../../contrib/tzcode/zic
PROG= zic
MAN= zic.8
@@ -9,7 +9,7 @@ SRCS= zic.c ialloc.c scheck.c
CFLAGS+= -DTM_GMTOFF=tm_gmtoff -DTM_ZONE=tm_zone -DSTD_INSPIRED -DPCTS
CFLAGS+= -DHAVE_LONG_DOUBLE -DTZDIR=\"/usr/share/zoneinfo\" -Demkdir=mkdir
CFLAGS+= -DHAVE_STRERROR -DHAVE_UNISTD_H
-CFLAGS+= -I${.CURDIR}/.. -I${.CURDIR}/../../../lib/libc/stdtime
+CFLAGS+= -I${.CURDIR}/.. -I${.CURDIR}/../../../contrib/tzcode/stdtime
WARNS?= 2
OpenPOWER on IntegriCloud