Browse Source

Plan 9 from Bell Labs 2004-09-09

David du Colombier 19 years ago
parent
commit
e31c892300

+ 28 - 27
dist/replica/_plan9.db

@@ -1,8 +1,8 @@
 386 - 20000000775 sys sys 1010957353 0
-386/9load - 775 sys sys 1088798345 188040
-386/9loaddebug - 775 sys sys 1091156989 270242
-386/9loadlite - 775 sys sys 1088798346 125004
-386/9loadlitedebug - 775 sys sys 1089402462 183654
+386/9load - 775 sys sys 1094674490 206624
+386/9loaddebug - 775 sys sys 1094674492 297770
+386/9loadlite - 775 sys sys 1094674491 130360
+386/9loadlitedebug - 775 sys sys 1094674492 192921
 386/9pc - 775 sys sys 1092110936 1817018
 386/9pc.gz - 664 sys sys 1077049336 635727
 386/9pccpu - 775 sys sys 1092110939 1473170
@@ -11,7 +11,7 @@
 386/9pcdisk.gz - 664 sys sys 1040006345 703136
 386/9pcf - 775 sys sys 1092110948 2351243
 386/9pcf.gz - 664 sys sys 1077049490 872650
-386/9pxeload - 775 sys sys 1088798346 188040
+386/9pxeload - 775 sys sys 1094674490 206624
 386/_9pcdisk.gz - 664 sys sys 1039764191 695837
 386/bin - 20000000775 sys sys 1018897690 0
 386/bin/8a - 775 sys sys 1089397305 112804
@@ -396,7 +396,7 @@
 386/bin/swap - 775 sys sys 1085077102 60111
 386/bin/syscall - 775 sys sys 1091849700 71497
 386/bin/tail - 775 sys sys 1085077102 63945
-386/bin/tar - 775 sys sys 1085077102 81780
+386/bin/tar - 775 sys sys 1094612761 81786
 386/bin/tbl - 775 sys sys 1085077103 111047
 386/bin/tcs - 775 sys sys 1085077103 256506
 386/bin/tee - 775 sys sys 1085077104 38401
@@ -503,7 +503,7 @@
 386/include/u.h - 664 sys sys 1042604326 1450
 386/include/ureg.h - 664 sys sys 944946012 523
 386/init - 775 sys sys 1085077133 98033
-386/ld.com - 775 sys sys 1088798347 64480
+386/ld.com - 775 sys sys 1094674493 69772
 386/lib - 20000000775 sys sys 1016826328 0
 386/lib/ape - 20000000775 sys sys 944969312 0
 386/lib/ape/lib9.a - 664 sys sys 1038237538 6378
@@ -5042,7 +5042,7 @@ sys/man/7/map - 664 sys sys 1032632790 13549
 sys/man/7/scat - 664 sys sys 970069855 8904
 sys/man/8 - 20000000775 sys sys 1018384448 0
 sys/man/8/0intro - 664 sys sys 944959679 247
-sys/man/8/9load - 664 sys sys 1056073409 8555
+sys/man/8/9load - 664 sys sys 1094676489 9170
 sys/man/8/9pcon - 664 sys sys 1018973955 2226
 sys/man/8/INDEX - 664 sys sys 1089339723 2669
 sys/man/8/INDEX.html - 664 sys sys 1089321186 7944
@@ -5079,7 +5079,7 @@ sys/man/8/nfsserver - 664 sys sys 1017251291 3397
 sys/man/8/pcmcia - 664 sys sys 944959679 408
 sys/man/8/pem - 664 sys sys 1060263669 1189
 sys/man/8/ping - 664 sys sys 1084473185 3436
-sys/man/8/plan9.ini - 664 sys sys 1092082105 20930
+sys/man/8/plan9.ini - 664 sys sys 1094650551 20806
 sys/man/8/pop3 - 664 sys sys 1063854676 2720
 sys/man/8/ppp - 664 sys sys 1050361032 4424
 sys/man/8/prep - 664 sys sys 1079705872 13820
@@ -6449,24 +6449,23 @@ sys/src/boot/pc/apm.c - 664 sys sys 1015007947 289
 sys/src/boot/pc/bcom.c - 664 sys sys 1032215919 6421
 sys/src/boot/pc/boot.c - 664 sys sys 1021579983 3353
 sys/src/boot/pc/bootld.c - 664 sys sys 1015007948 1801
-sys/src/boot/pc/bootp.c - 664 sys sys 1015007948 9417
+sys/src/boot/pc/bootp.c - 664 sys sys 1094674486 12069
 sys/src/boot/pc/cga.c - 664 sys sys 1015007948 1362
 sys/src/boot/pc/clock.c - 664 sys sys 1088089722 5783
-sys/src/boot/pc/conf.c - 664 sys sys 1063855536 10128
-sys/src/boot/pc/console.c - 664 sys sys 1068158999 3487
-sys/src/boot/pc/dat.h - 664 sys sys 1056073257 3432
+sys/src/boot/pc/conf.c - 664 sys sys 1094674484 10217
+sys/src/boot/pc/console.c - 664 sys sys 1094674483 3388
+sys/src/boot/pc/dat.h - 664 sys sys 1094674488 3518
 sys/src/boot/pc/devfloppy.c - 664 sys sys 1032215913 15505
 sys/src/boot/pc/devfloppy.h - 664 sys sys 1032409559 4081
 sys/src/boot/pc/devi82365.c - 664 sys sys 1019533020 23202
 sys/src/boot/pc/devpccard.c - 664 sys sys 1019533020 41357
 sys/src/boot/pc/devsd.c - 664 sys sys 1077033681 11262
 sys/src/boot/pc/dma.c - 664 sys sys 1015007949 4972
-sys/src/boot/pc/donprint.c - 664 sys sys 1019240172 4212
 sys/src/boot/pc/dosboot.c - 664 sys sys 1088798342 11096
 sys/src/boot/pc/dosfs.h - 664 sys sys 1032215924 1467
 sys/src/boot/pc/eoffs - 664 sys sys 1015007950 0
 sys/src/boot/pc/error.h - 664 sys sys 1015007950 3081
-sys/src/boot/pc/ether.c - 664 sys sys 1071175087 4727
+sys/src/boot/pc/ether.c - 664 sys sys 1094674486 5055
 sys/src/boot/pc/ether2000.c - 664 sys sys 1015007950 2609
 sys/src/boot/pc/ether2114x.c - 664 sys sys 1066618033 37048
 sys/src/boot/pc/ether589.c - 664 sys sys 1015007950 4628
@@ -6481,27 +6480,28 @@ sys/src/boot/pc/etherec2t.c - 664 sys sys 1015007951 3598
 sys/src/boot/pc/etherelnk3.c - 664 sys sys 1034454878 44068
 sys/src/boot/pc/etherelnk3x.c - 664 sys sys 1015007951 24989
 sys/src/boot/pc/etherif.h - 664 sys sys 1015007951 1285
+sys/src/boot/pc/etherigbe.c - 664 sys sys 1094674487 39270
 sys/src/boot/pc/ethermii.c - 664 sys sys 1071175087 4493
 sys/src/boot/pc/ethermii.h - 664 sys sys 1071175087 3259
 sys/src/boot/pc/etherrhine.c - 664 sys sys 1071175087 12403
-sys/src/boot/pc/fns.h - 664 sys sys 1032215922 4081
-sys/src/boot/pc/fs.c - 664 sys sys 1032215914 1487
-sys/src/boot/pc/fs.h - 664 sys sys 1032215924 627
+sys/src/boot/pc/fns.h - 664 sys sys 1094674488 4146
+sys/src/boot/pc/fs.c - 664 sys sys 1094674483 1509
+sys/src/boot/pc/fs.h - 664 sys sys 1094674488 653
 sys/src/boot/pc/ilock.c - 664 sys sys 1015007952 303
 sys/src/boot/pc/inflate.c - 664 sys sys 1021579984 2802
 sys/src/boot/pc/io.h - 664 sys sys 1015007952 5420
-sys/src/boot/pc/ip.h - 664 sys sys 1089814405 2435
+sys/src/boot/pc/ip.h - 664 sys sys 1094674489 2461
 sys/src/boot/pc/kbd.c - 664 sys sys 1015007952 10188
 sys/src/boot/pc/kfs.h - 664 sys sys 1032215924 861
 sys/src/boot/pc/kfsboot.c - 664 sys sys 1032215914 4788
-sys/src/boot/pc/l.s - 664 sys sys 1063855535 13012
-sys/src/boot/pc/lib.h - 664 sys sys 1088798344 2089
-sys/src/boot/pc/load.c - 664 sys sys 1088798343 8358
+sys/src/boot/pc/l.s - 664 sys sys 1094674488 13107
+sys/src/boot/pc/lib.h - 664 sys sys 1094674487 2794
+sys/src/boot/pc/load.c - 664 sys sys 1094674484 8635
 sys/src/boot/pc/mbr.s - 664 sys sys 1015007953 6234
 sys/src/boot/pc/mem.h - 664 sys sys 1015007953 3407
 sys/src/boot/pc/memory.c - 664 sys sys 1019533021 10272
-sys/src/boot/pc/mkfile - 664 sys sys 1077739195 3063
-sys/src/boot/pc/noether.c - 664 sys sys 1018553453 300
+sys/src/boot/pc/mkfile - 664 sys sys 1094674483 3088
+sys/src/boot/pc/noether.c - 664 sys sys 1094674488 358
 sys/src/boot/pc/part.c - 664 sys sys 1032215918 7505
 sys/src/boot/pc/pbs.s - 664 sys sys 1017854325 8279
 sys/src/boot/pc/pbsdisk - 775 sys sys 1017854325 509
@@ -6510,11 +6510,12 @@ sys/src/boot/pc/pbsdisklba - 775 sys sys 1015007954 509
 sys/src/boot/pc/pbsdisklba.s - 664 sys sys 1015007954 6022
 sys/src/boot/pc/pbslba.s - 664 sys sys 1017854326 8147
 sys/src/boot/pc/pci.c - 664 sys sys 1065815736 17580
+sys/src/boot/pc/print.c - 664 sys sys 1094674483 219
 sys/src/boot/pc/queue.c - 664 sys sys 1015007954 566
-sys/src/boot/pc/sd.h - 664 sys sys 1032215925 2404
+sys/src/boot/pc/sd.h - 664 sys sys 1094674489 2271
 sys/src/boot/pc/sd53c8xx.c - 664 sys sys 1077033951 52135
 sys/src/boot/pc/sd53c8xx.i - 664 sys sys 1015007955 27245
-sys/src/boot/pc/sdata.c - 664 sys sys 1071615664 35424
+sys/src/boot/pc/sdata.c - 664 sys sys 1094674485 35425
 sys/src/boot/pc/sdmylex.c - 664 sys sys 1015007955 28743
 sys/src/boot/pc/sdscsi.c - 664 sys sys 1077033682 7022
 sys/src/boot/pc/trap.c - 664 sys sys 1018462833 7098
@@ -12337,4 +12338,4 @@ usr/glenda/lib/profile - 664 glenda glenda 1021580005 847
 usr/glenda/readme.acme - 664 glenda glenda 1019860628 4753
 usr/glenda/readme.rio - 664 glenda glenda 1019860628 6370
 usr/glenda/tmp - 20000000775 glenda glenda 1018802620 0
-386/bin/tar - 775 sys sys 1094612761 81786
+sys/src/boot/pc/mkfile - 664 sys sys 1094700526 3090

+ 26 - 25
dist/replica/plan9.db

@@ -1,8 +1,8 @@
 386 - 20000000775 sys sys 1010957353 0
-386/9load - 775 sys sys 1088798345 188040
-386/9loaddebug - 775 sys sys 1091156989 270242
-386/9loadlite - 775 sys sys 1088798346 125004
-386/9loadlitedebug - 775 sys sys 1089402462 183654
+386/9load - 775 sys sys 1094674490 206624
+386/9loaddebug - 775 sys sys 1094674492 297770
+386/9loadlite - 775 sys sys 1094674491 130360
+386/9loadlitedebug - 775 sys sys 1094674492 192921
 386/9pc - 775 sys sys 1092110936 1817018
 386/9pc.gz - 664 sys sys 1077049336 635727
 386/9pccpu - 775 sys sys 1092110939 1473170
@@ -11,7 +11,7 @@
 386/9pcdisk.gz - 664 sys sys 1040006345 703136
 386/9pcf - 775 sys sys 1092110948 2351243
 386/9pcf.gz - 664 sys sys 1077049490 872650
-386/9pxeload - 775 sys sys 1088798346 188040
+386/9pxeload - 775 sys sys 1094674490 206624
 386/_9pcdisk.gz - 664 sys sys 1039764191 695837
 386/bin - 20000000775 sys sys 1018897690 0
 386/bin/8a - 775 sys sys 1089397305 112804
@@ -503,7 +503,7 @@
 386/include/u.h - 664 sys sys 1042604326 1450
 386/include/ureg.h - 664 sys sys 944946012 523
 386/init - 775 sys sys 1085077133 98033
-386/ld.com - 775 sys sys 1088798347 64480
+386/ld.com - 775 sys sys 1094674493 69772
 386/lib - 20000000775 sys sys 1016826328 0
 386/lib/ape - 20000000775 sys sys 944969312 0
 386/lib/ape/lib9.a - 664 sys sys 1038237538 6378
@@ -5042,7 +5042,7 @@ sys/man/7/map - 664 sys sys 1032632790 13549
 sys/man/7/scat - 664 sys sys 970069855 8904
 sys/man/8 - 20000000775 sys sys 1018384448 0
 sys/man/8/0intro - 664 sys sys 944959679 247
-sys/man/8/9load - 664 sys sys 1056073409 8555
+sys/man/8/9load - 664 sys sys 1094676489 9170
 sys/man/8/9pcon - 664 sys sys 1018973955 2226
 sys/man/8/INDEX - 664 sys sys 1089339723 2669
 sys/man/8/INDEX.html - 664 sys sys 1089321186 7944
@@ -5079,7 +5079,7 @@ sys/man/8/nfsserver - 664 sys sys 1017251291 3397
 sys/man/8/pcmcia - 664 sys sys 944959679 408
 sys/man/8/pem - 664 sys sys 1060263669 1189
 sys/man/8/ping - 664 sys sys 1084473185 3436
-sys/man/8/plan9.ini - 664 sys sys 1092082105 20930
+sys/man/8/plan9.ini - 664 sys sys 1094650551 20806
 sys/man/8/pop3 - 664 sys sys 1063854676 2720
 sys/man/8/ppp - 664 sys sys 1050361032 4424
 sys/man/8/prep - 664 sys sys 1079705872 13820
@@ -6449,24 +6449,23 @@ sys/src/boot/pc/apm.c - 664 sys sys 1015007947 289
 sys/src/boot/pc/bcom.c - 664 sys sys 1032215919 6421
 sys/src/boot/pc/boot.c - 664 sys sys 1021579983 3353
 sys/src/boot/pc/bootld.c - 664 sys sys 1015007948 1801
-sys/src/boot/pc/bootp.c - 664 sys sys 1015007948 9417
+sys/src/boot/pc/bootp.c - 664 sys sys 1094674486 12069
 sys/src/boot/pc/cga.c - 664 sys sys 1015007948 1362
 sys/src/boot/pc/clock.c - 664 sys sys 1088089722 5783
-sys/src/boot/pc/conf.c - 664 sys sys 1063855536 10128
-sys/src/boot/pc/console.c - 664 sys sys 1068158999 3487
-sys/src/boot/pc/dat.h - 664 sys sys 1056073257 3432
+sys/src/boot/pc/conf.c - 664 sys sys 1094674484 10217
+sys/src/boot/pc/console.c - 664 sys sys 1094674483 3388
+sys/src/boot/pc/dat.h - 664 sys sys 1094674488 3518
 sys/src/boot/pc/devfloppy.c - 664 sys sys 1032215913 15505
 sys/src/boot/pc/devfloppy.h - 664 sys sys 1032409559 4081
 sys/src/boot/pc/devi82365.c - 664 sys sys 1019533020 23202
 sys/src/boot/pc/devpccard.c - 664 sys sys 1019533020 41357
 sys/src/boot/pc/devsd.c - 664 sys sys 1077033681 11262
 sys/src/boot/pc/dma.c - 664 sys sys 1015007949 4972
-sys/src/boot/pc/donprint.c - 664 sys sys 1019240172 4212
 sys/src/boot/pc/dosboot.c - 664 sys sys 1088798342 11096
 sys/src/boot/pc/dosfs.h - 664 sys sys 1032215924 1467
 sys/src/boot/pc/eoffs - 664 sys sys 1015007950 0
 sys/src/boot/pc/error.h - 664 sys sys 1015007950 3081
-sys/src/boot/pc/ether.c - 664 sys sys 1071175087 4727
+sys/src/boot/pc/ether.c - 664 sys sys 1094674486 5055
 sys/src/boot/pc/ether2000.c - 664 sys sys 1015007950 2609
 sys/src/boot/pc/ether2114x.c - 664 sys sys 1066618033 37048
 sys/src/boot/pc/ether589.c - 664 sys sys 1015007950 4628
@@ -6481,27 +6480,28 @@ sys/src/boot/pc/etherec2t.c - 664 sys sys 1015007951 3598
 sys/src/boot/pc/etherelnk3.c - 664 sys sys 1034454878 44068
 sys/src/boot/pc/etherelnk3x.c - 664 sys sys 1015007951 24989
 sys/src/boot/pc/etherif.h - 664 sys sys 1015007951 1285
+sys/src/boot/pc/etherigbe.c - 664 sys sys 1094674487 39270
 sys/src/boot/pc/ethermii.c - 664 sys sys 1071175087 4493
 sys/src/boot/pc/ethermii.h - 664 sys sys 1071175087 3259
 sys/src/boot/pc/etherrhine.c - 664 sys sys 1071175087 12403
-sys/src/boot/pc/fns.h - 664 sys sys 1032215922 4081
-sys/src/boot/pc/fs.c - 664 sys sys 1032215914 1487
-sys/src/boot/pc/fs.h - 664 sys sys 1032215924 627
+sys/src/boot/pc/fns.h - 664 sys sys 1094674488 4146
+sys/src/boot/pc/fs.c - 664 sys sys 1094674483 1509
+sys/src/boot/pc/fs.h - 664 sys sys 1094674488 653
 sys/src/boot/pc/ilock.c - 664 sys sys 1015007952 303
 sys/src/boot/pc/inflate.c - 664 sys sys 1021579984 2802
 sys/src/boot/pc/io.h - 664 sys sys 1015007952 5420
-sys/src/boot/pc/ip.h - 664 sys sys 1089814405 2435
+sys/src/boot/pc/ip.h - 664 sys sys 1094674489 2461
 sys/src/boot/pc/kbd.c - 664 sys sys 1015007952 10188
 sys/src/boot/pc/kfs.h - 664 sys sys 1032215924 861
 sys/src/boot/pc/kfsboot.c - 664 sys sys 1032215914 4788
-sys/src/boot/pc/l.s - 664 sys sys 1063855535 13012
-sys/src/boot/pc/lib.h - 664 sys sys 1088798344 2089
-sys/src/boot/pc/load.c - 664 sys sys 1088798343 8358
+sys/src/boot/pc/l.s - 664 sys sys 1094674488 13107
+sys/src/boot/pc/lib.h - 664 sys sys 1094674487 2794
+sys/src/boot/pc/load.c - 664 sys sys 1094674484 8635
 sys/src/boot/pc/mbr.s - 664 sys sys 1015007953 6234
 sys/src/boot/pc/mem.h - 664 sys sys 1015007953 3407
 sys/src/boot/pc/memory.c - 664 sys sys 1019533021 10272
-sys/src/boot/pc/mkfile - 664 sys sys 1077739195 3063
-sys/src/boot/pc/noether.c - 664 sys sys 1018553453 300
+sys/src/boot/pc/mkfile - 664 sys sys 1094700526 3090
+sys/src/boot/pc/noether.c - 664 sys sys 1094674488 358
 sys/src/boot/pc/part.c - 664 sys sys 1032215918 7505
 sys/src/boot/pc/pbs.s - 664 sys sys 1017854325 8279
 sys/src/boot/pc/pbsdisk - 775 sys sys 1017854325 509
@@ -6510,11 +6510,12 @@ sys/src/boot/pc/pbsdisklba - 775 sys sys 1015007954 509
 sys/src/boot/pc/pbsdisklba.s - 664 sys sys 1015007954 6022
 sys/src/boot/pc/pbslba.s - 664 sys sys 1017854326 8147
 sys/src/boot/pc/pci.c - 664 sys sys 1065815736 17580
+sys/src/boot/pc/print.c - 664 sys sys 1094674483 219
 sys/src/boot/pc/queue.c - 664 sys sys 1015007954 566
-sys/src/boot/pc/sd.h - 664 sys sys 1032215925 2404
+sys/src/boot/pc/sd.h - 664 sys sys 1094674489 2271
 sys/src/boot/pc/sd53c8xx.c - 664 sys sys 1077033951 52135
 sys/src/boot/pc/sd53c8xx.i - 664 sys sys 1015007955 27245
-sys/src/boot/pc/sdata.c - 664 sys sys 1071615664 35424
+sys/src/boot/pc/sdata.c - 664 sys sys 1094674485 35425
 sys/src/boot/pc/sdmylex.c - 664 sys sys 1015007955 28743
 sys/src/boot/pc/sdscsi.c - 664 sys sys 1077033682 7022
 sys/src/boot/pc/trap.c - 664 sys sys 1018462833 7098

+ 28 - 0
dist/replica/plan9.log

@@ -16659,3 +16659,31 @@
 1094571023 0 c sys/games/lib/fortunes - 664 sys sys 1094570700 249644
 1094599829 0 c sys/src/cmd/tar.c - 664 sys sys 1094598836 15585
 1094614232 0 c 386/bin/tar - 775 sys sys 1094612761 81786
+1094652039 0 c sys/man/8/plan9.ini - 664 sys sys 1094650551 20806
+1094675442 0 c 386/9load - 775 sys sys 1094674490 206624
+1094675442 1 c 386/9loaddebug - 775 sys sys 1094674492 297770
+1094675442 2 c 386/9loadlite - 775 sys sys 1094674491 130360
+1094675442 3 c 386/9loadlitedebug - 775 sys sys 1094674492 192921
+1094675442 4 c 386/9pxeload - 775 sys sys 1094674490 206624
+1094675442 5 c 386/ld.com - 775 sys sys 1094674493 69772
+1094675442 6 c sys/src/boot/pc/bootp.c - 664 sys sys 1094674486 12069
+1094675442 7 c sys/src/boot/pc/conf.c - 664 sys sys 1094674484 10217
+1094675442 8 c sys/src/boot/pc/console.c - 664 sys sys 1094674483 3388
+1094675442 9 c sys/src/boot/pc/dat.h - 664 sys sys 1094674488 3518
+1094675442 10 c sys/src/boot/pc/ether.c - 664 sys sys 1094674486 5055
+1094675442 11 a sys/src/boot/pc/etherigbe.c - 664 sys sys 1094674487 39270
+1094675442 12 c sys/src/boot/pc/fns.h - 664 sys sys 1094674488 4146
+1094675442 13 c sys/src/boot/pc/fs.c - 664 sys sys 1094674483 1509
+1094675442 14 c sys/src/boot/pc/fs.h - 664 sys sys 1094674488 653
+1094675442 15 c sys/src/boot/pc/ip.h - 664 sys sys 1094674489 2461
+1094675442 16 c sys/src/boot/pc/l.s - 664 sys sys 1094674488 13107
+1094675442 17 c sys/src/boot/pc/lib.h - 664 sys sys 1094674487 2794
+1094675442 18 c sys/src/boot/pc/load.c - 664 sys sys 1094674484 8635
+1094675442 19 c sys/src/boot/pc/mkfile - 664 sys sys 1094674483 3088
+1094675442 20 c sys/src/boot/pc/noether.c - 664 sys sys 1094674488 358
+1094675442 21 a sys/src/boot/pc/print.c - 664 sys sys 1094674483 219
+1094675442 22 c sys/src/boot/pc/sd.h - 664 sys sys 1094674489 2271
+1094675442 23 c sys/src/boot/pc/sdata.c - 664 sys sys 1094674485 35425
+1094675442 24 d sys/src/boot/pc/donprint.c - 664 sys sys 1019240172 0
+1094677243 0 c sys/man/8/9load - 664 sys sys 1094676489 9170
+1094700648 0 c sys/src/boot/pc/mkfile - 664 sys sys 1094700526 3090

+ 24 - 0
sys/man/8/9load

@@ -383,6 +383,22 @@ the disk.
 See 
 .IR dossrv (4)
 for information on ensuring this.
+.PP
+.I 9pxeload
+differs slightly in operation from
+.IR 9load .
+It is initially loaded by the PXE BIOS at physical address 0x7C00.
+Only devices which can be automatically configured,
+e.g. most PCI ethernet adapters,
+will be recognised.
+If the file
+.IB /cfg/pxe/ XXXXXXXXXXXX
+can be located via a DHCP server,
+where
+.B XXXXXXXXXXXX
+is the MAC address of a recognised ethernet adapter,
+the contents are obtained and used as a
+.IR plan9.ini .
 .SH FILES
 .RI [ drive :]
 [
@@ -415,3 +431,11 @@ it attempts to de-install it, but the technique
 used may not always work.
 It is safer not to install the Extended Memory Manager before running
 .IR ld .
+.PP
+The way
+.I 9pxeload
+obtains the information normally found in a disc
+.I plan9.ini
+file,
+and thereby the kernel to load and boot,
+is not ideal and may change in the future.

+ 3 - 6
sys/man/8/plan9.ini

@@ -315,12 +315,9 @@ attribute.
 .B rtl8139
 The Realtek 8139.
 .TP
-.B 82543gc
-The Intel RS-82543GC gigabit ethernet controller,
-as found on the Intel PRO/1000[FT] server adapter.
-The older non-[FT] cards based on the 82542 (LSI L2A1157)
-chip are not supported, although support would probably be
-easy to add.
+.B igbe
+The Intel 8254X Gigabit Ethernet controllers,
+as found on the Intel PRO/1000 adapters for copper (not fiber).
 .TP
 .B smc91cxx
 SMC 91cXX chip-based PCMCIA adapters, notably the SMC EtherEZ card.

+ 177 - 27
sys/src/boot/pc/bootp.c

@@ -143,14 +143,30 @@ printea(uchar *ea)
 		ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]);
 }
 
+enum {
+	/* this is only true of IPv4, but we're not doing v6 yet */
+	Min_udp_payload = ETHERMINTU - ETHERHDRSIZE - UDP_HDRSIZE,
+};
+
 static void
 udpsend(int ctlrno, Netaddr *a, void *data, int dlen)
 {
+	char payload[ETHERMAXTU];
 	Udphdr *uh;
 	Etherhdr *ip;
 	Etherpkt pkt;
 	int len, ptcllen;
 
+	/*
+	 * if packet is too short, make it longer rather than relying
+	 * on ethernet interface or lower layers to pad it.
+	 */
+	if (dlen < Min_udp_payload) {
+		memmove(payload, data, dlen);
+		data = payload;
+		dlen = Min_udp_payload;
+	}
+
 	uh = (Udphdr*)&pkt;
 
 	memset(uh, 0, sizeof(Etherpkt));
@@ -264,7 +280,7 @@ if(debug) print("not ip...");
 		}
 
 		if(h->udpproto != IP_UDPPROTO) {
-if(debug) print("not udp...");
+if(debug) print("not udp (%d)...", h->udpproto);
 			continue;
 		}
 
@@ -313,6 +329,14 @@ if(debug) print("bad ip\n");
 
 static int tftpblockno;
 
+/*
+ * format of a request packet, from the RFC:
+ *
+            2 bytes     string    1 byte     string   1 byte
+            ------------------------------------------------
+           | Opcode |  Filename  |   0  |    Mode    |   0  |
+            ------------------------------------------------
+ */
 static int
 tftpopen(int ctlrno, Netaddr *a, char *name, Tftp *tftp)
 {
@@ -321,8 +345,8 @@ tftpopen(int ctlrno, Netaddr *a, char *name, Tftp *tftp)
 
 	buf[0] = 0;
 	buf[1] = Tftp_READ;
-	len = sprint(buf+2, "%s", name) + 2;
-	len += sprint(buf+len+1, "octet") + 2;
+	len = 2 + sprint(buf+2, "%s", name) + 1;
+	len += sprint(buf+len, "octet") + 1;
 
 	oport = a->port;
 	for(i = 0; i < 5; i++){
@@ -396,11 +420,11 @@ tftpread(int ctlrno, Netaddr *a, Tftp *tftp, int dlen)
 	return -1;
 }
 
-int
-bootp(int ctlrno, char *file, Boot *b)
+static int
+bootpopen(int ctlrno, char *file, Bootp *rep, int dotftpopen)
 {
-	Bootp req, rep;
-	int i, dlen;
+	Bootp req;
+	int i, n;
 	uchar *ea;
 	char name[128], *filename, *sysname;
 
@@ -420,7 +444,6 @@ bootp(int ctlrno, char *file, Boot *b)
 		else
 			filename = name;
 	}
-		
 
 	memset(&req, 0, sizeof(req));
 	req.op = Bootrequest;
@@ -436,18 +459,19 @@ bootp(int ctlrno, char *file, Boot *b)
 	myaddr.port = BPportsrc;
 	memmove(myaddr.ea, ea, Eaddrlen);
 
+	etherrxflush(ctlrno);
 	for(i = 0; i < 10; i++) {
 		server.ip = Bcastip;
 		server.port = BPportdst;
 		memmove(server.ea, broadcast, sizeof(server.ea));
 		udpsend(ctlrno, &server, &req, sizeof(req));
-		if(udprecv(ctlrno, &server, &rep, sizeof(rep)) <= 0)
+		if(udprecv(ctlrno, &server, rep, sizeof(*rep)) <= 0)
 			continue;
-		if(memcmp(req.chaddr, rep.chaddr, Eaddrlen))
+		if(memcmp(req.chaddr, rep->chaddr, Eaddrlen))
 			continue;
-		if(rep.htype != 1 || rep.hlen != Eaddrlen)
+		if(rep->htype != 1 || rep->hlen != Eaddrlen)
 			continue;
-		if(sysname == 0 || strcmp(sysname, rep.sname) == 0)
+		if(sysname == 0 || strcmp(sysname, rep->sname) == 0)
 			break;
 	}
 	if(i >= 10) {
@@ -455,35 +479,161 @@ bootp(int ctlrno, char *file, Boot *b)
 		return -1;
 	}
 
-	if(filename == 0 || *filename == 0)
-		filename = rep.file;
+	if(!dotftpopen)
+		return 0;
 
-	if(rep.sname[0] != '\0')
-		 print("%s ", rep.sname);
+	if(filename == 0 || *filename == 0){
+		if(strcmp(rep->file, "/386/9pxeload") == 0)
+			return -1;
+		filename = rep->file;
+	}
+
+	if(rep->sname[0] != '\0')
+		 print("%s ", rep->sname);
 	print("(%d.%d.%d.%d!%d): %s\n",
-		rep.siaddr[0],
-		rep.siaddr[1],
-		rep.siaddr[2],
-		rep.siaddr[3],
+		rep->siaddr[0],
+		rep->siaddr[1],
+		rep->siaddr[2],
+		rep->siaddr[3],
 		server.port,
 		filename);
 
-	myaddr.ip = nhgetl(rep.yiaddr);
+	myaddr.ip = nhgetl(rep->yiaddr);
 	myaddr.port = tftpport++;
-	server.ip = nhgetl(rep.siaddr);
+	server.ip = nhgetl(rep->siaddr);
 	server.port = TFTPport;
 
-	if((dlen = tftpopen(ctlrno, &server, filename, &tftpb)) < 0)
+	if((n = tftpopen(ctlrno, &server, filename, &tftpb)) < 0)
 		return -1;
 
-	while(bootpass(b, tftpb.data, dlen) == MORE)
-		if((dlen = tftpread(ctlrno, &server, &tftpb, sizeof(tftpb.data))) < sizeof(tftpb.data))
+	return n;
+}
+
+int
+bootpboot(int ctlrno, char *file, Boot *b)
+{
+	int n;
+	Bootp rep;
+
+	if((n = bootpopen(ctlrno, file, &rep, 1)) < 0)
+		return -1;
+
+	while(bootpass(b, tftpb.data, n) == MORE){
+		n = tftpread(ctlrno, &server, &tftpb, sizeof(tftpb.data));
+		if(n < sizeof(tftpb.data))
 			break;
+	}
 
-	if(0 < dlen && dlen < sizeof(tftpb.data))	/* got to end of file */
-		bootpass(b, tftpb.data, dlen);
+	if(0 < n && n < sizeof(tftpb.data))	/* got to end of file */
+		bootpass(b, tftpb.data, n);
 	else
 		nak(ctlrno, &server, 3, "ok", 0);	/* tftpclose to abort transfer */
 	bootpass(b, nil, 0);	/* boot if possible */
 	return -1;
 }
+
+#include "fs.h"
+
+#define INIPATHLEN	64
+
+static struct {
+	Fs	fs;
+	char	ini[INIPATHLEN];
+} pxether[MaxEther];
+
+static vlong
+pxediskseek(Fs*, vlong)
+{
+	return -1LL;
+}
+
+static long
+pxediskread(Fs*, void*, long)
+{
+	return -1;
+}
+
+static long
+pxeread(File* f, void* va, long len)
+{
+	int n;
+	Bootp rep;
+	char *p, *v;
+
+	if((n = bootpopen(f->fs->dev, pxether[f->fs->dev].ini, &rep, 1)) < 0)
+		return -1;
+
+	p = v = va;
+	while(n > 0) {
+		if((p-v)+n > len)
+			n = len - (p-v);
+		memmove(p, tftpb.data, n);
+		p += n;
+		if(n != Segsize)
+			break;
+		if((n = tftpread(f->fs->dev, &server, &tftpb, sizeof(tftpb.data))) < 0)
+			return -1;
+	}
+	return p-v;
+}
+
+static int
+pxewalk(File* f, char* name)
+{
+	Bootp rep;
+	char *ini;
+
+	switch(f->walked){
+	default:
+		return -1;
+	case 0:
+		if(strcmp(name, "cfg") == 0){
+			f->walked = 1;
+			return 1;
+		}
+		break;
+	case 1:
+		if(strcmp(name, "pxe") == 0){
+			f->walked = 2;
+			return 1;
+		}
+		break;
+	case 2:
+		if(strcmp(name, "%E") != 0)
+			break;
+		f->walked = 3;
+
+		if(bootpopen(f->fs->dev, nil, &rep, 0) < 0)
+			return 0;
+
+		ini = pxether[f->fs->dev].ini;
+		snprint(ini, INIPATHLEN, "/cfg/pxe/%E", rep.chaddr);
+		f->path = ini;
+
+		return 1;
+	}
+	return 0;
+}
+
+void*
+pxegetfspart(int ctlrno, char* part, int)
+{
+	if(!pxe)
+		return nil;
+	if(strcmp(part, "*") != 0)
+		return nil;
+	if(ctlrno >= MaxEther)
+		return nil;
+
+	pxether[ctlrno].fs.dev = ctlrno;
+	pxether[ctlrno].fs.diskread = pxediskread;
+	pxether[ctlrno].fs.diskseek = pxediskseek;
+
+	pxether[ctlrno].fs.read = pxeread;
+	pxether[ctlrno].fs.walk = pxewalk;
+
+	pxether[ctlrno].fs.root.fs = &pxether[ctlrno].fs;
+	pxether[ctlrno].fs.root.walked = 0;
+
+	return &pxether[ctlrno].fs;
+}

+ 9 - 2
sys/src/boot/pc/conf.c

@@ -311,15 +311,22 @@ getconf(char *name)
 void
 addconf(char *fmt, ...)
 {
-	donprint(BOOTARGS+strlen(BOOTARGS), BOOTARGS+BOOTARGSLEN, fmt, (&fmt+1));
+	va_list arg;
+
+	va_start(arg, fmt);
+	vseprint(BOOTARGS+strlen(BOOTARGS), BOOTARGS+BOOTARGSLEN, fmt, arg);
+	va_end(arg);
 }
 
 void
 changeconf(char *fmt, ...)
 {
+	va_list arg;
 	char *p, *q, pref[20], buf[128];
 
-	donprint(buf, buf+sizeof buf, fmt, (&fmt+1));
+	va_start(arg, fmt);
+	vseprint(buf, buf+sizeof buf, fmt, arg);
+	va_end(arg);
 	strncpy(pref+1, buf, 19);
 	pref[19] = '\0';
 	if(p = strchr(pref, '='))

+ 13 - 18
sys/src/boot/pc/console.c

@@ -178,26 +178,18 @@ getstr(char *prompt, char *buf, int size, char *def, int timeout)
 	return 0;
 }
 
-int
-sprint(char *s, char *fmt, ...)
-{
-	return donprint(s, s+PRINTSIZE, fmt, (&fmt+1)) - s;
-}
-
-int
-snprint(char *s, int n, char *fmt, ...)
-{
-	return donprint(s, s+n, fmt, (&fmt+1)) - s;
-}
-
 int
 print(char *fmt, ...)
 {
-	char buf[PRINTSIZE];
 	int n;
+	va_list arg;
+	char buf[PRINTSIZE];
 
-	n = donprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
+	va_start(arg, fmt);
+	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
+	va_end(arg);
 	consputs(buf, n);
+
 	return n;
 }
 
@@ -205,12 +197,15 @@ void
 panic(char *fmt, ...)
 {
 	int n;
+	va_list arg;
 	char buf[PRINTSIZE];
 
-	consputs("panic: ", 7);
-	n = donprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
-	consputs(buf, n);
-	consputs("\n", 1);
+	strcpy(buf, "panic: ");
+	va_start(arg, fmt);
+	n = vseprint(buf+7, buf+sizeof(buf), fmt, arg) - buf;
+	va_end(arg);
+	buf[n] = '\n';
+	consputs(buf, n+1);
 
 //floppymemwrite();
 //splhi(); for(;;);

+ 4 - 0
sys/src/boot/pc/dat.h

@@ -45,6 +45,7 @@ typedef struct IOQ {
 
 enum {
 	Eaddrlen	= 6,
+	/* next two exclude 4-byte ether CRC */
 	ETHERMINTU	= 60,		/* minimum transmit size */
 	ETHERMAXTU	= 1514,		/* maximum transmit size */
 	ETHERHDRSIZE	= 14,		/* size of an ethernet header */
@@ -161,6 +162,8 @@ typedef struct Type {
 	void	(*addconf)(int);
 	int	(*boot)(int, char*, Boot*);
 	void	(*printdevs)(int);
+	char**	parts;
+	char**	inis;
 	int	mask;
 	Medium*	media;
 } Type;
@@ -202,3 +205,4 @@ extern int	debug;
 extern Apminfo	apm;
 extern char	*defaultpartition;
 extern int	iniread;
+extern int	pxe;

+ 0 - 341
sys/src/boot/pc/donprint.c

@@ -1,341 +0,0 @@
-#include	"u.h"
-#include	"lib.h"
-
-#define	PTR	sizeof(char*)
-#define	SHORT	sizeof(int)
-#define	INT	sizeof(int)
-#define	LONG	sizeof(long)
-#define	IDIGIT	30
-#define	MAXCON	30
-
-#define	FLONG	(1<<0)
-#define	FSHORT	(1<<1)
-#define	FUNSIGN	(1<<2)
-
-typedef struct Op	Op;
-struct Op
-{
-	char	*p;
-	char	*ep;
-	void	*argp;
-	int	f1;
-	int	f2;
-	int	f3;
-};
-
-static	int	noconv(Op*);
-static	int	cconv(Op*);
-static	int	dconv(Op*);
-static	int	hconv(Op*);
-static	int	lconv(Op*);
-static	int	oconv(Op*);
-static	int	sconv(Op*);
-static	int	uconv(Op*);
-static	int	xconv(Op*);
-static	int	Xconv(Op*);
-static	int	percent(Op*);
-static	int	pconv(Op*);
-
-static
-int	(*fmtconv[MAXCON])(Op*) =
-{
-	noconv,
-	cconv, dconv, hconv, lconv,
-	oconv, sconv, uconv, xconv,
-	Xconv, percent, pconv,
-};
-static
-char	fmtindex[128] =
-{
-	['c'] 1,
-	['d'] 2,
-	['h'] 3,
-	['l'] 4,
-	['o'] 5,
-	['s'] 6,
-	['u'] 7,
-	['x'] 8,
-	['X'] 9,
-	['%'] 10,
-	['p'] 11,
-};
-
-static	int	convcount  = { 12 };
-static	int	ucase;
-
-static void
-PUT(Op *o, int c)
-{
-	static int pos;
-	int opos;
-
-	if(c == '\t'){
-		opos = pos;
-		pos = (opos+8) & ~7;
-		while(opos++ < pos && o->p < o->ep)
-			*o->p++ = ' ';
-		return;
-	}
-	if(o->p < o->ep){
-		*o->p++ = c;
-		pos++;
-	}
-	if(c == '\n')
-		pos = 0;
-}
-
-int
-fmtinstall(char c, int (*f)(Op*))
-{
-
-	c &= 0177;
-	if(fmtindex[c] == 0) {
-		if(convcount >= MAXCON)
-			return 1;
-		fmtindex[c] = convcount++;
-	}
-	fmtconv[fmtindex[c]] = f;
-	return 0;
-}
-
-char*
-donprint(char *p, char *ep, char *fmt, void *argp)
-{
-	int sf1, c;
-	Op o;
-
-	o.p = p;
-	o.ep = ep;
-	o.argp = argp;
-
-loop:
-	c = *fmt++;
-	if(c != '%') {
-		if(c == 0) {
-			if(o.p < o.ep)
-				*o.p = 0;
-			return o.p;
-		}
-		PUT(&o, c);
-		goto loop;
-	}
-	o.f1 = 0;
-	o.f2 = -1;
-	o.f3 = 0;
-	c = *fmt++;
-	sf1 = 0;
-	if(c == '-') {
-		sf1 = 1;
-		c = *fmt++;
-	}
-	while(c >= '0' && c <= '9') {
-		o.f1 = o.f1*10 + c-'0';
-		c = *fmt++;
-	}
-	if(sf1)
-		o.f1 = -o.f1;
-	if(c != '.')
-		goto l1;
-	c = *fmt++;
-	while(c >= '0' && c <= '9') {
-		if(o.f2 < 0)
-			o.f2 = 0;
-		o.f2 = o.f2*10 + c-'0';
-		c = *fmt++;
-	}
-l1:
-	if(c == 0)
-		fmt--;
-	c = (*fmtconv[fmtindex[c&0177]])(&o);
-	if(c < 0) {
-		o.f3 |= -c;
-		c = *fmt++;
-		goto l1;
-	}
-	o.argp = (char*)o.argp + c;
-	goto loop;
-}
-
-void
-strconv(char *o, Op *op, int f1, int f2)
-{
-	int n, c;
-	char *p;
-
-	n = strlen(o);
-	if(f1 >= 0)
-		while(n < f1) {
-			PUT(op, ' ');
-			n++;
-		}
-	for(p=o; c = *p++;)
-		if(f2 != 0) {
-			PUT(op, c);
-			f2--;
-		}
-	if(f1 < 0) {
-		f1 = -f1;
-		while(n < f1) {
-			PUT(op, ' ');
-			n++;
-		}
-	}
-}
-
-int
-numbconv(Op *op, int base)
-{
-	char b[IDIGIT];
-	int i, f, n, r;
-	long v;
-	short h;
-
-	f = 0;
-	switch(op->f3 & (FLONG|FSHORT|FUNSIGN)) {
-	case FLONG:
-		v = *(long*)op->argp;
-		r = LONG;
-		break;
-
-	case FUNSIGN|FLONG:
-		v = *(ulong*)op->argp;
-		r = LONG;
-		break;
-
-	case FSHORT:
-		h = *(int*)op->argp;
-		v = h;
-		r = SHORT;
-		break;
-
-	case FUNSIGN|FSHORT:
-		h = *(int*)op->argp;
-		v = (ushort)h;
-		r = SHORT;
-		break;
-
-	default:
-		v = *(int*)op->argp;
-		r = INT;
-		break;
-
-	case FUNSIGN:
-		v = *(unsigned*)op->argp;
-		r = INT;
-		break;
-	}
-	if(!(op->f3 & FUNSIGN) && v < 0) {
-		v = -v;
-		f = 1;
-	}
-	b[IDIGIT-1] = 0;
-	for(i = IDIGIT-2;; i--) {
-		n = (ulong)v % base;
-		n += '0';
-		if(n > '9'){
-			n += 'a' - ('9'+1);
-			if(ucase)
-				n += 'A'-'a';
-		}
-		b[i] = n;
-		if(i < 2)
-			break;
-		v = (ulong)v / base;
-		if(op->f2 >= 0 && i >= IDIGIT-op->f2)
-			continue;
-		if(v <= 0)
-			break;
-	}
-	if(f)
-		b[--i] = '-';
-	strconv(b+i, op, op->f1, -1);
-	return r;
-}
-
-static	int
-noconv(Op *op)
-{
-
-	strconv("***", op, 0, -1);
-	return 0;
-}
-
-static	int
-cconv(Op *op)
-{
-	char b[2];
-
-	b[0] = *(int*)op->argp;
-	b[1] = 0;
-	strconv(b, op, op->f1, -1);
-	return INT;
-}
-
-static	int
-dconv(Op *op)
-{
-	return numbconv(op, 10);
-}
-
-static	int
-hconv(Op*)
-{
-	return -FSHORT;
-}
-
-static	int
-lconv(Op*)
-{
-	return -FLONG;
-}
-
-static	int
-oconv(Op *op)
-{
-	return numbconv(op, 8);
-}
-
-static	int
-sconv(Op *op)
-{
-	strconv(*(char**)op->argp, op, op->f1, op->f2);
-	return PTR;
-}
-
-static	int
-uconv(Op*)
-{
-	return -FUNSIGN;
-}
-
-static	int
-xconv(Op *op)
-{
-	return numbconv(op, 16);
-}
-
-static	int
-pconv(Op *op)
-{
-	op->f3 |= FLONG|FUNSIGN;
-	return numbconv(op, 16);
-}
-
-static	int
-Xconv(Op *op)
-{
-	int r;
-
-	ucase = 1;
-	r = numbconv(op, 16);
-	ucase = 0;
-	return r;
-}
-
-static	int
-percent(Op *op)
-{
-
-	PUT(op, '%');
-	return 0;
-}

+ 30 - 4
sys/src/boot/pc/ether.c

@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
+#include "ip.h"
 
 #include "etherif.h"
 
@@ -12,6 +13,7 @@ static Ether ether[MaxEther];
 extern int ether2114xreset(Ether*);
 extern int elnk3reset(Ether*);
 extern int i82557reset(Ether*);
+extern int igbepnp(Ether *);
 extern int elnk3reset(Ether*);
 extern int ether589reset(Ether*);
 extern int ne2000reset(Ether*);
@@ -30,6 +32,7 @@ struct {
 	{ "21140", ether2114xreset, 0, },
 	{ "2114x", ether2114xreset, 0, },
 	{ "i82557", i82557reset, 0, },
+	{ "igbe",  igbepnp, 0, },
 	{ "elnk3", elnk3reset, 0, },
 	{ "3C509", elnk3reset, 0, },
 	{ "3C575", elnk3reset, 0, },
@@ -55,6 +58,8 @@ etherinit(void)
 	Ether *ctlr;
 	int ctlrno, i, mask, n, x;
 
+	fmtinstall('E', eipfmt);
+
 	etherdetach = xetherdetach;
 	mask = 0;
 	for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
@@ -95,10 +100,7 @@ etherinit(void)
 				print(" addr 0x%luX", ctlr->mem & ~KZERO);
 			if(ctlr->size)
 				print(" size 0x%luX", ctlr->size);
-			print(": ");
-			for(i = 0; i < sizeof(ctlr->ea); i++)
-				print("%2.2uX", ctlr->ea[i]);
-			print("\n");
+			print(": %E\n", ctlr->ea);
 		
 			if(ctlr->nrb == 0)
 				ctlr->nrb = Nrb;
@@ -220,6 +222,30 @@ etherrxpkt(int ctlrno, Etherpkt* pkt, int timo)
 	return n;
 }
 
+int
+etherrxflush(int ctlrno)
+{
+	int n;
+	Ether *ctlr;
+	RingBuf *ring;
+
+	if((ctlr = attach(ctlrno)) == 0)
+		return 0;
+
+	n = 0;
+	for(;;){
+		ring = &ctlr->rb[ctlr->rh];
+		if(wait(ring, Interface, 100) == 0)
+			break;
+
+		ring->owner = Interface;
+		ctlr->rh = NEXT(ctlr->rh, ctlr->nrb);
+		n++;
+	}
+
+	return n;
+}
+
 int
 ethertxpkt(int ctlrno, Etherpkt* pkt, int len, int)
 {

+ 1623 - 0
sys/src/boot/pc/etherigbe.c

@@ -0,0 +1,1623 @@
+/*
+ * bootstrap driver for
+ * Intel RS-82543GC Gigabit Ethernet Controller
+ * as found on the Intel PRO/1000[FT] Server Adapter.
+ * The older non-[FT] cards use the 82542 (LSI L2A1157) chip; no attempt
+ * is made to handle the older chip although it should be possible.
+ *
+ * updated just enough to cope with the
+ * Intel 8254[340]NN Gigabit Ethernet Controller
+ * as found on the Intel PRO/1000 series of adapters:
+ *	82543GC	Intel PRO/1000 T
+ *	82544EI Intel PRO/1000 XT
+ *	82540EM Intel PRO/1000 MT
+ *
+ * The datasheet is not very clear about running on a big-endian system
+ * and this driver assumes little-endian throughout.
+ * To do:
+ *	GMII/MII
+ *	check recovery from receive no buffers condition
+ *	automatic ett adjustment
+ */
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#include "etherif.h"
+#include "ethermii.h"
+
+/* compatibility with cpu kernels */
+#define iallocb allocb
+#ifndef CACHELINESZ
+#define CACHELINESZ	32		/* pentium & later */
+#endif
+
+/* from pci.c */
+enum
+{					/* command register (pcidev->pcr) */
+	IOen		= (1<<0),
+	MEMen		= (1<<1),
+	MASen		= (1<<2),
+	MemWrInv	= (1<<4),
+	PErrEn		= (1<<6),
+	SErrEn		= (1<<8),
+};
+enum {
+	Ctrl		= 0x00000000,	/* Device Control */
+	Status		= 0x00000008,	/* Device Status */
+	Eecd		= 0x00000010,	/* EEPROM/Flash Control/Data */
+	Ctrlext		= 0x00000018,	/* Extended Device Control */
+	Mdic		= 0x00000020,	/* MDI Control */
+	Fcal		= 0x00000028,	/* Flow Control Address Low */
+	Fcah		= 0x0000002C,	/* Flow Control Address High */
+	Fct		= 0x00000030,	/* Flow Control Type */
+	Icr		= 0x000000C0,	/* Interrupt Cause Read */
+	Ics		= 0x000000C8,	/* Interrupt Cause Set */
+	Ims		= 0x000000D0,	/* Interrupt Mask Set/Read */
+	Imc		= 0x000000D8,	/* Interrupt mask Clear */
+	Rctl		= 0x00000100,	/* Receive Control */
+	Fcttv		= 0x00000170,	/* Flow Control Transmit Timer Value */
+	Txcw		= 0x00000178,	/* Transmit Configuration Word */
+	Tctl		= 0x00000400,	/* Transmit Control */
+	Tipg		= 0x00000410,	/* Transmit IPG */
+	Tbt		= 0x00000448,	/* Transmit Burst Timer */
+	Ait		= 0x00000458,	/* Adaptive IFS Throttle */
+	Fcrtl		= 0x00002160,	/* Flow Control RX Threshold Low */
+	Fcrth		= 0x00002168,	/* Flow Control Rx Threshold High */
+	Rdbal		= 0x00002800,	/* Rdesc Base Address Low */
+	Rdbah		= 0x00002804,	/* Rdesc Base Address High */
+	Rdlen		= 0x00002808,	/* Receive Descriptor Length */
+	Rdh		= 0x00002810,	/* Receive Descriptor Head */
+	Rdt		= 0x00002818,	/* Receive Descriptor Tail */
+	Rdtr		= 0x00002820,	/* Receive Descriptor Timer Ring */
+	Rxdctl		= 0x00002828,	/* Receive Descriptor Control */
+	Radv		= 0x0000282C,	/* Receive Interrupt Absolute Delay Timer */
+	Txdmac		= 0x00003000,	/* Transfer DMA Control */
+	Ett		= 0x00003008,	/* Early Transmit Control */
+	Tdbal		= 0x00003800,	/* Tdesc Base Address Low */
+	Tdbah		= 0x00003804,	/* Tdesc Base Address High */
+	Tdlen		= 0x00003808,	/* Transmit Descriptor Length */
+	Tdh		= 0x00003810,	/* Transmit Descriptor Head */
+	Tdt		= 0x00003818,	/* Transmit Descriptor Tail */
+	Tidv		= 0x00003820,	/* Transmit Interrupt Delay Value */
+	Txdctl		= 0x00003828,	/* Transmit Descriptor Control */
+	Tadv		= 0x0000382C,	/* Transmit Interrupt Absolute Delay Timer */
+
+	Statistics	= 0x00004000,	/* Start of Statistics Area */
+	Gorcl		= 0x88/4,	/* Good Octets Received Count */
+	Gotcl		= 0x90/4,	/* Good Octets Transmitted Count */
+	Torl		= 0xC0/4,	/* Total Octets Received */
+	Totl		= 0xC8/4,	/* Total Octets Transmitted */
+	Nstatistics	= 64,
+
+	Rxcsum		= 0x00005000,	/* Receive Checksum Control */
+	Mta		= 0x00005200,	/* Multicast Table Array */
+	Ral		= 0x00005400,	/* Receive Address Low */
+	Rah		= 0x00005404,	/* Receive Address High */
+	Manc		= 0x00005820,	/* Management Control */
+};
+
+enum {					/* Ctrl */
+	Bem		= 0x00000002,	/* Big Endian Mode */
+	Prior		= 0x00000004,	/* Priority on the PCI bus */
+	Lrst		= 0x00000008,	/* Link Reset */
+	Asde		= 0x00000020,	/* Auto-Speed Detection Enable */
+	Slu		= 0x00000040,	/* Set Link Up */
+	Ilos		= 0x00000080,	/* Invert Loss of Signal (LOS) */
+	SspeedMASK	= 0x00000300,	/* Speed Selection */
+	SspeedSHIFT	= 8,
+	Sspeed10	= 0x00000000,	/* 10Mb/s */
+	Sspeed100	= 0x00000100,	/* 100Mb/s */
+	Sspeed1000	= 0x00000200,	/* 1000Mb/s */
+	Frcspd		= 0x00000800,	/* Force Speed */
+	Frcdplx		= 0x00001000,	/* Force Duplex */
+	SwdpinsloMASK	= 0x003C0000,	/* Software Defined Pins - lo nibble */
+	SwdpinsloSHIFT	= 18,
+	SwdpioloMASK	= 0x03C00000,	/* Software Defined Pins - I or O */
+	SwdpioloSHIFT	= 22,
+	Devrst		= 0x04000000,	/* Device Reset */
+	Rfce		= 0x08000000,	/* Receive Flow Control Enable */
+	Tfce		= 0x10000000,	/* Transmit Flow Control Enable */
+	Vme		= 0x40000000,	/* VLAN Mode Enable */
+};
+
+enum {					/* Status */
+	Lu		= 0x00000002,	/* Link Up */
+	Tckok		= 0x00000004,	/* Transmit clock is running */
+	Rbcok		= 0x00000008,	/* Receive clock is running */
+	Txoff		= 0x00000010,	/* Transmission Paused */
+	Tbimode		= 0x00000020,	/* TBI Mode Indication */
+	SpeedMASK	= 0x000000C0,
+	Speed10		= 0x00000000,	/* 10Mb/s */
+	Speed100	= 0x00000040,	/* 100Mb/s */
+	Speed1000	= 0x00000080,	/* 1000Mb/s */
+	Mtxckok		= 0x00000400,	/* MTX clock is running */
+	Pci66		= 0x00000800,	/* PCI Bus speed indication */
+	Bus64		= 0x00001000,	/* PCI Bus width indication */
+};
+
+enum {					/* Ctrl and Status */
+	Fd		= 0x00000001,	/* Full-Duplex */
+	AsdvMASK	= 0x00000300,
+	Asdv10		= 0x00000000,	/* 10Mb/s */
+	Asdv100		= 0x00000100,	/* 100Mb/s */
+	Asdv1000	= 0x00000200,	/* 1000Mb/s */
+};
+
+enum {					/* Eecd */
+	Sk		= 0x00000001,	/* Clock input to the EEPROM */
+	Cs		= 0x00000002,	/* Chip Select */
+	Di		= 0x00000004,	/* Data Input to the EEPROM */
+	Do		= 0x00000008,	/* Data Output from the EEPROM */
+	Areq		= 0x00000040,	/* EEPROM Access Request */
+	Agnt		= 0x00000080,	/* EEPROM Access Grant */
+	Eesz256		= 0x00000200,	/* EEPROM is 256 words not 64 */
+	Spi		= 0x00002000,	/* EEPROM is SPI not Microwire */
+};
+
+enum {					/* Ctrlext */
+	Gpien		= 0x0000000F,	/* General Purpose Interrupt Enables */
+	SwdpinshiMASK	= 0x000000F0,	/* Software Defined Pins - hi nibble */
+	SwdpinshiSHIFT	= 4,
+	SwdpiohiMASK	= 0x00000F00,	/* Software Defined Pins - I or O */
+	SwdpiohiSHIFT	= 8,
+	Asdchk		= 0x00001000,	/* ASD Check */
+	Eerst		= 0x00002000,	/* EEPROM Reset */
+	Ips		= 0x00004000,	/* Invert Power State */
+	Spdbyps		= 0x00008000,	/* Speed Select Bypass */
+};
+
+enum {					/* EEPROM content offsets */
+	Ea		= 0x00,		/* Ethernet Address */
+	Cf		= 0x03,		/* Compatibility Field */
+	Pba		= 0x08,		/* Printed Board Assembly number */
+	Icw1		= 0x0A,		/* Initialization Control Word 1 */
+	Sid		= 0x0B,		/* Subsystem ID */
+	Svid		= 0x0C,		/* Subsystem Vendor ID */
+	Did		= 0x0D,		/* Device ID */
+	Vid		= 0x0E,		/* Vendor ID */
+	Icw2		= 0x0F,		/* Initialization Control Word 2 */
+};
+
+enum {					/* Mdic */
+	MDIdMASK	= 0x0000FFFF,	/* Data */
+	MDIdSHIFT	= 0,
+	MDIrMASK	= 0x001F0000,	/* PHY Register Address */
+	MDIrSHIFT	= 16,
+	MDIpMASK	= 0x03E00000,	/* PHY Address */
+	MDIpSHIFT	= 21,
+	MDIwop		= 0x04000000,	/* Write Operation */
+	MDIrop		= 0x08000000,	/* Read Operation */
+	MDIready	= 0x10000000,	/* End of Transaction */
+	MDIie		= 0x20000000,	/* Interrupt Enable */
+	MDIe		= 0x40000000,	/* Error */
+};
+
+enum {					/* Icr, Ics, Ims, Imc */
+	Txdw		= 0x00000001,	/* Transmit Descriptor Written Back */
+	Txqe		= 0x00000002,	/* Transmit Queue Empty */
+	Lsc		= 0x00000004,	/* Link Status Change */
+	Rxseq		= 0x00000008,	/* Receive Sequence Error */
+	Rxdmt0		= 0x00000010,	/* Rdesc Minimum Threshold Reached */
+	Rxo		= 0x00000040,	/* Receiver Overrun */
+	Rxt0		= 0x00000080,	/* Receiver Timer Interrupt */
+	Mdac		= 0x00000200,	/* MDIO Access Completed */
+	Rxcfg		= 0x00000400,	/* Receiving /C/ ordered sets */
+	Gpi0		= 0x00000800,	/* General Purpose Interrupts */
+	Gpi1		= 0x00001000,
+	Gpi2		= 0x00002000,
+	Gpi3		= 0x00004000,
+};
+
+/*
+ * The Mdic register isn't implemented on the 82543GC,
+ * the software defined pins are used instead.
+ * These definitions work for the Intel PRO/1000 T Server Adapter.
+ * The direction pin bits are read from the EEPROM.
+ */
+enum {
+	Mdd		= ((1<<2)<<SwdpinsloSHIFT),	/* data */
+	Mddo		= ((1<<2)<<SwdpioloSHIFT),	/* pin direction */
+	Mdc		= ((1<<3)<<SwdpinsloSHIFT),	/* clock */
+	Mdco		= ((1<<3)<<SwdpioloSHIFT),	/* pin direction */
+	Mdr		= ((1<<0)<<SwdpinshiSHIFT),	/* reset */
+	Mdro		= ((1<<0)<<SwdpiohiSHIFT),	/* pin direction */
+};
+
+enum {					/* Txcw */
+	TxcwFd		= 0x00000020,	/* Full Duplex */
+	TxcwHd		= 0x00000040,	/* Half Duplex */
+	TxcwPauseMASK	= 0x00000180,	/* Pause */
+	TxcwPauseSHIFT	= 7,
+	TxcwPs		= (1<<TxcwPauseSHIFT),	/* Pause Supported */
+	TxcwAs		= (2<<TxcwPauseSHIFT),	/* Asymmetric FC desired */
+	TxcwRfiMASK	= 0x00003000,	/* Remote Fault Indication */
+	TxcwRfiSHIFT	= 12,
+	TxcwNpr		= 0x00008000,	/* Next Page Request */
+	TxcwConfig	= 0x40000000,	/* Transmit COnfig Control */
+	TxcwAne		= 0x80000000,	/* Auto-Negotiation Enable */
+};
+
+enum {					/* Rctl */
+	Rrst		= 0x00000001,	/* Receiver Software Reset */
+	Ren		= 0x00000002,	/* Receiver Enable */
+	Sbp		= 0x00000004,	/* Store Bad Packets */
+	Upe		= 0x00000008,	/* Unicast Promiscuous Enable */
+	Mpe		= 0x00000010,	/* Multicast Promiscuous Enable */
+	Lpe		= 0x00000020,	/* Long Packet Reception Enable */
+	LbmMASK		= 0x000000C0,	/* Loopback Mode */
+	LbmOFF		= 0x00000000,	/* No Loopback */
+	LbmTBI		= 0x00000040,	/* TBI Loopback */
+	LbmMII		= 0x00000080,	/* GMII/MII Loopback */
+	LbmXCVR		= 0x000000C0,	/* Transceiver Loopback */
+	RdtmsMASK	= 0x00000300,	/* Rdesc Minimum Threshold Size */
+	RdtmsHALF	= 0x00000000,	/* Threshold is 1/2 Rdlen */
+	RdtmsQUARTER	= 0x00000100,	/* Threshold is 1/4 Rdlen */
+	RdtmsEIGHTH	= 0x00000200,	/* Threshold is 1/8 Rdlen */
+	MoMASK		= 0x00003000,	/* Multicast Offset */
+	Bam		= 0x00008000,	/* Broadcast Accept Mode */
+	BsizeMASK	= 0x00030000,	/* Receive Buffer Size */
+	Bsize2048	= 0x00000000,
+	Bsize1024	= 0x00010000,
+	Bsize512	= 0x00020000,
+	Bsize256	= 0x00030000,
+	Vfe		= 0x00040000,	/* VLAN Filter Enable */
+	Cfien		= 0x00080000,	/* Canonical Form Indicator Enable */
+	Cfi		= 0x00100000,	/* Canonical Form Indicator value */
+	Dpf		= 0x00400000,	/* Discard Pause Frames */
+	Pmcf		= 0x00800000,	/* Pass MAC Control Frames */
+	Bsex		= 0x02000000,	/* Buffer Size Extension */
+	Secrc		= 0x04000000,	/* Strip CRC from incoming packet */
+};
+
+enum {					/* Tctl */
+	Trst		= 0x00000001,	/* Transmitter Software Reset */
+	Ten		= 0x00000002,	/* Transmit Enable */
+	Psp		= 0x00000008,	/* Pad Short Packets */
+	CtMASK		= 0x00000FF0,	/* Collision Threshold */
+	CtSHIFT		= 4,
+	ColdMASK	= 0x003FF000,	/* Collision Distance */
+	ColdSHIFT	= 12,
+	Swxoff		= 0x00400000,	/* Sofware XOFF Transmission */
+	Pbe		= 0x00800000,	/* Packet Burst Enable */
+	Rtlc		= 0x01000000,	/* Re-transmit on Late Collision */
+	Nrtu		= 0x02000000,	/* No Re-transmit on Underrrun */
+};
+
+enum {					/* [RT]xdctl */
+	PthreshMASK	= 0x0000003F,	/* Prefetch Threshold */
+	PthreshSHIFT	= 0,
+	HthreshMASK	= 0x00003F00,	/* Host Threshold */
+	HthreshSHIFT	= 8,
+	WthreshMASK	= 0x003F0000,	/* Writebacj Threshold */
+	WthreshSHIFT	= 16,
+	Gran		= 0x01000000,	/* Granularity */
+};
+
+enum {					/* Rxcsum */
+	PcssMASK	= 0x000000FF,	/* Packet Checksum Start */
+	PcssSHIFT	= 0,
+	Ipofl		= 0x00000100,	/* IP Checksum Off-load Enable */
+	Tuofl		= 0x00000200,	/* TCP/UDP Checksum Off-load Enable */
+};
+
+enum {					/* Manc */
+	Arpen		= 0x00002000,	/* Enable ARP Request Filtering */
+};
+
+typedef struct Rdesc {			/* Receive Descriptor */
+	uint	addr[2];
+	ushort	length;
+	ushort	checksum;
+	uchar	status;
+	uchar	errors;
+	ushort	special;
+} Rdesc;
+
+enum {					/* Rdesc status */
+	Rdd		= 0x01,		/* Descriptor Done */
+	Reop		= 0x02,		/* End of Packet */
+	Ixsm		= 0x04,		/* Ignore Checksum Indication */
+	Vp		= 0x08,		/* Packet is 802.1Q (matched VET) */
+	Tcpcs		= 0x20,		/* TCP Checksum Calculated on Packet */
+	Ipcs		= 0x40,		/* IP Checksum Calculated on Packet */
+	Pif		= 0x80,		/* Passed in-exact filter */
+};
+
+enum {					/* Rdesc errors */
+	Ce		= 0x01,		/* CRC Error or Alignment Error */
+	Se		= 0x02,		/* Symbol Error */
+	Seq		= 0x04,		/* Sequence Error */
+	Cxe		= 0x10,		/* Carrier Extension Error */
+	Tcpe		= 0x20,		/* TCP/UDP Checksum Error */
+	Ipe		= 0x40,		/* IP Checksum Error */
+	Rxe		= 0x80,		/* RX Data Error */
+};
+
+typedef struct Tdesc {			/* Legacy+Normal Transmit Descriptor */
+	uint	addr[2];
+	uint	control;		/* varies with descriptor type */
+	uint	status;			/* varies with descriptor type */
+} Tdesc;
+
+enum {					/* Tdesc control */
+	LenMASK		= 0x000FFFFF,	/* Data/Packet Length Field */
+	LenSHIFT	= 0,
+	DtypeCD		= 0x00000000,	/* Data Type 'Context Descriptor' */
+	DtypeDD		= 0x00100000,	/* Data Type 'Data Descriptor' */
+	PtypeTCP	= 0x01000000,	/* TCP/UDP Packet Type (CD) */
+	Teop		= 0x01000000,	/* End of Packet (DD) */
+	PtypeIP		= 0x02000000,	/* IP Packet Type (CD) */
+	Ifcs		= 0x02000000,	/* Insert FCS (DD) */
+	Tse		= 0x04000000,	/* TCP Segmentation Enable */
+	Rs		= 0x08000000,	/* Report Status */
+	Rps		= 0x10000000,	/* Report Status Sent */
+	Dext		= 0x20000000,	/* Descriptor Extension */
+	Vle		= 0x40000000,	/* VLAN Packet Enable */
+	Ide		= 0x80000000,	/* Interrupt Delay Enable */
+};
+
+enum {					/* Tdesc status */
+	Tdd		= 0x00000001,	/* Descriptor Done */
+	Ec		= 0x00000002,	/* Excess Collisions */
+	Lc		= 0x00000004,	/* Late Collision */
+	Tu		= 0x00000008,	/* Transmit Underrun */
+	CssMASK		= 0x0000FF00,	/* Checksum Start Field */
+	CssSHIFT	= 8,
+};
+
+enum {
+	Nrdesc		= 128,		/* multiple of 8 */
+	Ntdesc		= 128,		/* multiple of 8 */
+};
+
+typedef struct Ctlr Ctlr;
+typedef struct Ctlr {
+	int	port;
+	Pcidev*	pcidev;
+	Ctlr*	next;
+	int	active;
+	int	id;
+	int	cls;
+	ushort	eeprom[0x40];
+
+	int*	nic;
+	Lock	imlock;
+	int	im;			/* interrupt mask */
+
+	Mii*	mii;
+
+	Lock	slock;
+	uint	statistics[Nstatistics];
+
+	uchar	ra[Eaddrlen];		/* receive address */
+	ulong	mta[128];		/* multicast table array */
+
+	Rdesc*	rdba;			/* receive descriptor base address */
+	Block**	rb;			/* receive buffers */
+	int	rdh;			/* receive descriptor head */
+	int	rdt;			/* receive descriptor tail */
+
+	Tdesc*	tdba;			/* transmit descriptor base address */
+	Lock	tdlock;
+	Block**	tb;			/* transmit buffers */
+	int	tdh;			/* transmit descriptor head */
+	int	tdt;			/* transmit descriptor tail */
+	int	ett;			/* early transmit threshold */
+
+	int	txcw;
+	int	fcrtl;
+	int	fcrth;
+
+	/* bootstrap goo */
+	Block*	bqhead;	/* transmission queue */
+	Block*	bqtail;
+} Ctlr;
+
+static Ctlr* ctlrhead;
+static Ctlr* ctlrtail;
+
+#define csr32r(c, r)	(*((c)->nic+((r)/4)))
+#define csr32w(c, r, v)	(*((c)->nic+((r)/4)) = (v))
+
+static void
+igbeim(Ctlr* ctlr, int im)
+{
+	ilock(&ctlr->imlock);
+	ctlr->im |= im;
+	csr32w(ctlr, Ims, ctlr->im);
+	iunlock(&ctlr->imlock);
+}
+
+static void
+igbeattach(Ether* edev)
+{
+	int ctl;
+	Ctlr *ctlr;
+
+	/*
+	 * To do here:
+	 *	one-time stuff;
+	 *	start off a kproc for link status change:
+	 *		adjust queue length depending on speed;
+	 *		flow control.
+	 *	more needed here...
+	 */
+	ctlr = edev->ctlr;
+	igbeim(ctlr, 0);
+	ctl = csr32r(ctlr, Rctl)|Ren;
+	csr32w(ctlr, Rctl, ctl);
+	ctl = csr32r(ctlr, Tctl)|Ten;
+	csr32w(ctlr, Tctl, ctl);
+}
+
+static char* statistics[Nstatistics] = {
+	"CRC Error",
+	"Alignment Error",
+	"Symbol Error",
+	"RX Error",
+	"Missed Packets",
+	"Single Collision",
+	"Excessive Collisions",
+	"Multiple Collision",
+	"Late Collisions",
+	nil,
+	"Collision",
+	"Transmit Underrun",
+	"Defer",
+	"Transmit - No CRS",
+	"Sequence Error",
+	"Carrier Extension Error",
+	"Receive Error Length",
+	nil,
+	"XON Received",
+	"XON Transmitted",
+	"XOFF Received",
+	"XOFF Transmitted",
+	"FC Received Unsupported",
+	"Packets Received (64 Bytes)",
+	"Packets Received (65-127 Bytes)",
+	"Packets Received (128-255 Bytes)",
+	"Packets Received (256-511 Bytes)",
+	"Packets Received (512-1023 Bytes)",
+	"Packets Received (1024-1522 Bytes)",
+	"Good Packets Received",
+	"Broadcast Packets Received",
+	"Multicast Packets Received",
+	"Good Packets Transmitted",
+	nil,
+	"Good Octets Received",
+	nil,
+	"Good Octets Transmitted",
+	nil,
+	nil,
+	nil,
+	"Receive No Buffers",
+	"Receive Undersize",
+	"Receive Fragment",
+	"Receive Oversize",
+	"Receive Jabber",
+	nil,
+	nil,
+	nil,
+	"Total Octets Received",
+	nil,
+	"Total Octets Transmitted",
+	nil,
+	"Total Packets Received",
+	"Total Packets Transmitted",
+	"Packets Transmitted (64 Bytes)",
+	"Packets Transmitted (65-127 Bytes)",
+	"Packets Transmitted (128-255 Bytes)",
+	"Packets Transmitted (256-511 Bytes)",
+	"Packets Transmitted (512-1023 Bytes)",
+	"Packets Transmitted (1024-1522 Bytes)",
+	"Multicast Packets Transmitted",
+	"Broadcast Packets Transmitted",
+	"TCP Segmentation Context Transmitted",
+	"TCP Segmentation Context Fail",
+};
+
+static void
+txstart(Ether *edev)
+{
+	int tdh, tdt, len, olen;
+	Ctlr *ctlr = edev->ctlr;
+	Block *bp;
+	Tdesc *tdesc;
+
+	/*
+	 * Try to fill the ring back up, moving buffers from the transmit q.
+	 */
+	tdh = PREV(ctlr->tdh, Ntdesc);
+	for(tdt = ctlr->tdt; tdt != tdh; tdt = NEXT(tdt, Ntdesc)){
+		/* pull off the head of the transmission queue */
+		if((bp = ctlr->bqhead) == nil)		/* was qget(edev->oq) */
+			break;
+		ctlr->bqhead = bp->next;
+		if (ctlr->bqtail == bp)
+			ctlr->bqtail = nil;
+		len = olen = BLEN(bp);
+
+		/*
+		 * if packet is too short, make it longer rather than relying
+		 * on ethernet interface to pad it and complain so the caller
+		 * will get fixed.  I don't think Psp is working right, or it's
+		 * getting cleared.
+		 */
+		if (len < ETHERMINTU) {
+			if (bp->rp + ETHERMINTU <= bp->lim)
+				bp->wp = bp->rp + ETHERMINTU;
+			else
+				bp->wp = bp->lim;
+			len = BLEN(bp);
+			print("txstart: extended short pkt %d -> %d bytes\n",
+				olen, len);
+		}
+
+		/* set up a descriptor for it */
+		tdesc = &ctlr->tdba[tdt];
+		tdesc->addr[0] = PCIWADDR(bp->rp);
+		tdesc->addr[1] = 0;
+		tdesc->control = /* Ide| */ Rs|Dext|Ifcs|Teop|DtypeDD|len;
+		tdesc->status = 0;
+
+		ctlr->tb[tdt] = bp;
+	}
+	ctlr->tdt = tdt;
+	csr32w(ctlr, Tdt, tdt);
+	igbeim(ctlr, Txdw);
+}
+
+static Block *
+fromringbuf(Ether *ether)
+{
+	RingBuf *tb = &ether->tb[ether->ti];
+	Block *bp = allocb(tb->len);
+
+	memmove(bp->wp, tb->pkt, tb->len);
+	memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen);
+	bp->wp += tb->len;
+	return bp;
+}
+
+static void
+igbetransmit(Ether* edev)
+{
+	Block *bp;
+	Ctlr *ctlr;
+	Tdesc *tdesc;
+	RingBuf *tb;
+	int tdh;
+
+	/*
+	 * For now there are no smarts here. Tuning comes later.
+	 */
+	ctlr = edev->ctlr;
+	ilock(&ctlr->tdlock);
+
+	/*
+	 * Free any completed packets
+	 * - try to get the soft tdh to catch the tdt;
+	 * - if the packet had an underrun bump the threshold
+	 *   - the Tu bit doesn't seem to ever be set, perhaps
+	 *     because Rs mode is used?
+	 */
+	tdh = ctlr->tdh;
+	for(;;){
+		tdesc = &ctlr->tdba[tdh];
+		if(!(tdesc->status & Tdd))
+			break;
+		if(tdesc->status & Tu){
+			ctlr->ett++;
+			csr32w(ctlr, Ett, ctlr->ett);
+		}
+		tdesc->status = 0;
+		if(ctlr->tb[tdh] != nil){
+			freeb(ctlr->tb[tdh]);
+			ctlr->tb[tdh] = nil;
+		}
+		tdh = NEXT(tdh, Ntdesc);
+	}
+	ctlr->tdh = tdh;
+
+	/* copy packets from the software RingBuf to the transmission q */
+	/* from boot ether83815.c */
+	while((tb = &edev->tb[edev->ti])->owner == Interface){
+		bp = fromringbuf(edev);
+
+		/* put the buffer on the transmit queue */
+		if(ctlr->bqhead)
+			ctlr->bqtail->next = bp;
+		else
+			ctlr->bqhead = bp;
+		ctlr->bqtail = bp;
+
+		txstart(edev);		/* kick transmitter */
+		tb->owner = Host;	/* give descriptor back */
+
+		edev->ti = NEXT(edev->ti, edev->ntb);
+	}
+
+	iunlock(&ctlr->tdlock);
+}
+
+static void
+igbereplenish(Ctlr* ctlr)
+{
+	int rdt;
+	Block *bp;
+	Rdesc *rdesc;
+
+	rdt = ctlr->rdt;
+	while(NEXT(rdt, Nrdesc) != ctlr->rdh){
+		rdesc = &ctlr->rdba[rdt];
+		if(ctlr->rb[rdt] != nil){
+			/* nothing to do */
+		}
+		else if((bp = iallocb(2048)) != nil){
+			ctlr->rb[rdt] = bp;
+			rdesc->addr[0] = PCIWADDR(bp->rp);
+			rdesc->addr[1] = 0;
+		}
+		else
+			break;
+		rdesc->status = 0;
+
+		rdt = NEXT(rdt, Nrdesc);
+	}
+	ctlr->rdt = rdt;
+	csr32w(ctlr, Rdt, rdt);
+}
+
+static void
+toringbuf(Ether *ether, Block *bp)
+{
+	RingBuf *rb = &ether->rb[ether->ri];
+
+	if (rb->owner == Interface) {
+		rb->len = BLEN(bp);
+		memmove(rb->pkt, bp->rp, rb->len);
+		rb->owner = Host;
+		ether->ri = NEXT(ether->ri, ether->nrb);
+	}
+	/* else no one is expecting packets from the network */
+}
+
+static void
+igbeinterrupt(Ureg*, void* arg)
+{
+	Block *bp;
+	Ctlr *ctlr;
+	Ether *edev;
+	Rdesc *rdesc;
+	int icr, im, rdh, txdw = 0;
+
+	edev = arg;
+	ctlr = edev->ctlr;
+
+	ilock(&ctlr->imlock);
+	csr32w(ctlr, Imc, ~0);
+	im = ctlr->im;
+
+	for(icr = csr32r(ctlr, Icr); icr & ctlr->im; icr = csr32r(ctlr, Icr)){
+		/*
+		 * Link status changed.
+		 */
+		if(icr & (Rxseq|Lsc)){
+			/*
+			 * More here...
+			 */
+		}
+
+		/*
+		 * Process any received packets.
+		 */
+		rdh = ctlr->rdh;
+		for(;;){
+			rdesc = &ctlr->rdba[rdh];
+			if(!(rdesc->status & Rdd))
+				break;
+			if ((rdesc->status & Reop) && rdesc->errors == 0) {
+				bp = ctlr->rb[rdh];
+				ctlr->rb[rdh] = nil;
+				/*
+				 * it appears that the original 82543 needed
+				 * to have the Ethernet CRC excluded, but that
+				 * the newer chips do not?
+				 */
+				bp->wp += rdesc->length /* -4 */;
+				toringbuf(edev, bp);
+				freeb(bp);
+			} else if ((rdesc->status & Reop) && rdesc->errors)
+				print("igbe: input packet error 0x%ux\n",
+					rdesc->errors);
+			rdesc->status = 0;
+			rdh = NEXT(rdh, Nrdesc);
+		}
+		ctlr->rdh = rdh;
+
+		if(icr & Rxdmt0)
+			igbereplenish(ctlr);
+		if(icr & Txdw){
+			im &= ~Txdw;
+			txdw++;
+		}
+	}
+
+	ctlr->im = im;
+	csr32w(ctlr, Ims, im);
+	iunlock(&ctlr->imlock);
+
+	if(txdw)
+		igbetransmit(edev);
+}
+
+static int
+igbeinit(Ether* edev)
+{
+	int csr, i, r, ctrl;
+	MiiPhy *phy;
+	Ctlr *ctlr;
+
+	ctlr = edev->ctlr;
+
+	/*
+	 * Set up the receive addresses.
+	 * There are 16 addresses. The first should be the MAC address.
+	 * The others are cleared and not marked valid (MS bit of Rah).
+	 */
+	csr = (edev->ea[3]<<24)|(edev->ea[2]<<16)|(edev->ea[1]<<8)|edev->ea[0];
+	csr32w(ctlr, Ral, csr);
+	csr = 0x80000000|(edev->ea[5]<<8)|edev->ea[4];
+	csr32w(ctlr, Rah, csr);
+	for(i = 1; i < 16; i++){
+		csr32w(ctlr, Ral+i*8, 0);
+		csr32w(ctlr, Rah+i*8, 0);
+	}
+
+	/*
+	 * Clear the Multicast Table Array.
+	 * It's a 4096 bit vector accessed as 128 32-bit registers.
+	 */
+	for(i = 0; i < 128; i++)
+		csr32w(ctlr, Mta+i*4, 0);
+
+	/*
+	 * Receive initialisation.
+	 * Mostly defaults from the datasheet, will
+	 * need some tuning for performance:
+	 *	Rctl	descriptor mimimum threshold size
+	 *		discard pause frames
+	 *		strip CRC
+	 * 	Rdtr	interrupt delay
+	 * 	Rxdctl	all the thresholds
+	 */
+	csr32w(ctlr, Rctl, 0);
+
+	/*
+	 * Allocate the descriptor ring and load its
+	 * address and length into the NIC.
+	 */
+	ctlr->rdba = xspanalloc(Nrdesc*sizeof(Rdesc), 128 /* was 16 */, 0);
+	csr32w(ctlr, Rdbal, PCIWADDR(ctlr->rdba));
+	csr32w(ctlr, Rdbah, 0);
+	csr32w(ctlr, Rdlen, Nrdesc*sizeof(Rdesc));
+
+	/*
+	 * Initialise the ring head and tail pointers and
+	 * populate the ring with Blocks.
+	 * The datasheet says the tail pointer is set to beyond the last
+	 * descriptor hardware can process, which implies the initial
+	 * condition is Rdh == Rdt. However, experience shows Rdt must
+	 * always be 'behind' Rdh; the replenish routine ensures this.
+	 */
+	ctlr->rdh = 0;
+	csr32w(ctlr, Rdh, ctlr->rdh);
+	ctlr->rdt = 0;
+	csr32w(ctlr, Rdt, ctlr->rdt);
+	ctlr->rb = malloc(sizeof(Block*)*Nrdesc);
+	igbereplenish(ctlr);
+
+	/*
+	 * Set up Rctl but don't enable receiver (yet).
+	 */
+	csr32w(ctlr, Rdtr, 0);
+	switch(ctlr->id){
+	case (0x100E<<16)|0x8086:		/* 82540EM */
+	case (0x101E<<16)|0x8086:		/* 82540EPLP */
+		csr32w(ctlr, Radv, 64);
+		break;
+	}
+	csr32w(ctlr, Rxdctl, (8<<WthreshSHIFT)|(8<<HthreshSHIFT)|4);
+	/*
+	 * Enable checksum offload.
+	 */
+	csr32w(ctlr, Rxcsum, Tuofl|Ipofl|(ETHERHDRSIZE<<PcssSHIFT));
+
+	csr32w(ctlr, Rctl, Dpf|Bsize2048|Bam|RdtmsHALF);
+	igbeim(ctlr, Rxt0|Rxo|Rxdmt0|Rxseq);
+
+	/*
+	 * Transmit initialisation.
+	 * Mostly defaults from the datasheet, will
+	 * need some tuning for performance. The normal mode will
+	 * be full-duplex and things to tune for half-duplex are
+	 *	Tctl	re-transmit on late collision
+	 *	Tipg	all IPG times
+	 *	Tbt	burst timer
+	 *	Ait	adaptive IFS throttle
+	 * and in general
+	 *	Txdmac	packet prefetching
+	 *	Ett	transmit early threshold
+	 *	Tidv	interrupt delay value
+	 *	Txdctl	all the thresholds
+	 */
+	csr32w(ctlr, Tctl, (0x0F<<CtSHIFT)|Psp|(66<<ColdSHIFT));	/* Fd */
+	switch(ctlr->id){
+	default:
+		r = 6;
+		break;
+	case (0x1004<<16)|0x8086:	/* 82543GC */
+	case (0x1008<<16)|0x8086:	/* 82544EI */
+	case (0x100E<<16)|0x8086:	/* 82440EM */
+	case (0x101E<<16)|0x8086:	/* 82540EPLP */
+		r = 8;
+		break;
+	}
+	csr32w(ctlr, Tipg, (6<<20)|(8<<10)|r);
+	csr32w(ctlr, Ait, 0);
+	csr32w(ctlr, Txdmac, 0);
+	csr32w(ctlr, Tidv, 128);
+
+	/*
+	 * Allocate the descriptor ring and load its
+	 * address and length into the NIC.
+	 */
+	ctlr->tdba = xspanalloc(Ntdesc*sizeof(Tdesc), 128 /* was 16 */, 0);
+	csr32w(ctlr, Tdbal, PCIWADDR(ctlr->tdba));
+	csr32w(ctlr, Tdbah, 0);
+	csr32w(ctlr, Tdlen, Ntdesc*sizeof(Tdesc));
+
+	/*
+	 * Initialise the ring head and tail pointers.
+	 */
+	ctlr->tdh = 0;
+	csr32w(ctlr, Tdh, ctlr->tdh);
+	ctlr->tdt = 0;
+	csr32w(ctlr, Tdt, ctlr->tdt);
+	ctlr->tb = malloc(sizeof(Block*)*Ntdesc);
+//	ctlr->im |= Txqe|Txdw;
+
+	r = (4<<WthreshSHIFT)|(4<<HthreshSHIFT)|(8<<PthreshSHIFT);
+	switch(ctlr->id){
+	default:
+		break;
+	case (0x100E<<16)|0x8086:	/* 82540EM */
+	case (0x101E<<16)|0x8086:	/* 82540EPLP */
+		r = csr32r(ctlr, Txdctl);
+		r &= ~WthreshMASK;
+		r |= Gran|(4<<WthreshSHIFT);
+
+		csr32w(ctlr, Tadv, 64);
+		break;
+	}
+	csr32w(ctlr, Txdctl, r);
+
+	r = csr32r(ctlr, Tctl);
+	r |= Ten;
+	csr32w(ctlr, Tctl, r);
+
+	if(ctlr->mii == nil || ctlr->mii->curphy == nil) {
+		print("igbe: no mii (yet)\n");
+		return 0;
+	}
+	/* wait for the link to come up */
+	if (miistatus(ctlr->mii) < 0)
+		return -1;
+	print("igbe: phy: ");
+	phy = ctlr->mii->curphy;
+	if (phy->fd)
+		print("full duplex");
+	else
+		print("half duplex");
+	print(", %d Mb/s\n", phy->speed);
+
+	/*
+	 * Flow control.
+	 */
+	ctrl = csr32r(ctlr, Ctrl);
+	if(phy->rfc)
+		ctrl |= Rfce;
+	if(phy->tfc)
+		ctrl |= Tfce;
+	csr32w(ctlr, Ctrl, ctrl);
+
+	return 0;
+}
+
+static int
+i82543mdior(Ctlr* ctlr, int n)
+{
+	int ctrl, data, i, r;
+
+	/*
+	 * Read n bits from the Management Data I/O Interface.
+	 */
+	ctrl = csr32r(ctlr, Ctrl);
+	r = (ctrl & ~Mddo)|Mdco;
+	data = 0;
+	for(i = n-1; i >= 0; i--){
+		if(csr32r(ctlr, Ctrl) & Mdd)
+			data |= (1<<i);
+		csr32w(ctlr, Ctrl, Mdc|r);
+		csr32w(ctlr, Ctrl, r);
+	}
+	csr32w(ctlr, Ctrl, ctrl);
+
+	return data;
+}
+
+static int
+i82543mdiow(Ctlr* ctlr, int bits, int n)
+{
+	int ctrl, i, r;
+
+	/*
+	 * Write n bits to the Management Data I/O Interface.
+	 */
+	ctrl = csr32r(ctlr, Ctrl);
+	r = Mdco|Mddo|ctrl;
+	for(i = n-1; i >= 0; i--){
+		if(bits & (1<<i))
+			r |= Mdd;
+		else
+			r &= ~Mdd;
+		csr32w(ctlr, Ctrl, Mdc|r);
+		csr32w(ctlr, Ctrl, r);
+	}
+	csr32w(ctlr, Ctrl, ctrl);
+
+	return 0;
+}
+
+static int
+i82543miimir(Mii* mii, int pa, int ra)
+{
+	int data;
+	Ctlr *ctlr;
+
+	ctlr = mii->ctlr;
+
+	/*
+	 * MII Management Interface Read.
+	 *
+	 * Preamble;
+	 * ST+OP+PHYAD+REGAD;
+	 * TA + 16 data bits.
+	 */
+	i82543mdiow(ctlr, 0xFFFFFFFF, 32);
+	i82543mdiow(ctlr, 0x1800|(pa<<5)|ra, 14);
+	data = i82543mdior(ctlr, 18);
+
+	if(data & 0x10000)
+		return -1;
+
+	return data & 0xFFFF;
+}
+
+static int
+i82543miimiw(Mii* mii, int pa, int ra, int data)
+{
+	Ctlr *ctlr;
+
+	ctlr = mii->ctlr;
+
+	/*
+	 * MII Management Interface Write.
+	 *
+	 * Preamble;
+	 * ST+OP+PHYAD+REGAD+TA + 16 data bits;
+	 * Z.
+	 */
+	i82543mdiow(ctlr, 0xFFFFFFFF, 32);
+	data &= 0xFFFF;
+	data |= (0x05<<(5+5+2+16))|(pa<<(5+2+16))|(ra<<(2+16))|(0x02<<16);
+	i82543mdiow(ctlr, data, 32);
+
+	return 0;
+}
+
+static int
+igbemiimir(Mii* mii, int pa, int ra)
+{
+	Ctlr *ctlr;
+	int mdic, timo;
+
+	ctlr = mii->ctlr;
+
+	csr32w(ctlr, Mdic, MDIrop|(pa<<MDIpSHIFT)|(ra<<MDIrSHIFT));
+	mdic = 0;
+	for(timo = 64; timo; timo--){
+		mdic = csr32r(ctlr, Mdic);
+		if(mdic & (MDIe|MDIready))
+			break;
+		microdelay(1);
+	}
+
+	if((mdic & (MDIe|MDIready)) == MDIready)
+		return mdic & 0xFFFF;
+	return -1;
+}
+
+static int
+igbemiimiw(Mii* mii, int pa, int ra, int data)
+{
+	Ctlr *ctlr;
+	int mdic, timo;
+
+	ctlr = mii->ctlr;
+
+	data &= MDIdMASK;
+	csr32w(ctlr, Mdic, MDIwop|(pa<<MDIpSHIFT)|(ra<<MDIrSHIFT)|data);
+	mdic = 0;
+	for(timo = 64; timo; timo--){
+		mdic = csr32r(ctlr, Mdic);
+		if(mdic & (MDIe|MDIready))
+			break;
+		microdelay(1);
+	}
+	if((mdic & (MDIe|MDIready)) == MDIready)
+		return 0;
+	return -1;
+}
+
+static int
+igbemii(Ctlr* ctlr)
+{
+	MiiPhy *phy;
+	int ctrl, p, r;
+
+	r = csr32r(ctlr, Status);
+	if(r & Tbimode)
+		return -1;
+	if((ctlr->mii = malloc(sizeof(Mii))) == nil)
+		return -1;
+	ctlr->mii->ctlr = ctlr;
+
+	ctrl = csr32r(ctlr, Ctrl);
+	ctrl |= Slu;
+
+	switch(ctlr->id){
+	case (0x1004<<16)|0x8086:		/* 82543GC */
+		ctrl |= Frcdplx|Frcspd;
+		csr32w(ctlr, Ctrl, ctrl);
+
+		/*
+		 * The reset pin direction (Mdro) should already
+		 * be set from the EEPROM load.
+		 * If it's not set this configuration is unexpected
+		 * so bail.
+		 */
+		r = csr32r(ctlr, Ctrlext);
+		if(!(r & Mdro))
+			return -1;
+		csr32w(ctlr, Ctrlext, r);
+		delay(20);
+		r = csr32r(ctlr, Ctrlext);
+		r &= ~Mdr;
+		csr32w(ctlr, Ctrlext, r);
+		delay(20);
+		r = csr32r(ctlr, Ctrlext);
+		r |= Mdr;
+		csr32w(ctlr, Ctrlext, r);
+		delay(20);
+
+		ctlr->mii->mir = i82543miimir;
+		ctlr->mii->miw = i82543miimiw;
+		break;
+	case (0x1008<<16)|0x8086:		/* 82544EI*/
+	case (0x100E<<16)|0x8086:		/* 82540EM */
+	case (0x101E<<16)|0x8086:		/* 82540EPLP */
+		ctrl &= ~(Frcdplx|Frcspd);
+		csr32w(ctlr, Ctrl, ctrl);
+		ctlr->mii->mir = igbemiimir;
+		ctlr->mii->miw = igbemiimiw;
+		break;
+	default:
+		free(ctlr->mii);
+		ctlr->mii = nil;
+		return -1;
+	}
+
+	if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
+		free(ctlr->mii);
+		ctlr->mii = nil;
+		return -1;
+	}
+	print("oui %X phyno %d\n", phy->oui, phy->phyno);
+
+	/*
+	 * 8254X-specific PHY registers not in 802.3:
+	 *	0x10	PHY specific control
+	 *	0x14	extended PHY specific control
+	 * Set appropriate values then reset the PHY to have
+	 * changes noted.
+	 */
+	r = miimir(ctlr->mii, 0x10);
+	r |= 0x0800;				/* assert CRS on Tx */
+	r |= 0x0060;				/* auto-crossover all speeds */
+	r |= 0x0002;				/* polarity reversal enabled */
+	miimiw(ctlr->mii, 0x10, r);
+
+	r = miimir(ctlr->mii, 0x14);
+	r |= 0x0070;				/* +25MHz clock */
+	r &= ~0x0F00;
+	r |= 0x0100;				/* 1x downshift */
+	miimiw(ctlr->mii, 0x14, r);
+
+	miireset(ctlr->mii);
+
+	p = 0;
+	if(ctlr->txcw & TxcwPs)
+		p |= AnaP;
+	if(ctlr->txcw & TxcwAs)
+		p |= AnaAP;
+	miiane(ctlr->mii, ~0, p, ~0);
+
+	return 0;
+}
+
+static int
+at93c46io(Ctlr* ctlr, char* op, int data)
+{
+	char *lp, *p;
+	int i, loop, eecd, r;
+
+	eecd = csr32r(ctlr, Eecd);
+
+	r = 0;
+	loop = -1;
+	lp = nil;
+	for(p = op; *p != '\0'; p++){
+		switch(*p){
+		default:
+			return -1;
+		case ' ':
+			continue;
+		case ':':			/* start of loop */
+			loop = strtol(p+1, &lp, 0)-1;
+			lp--;
+			if(p == lp)
+				loop = 7;
+			p = lp;
+			continue;
+		case ';':			/* end of loop */
+			if(lp == nil)
+				return -1;
+			loop--;
+			if(loop >= 0)
+				p = lp;
+			else
+				lp = nil;
+			continue;
+		case 'C':			/* assert clock */
+			eecd |= Sk;
+			break;
+		case 'c':			/* deassert clock */
+			eecd &= ~Sk;
+			break;
+		case 'D':			/* next bit in 'data' byte */
+			if(loop < 0)
+				return -1;
+			if(data & (1<<loop))
+				eecd |= Di;
+			else
+				eecd &= ~Di;
+			break;
+		case 'O':			/* collect data output */
+			i = (csr32r(ctlr, Eecd) & Do) != 0;
+			if(loop >= 0)
+				r |= (i<<loop);
+			else
+				r = i;
+			continue;
+		case 'I':			/* assert data input */
+			eecd |= Di;
+			break;
+		case 'i':			/* deassert data input */
+			eecd &= ~Di;
+			break;
+		case 'S':			/* enable chip select */
+			eecd |= Cs;
+			break;
+		case 's':			/* disable chip select */
+			eecd &= ~Cs;
+			break;
+		}
+		csr32w(ctlr, Eecd, eecd);
+		microdelay(1);
+	}
+	if(loop >= 0)
+		return -1;
+	return r;
+}
+
+static int
+at93c46r(Ctlr* ctlr)
+{
+	ushort sum;
+	char rop[20];
+	int addr, areq, bits, data, eecd, i;
+
+	eecd = csr32r(ctlr, Eecd);
+	if(eecd & Spi){
+		print("igbe: SPI EEPROM access not implemented\n");
+		return 0;
+	}
+	if(eecd & Eesz256)
+		bits = 8;
+	else
+		bits = 6;
+	snprint(rop, sizeof(rop), "S :%dDCc;", bits+3);
+
+	sum = 0;
+
+	switch(ctlr->id){
+	default:
+		areq = 0;
+		break;
+	case (0x100E<<16)|0x8086:		/* 82540EM */
+	case (0x101E<<16)|0x8086:		/* 82540EPLP */
+		areq = 1;
+		csr32w(ctlr, Eecd, eecd|Areq);
+		for(i = 0; i < 1000; i++){
+			if((eecd = csr32r(ctlr, Eecd)) & Agnt)
+				break;
+			microdelay(5);
+		}
+		if(!(eecd & Agnt)){
+			print("igbe: not granted EEPROM access\n");
+			goto release;
+		}
+		break;
+	}
+
+	for(addr = 0; addr < 0x40; addr++){
+		/*
+		 * Read a word at address 'addr' from the Atmel AT93C46
+		 * 3-Wire Serial EEPROM or compatible. The EEPROM access is
+		 * controlled by 4 bits in Eecd. See the AT93C46 datasheet
+		 * for protocol details.
+		 */
+		if(at93c46io(ctlr, rop, (0x06<<bits)|addr) != 0){
+			print("igbe: can't set EEPROM address 0x%2.2X\n", addr);
+			goto release;
+		}
+		data = at93c46io(ctlr, ":16COc;", 0);
+		at93c46io(ctlr, "sic", 0);
+		ctlr->eeprom[addr] = data;
+		sum += data;
+	}
+
+release:
+	if(areq)
+		csr32w(ctlr, Eecd, eecd & ~Areq);
+	return sum;
+}
+
+static void
+detach(Ctlr *ctlr)
+{
+	int r;
+
+	/*
+	 * Perform a device reset to get the chip back to the
+	 * power-on state, followed by an EEPROM reset to read
+	 * the defaults for some internal registers.
+	 */
+	csr32w(ctlr, Imc, ~0);
+	csr32w(ctlr, Rctl, 0);
+	csr32w(ctlr, Tctl, 0);
+
+	delay(10);
+
+	csr32w(ctlr, Ctrl, Devrst);
+	while(csr32r(ctlr, Ctrl) & Devrst)
+		;
+
+	csr32w(ctlr, Ctrlext, Eerst);
+	while(csr32r(ctlr, Ctrlext) & Eerst)
+		;
+
+	switch(ctlr->id){
+	default:
+		break;
+	case (0x100E<<16)|0x8086:		/* 82540EM */
+	case (0x101E<<16)|0x8086:		/* 82540EPLP */
+		r = csr32r(ctlr, Manc);
+		r &= ~Arpen;
+		csr32w(ctlr, Manc, r);
+		break;
+	}
+
+	csr32w(ctlr, Imc, ~0);
+	while(csr32r(ctlr, Icr))
+		;
+}
+
+static void
+igbedetach(Ether *edev)
+{
+	detach(edev->ctlr);
+}
+
+static void
+igbeshutdown(Ether* ether)
+{
+print("igbeshutdown\n");
+	igbedetach(ether);
+}
+
+static int
+igbereset(Ctlr* ctlr)
+{
+	int ctrl, i, pause, r, swdpio, txcw;
+
+	detach(ctlr);
+
+	/*
+	 * Read the EEPROM, validate the checksum
+	 * then get the device back to a power-on state.
+	 */
+	if((r = at93c46r(ctlr)) != 0xBABA){
+		print("igbe: bad EEPROM checksum - 0x%4.4uX\n", r);
+		return -1;
+	}
+
+	/*
+	 * Snarf and set up the receive addresses.
+	 * There are 16 addresses. The first should be the MAC address.
+	 * The others are cleared and not marked valid (MS bit of Rah).
+	 */
+	for(i = Ea; i < Eaddrlen/2; i++){
+		ctlr->ra[2*i] = ctlr->eeprom[i];
+		ctlr->ra[2*i+1] = ctlr->eeprom[i]>>8;
+	}
+	r = (ctlr->ra[3]<<24)|(ctlr->ra[2]<<16)|(ctlr->ra[1]<<8)|ctlr->ra[0];
+	csr32w(ctlr, Ral, r);
+	r = 0x80000000|(ctlr->ra[5]<<8)|ctlr->ra[4];
+	csr32w(ctlr, Rah, r);
+	for(i = 1; i < 16; i++){
+		csr32w(ctlr, Ral+i*8, 0);
+		csr32w(ctlr, Rah+i*8, 0);
+	}
+
+	/*
+	 * Clear the Multicast Table Array.
+	 * It's a 4096 bit vector accessed as 128 32-bit registers.
+	 */
+	memset(ctlr->mta, 0, sizeof(ctlr->mta));
+	for(i = 0; i < 128; i++)
+		csr32w(ctlr, Mta+i*4, 0);
+
+	/*
+	 * Just in case the Eerst didn't load the defaults
+	 * (doesn't appear to fully on the 8243GC), do it manually.
+	 */
+	txcw = csr32r(ctlr, Txcw);
+	txcw &= ~(TxcwAne|TxcwPauseMASK|TxcwFd);
+	ctrl = csr32r(ctlr, Ctrl);
+	ctrl &= ~(SwdpioloMASK|Frcspd|Ilos|Lrst|Fd);
+
+	if(ctlr->eeprom[Icw1] & 0x0400){
+		ctrl |= Fd;
+		txcw |= TxcwFd;
+	}
+	if(ctlr->eeprom[Icw1] & 0x0200)
+		ctrl |= Lrst;
+	if(ctlr->eeprom[Icw1] & 0x0010)
+		ctrl |= Ilos;
+	if(ctlr->eeprom[Icw1] & 0x0800)
+		ctrl |= Frcspd;
+	swdpio = (ctlr->eeprom[Icw1] & 0x01E0)>>5;
+	ctrl |= swdpio<<SwdpioloSHIFT;
+	csr32w(ctlr, Ctrl, ctrl);
+
+	ctrl = csr32r(ctlr, Ctrlext);
+	ctrl &= ~(Ips|SwdpiohiMASK);
+	swdpio = (ctlr->eeprom[Icw2] & 0x00F0)>>4;
+	if(ctlr->eeprom[Icw1] & 0x1000)
+		ctrl |= Ips;
+	ctrl |= swdpio<<SwdpiohiSHIFT;
+	csr32w(ctlr, Ctrlext, ctrl);
+
+	if(ctlr->eeprom[Icw2] & 0x0800)
+		txcw |= TxcwAne;
+	pause = (ctlr->eeprom[Icw2] & 0x3000)>>12;
+	txcw |= pause<<TxcwPauseSHIFT;
+	switch(pause){
+	default:
+		ctlr->fcrtl = 0x00002000;
+		ctlr->fcrth = 0x00004000;
+		txcw |= TxcwAs|TxcwPs;
+		break;
+	case 0:
+		ctlr->fcrtl = 0x00002000;
+		ctlr->fcrth = 0x00004000;
+		break;
+	case 2:
+		ctlr->fcrtl = 0;
+		ctlr->fcrth = 0;
+		txcw |= TxcwAs;
+		break;
+	}
+	ctlr->txcw = txcw;
+	csr32w(ctlr, Txcw, txcw);
+
+	/*
+	 * Flow control - values from the datasheet.
+	 */
+	csr32w(ctlr, Fcal, 0x00C28001);
+	csr32w(ctlr, Fcah, 0x00000100);
+	csr32w(ctlr, Fct, 0x00008808);
+	csr32w(ctlr, Fcttv, 0x00000100);
+
+	csr32w(ctlr, Fcrtl, ctlr->fcrtl);
+	csr32w(ctlr, Fcrth, ctlr->fcrth);
+
+	ilock(&ctlr->imlock);
+	csr32w(ctlr, Imc, ~0);
+	ctlr->im = Lsc;
+	csr32w(ctlr, Ims, ctlr->im);
+	iunlock(&ctlr->imlock);
+
+	if(!(csr32r(ctlr, Status) & Tbimode) && igbemii(ctlr) < 0) {
+		print("igbe: igbemii failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void
+igbepci(void)
+{
+	int port, cls;
+	Pcidev *p;
+	Ctlr *ctlr;
+
+	p = nil;
+	while(p = pcimatch(p, 0, 0)){
+		if(p->ccrb != 0x02 || p->ccru != 0)
+			continue;
+
+		switch((p->did<<16)|p->vid){
+		case (0x1000<<16)|0x8086:	/* LSI L2A1157 (82542) */
+		default:
+			continue;
+		case (0x1001<<16)|0x8086:	/* Intel PRO/1000 F */
+			break;
+		case (0x1004<<16)|0x8086:	/* 82543GC - copper (PRO/1000 T) */
+		case (0x1008<<16)|0x8086:	/* 82544EI - copper */
+		case (0x100E<<16)|0x8086:	/* 82540EM - copper */
+		case (0x101E<<16)|0x8086:	/* 82540EPLP - copper */
+			break;
+		}
+
+		port = upamalloc(p->mem[0].bar & ~0x0F, p->mem[0].size, 0);
+		if(port == 0){
+			print("igbe: can't map %8.8luX\n", p->mem[0].bar);
+			continue;
+		}
+
+		/*
+		 * from etherga620.c:
+		 * If PCI Write-and-Invalidate is enabled set the max write DMA
+		 * value to the host cache-line size (32 on Pentium or later).
+		 */
+		if(p->pcr & MemWrInv){
+			cls = pcicfgr8(p, PciCLS) * 4;
+			if(cls != CACHELINESZ)
+				pcicfgw8(p, PciCLS, CACHELINESZ/4);
+		}
+
+		cls = pcicfgr8(p, PciCLS);
+		switch(cls){
+			default:
+				print("igbe: unexpected CLS - %d bytes\n",
+					cls*sizeof(long));
+				break;
+			case 0x00:
+			case 0xFF:
+				/* alphapc 164lx returns 0 */
+				print("igbe: unusable PciCLS: %d, using %d longs\n",
+					cls, CACHELINESZ/sizeof(long));
+				cls = CACHELINESZ/sizeof(long);
+				pcicfgw8(p, PciCLS, cls);
+				break;
+			case 0x08:
+			case 0x10:
+				break;
+		}
+
+		ctlr = malloc(sizeof(Ctlr));
+		ctlr->port = port;
+		ctlr->pcidev = p;
+		ctlr->id = (p->did<<16)|p->vid;
+		ctlr->cls = cls*4;
+		ctlr->nic = KADDR(ctlr->port);
+print("status0 %8.8uX\n", csr32r(ctlr, Status));
+		if(igbereset(ctlr)){
+			free(ctlr);
+			continue;
+		}
+print("status1 %8.8uX\n", csr32r(ctlr, Status));
+		pcisetbme(p);
+
+		if(ctlrhead != nil)
+			ctlrtail->next = ctlr;
+		else
+			ctlrhead = ctlr;
+		ctlrtail = ctlr;
+	}
+}
+
+int
+igbepnp(Ether* edev)
+{
+	int i;
+	Ctlr *ctlr;
+	uchar ea[Eaddrlen];
+
+	if(ctlrhead == nil)
+		igbepci();
+
+	/*
+	 * Any adapter matches if no edev->port is supplied,
+	 * otherwise the ports must match.
+	 */
+	for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
+		if(ctlr->active)
+			continue;
+		if(edev->port == 0 || edev->port == ctlr->port){
+			ctlr->active = 1;
+			break;
+		}
+	}
+	if(ctlr == nil)
+		return -1;
+
+	edev->ctlr = ctlr;
+	edev->port = ctlr->port;
+	edev->irq = ctlr->pcidev->intl;
+	edev->tbdf = ctlr->pcidev->tbdf;
+//	edev->mbps = 1000;
+
+	/*
+	 * Check if the adapter's station address is to be overridden.
+	 * If not, read it from the EEPROM and set in ether->ea prior to
+	 * loading the station address in the hardware.
+	 */
+	memset(ea, 0, Eaddrlen);
+	if(memcmp(ea, edev->ea, Eaddrlen) == 0){
+		for(i = 0; i < Eaddrlen/2; i++){
+			edev->ea[2*i] = ctlr->eeprom[i];
+			edev->ea[2*i+1] = ctlr->eeprom[i]>>8;
+		}
+	}
+	igbeinit(edev);
+
+	/*
+	 * Linkage to the generic ethernet driver.
+	 */
+	edev->attach = igbeattach;
+	edev->transmit = igbetransmit;
+	edev->interrupt = igbeinterrupt;
+	edev->detach = igbedetach;
+
+	return 0;
+}

+ 10 - 8
sys/src/boot/pc/fns.h

@@ -4,7 +4,7 @@ Alarm*	alarm(int, void (*)(Alarm*), void*);
 void	alarminit(void);
 Block*	allocb(int);
 void	apminit(void);
-int	bootp(int, char*, Boot*);
+int	bootpboot(int, char*, Boot*);
 int	bootpass(Boot*, void*, int);
 void	cancel(Alarm*);
 int	cdinit(void);
@@ -23,6 +23,7 @@ uchar*	etheraddr(int);
 int	etherinit(void);
 void	etherinitdev(int, char*);
 void	etherprintdevs(int);
+int	etherrxflush(int);
 int	etherrxpkt(int, Etherpkt*, int);
 int	ethertxpkt(int, Etherpkt*, int, int);
 #define	evenaddr(x)		/* 386 doesn't care */
@@ -30,7 +31,7 @@ int	floppyboot(int, char*, Boot*);
 int	floppyinit(void);
 void	floppyinitdev(int, char*);
 void	floppyprintdevs(int);
-void* floppygetfspart(int, char*, int);
+void*	floppygetfspart(int, char*, int);
 void	freeb(Block*);
 char*	getconf(char*);
 ulong	getcr0(void);
@@ -61,7 +62,7 @@ void	meminit(ulong);
 void	microdelay(int);
 void	mmuinit(void);
 #define	nelem(x)	(sizeof(x)/sizeof(x[0]))
-char *nextelem(char*, char*);
+char*	nextelem(char*, char*);
 uchar	nvramread(int);
 void	outb(int, int);
 void	outs(int, ushort);
@@ -77,9 +78,9 @@ void	pcicfgw8(Pcidev*, int, int);
 void	pcicfgw16(Pcidev*, int, int);
 void	pcicfgw32(Pcidev*, int, int);
 void	pcihinv(Pcidev*);
-Pcidev* pcimatch(Pcidev*, int, int);
-uchar pciintl(Pcidev *);
-uchar pciipin(Pcidev *, uchar);
+Pcidev*	pcimatch(Pcidev*, int, int);
+uchar	pciintl(Pcidev *);
+uchar	pciipin(Pcidev *, uchar);
 void	pcireset(void);
 void	pcisetbme(Pcidev*);
 int	pcmcistuple(int, int, void*, int);
@@ -89,6 +90,7 @@ void	pcmunmap(int, PCMmap*);
 void	ptcheck(char*);
 void	putcr3(ulong);
 void	putidt(Segdesc*, int);
+void*	pxegetfspart(int, char*, int);
 void	qinit(IOQ*);
 void	readlsconf(void);
 void	sdaddconf(int);
@@ -119,7 +121,7 @@ void*	xspanalloc(ulong, int, ulong);
 
 #define malloc(n)	ialloc(n, 0)
 #define mallocz(n, c)	ialloc(n, 0)
-#define free(v) while(0)
+#define free(v)		while(0)
 
 #define	GSHORT(p)	(((p)[1]<<8)|(p)[0])
 #define	GLONG(p)	((GSHORT(p+2)<<16)|GSHORT(p))
@@ -134,7 +136,7 @@ void*	xspanalloc(ulong, int, ulong);
 
 
 #define xalloc(n)	ialloc(n, 0)
-#define xfree(v) while(0)
+#define xfree(v)	while(0)
 #define lock(l)		if(l){/* nothing to do */;}else{/* nothing to do */;}
 #define unlock(l)	if(l){/* nothing to do */;}else{/* nothing to do */;}
 

+ 2 - 1
sys/src/boot/pc/fs.c

@@ -21,7 +21,7 @@ nextelem(char *path, char *elem)
 	if(*path==0 || *path==' ')
 		return 0;
 	for(i=0; *path!='\0' && *path!='/' && *path!=' '; i++){
-		if(i==28){
+		if(i==NAMELEN){
 			print("name component too long\n");
 			return 0;
 		}
@@ -40,6 +40,7 @@ fswalk(Fs *fs, char *path, File *f)
 	if(BADPTR(fs->walk))
 		panic("fswalk bad pointer fs->walk");
 
+	f->path = path;
 	while(path = nextelem(path, element)){
 		switch(fs->walk(f, element)){
 		case -1:

+ 4 - 2
sys/src/boot/pc/fs.h

@@ -1,5 +1,5 @@
 typedef struct File File;
-typedef struct Fs	Fs;
+typedef struct Fs Fs;
 
 #include "dosfs.h"
 #include "kfs.h"
@@ -8,8 +8,10 @@ struct File{
 	union{
 		Dosfile	dos;
 		Kfsfile	kfs;
+		int walked;
 	};
 	Fs	*fs;
+	char	*path;
 };
 
 struct Fs{
@@ -19,7 +21,7 @@ struct Fs{
 	};
 	int	dev;				/* device id */
 	long	(*diskread)(Fs*, void*, long);	/* disk read routine */
-	vlong	(*diskseek)(Fs*, vlong);		/* disk seek routine */
+	vlong	(*diskseek)(Fs*, vlong);	/* disk seek routine */
 	long	(*read)(File*, void*, long);
 	int	(*walk)(File*, char*);
 	File	root;

+ 2 - 0
sys/src/boot/pc/ip.h

@@ -96,3 +96,5 @@ struct Netaddr
 	ushort	port;
 	char	ea[Eaddrlen];
 };
+
+extern int	eipfmt(Fmt*);

+ 7 - 0
sys/src/boot/pc/l.s

@@ -807,3 +807,10 @@ TEXT hello(SB), $0
 
 TEXT rock(SB), $0
 	BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+
+GLOBL pxe(SB), $4
+#ifdef PXE
+DATA	pxe+0(SB)/4, $1
+#else
+DATA	pxe+0(SB)/4, $0
+#endif /* PXE */

+ 29 - 6
sys/src/boot/pc/lib.h

@@ -25,18 +25,38 @@ extern	long	strlen(char*);
 extern	char*	strrchr(char*, char);
 extern	char*	strstr(char*, char*);
 
+
 /*
  * print routines
  */
-extern	char*	donprint(char*, char*, char*, void*);
+typedef struct Fmt	Fmt;
+typedef int (*Fmts)(Fmt*);
+struct Fmt{
+	uchar	runes;			/* output buffer is runes or chars? */
+	void	*start;			/* of buffer */
+	void	*to;			/* current place in the buffer */
+	void	*stop;			/* end of the buffer; overwritten if flush fails */
+	int	(*flush)(Fmt *);	/* called when to == stop */
+	void	*farg;			/* to make flush a closure */
+	int	nfmt;			/* num chars formatted so far */
+	va_list	args;			/* args passed to dofmt */
+	int	r;			/* % format Rune */
+	int	width;
+	int	prec;
+	ulong	flags;
+};
+extern	int	print(char*, ...);
+extern	char*	vseprint(char*, char*, char*, va_list);
 extern	int	sprint(char*, char*, ...);
 extern 	int	snprint(char*, int, char*, ...);
-extern	int	print(char*, ...);
+extern	int	fmtinstall(int, int (*)(Fmt*));
 
-#define	PRINTSIZE	256
-#pragma varargck argpos print 1
-#pragma varargck argpos snprint 3
-#pragma varargck argpos sprint 2
+#pragma	varargck	argpos	fmtprint	2
+#pragma	varargck	argpos	print		1
+#pragma	varargck	argpos	seprint		3
+#pragma	varargck	argpos	snprint		3
+#pragma	varargck	argpos	sprint		2
+#pragma varargck	type	"H" void*
 
 #pragma	varargck	type	"lld"	vlong
 #pragma	varargck	type	"llx"	vlong
@@ -66,6 +86,9 @@ extern	int	print(char*, ...);
 #pragma	varargck	type	"|"	int
 #pragma	varargck	type	"p"	void*
 #pragma varargck	type	"lux"	void*
+#pragma	varargck	type	"E"	uchar*
+
+#define PRINTSIZE	256
 
 /*
  * one-of-a-kind

+ 34 - 18
sys/src/boot/pc/load.c

@@ -7,35 +7,59 @@
 
 #include "fs.h"
 
+static char *diskparts[] = { "dos", "9fat", "fs", "data", "cdboot", 0 };
+static char *etherparts[] = { "*", 0 };
+
+static char *diskinis[] = {
+	"plan9/plan9.ini",
+	"plan9.ini",
+	0
+};
+static char *etherinis[] = {
+	"/cfg/pxe/%E",
+	0
+};
+
 Type types[] = {
 	{	Tfloppy,
 		Fini|Ffs,
 		floppyinit, floppyinitdev,
 		floppygetfspart, 0, floppyboot,
 		floppyprintdevs,
+		diskparts,
+		diskinis,
 	},
 	{	Tcd,
 		Fini|Ffs,
 		cdinit, sdinitdev,
 		sdgetfspart, sdaddconf, sdboot,
 		sdprintdevs,
+		diskparts,
+		diskinis,
 	},
 	{	Tether,
-		Fbootp,
+		Fini|Fbootp,
 		etherinit, etherinitdev,
-		0, 0, bootp,
+		pxegetfspart, 0, bootpboot,
 		etherprintdevs,
+		etherparts,
+		etherinis,
 	},
 	{	Tsd,
 		Fini|Ffs,
 		sdinit, sdinitdev,
 		sdgetfspart, sdaddconf, sdboot,
 		sdprintdevs,
+		diskparts,
+		diskinis,
 	},
 	{	Tnil,
 		0,
-		0, 0, 0, 0,
-		{ 0, },
+		nil, nil, nil, nil, nil, nil,
+		nil,
+		nil,
+		0,
+		nil,
 	},
 };
 
@@ -107,12 +131,6 @@ static Mode modes[NMode+1] = {
 	[Manual]	{ "manual", Manual, },
 };
 
-static char *inis[] = {
-	"plan9/plan9.ini",
-	"plan9.ini",
-	0
-};
-
 char **ini;
 
 int scsi0port;
@@ -178,8 +196,6 @@ allocm(Type *tp)
 	return *l;
 }
 
-char *parts[] = { "dos", "9fat", "fs", "data", "cdboot", 0 };
-
 Medium*
 probe(int type, int flag, int dev)
 {
@@ -221,15 +237,15 @@ probe(int type, int flag, int dev)
 
 			if(mp->flag & Fini){
 				mp->flag &= ~Fini;
-				for(partp = parts; *partp; partp++){
+				for(partp = tp->parts; *partp; partp++){
 					if((fs = (*tp->getfspart)(i, *partp, 0)) == nil)
 						continue;
 
-					for(ini = inis; *ini; ini++){
+					for(ini = tp->inis; *ini; ini++){
 						if(fswalk(fs, *ini, &f) > 0){
 							mp->inifs = fs;
 							mp->part = *partp;
-							mp->ini = *ini;
+							mp->ini = f.path;
 							mp->flag |= Fini;
 							goto Break2;
 						}
@@ -267,8 +283,8 @@ main(void)
 
 	readlsconf();
 	for(tp = types; tp->type != Tnil; tp++){
-		if(tp->type == Tether)
-			continue;
+		//if(tp->type == Tether)
+		//	continue;
 		if((mp = probe(tp->type, Fini, Dany)) && (mp->flag & Fini)){
 			print("using %s!%s!%s\n", mp->name, mp->part, mp->ini);
 			iniread = !dotini(mp->inifs);
@@ -313,7 +329,7 @@ done:
 		if(mode == Mlocal)
 			flag &= ~Fbootp;
 		if((mp = probe(Tany, flag, Dany)) && mp->type->type != Tfloppy)
-			boot(mp, 0);
+			boot(mp, "");
 	}
 
 	def[0] = 0;

+ 5 - 4
sys/src/boot/pc/mkfile

@@ -19,13 +19,13 @@ CORE=\
 	clock.$O\
 	console.$O\
 	dosboot.$O\
-	donprint.$O\
 	devfloppy.$O\
 	dma.$O\
 	fs.$O\
 	ilock.$O\
 	kbd.$O\
 	kfsboot.$O\
+	print.$O\
 	queue.$O\
 	trap.$O\
 
@@ -61,6 +61,7 @@ ETHER=\
 	ether8390.$O\
 	etherec2t.$O\
 	etherelnk3.$O\
+	etherigbe.$O\
 	ethermii.$O\
 	etherrhine.$O\
 
@@ -86,15 +87,15 @@ CFLAGS=-FVw -I.
 all:V:	$TARG
 
 9load:	l.$O $CORE $LOAD $ETHER
-	$LD -o $target -H3 -T0x80010000 -l $prereq -lflate -lc
+	$LD -o $target -H3 -T0x80010000 -l $prereq -lflate -lc -lip
 	ls -l $target
 
 9pxeload:	lpxe.$O $CORE $LOAD $ETHER
-	$LD -o $target -H3 -T0x80007C00 -l $prereq -lflate -lc
+	$LD -o $target -H3 -T0x80007C00 -l $prereq -lflate -lc -lip
 	ls -l $target
 
 9loaddebug:	l.$O $CORE $LOAD $ETHER
-	$LD -o $target -T0x80010000 -l $prereq -lflate -lc
+	$LD -o $target -T0x80010000 -l $prereq -lflate -lc -lip
 	ls -l $target
 	# acid $target
 	# map({"text", 0x80010000, 0x80090000, 0x00000020})

+ 7 - 1
sys/src/boot/pc/noether.c

@@ -28,7 +28,13 @@ etherrxpkt(int, Etherpkt*, int)
 }
 
 int
-bootp(int, char*, Boot*)
+bootpboot(int, char*, Boot*)
 {
 	return -1;
 }
+
+void*
+pxegetfspart(int, char*, int)
+{
+	return nil;
+}

+ 25 - 0
sys/src/boot/pc/print.c

@@ -0,0 +1,25 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+static Lock fmtl;
+
+void
+_fmtlock(void)
+{
+	lock(&fmtl);
+}
+
+void
+_fmtunlock(void)
+{
+	unlock(&fmtl);
+}
+
+int
+_efgfmt(Fmt*)
+{
+	return -1;
+}

+ 0 - 6
sys/src/boot/pc/sd.h

@@ -113,12 +113,6 @@ extern SDev* scsiid(SDev*, SDifc*);
 #define IrqATA1 15
 #define qlock(i)	while(0)
 #define qunlock(i)	while(0)
-#undef va_start
-#undef va_end
-#define va_list void**
-#define va_start(a, b) (a=(&(b)+1))
-#define va_end(x) 
-#define doprint donprint
 
 #define putstrn consputs
 

+ 1 - 1
sys/src/boot/pc/sdata.c

@@ -285,7 +285,7 @@ atadebug(int cmdport, int ctlport, char* fmt, ...)
 	}
 
 	va_start(arg, fmt);
-	n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf;
+	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
 	va_end(arg);
 
 	if(cmdport){