Browse Source

Plan 9 from Bell Labs 2003-11-02

David du Colombier 20 years ago
parent
commit
9a56d75026
100 changed files with 2942 additions and 2323 deletions
  1. 167 161
      dist/replica/plan9.db
  2. 202 0
      dist/replica/plan9.log
  3. 22 0
      mail/lib/white.starter
  4. 20 0
      sys/doc/compiler.ms
  5. 2 0
      sys/games/lib/fortunes
  6. 15 1
      sys/include/libc.h
  7. 21 0
      sys/include/tos.h
  8. 21 0
      sys/include/trace.h
  9. 6 0
      sys/man/1/hget
  10. 26 0
      sys/man/1/prof
  11. 9 1
      sys/man/2/quote
  12. 3 2
      sys/man/3/cons
  13. 80 1
      sys/man/3/proc
  14. 113 298
      sys/man/3/realtime
  15. 8 1
      sys/man/8/qer
  16. 17 5
      sys/man/8/smtp
  17. 6 3
      sys/man/8/stats
  18. 1 0
      sys/src/9/alphapc/dat.h
  19. 1 0
      sys/src/9/alphapc/fns.h
  20. 19 0
      sys/src/9/alphapc/l.s
  21. 2 1
      sys/src/9/alphapc/mkfile
  22. 0 1
      sys/src/9/bitsy/bitsy
  23. 1 0
      sys/src/9/bitsy/dat.h
  24. 1 0
      sys/src/9/bitsy/devpenmouse.c
  25. 1 0
      sys/src/9/bitsy/fns.h
  26. 22 0
      sys/src/9/bitsy/main.c
  27. 2 1
      sys/src/9/bitsy/mkfile
  28. 13 4
      sys/src/9/bitsy/trap.c
  29. 1 1
      sys/src/9/boot/paq.c
  30. 3 3
      sys/src/9/ip/devip.c
  31. 3 5
      sys/src/9/ip/tcp.c
  32. 1 0
      sys/src/9/mtx/dat.h
  33. 3 2
      sys/src/9/mtx/fns.h
  34. 20 0
      sys/src/9/mtx/l.s
  35. 2 1
      sys/src/9/mtx/mkfile
  36. 2 1
      sys/src/9/mtx/trap.c
  37. 18 20
      sys/src/9/pc/archmp.c
  38. 1 1
      sys/src/9/pc/dat.h
  39. 7 7
      sys/src/9/pc/ether8390.c
  40. 2 2
      sys/src/9/pc/etherga620.c
  41. 79 20
      sys/src/9/pc/etherigbe.c
  42. 2 2
      sys/src/9/pc/fns.h
  43. 4 4
      sys/src/9/pc/i8253.c
  44. 1 0
      sys/src/9/pc/io.h
  45. 131 4
      sys/src/9/pc/l.s
  46. 18 1
      sys/src/9/pc/main.c
  47. 5 3
      sys/src/9/pc/mkfile
  48. 4 4
      sys/src/9/pc/pc
  49. 0 1
      sys/src/9/pc/pccpu
  50. 26 1
      sys/src/9/pc/pccpuf
  51. 0 2
      sys/src/9/pc/pcdisk
  52. 0 1
      sys/src/9/pc/pcf
  53. 3 4
      sys/src/9/pc/pcflop
  54. 3 3
      sys/src/9/pc/piix4smbus.c
  55. 1 0
      sys/src/9/pc/sdata.c
  56. 96 22
      sys/src/9/pc/trap.c
  57. 69 28
      sys/src/9/pc/uarti8250.c
  58. 0 22
      sys/src/9/port/alarm.c
  59. 1 1
      sys/src/9/port/alloc.c
  60. 2 2
      sys/src/9/port/allocb.c
  61. 9 9
      sys/src/9/port/chan.c
  62. 1 4
      sys/src/9/port/dev.c
  63. 1 1
      sys/src/9/port/devaudio.c
  64. 6 0
      sys/src/9/port/devcons.c
  65. 5 2
      sys/src/9/port/devfs.c
  66. 7 19
      sys/src/9/port/devloopback.c
  67. 8 8
      sys/src/9/port/devmnt.c
  68. 9 8
      sys/src/9/port/devmouse.c
  69. 267 22
      sys/src/9/port/devproc.c
  70. 7 0
      sys/src/9/port/devroot.c
  71. 28 20
      sys/src/9/port/devuart.c
  72. 454 1014
      sys/src/9/port/edf.c
  73. 35 152
      sys/src/9/port/edf.h
  74. 2 0
      sys/src/9/port/fault.c
  75. 2 2
      sys/src/9/port/pgrp.c
  76. 90 73
      sys/src/9/port/portclock.c
  77. 83 48
      sys/src/9/port/portdat.h
  78. 22 4
      sys/src/9/port/portfns.h
  79. 2 1
      sys/src/9/port/portmkfile
  80. 96 70
      sys/src/9/port/proc.c
  81. 2 8
      sys/src/9/port/qlock.c
  82. 39 19
      sys/src/9/port/sysfile.c
  83. 14 4
      sys/src/9/port/sysproc.c
  84. 31 7
      sys/src/9/port/taslock.c
  85. 139 51
      sys/src/9/port/tod.c
  86. 2 3
      sys/src/9/ppc/blast
  87. 12 13
      sys/src/9/ppc/dat.h
  88. 10 11
      sys/src/9/ppc/devirq.c
  89. 8 1
      sys/src/9/ppc/fns.h
  90. 226 11
      sys/src/9/ppc/l.s
  91. 2 2
      sys/src/9/ppc/mkfile
  92. 3 3
      sys/src/9/ppc/ucu
  93. 0 21
      sys/src/cmd/1a/lex.c
  94. 0 21
      sys/src/cmd/2a/lex.c
  95. 0 21
      sys/src/cmd/5a/lex.c
  96. 3 0
      sys/src/cmd/5c/list.c
  97. 2 0
      sys/src/cmd/5c/txt.c
  98. 1 0
      sys/src/cmd/5i/stats.c
  99. 0 21
      sys/src/cmd/6a/lex.c
  100. 5 1
      sys/src/cmd/6c/list.c

File diff suppressed because it is too large
+ 167 - 161
dist/replica/plan9.db


+ 202 - 0
dist/replica/plan9.log

@@ -13933,3 +13933,205 @@
 1067120173 0 c sys/src/9/bitsy/mkfile - 664 sys sys 1067120164 2454
 1067279475 0 c 386/bin/stats - 775 sys sys 1067278459 188751
 1067279475 1 c sys/src/cmd/stats.c - 664 sys sys 1067278458 28129
+1067720495 0 c sys/games/lib/fortunes - 664 sys sys 1067718902 246583
+1067720495 1 c sys/include/libc.h - 664 sys sys 1067718922 19305
+1067720495 2 a sys/include/tos.h - 664 sys sys 1067718947 562
+1067720495 3 c sys/man/1/prof - 664 sys sys 1067718952 3561
+1067720495 4 c sys/man/2/quote - 664 sys sys 1067719062 3072
+1067720495 5 c sys/src/9/bitsy/mkfile - 664 sys sys 1067718907 2466
+1067720495 6 c sys/src/cmd/jpg/mkfile - 664 sys sys 1067719079 1000
+1067720495 7 c sys/src/cmd/jpg/torgbv.c - 664 sys sys 1067719080 6443
+1067720495 8 a sys/src/cmd/jpg/yuv.c - 664 sys sys 1067719080 4234
+1067720495 9 c sys/src/cmd/du.c - 664 sys sys 1067719067 3144
+1067720495 10 c sys/src/cmd/prof.c - 664 sys sys 1067718957 5521
+1067720495 11 c sys/src/libc/386/argv0.s - 664 sys sys 1067718932 88
+1067720495 12 a sys/src/libc/386/cycles.s - 664 sys sys 1067718932 213
+1067720495 13 c sys/src/libc/386/main9.s - 664 sys sys 1067718933 373
+1067720495 14 c sys/src/libc/386/main9p.s - 664 sys sys 1067718933 698
+1067720495 15 c sys/src/libc/386/mkfile - 664 sys sys 1067718988 469
+1067720495 16 c sys/src/libc/386/vlop.s - 664 sys sys 1067718935 884
+1067720495 17 c sys/src/libc/9sys/pushtls.c - 664 sys sys 1067718964 2023
+1067720495 18 c sys/src/libc/alpha/argv0.s - 664 sys sys 1067718982 88
+1067720495 19 a sys/src/libc/alpha/cycles.c - 664 sys sys 1067718982 71
+1067720495 20 c sys/src/libc/alpha/main9.s - 664 sys sys 1067718982 522
+1067720495 21 c sys/src/libc/alpha/main9p.s - 664 sys sys 1067718983 698
+1067720495 22 c sys/src/libc/alpha/mkfile - 664 sys sys 1067718983 371
+1067720495 23 c sys/src/libc/arm/argv0.s - 664 sys sys 1067719006 88
+1067720495 24 a sys/src/libc/arm/cycles.c - 664 sys sys 1067719006 71
+1067720495 25 c sys/src/libc/arm/main9.s - 664 sys sys 1067719007 489
+1067720495 26 c sys/src/libc/arm/main9p.s - 664 sys sys 1067719007 745
+1067720495 27 c sys/src/libc/arm/mkfile - 664 sys sys 1067719008 385
+1067720495 28 c sys/src/libc/arm/vlrt.c - 664 sys sys 1067719009 8950
+1067720495 29 c sys/src/libc/mips/argv0.s - 664 sys sys 1067719028 88
+1067720495 30 a sys/src/libc/mips/cycles.c - 664 sys sys 1067719028 71
+1067720495 31 c sys/src/libc/mips/main9.s - 664 sys sys 1067719029 426
+1067720495 32 c sys/src/libc/mips/main9p.s - 664 sys sys 1067719029 619
+1067720495 33 c sys/src/libc/mips/mkfile - 664 sys sys 1067719029 446
+1067720495 34 c sys/src/libc/mips/vlrt.c - 664 sys sys 1067719030 9086
+1067720495 35 c sys/src/libc/port/atexit.c - 664 sys sys 1067719043 741
+1067720495 36 c sys/src/libc/port/mkfile - 664 sys sys 1067719044 1545
+1067720495 37 c sys/src/libc/port/pool.c - 664 sys sys 1067719044 27913
+1067720495 38 c sys/src/libc/port/profile.c - 664 sys sys 1067719045 5495
+1067720495 39 c sys/src/libc/power/argv0.s - 664 sys sys 1067719057 88
+1067720495 40 a sys/src/libc/power/cycles.s - 664 sys sys 1067719057 268
+1067720495 41 c sys/src/libc/power/main9.s - 664 sys sys 1067719057 415
+1067720495 42 c sys/src/libc/power/main9p.s - 664 sys sys 1067719058 620
+1067720495 43 c sys/src/libc/power/mkfile - 664 sys sys 1067719060 416
+1067720495 44 c sys/src/libc/power/vlrt.c - 664 sys sys 1067719060 9023
+1067722295 0 c sys/doc/compiler.ms - 664 sys sys 1067721142 30279
+1067722295 1 c sys/games/lib/fortunes - 664 sys sys 1067720544 246645
+1067722295 2 c sys/src/cmd/5c/list.c - 664 sys sys 1067720726 5290
+1067722295 3 c sys/src/cmd/5c/txt.c - 664 sys sys 1067720681 18592
+1067722295 4 c sys/src/cmd/6c/list.c - 664 sys sys 1067720726 4001
+1067722295 5 c sys/src/cmd/6c/txt.c - 664 sys sys 1067720681 18554
+1067722295 6 c sys/src/cmd/8c/list.c - 664 sys sys 1067720660 3975
+1067722295 7 c sys/src/cmd/8c/txt.c - 664 sys sys 1067720660 23563
+1067722295 8 c sys/src/cmd/9c/list.c - 664 sys sys 1067720727 3516
+1067722295 9 c sys/src/cmd/9c/txt.c - 664 sys sys 1067720683 20271
+1067722295 10 c sys/src/cmd/cc/cc.h - 664 sys sys 1067720645 11717
+1067722295 11 c sys/src/cmd/cc/dpchk.c - 664 sys sys 1067720645 6738
+1067722295 12 c sys/src/cmd/cc/lex.c - 664 sys sys 1067720645 23769
+1067722295 13 c sys/src/cmd/cc/macbody - 664 sys sys 1067720644 11182
+1067722295 14 c sys/src/cmd/kc/list.c - 664 sys sys 1067720728 3785
+1067722295 15 c sys/src/cmd/kc/txt.c - 664 sys sys 1067720683 19514
+1067722295 16 c sys/src/cmd/qc/list.c - 664 sys sys 1067720728 3785
+1067722295 17 c sys/src/cmd/qc/txt.c - 664 sys sys 1067720684 20029
+1067722295 18 c sys/src/cmd/vc/list.c - 664 sys sys 1067720729 4076
+1067722295 19 c sys/src/cmd/vc/txt.c - 664 sys sys 1067720684 22654
+1067723212 0 a sys/include/trace.h - 664 sys sys 1067722708 576
+1067723212 1 c sys/man/1/hget - 664 sys sys 1067722859 1483
+1067723212 2 c sys/man/3/cons - 664 sys sys 1067722911 8683
+1067723212 3 c sys/man/3/proc - 664 sys sys 1067722856 9526
+1067723212 4 c sys/man/3/realtime - 664 sys sys 1067722856 7946
+1067723212 5 c sys/man/8/qer - 664 sys sys 1067723129 4909
+1067723212 6 c sys/man/8/smtp - 664 sys sys 1067722775 4709
+1067723212 7 c sys/man/8/stats - 664 sys sys 1067722908 4291
+1067723212 8 c sys/src/9/alphapc/dat.h - 664 sys sys 1067722581 5162
+1067723212 9 c sys/src/9/alphapc/fns.h - 664 sys sys 1067722581 3906
+1067723212 10 c sys/src/9/alphapc/l.s - 664 sys sys 1067722580 9124
+1067723212 11 c sys/src/9/alphapc/mkfile - 664 sys sys 1067722619 2030
+1067723212 12 c sys/src/9/bitsy/bitsy - 664 sys sys 1067722592 424
+1067723212 13 c sys/src/9/bitsy/dat.h - 664 sys sys 1067722592 5739
+1067723212 14 c sys/src/9/bitsy/devpenmouse.c - 664 sys sys 1067722592 9296
+1067723212 15 c sys/src/9/bitsy/fns.h - 664 sys sys 1067722591 3366
+1067723212 16 c sys/src/9/bitsy/main.c - 664 sys sys 1067722593 9083
+1067723212 17 c sys/src/9/bitsy/trap.c - 664 sys sys 1067722593 19245
+1067723212 18 c sys/src/9/boot/paq.c - 664 sys sys 1067722601 1099
+1067723212 19 c sys/src/9/ip/devip.c - 664 sys sys 1067722615 24186
+1067723212 20 c sys/src/9/ip/tcp.c - 664 sys sys 1067722615 65141
+1067723212 21 c sys/src/9/mtx/dat.h - 664 sys sys 1067722599 3798
+1067723212 22 c sys/src/9/mtx/fns.h - 664 sys sys 1067722598 3154
+1067723212 23 c sys/src/9/mtx/l.s - 664 sys sys 1067722599 10730
+1067723212 24 c sys/src/9/mtx/mkfile - 664 sys sys 1067722598 1520
+1067723212 25 c sys/src/9/mtx/trap.c - 664 sys sys 1067722597 15713
+1067723212 26 c sys/src/9/pc/archmp.c - 664 sys sys 1067722683 2323
+1067723212 27 c sys/src/9/pc/dat.h - 664 sys sys 1067722637 6119
+1067723212 28 c sys/src/9/pc/ether8390.c - 664 sys sys 1067722623 17541
+1067723212 29 c sys/src/9/pc/etherigbe.c - 664 sys sys 1067722636 43330
+1067723212 30 c sys/src/9/pc/fns.h - 664 sys sys 1067722685 4271
+1067723212 31 c sys/src/9/pc/i8253.c - 664 sys sys 1067722684 6217
+1067723212 32 c sys/src/9/pc/io.h - 664 sys sys 1067722633 7991
+1067723212 33 c sys/src/9/pc/l.s - 664 sys sys 1067722634 23586
+1067723212 34 c sys/src/9/pc/main.c - 664 sys sys 1067722634 14685
+1067723212 35 c sys/src/9/pc/mkfile - 664 sys sys 1067722635 3217
+1067723212 36 c sys/src/9/pc/pc - 664 sys sys 1067722635 1335
+1067723212 37 c sys/src/9/pc/pccpu - 664 sys sys 1067722636 777
+1067723212 38 c sys/src/9/pc/pcdisk - 664 sys sys 1067722637 1402
+1067723212 39 c sys/src/9/pc/pcf - 664 sys sys 1067722637 1431
+1067723212 40 c sys/src/9/pc/piix4smbus.c - 664 sys sys 1067722684 5273
+1067723212 41 c sys/src/9/pc/sdata.c - 664 sys sys 1067722685 50288
+1067723212 42 c sys/src/9/pc/trap.c - 664 sys sys 1067722686 20552
+1067723212 43 c sys/src/9/pc/uarti8250.c - 664 sys sys 1067722686 13859
+1067723212 44 c sys/src/9/pc/etherga620.c - 664 sys sys 1067723192 28788
+1067723212 45 c sys/src/9/pc/pccpuf - 664 sys sys 1067722888 1286
+1067723212 46 c sys/src/9/pc/pcflop - 664 sys sys 1067722894 1383
+1067723212 47 c sys/src/9/port/alarm.c - 664 sys sys 1067722766 1426
+1067723212 48 c sys/src/9/port/alloc.c - 664 sys sys 1067722763 5329
+1067723212 49 c sys/src/9/port/allocb.c - 664 sys sys 1067722759 3200
+1067723212 50 c sys/src/9/port/chan.c - 664 sys sys 1067722721 29156
+1067723212 51 c sys/src/9/port/dev.c - 664 sys sys 1067722718 8348
+1067723212 52 c sys/src/9/port/devaudio.c - 664 sys sys 1067722761 21130
+1067723212 53 c sys/src/9/port/devcons.c - 664 sys sys 1067722767 22064
+1067723212 54 c sys/src/9/port/devloopback.c - 664 sys sys 1067722759 14670
+1067723212 55 c sys/src/9/port/devmnt.c - 664 sys sys 1067722762 21601
+1067723212 56 c sys/src/9/port/devmouse.c - 664 sys sys 1067722758 12203
+1067723212 57 c sys/src/9/port/devproc.c - 664 sys sys 1067722717 28273
+1067723212 58 c sys/src/9/port/devroot.c - 664 sys sys 1067722764 4254
+1067723212 59 c sys/src/9/port/devuart.c - 664 sys sys 1067722718 11683
+1067723212 60 c sys/src/9/port/edf.c - 664 sys sys 1067722765 11931
+1067723212 61 c sys/src/9/port/edf.h - 664 sys sys 1067722760 1124
+1067723212 62 c sys/src/9/port/fault.c - 664 sys sys 1067722722 6628
+1067723212 63 c sys/src/9/port/pgrp.c - 664 sys sys 1067722718 3944
+1067723212 64 c sys/src/9/port/portclock.c - 664 sys sys 1067722761 4271
+1067723212 65 c sys/src/9/port/portdat.h - 664 sys sys 1067722763 22621
+1067723212 66 c sys/src/9/port/portfns.h - 664 sys sys 1067722759 11369
+1067723212 67 c sys/src/9/port/portmkfile - 664 sys sys 1067722766 2098
+1067723212 68 c sys/src/9/port/proc.c - 664 sys sys 1067722762 24755
+1067723212 69 c sys/src/9/port/qlock.c - 664 sys sys 1067722765 3196
+1067723212 70 c sys/src/9/port/sysfile.c - 664 sys sys 1067722760 22127
+1067723212 71 c sys/src/9/port/sysproc.c - 664 sys sys 1067722765 15396
+1067723212 72 c sys/src/9/port/taslock.c - 664 sys sys 1067722721 3348
+1067723212 73 c sys/src/9/port/tod.c - 664 sys sys 1067722762 4856
+1067723212 74 c sys/src/9/port/devfs.c - 664 sys sys 1067722764 10760
+1067723212 75 c sys/src/9/ppc/blast - 664 sys sys 1067722850 659
+1067723212 76 c sys/src/9/ppc/dat.h - 664 sys sys 1067723142 4676
+1067723212 77 c sys/src/9/ppc/devirq.c - 664 sys sys 1067722849 6057
+1067723212 78 c sys/src/9/ppc/fns.h - 664 sys sys 1067722798 4211
+1067723212 79 c sys/src/9/ppc/l.s - 664 sys sys 1067722848 21035
+1067723212 80 c sys/src/9/ppc/mkfile - 664 sys sys 1067722849 1813
+1067723212 81 c sys/src/9/ppc/ucu - 664 sys sys 1067722849 672
+1067723212 82 c sys/src/cmd/acme/dat.h - 664 sys sys 1067723164 10956
+1067723212 83 c sys/src/cmd/acme/ecmd.c - 664 sys sys 1067723163 24152
+1067723212 84 c sys/src/cmd/acme/elog.c - 664 sys sys 1067723163 7241
+1067723212 85 c sys/src/cmd/acme/exec.c - 664 sys sys 1067723165 27057
+1067723212 86 c sys/src/cmd/acme/fns.h - 664 sys sys 1067723164 2922
+1067723212 87 c sys/src/cmd/acme/xfid.c - 664 sys sys 1067723165 19180
+1067723212 88 c sys/src/cmd/hget.c - 664 sys sys 1067722871 22715
+1067723212 89 c sys/src/cmd/ip/snoopy/ip6.c - 664 sys sys 1067722979 5362
+1067723212 90 c sys/src/cmd/webfs/http.c - 664 sys sys 1067722969 6726
+1067723212 91 c sys/src/cmd/webfs/main.c - 664 sys sys 1067722969 1062
+1067723212 92 c sys/src/cmd/pwd.c - 664 sys sys 1067722792 287
+1067723212 93 c sys/src/cmd/upas/marshal/marshal.c - 664 sys sys 1067722960 32467
+1067723212 94 c sys/src/cmd/upas/ned/nedmail.c - 664 sys sys 1067722837 42995
+1067723212 95 c sys/src/cmd/upas/smtp/mkfile - 664 sys sys 1067722781 746
+1067723212 96 c sys/src/cmd/upas/smtp/smtpd.c - 664 sys sys 1067722780 24439
+1067723212 97 c sys/src/cmd/upas/smtp/smtpd.h - 664 sys sys 1067722781 1111
+1067723212 98 c sys/src/cmd/upas/smtp/spam.c - 664 sys sys 1067722785 9661
+1067723212 99 c sys/src/cmd/7c/list.c - 644 sys sys 1067723063 3862
+1067723212 100 c sys/src/cmd/7c/txt.c - 644 sys sys 1067723062 20149
+1067723212 101 c sys/src/libc/29000/argv0.s - 664 sys sys 1067722825 88
+1067723212 102 c sys/src/libc/29000/main9.s - 664 sys sys 1067722823 489
+1067723212 103 c sys/src/libc/29000/main9p.s - 664 sys sys 1067722815 700
+1067723212 104 c sys/src/libc/29000/mkfile - 664 sys sys 1067723170 320
+1067723212 105 c sys/src/libc/386/vlrt.c - 664 sys sys 1067723053 9567
+1067723212 106 c sys/src/libc/68000/argv0.s - 664 sys sys 1067722826 88
+1067723212 107 c sys/src/libc/68000/main9.s - 664 sys sys 1067722824 336
+1067723212 108 c sys/src/libc/68000/main9p.s - 664 sys sys 1067722815 586
+1067723212 109 c sys/src/libc/68000/mkfile - 664 sys sys 1067723171 462
+1067723212 110 c sys/src/libc/68020/argv0.s - 664 sys sys 1067722826 88
+1067723212 111 c sys/src/libc/68020/main9.s - 664 sys sys 1067722824 355
+1067723212 112 c sys/src/libc/68020/main9p.s - 664 sys sys 1067722816 605
+1067723212 113 c sys/src/libc/68020/mkfile - 664 sys sys 1067723172 615
+1067723212 114 c sys/src/libc/sparc/argv0.s - 664 sys sys 1067722827 88
+1067723212 115 c sys/src/libc/sparc/main9.s - 664 sys sys 1067722825 537
+1067723212 116 c sys/src/libc/sparc/main9p.s - 664 sys sys 1067722817 749
+1067723212 117 c sys/src/libc/sparc/mkfile - 664 sys sys 1067723173 434
+1067723212 118 c sys/src/libc/sparc/vlrt.c - 664 sys sys 1067723054 9066
+1067723212 119 d sys/src/9/boot/libboot.a8 - 664 sys sys 1066515074 0
+1067725175 0 c sys/src/cmd/2a/lex.c - 664 sys sys 1067725158 19370
+1067725175 1 c sys/src/cmd/5a/lex.c - 664 sys sys 1067725159 11049
+1067725175 2 c sys/src/cmd/6a/lex.c - 664 sys sys 1067725159 11684
+1067725175 3 c sys/src/cmd/8a/lex.c - 664 sys sys 1067725160 18023
+1067725175 4 c sys/src/cmd/9a/lex.c - 664 sys sys 1067725161 9981
+1067725175 5 c sys/src/cmd/ka/lex.c - 664 sys sys 1067725162 12759
+1067725175 6 c sys/src/cmd/qa/lex.c - 664 sys sys 1067725162 13720
+1067725175 7 c sys/src/cmd/va/lex.c - 664 sys sys 1067725163 11825
+1067725175 8 c sys/src/cmd/1a/lex.c - 664 sys sys 1067725158 19259
+1067725175 9 c sys/src/cmd/7a/lex.c - 664 sys sys 1067725160 12389
+1067725896 0 c sys/src/cmd/cc/lexbody - 664 sys sys 1067725942 8953
+1067739546 0 c sys/src/cmd/5i/stats.c - 664 sys sys 1067739537 3943
+1067740300 0 a mail/lib/white.starter - 664 upas upas 1067739606 326
+1067742100 0 c sys/src/cmd/ip/httpd/mkfile - 664 sys sys 1067742150 1406
+1067742100 1 a sys/src/cmd/upas/smtp/greylist.c - 664 sys sys 1067741333 5588
+1067742845 0 a sys/src/cmd/jpg/readyuv.c - 664 sys sys 1067742240 3502
+1067746800 0 c sys/src/cmd/vi/stats.c - 664 sys sys 1067746789 5386

+ 22 - 0
mail/lib/white.starter

@@ -0,0 +1,22 @@
+# internal net
+10.0.0.0/8
+# yahoo mail hosts
+66.218.66.0/24
+66.218.84.0/24
+# bellnexxia.net
+209.226.175.0/24
+# telus.net
+199.185.220.0/24
+# amazon
+207.171.188.0/24
+# careerbuilder.com
+66.45.112.0/24
+
+# psuvax1.cse.psu.edu - 9fans
+130.203.4.6
+# plan9.bell-labs.com
+204.178.31.2
+# ieee
+140.98.194.25
+# jetblue.com
+64.50.124.126

+ 20 - 0
sys/doc/compiler.ms

@@ -369,6 +369,26 @@ to be laid out in memory tightly packed in successive bytes, disregarding
 the usual alignment rules.
 Accessing such data can cause faults.
 .LP
+Similarly, 
+.CW #pragma
+.CW profile
+.CW off
+(or
+.CW no
+or
+.CW 0 )
+causes subsequently declared functions, until
+.CW #pragma
+.CW profile
+.CW on
+(or
+.CW yes
+or
+.CW 1 ),
+to be marked as unprofiled.
+Such functions will not be profiled when 
+profiling is enabled for the rest of the program.
+.LP
 Two
 .CW #pragma
 statements allow type-checking of

+ 2 - 0
sys/games/lib/fortunes

@@ -3989,3 +3989,5 @@ if_de.c:2401: 		    sc->tulip_mediums[media] = mi;
 Please let us know if there is anything we can do to make your stay more magical.  Please note the field below is limited to 29 characters.  - Disney World hotel reservation web page
 Telegraph is a kind of a very, very long cat. You pull his tail in New York and his head meows in Los Angeles. And radio operates exactly the same way — you send signals here, they receive them there. The only difference is that there is no cat. -Albert Einstein
 Hi.  My name is %{NAME%}%, I am 25 years of age.  I happen to see your profile on the internet.  Come visit me some more by viewing my site.  Ethel
+As complicated as the semantics of virtual inheritance may seem, its support within the compiler has proven even more complicated.  - Stanley Lippman, Inside the C++ Object Model
+Who needs hallucinatory drugs when we've got quantum physics?

+ 15 - 1
sys/include/libc.h

@@ -312,6 +312,8 @@ extern	long	times(long*);
 extern	long	tm2sec(Tm*);
 extern	vlong	nsec(void);
 
+extern	void	cycles(uvlong*);	/* 64-bit value of the cycle counter if there is one, 0 if there isn't */
+
 /*
  * one-of-a-kind
  */
@@ -358,7 +360,7 @@ extern	double	modf(double, double*);
 extern	int	netcrypt(void*, void*);
 extern	void	notejmp(void*, jmp_buf, int);
 extern	void	perror(char*);
-extern  int	postnote(int, int, char *);
+extern	int	postnote(int, int, char *);
 extern	double	pow10(int);
 extern	int	putenv(char*, char*);
 extern	void	qsort(void*, long, long, int (*)(void*, void*));
@@ -376,6 +378,18 @@ extern	long	time(long*);
 extern	int	tolower(int);
 extern	int	toupper(int);
 
+/*
+ *  profiling
+ */
+enum {
+	Profoff,			/* No profiling */
+	Profuser,			/* Measure user time only (default) */
+	Profkernel,		/* Measure user + kernel time */
+	Proftime,			/* Measure total time */
+	Profsample,		/* Use clock interrupt to sample (default when there is no cycle counter) */
+}; /* what */
+extern	void	prof(void (*fn)(void*), void *arg, int entries, int what);
+
 /*
  *  synchronization
  */

+ 21 - 0
sys/include/tos.h

@@ -0,0 +1,21 @@
+typedef struct Tos Tos;
+typedef struct Plink Plink;
+struct Tos {
+	struct			/* Per process profiling */
+	{
+		Plink		*pp;		/* known to be 0(ptr) */
+		Plink		*next;	/* known to be 4(ptr) */
+		Plink		*last;
+		Plink		*first;
+		ulong	pid;
+		ulong	what;
+	} prof;
+	uvlong		cyclefreq;		/* cycle clock frequency if there is one, 0 otherwise */
+	vlong		kcycles;		/* cycles spent in kernel */
+	vlong		pcycles;		/* cycles spent in process (kernel + user) */
+	ulong		pid;			/* might as well put the pid here */
+	ulong		clock;
+	/* top of stack is here */
+};
+
+extern Tos *_tos;

+ 21 - 0
sys/include/trace.h

@@ -0,0 +1,21 @@
+typedef enum Tevent {
+	SAdmit,		/* Edf admit */
+	SRelease,	/* Edf release, waiting to be scheduled */
+	SEdf,		/* running under EDF */
+	SRun,		/* running best effort */
+	SReady,		/* runnable but not running  */
+	SSleep,		/* blocked */
+	SYield,		/* blocked waiting for release */
+	SSlice,		/* slice exhausted */
+	SDeadline,	/* proc's deadline */
+	SExpel,		/* Edf expel */
+	SDead,		/* proc dies */
+	SUser,		/* user event */
+} Tevent;
+
+typedef struct Traceevent	Traceevent;
+struct Traceevent {
+	ulong	pid;	
+	Tevent	etype;		/* Event type */
+	vlong	time;		/* time stamp (ns)  */
+};

+ 6 - 0
sys/man/1/hget

@@ -67,6 +67,12 @@ Option
 writes progress lines to standard output once a second.
 Each line contains two numbers, the bytes transferred so
 far and the total length to be transferred.
+.PP
+If the environment variable
+.B httpproxy
+is set, it is used as a URL denoting an HTTP proxy server.
+All HTTP accesses use this server to get the page instead of
+calling the destination server.
 .SH SOURCE
 .B /sys/src/cmd/hget.c
 .SH "SEE ALSO"

+ 26 - 0
sys/man/1/prof

@@ -82,6 +82,32 @@ before running
 .IR program .
 If the buffer fills, subsequent function calls may not be recorded.
 .PP
+The profiling code provided by the linker initializes itself to profile the current pid,
+producing a file called
+.B prof.\f2pid\fP.
+If a process forks, only the parent will continue to be profiled.  Forked children
+can cause themselves to be profile by calling
+.EX
+    prof(fn, arg, entries, what)
+.EE
+which causes the function \f2fn\fP(\f2arg\fP) to be profiled.  When \f2fn\fP
+returns 
+.B prof.\f2pid\fP
+is produced for the current process pid.
+.PP
+The environment variable
+.B proftype
+can be set to one of
+.BR user ,
+.BR kernel ,
+.BR elapsed ,
+or
+.BR sample ,
+to profile time measured spent in user mode, time spent in user+kernel mode, or elapsed time,
+using the cycle counter, or the time in user mode using the kernel's HZ clock.  The cycle counter
+is currently only available on modern PCs and on the PowerPC.  Default profiling measures user
+time, using the cycle counter if it is available.
+.PP
 .I Tprof
 is similar to
 .IR prof ,

+ 9 - 1
sys/man/2/quote

@@ -1,6 +1,6 @@
 .TH QUOTE 2
 .SH NAME
-quotestrdup, quoterunestrdup, unquotestrdup, unquoterunestrdup, quotestrfmt, quoterunestrfmt, quotefmtinstall, doquote \- quoted character strings
+quotestrdup, quoterunestrdup, unquotestrdup, unquoterunestrdup, quotestrfmt, quoterunestrfmt, quotefmtinstall, doquote, needsrcquote \- quoted character strings
 .SH SYNOPSIS
 .B #include <u.h>
 .br
@@ -30,6 +30,9 @@ void quotefmtinstall(void)
 .B
 int (*doquote)(int c)
 .PP
+.B
+int needsrcquote(int c)
+.PP
 .SH DESCRIPTION
 These routines manipulate character strings, either adding or removing
 quotes as necessary.
@@ -117,6 +120,11 @@ characters other than blanks, control characters, or quotes be quoted.
 Regardless of the return value of
 .IR *doquote ,
 blanks, control characters, and quotes are always quoted.
+.I Needsrcquote
+is provided as a
+.I doquote
+function that flags any character special to
+.IR rc (1).
 .PP
 .I Quotestrfmt
 and

+ 3 - 2
sys/man/3/cons

@@ -282,10 +282,11 @@ if known.
 .PP
 The
 .B sysstat
-file holds 8 numbers:
+file holds 10 numbers:
 processor number, context switches, interrupts, system calls, page faults,
-TLB faults, TLB purges, and load average.
+TLB faults, TLB purges, load average, idle time and time spent servicing interrupts.
 The load average is in units of milli-CPUs and is decayed over time;
+idle time and interrupt time are percentage units;
 the others are total counts from boot time.
 If the machine is a multiprocessor,
 .B sysstat

+ 80 - 1
sys/man/3/proc

@@ -265,7 +265,86 @@ Set the base priority for the process to the integer
 .B "wire\ \fIn
 Wire the process to processor
 .IR n .
-.PD
+.TP 10n
+.B "period\ \fInu
+Set the real-time scheduling period of the process to
+.IR nu ,
+where
+.I n
+is an optionally signed number containing an optional decimal point and
+.I u
+is one of
+.BR s ,
+.BR ms ,
+.BR us ,
+.BR µs ,
+.BR ns ,
+or
+empty.  The time is interpreted, respectively, as
+.IR seconds ,
+.IR milliseconds ,
+.IR microseconds ,
+.IR microseconds ,
+.IR nanoseconds ,
+or, in the case of an absent units specifier, as
+.IR nanoseconds .
+If the time specifier is signed, it is interpreted as an increment or decrement
+from a previously set value.
+See
+.IR realtime (3).
+.TP 10n
+.B "deadline\ \fInu
+Set the real-time deadline interval of the process to
+.IR nu ,
+where
+.I n
+and
+.I u
+are interpreted as for
+.B period
+above.
+See
+.IR realtime (3).
+.TP 10n
+.B "cost\ \fInu
+Set the real-time cost (maximum CPU time per period) of the process to
+.IR nu ,
+where
+.I n
+and
+.I u
+are interpreted as for
+.B period
+above.
+.TP 10n
+.B "sporadic
+Use sporadic scheduling for the real-time process.
+See
+.IR realtime (3).
+.TP 10n
+.B "yieldonblock
+Make the real-time process yield on blocking I/O.
+See
+.IR realtime (3).
+.TP 10n
+.B "admit
+Given real-time
+.IR period ,
+.I deadline
+and
+.I cost
+are set (an unset
+.I deadline
+will set
+.I deadline
+to
+.IR period ),
+perform a schedulability test and start scheduling the process as a real-time
+process if the test succeeds.  If the test fails, the
+.B write
+will fail with error set to the reason for failure.
+See
+.IR realtime (3).
 .PP
 The priority is interpreted by Plan 9's multilevel process scheduler.
 Priorities run from 0 to 19, with higher

+ 113 - 298
sys/man/3/realtime

@@ -10,43 +10,7 @@ realtime \- real time scheduling
 .B bind -a #R /dev
 .ift .sp 0.5
 .ifn .sp
-/dev/realtime/clone
-/dev/realtime/debug
-/dev/realtime/log
-/dev/realtime/nblog
-/dev/realtime/resources
-/dev/realtime/task/0
-/dev/realtime/task/1
-/dev/realtime/task/...
-/dev/realtime/time
-.sp
-#include "realtime.h"
-.ift .sp 0.5
-.ifn .sp
-enum SEvent {
-	SAdmit,	/* new proc arrives*/
-	SRelease,	/* released, but not yet scheduled */
-	SRun,	/* one of this task's procs started running */
-	SPreempt,	/* the running task was preempted */
-	SBlock,	/* the last of the runnable procs in a task blocked */
-	SResume,	/* task was scheduled after blocking */
-	SDeadline,	/* proc's deadline (reported ahead of time) */
-	SYield,	/* proc reached voluntary early deadline */
-	SSlice,	/* slice exhausted */
-	SExpel,	/* proc was expelled */
-	SResack,	/* acquire resource */
-	SResrel,	/* release resource */
-};
-typedef enum SEvent SEvent;
-typedef vlong Time;
-typedef struct Schedevent Schedevent;
-.ift .sp 0.5
-.ifn .sp
-struct Schedevent {
-	ushort	tid;	/* Task ID */
-	SEvent	etype;	/* Event type */
-	Time	ts;	/* Event time */
-};
+/proc/\fIn\fP/ctl
 .EE
 .SH DESCRIPTION
 The Plan 9 real-time scheduler allows mixing real-time processes and best-effort
@@ -55,145 +19,112 @@ under 100% CPU utilization with minimum periods in the order of a hundred thousa
 instruction times.  The precision of the scheduler depends on the precision of the
 machine's programmable real-time clock.
 .PP
-The unit of real-time scheduling is a
-.BR task .
-A task can contain zero or more processes.  The processes in a task
-share a common period, deadline and CPU allocation.  Tasks allow
-cooperating processes to collaborate to achieve a common deadline, for
-instance, processes receiving, decompressing and displaying video in a
-pipeline can share a single task.
-.PP
-Tasks are scheduled using Earliest-Deadline First (EDF).  Each task
+Real-time processes are scheduled using Earliest-Deadline First (EDF).  Each process
 has three primary scheduling parameters, a period $T$, a deadline $D$
-and a cost $C$, expressed in nanoseconds (but converted internally to
-a machine- and architecture-dependent unit called
-.IR tick ).
-Every $T$ nanoseconds, the task is
+and a cost $C$, expressed in nanoseconds.
+Every $T$ nanoseconds, the process is
 .I released
 — i.e., it becomes schedulable — and it receives a
 .I slice
 of $C$ nsec.
-When the task is released, its
+When the process is released, its
 .I "release time"
 $r$ is set to the current time.
-The task's
+The process's
 .I "absolute deadline"
 $d$ is set to $r + D$.
 (Note the use of capital letters to indicate intervals and lower-case
 letters to indicate `points in time'.)
-Between release and deadline the task must be scheduled often enough
+Between release and deadline, the process must be scheduled often enough
 to be able to consume its slice of $C$ nsec of CPU time.
 So, to be schedulable, $C <= D <= T$ must hold.
-If $D < T$, tasks are not schedulable (runnable) between their
-deadline and the next release.
-Tasks are
-.I released
+If $D < T$, processes are not real-time schedulable (runnable) between their
+deadline and the next release, but they may run as best-effort processes and compete with
+other processes for the CPU.
+Processes are scheduled according to the EDF rule
 from the moment of release until their deadline or their slice runs
-out, whichever happens first.  Additionally, tasks can voluntarily
+out, whichever happens first.  Additionally, processes can voluntarily
 declare the slice for the current period empty, allowing other
-real-time tasks or best-effort tasks the CPU time remaining in their
+real-time processes or best-effort processes to use the CPU time remaining in their
 slice.
 .PP
-Before they are released for the first time, tasks have to be
+Before they are released for the first time, processes have to be
 .IR admitted
 into the system.  Before admission, a test is conducted to determine
-whether the task, plus the already admitted tasks can all meet their
-deadlines, given their scheduling parameters.  When a task changes its
-scheduling parameters, it is temporarily
+whether the process, plus the already admitted processes, given their
+scheduling parameters, can all meet their deadlines.  When a process
+changes its scheduling parameters, it is temporarily
 .I expelled
-and will be readmitted if the new scheduling parameters allow all
-tasks to continue to meet their deadlines.
+and will be readmitted only if the new scheduling parameters allow all
+processes to continue to meet their deadlines.
 .PP
-The EDF scheduler schedules the released task with the earliest
-deadline.  When a task is released it can, therefore, preempt a task
+The EDF scheduler schedules the released process with the earliest
+deadline.  When a process is released it can, therefore, preempt a process
 that has a later deadline, but was released earlier.
-.PP
-Real-time tasks sharing resources, however, may need to be prevented
-from preempting each other.  They must do this by declaring their shared
-resources.  The scheduler will not preempt one task with another that
-shares a common resource.  To do this, the scheduler needs to know the
-names of the sharable resources used by each of the tasks, the amount
-of time the resources are used, and the way in which resource usage is
-nested.
-.PP
-Resource usage must be strictly nested; i.e., it is legal for a task to
-first to acquire resource $A$, then to acquire resource $B$, to
-release $B$ again and finally to release $A$.  It is also legal for it
-to acquire and release $A$ before acquiring and releasing $B$.  But
-it is not legal to acquire $A$, acquire $B$, release $A$ and release $B$
-in that order.
-.PP
-During the admission test, information about resource sharing is used
-to calculate
-.IR "inherited deadlines" ,
-for each task.  A resource's
-.IR "inherited deadline" ,
-$Δ$, is the minimum of the deadlines $D$ of each of the tasks
-that shares that resource.  A task's $Δ$ is the minimum of the
-resource $Δ$s of all resources held by the task.
-.PP
-Acquiring a resource may lower the $Δ$ of the task; releasing one
-may increase it.
-.PP
-The scheduler allows a released task $T$ to preempt running task $T'$
-iff $d < d' ^ D < Δ'$; the first half of the condition says that the
-released task's deadline must be earlier, the second implies that the
-released task may not share resources with the running one (after all,
-if $T'$ had acquired a resource that $T$ uses, its $Δ'$ would, by the
-definition of inherited deadlines, be less than or equal to $D$).
-.PP
-The admission test takes these limitations into account.  Note that,
-in practice, tasks rarely share resources.
-.PP
-Normally, tasks can block (when all their processes are blocked on
-system calls) during their release.  The time spent blocking is not
-accounted against the current slice, but, since the scheduler has no
-control over the time spent blocking, there are no guarantees that the
-deadline will be made if a task blocks during its release.  Whether or
-not tasks actually block, they will normally complete the work to be
-done in a period (slightly) before the slice runs out — and before
-the deadline.  To tell the scheduler that they no longer require the
-CPU until the next release, tasks can
-.I yield
+.\" .PP
+.\" Real-time processes sharing resources, however, may need to be prevented
+.\" from preempting each other.  They must do this by declaring their shared
+.\" resources.  The scheduler will not preempt one process with another that
+.\" shares a common resource.  To do this, processes can name resources they use
+.\" and the scheduler will not allow preemption of a process by another that
+.\" has named the same resource.
+.\" .PP
+.\" Note that, if all processes share a common resource, the scheduler reduces to
+.\" non-preemptive EDF scheduling.  Note also that resources in this context
+.\" are just named placeholders for the actual resources shared by the processes.
+.\" It is up to the programmer to define the relationship between actual
+.\" shared resources (data structures, for example) and the named resources
+.\" used by the scheduler.
+.\" .PP
+.\" During the admission test, information about resource sharing is used
+.\" to calculate
+.\" .IR "inherited deadlines" ,
+.\" for each process.  A resource's
+.\" .IR "inherited deadline" ,
+.\" $Δ$, is the minimum of the deadlines $D$ of each of the processes
+.\" that shares that resource.  A process's $Δ$ is the minimum of the
+.\" resource $Δ$s of all resources held by the process.
+.\" .PP
+.\" The scheduler allows a released process $T$ to preempt running process $T'$
+.\" iff $d < d' ^ D < Δ'$; the first half of the condition says that the
+.\" released process's deadline must be earlier, the second implies that the
+.\" released process may not share resources with the running one (after all,
+.\" if $T'$ had acquired a resource that $T$ uses, its $Δ'$ would, by the
+.\" definition of inherited deadlines, be less than or equal to $D$).
+.\" .PP
+.\" The admission test takes these limitations into account.  Note that,
+.\" in practice, processes rarely share resources.
+.PP
+Normally, processes can block (when all their processes are blocked on
+system calls) during their release.  The time spent blocking may be
+accounted against the current slice, because blocked processes may stop
+other processes from getting the processor (due to shared resources).
+Processes can tell the scheduler that they no longer require the CPU until the next
+release, by
+.I yielding
 (see below).
 .PP
-Tasks can also run in another mode where blocking automatically
+Processes can also run in another mode where blocking automatically
 implies immediate yielding.  This mode truly guarantees that deadlines
 will be made, but programmers must know more about the (blocking)
-nature of the system calls used in order to use this mode.
+nature of system calls used in order to use this mode.
 .sp
 .LP
-The real-time scheduler is controlled through the
-.B #R
-file system, normally bound to
-.BR /dev .
-Opening
-.B /dev/realtime/clone
-for writing (and reading, if desired), causes a new task to be created in the
-non-admitted (expelled) state.  The new task will be represented by a file in
-the
-.B /dev/realtime/task
-directory whose name $n$ is the task's number.
-The file descriptor resulting from opening
-.B /dev/realtime/clone
-provides the equivalent functionality as that resulting from opening
-.BI /dev/realtime/task/ n
-except for the initial creation of a new task when opening the
-.B clone
-file.  The task file may also be opened read-only.
+The real-time scheduler is controlled through
+.BR /proc/\fPpid\fP/ctl .
+See
+.IR proc (3).
 .PP
-The task's parameters are set or modified by writing one of these files and they
+The process' parameters are set or modified by writing one of these files and they
 can be examined by reading it.
 A parameter is presented in the form
-\f2name\fP=\f2value\fP, \f2name\fP+=\f2value\fP, or \f2name\fP-=\f2value\fP.
+\f2name\fP \f2value\fP, \f2name\fP +\f2value\fP, or \f2name\fP -\f2value\fP.
 A command is presented in the form
 .IR commandname .
-Parameters and commands are separated by white space; quoting conventions apply
-(see
-.IR quote (2)).
+Parameters and commands are separated by semicolons.
 The settable parameters are
 .TP
-.B T
+.B period
 Sets the period.  The value must be given as a number with or without decimal point
 and directly followed (no white space) by one of
 .I s
@@ -207,190 +138,74 @@ for microseconds,
 .I ns
 or
 nothing
-for nanoseconds.  The
-.B +=
-operator adds to the period already set, the
-.B -=
-operator subtracts from it.
-.TP
-.B D
-Sets the deadline.  Value syntax and operators as above.
+for nanoseconds.
+If the value is signed, it is taken as an increment (decrement) of the value
+perviously set.
 .TP
-.B C
-Sets the cost.  Value syntax and operators as above.
+.B deadline
+Sets the deadline.  Value specified as above.
 .TP
-.B resources
-Sets the list of resources; resource names must consist of letters, digits, or underscores
-and they must not start with a digit.  A resource name may be followed by its cost
-(using the same notation of time as in setting the $T$ attribute) and by resources
-nested within.  These nested resources are indicated by an open brace '{', a list of
-nested resources and a closing brace '}'.  Quoting is usually necessary.
-An example of a resource specification is
-.ti +2m
-.B "resources='a 10ms { b 2ms c 3ms {d} }'
-.br
-Here, resource $a$ is held for at most 10 ms; during this time, resource $b$ is
-acquired and then released within 2 ms.  After releasing $b$, resource $c$ can
-be acquired and then resource $d$.  No time is specified for $d$, so its cost
-is inherited from its parent: 3 ms.  Resources $d$, $c$ and $a$ must be released
-in that order.
-.br
-.ti +1m
-The
-.B +=
-and
-.B -=
-operators are not allowed for resources (they must be specified completely every time).
-.TP
-.B acquire
-is a run time command which tells the scheduler that the named resource is being acquired.
-The scheduler will adjust the task's $Δ$ accordingly.  It is illegal to acquire a resource
-not specified or not to follow the nesting order.  It is legal, however, not to acquire a resource
-(and all the ones nested inside) that may legally be acquired.
-The
-.B +=
-and
-.B -=
-operators do not apply.
-.TP
-.B procs
-Sets, adds to, or subtracts from the process membership of a task.  Processes
-are identified by their
-.I pid
-or the special value
-.B self
-identifying the process writing the
-.I clone
-or
-.I task
-file.
+.B cost
+Sets the cost.  Value specified as above.
 .TP
 .B yieldonblock
-When the (integer) value is non-zero, the task is placed in
+When the (integer) value is non-zero or absent, the process is placed in
 .I yield-on-block
-mode: when all processes in the task are blocked on system calls, the task automatically
-declares the current deadline reached and will be released again in the next period.
-When the value is zero, the task can block without forfeiting the current release.
-However, when the task blocks long, the deadline may be missed.  The default value is zero.
-.LP
-In addition to these settable attributes, there are a number of attributes
-to be read:
-.TP
-.B n
-Number of releases of this task,
-.TP
-.B m
-Number of deadlines missed,
-.TP
-.B p
-Number of times the task was preempted by one with an earlier deadline,
-.TP
-.B t
-Total time used (divide this by
-.I n
-to get the average time used per period),
-.TP
-.B c
-Aged average time used,
-.LP
-The commands accepted are
-.TP
-.B verbose
-This is for debugging and causes the progression of the admission test to be displayed.
+mode: when the process is blocked on a system call, the process automatically
+declares the current deadline reached and will be released again in the next period or when the process
+becomes runnable again, whichever occurs last.
+When the value is zero, the process can block without forfeiting the current release.
+The default value is zero.
+.TP
+.B sporadic
+When the (integer) value is non-zero or absent, the process is placed in
+.I sporadic
+mode.  This mode resembles
+.IR yield-on-block .
+When the process unblocks and the time elapsed since last release is more than the period, it
+is released immediately, rather than at the next period boundary.  Sporadic scheduling is
+useful for processes that are interrupt driven.  The period merely specifies the maximum
+invocation rate.  The default value is zero.
 .TP
 .B admit
 This initiates an admission test.  If the test fails, the write containing the
 .B admit
-command will fail.  If the test succeeds the task is admitted and, if it contains
-runnable processes, it will be released (almost) immediately.
+command will fail.  If the test succeeds the process is admitted and will be released.
 .TP
 .B expel
-Expel the task.
-.TP
-.B remove
-Remove the task, the file descriptor will become invalid.
-.TP
-.B release
-Release the last resource acquired.  There is no attribute.
-.TP
-.B yield
-Gives up the processor until the next release.
+Expels the process by turning it back into a regular best-effort process.
 .LP
-.sp
-.B /dev/realtime/debug
-prints debugging information about the task queues maintained by the scheduler.
-This file will go away.
-.PP
-.B /dev/realtime/log
-and
-.B /dev/realtime/nblog
-are files used by real-time monitoring processes such as
-.B rtstats
-(see
-.IR rtstats (1)).
-Reading them produces a stream of
-.B Schedevent
-structures in the machine representation.  These events are
-nearly ordered by Time (nanoseconds since boot); some events can
-be reported earlier or later than they occur.
-.I Tid
-corresponds to the file name in the directory
-.BR /dev/realtime/task ,
-.I etype
-is one of the events of
-.I SEvent
-as explained in
-.BR /sys/src/9/port/devrealtime.h ,
-and
-.I ts
-is the time at which the event occurred (or will occur).
-.B Nblog
-is a non-blocking version that returns zero bytes each time there is
-nothing left to read.
-.PP
-.B /dev/realtime/resources
-is a read-only file listing the resources declared by the current set of tasks.
-.PP
-.B /dev/realtime/time
-returns the number of nanoseconds since boot, the number of ticks since boot and
-.IR fasthz ,
-the number of clock ticks per second, a billion times the ratio between the other two numbers.
-Each number is returned as a binary
-.I vlong
-in architecture-dependent representation.
+.BR Sleep(0)
+will yield (i.e., giveup the processor until the next release time).  In non-real-time
+processes,
+.B sleep(0)
+will invoke the scheduler, allowing higher priority processes to run.
+.TP
 .SH EXAMPLE
 .EX
 .ta 4n +4n +4n +4n +4n +4n +4n
-char *clonedev = "#R/realtime/clone";
+char *ctl[128];
 
 void
 processvideo(){
 	int fd;
 
-	if ((fd = open(clonedev, ORDWR)) < 0) 
-		sysfatal("%s: %r", clonedev);
-	if (fprint(fd, "T=33ms D=20ms C=8ms procs=self admit") < 0)
-		sysfatal("%s: admit: %r", clonedev);
+	snprint(ctl, sizeof ctl, "/proc/%ld/ctl", getpid());
+	if ((fd = open(ctl, ORDWR)) < 0) 
+		sysfatal("%s: %r", ctl);
+	if (fprint(fd, "period 33ms;deadline 20ms;cost 8ms;admit") < 0)
+		sysfatal("%s: admit: %r", ctl);
+	close(fd);
 	for (;;){
 		processframe();
-		if (fprint(fd, "yield") < 0)
-			sysfatal("%s: yield: %r", clonedev);
+		sleep(0);
 	}
-	if (fprint(fd, "remove") < 0)
-		sysfatal("%s: remove: %r", clonedev);
-	close(fd);
 }
 .EE
 .SH "SEE ALSO
-.IR rtstats (1)
-.SH FILES
-.B /sys/src/cmd/rtstats/edfproc.c
-as an example of using the scheduler for a trivial test run.
-.B /sys/src/cmd/rtstats/resproc.c
-as an example of using resources.
+.IR trace (1)
+.LP
 .SH SOURCE
-.B /sys/src/9/port/devrealtime.c
-.br
 .B /sys/src/9/port/edf.c
 .SH BUGS
 The admission test does not take multiprocessors into account.  The total

+ 8 - 1
sys/man/8/qer

@@ -15,7 +15,7 @@ qer, runq \- queue management for spooled files
 .br
 .B runq
 [
-.B -adsE
+.B -adsER
 ]
 [
 .B -f
@@ -140,6 +140,13 @@ flag causes all files to be reprocessed regardless of
 the file times.
 .P
 The
+.B -R
+flag instructs
+.I runq
+never to give up on a failed queue job, instead leaving
+it in the queue to be retried.
+.P
+The
 .B -d
 option causes debugging output on standard error
 describing the progress through the queues.

+ 17 - 5
sys/man/8/smtp

@@ -24,7 +24,7 @@ smtp, smtpd \-  mail transport
 .PP
 .B upas/smtpd
 [
-.B -dfr
+.B -dfrg
 ][
 .B -n
 .I netdir
@@ -76,10 +76,7 @@ use
 .I host
 as the local system name;
 it may be fully-qualified or not.  If not
-specified, the local system name will be
-contents of the environment variable
-.BR site .
-If that isn't specified, it will be the contents of
+specified, it will default to the contents of
 .BR /dev/sysname .
 .TP
 .B -f
@@ -115,6 +112,21 @@ turns on debugging output to standard error.
 .B -r
 turns on forward DNS validation of non-trusted sender address.
 .TP
+.B -g
+turns on grey/white list processing.  All mail is rejected (with a
+retry code) unless the sender's IP address is on the whitelist,
+.BR /mail/lib/whitelist .
+Addresses can be added to the whitelist by the administrator.  However,
+the usual way for addresses to be added is by smtpd itself.  Whenever,
+a message is received and the sender's address isn't on the whitelist,
+.B smtpd
+first looks for the file,
+.B /mail/grey/<remote ipaddr>/<local ipaddr>/<recipient> .
+If that file exists, the remote address is added to the whitelist.  If
+not, the file is created and the mail is rejected with a 'try again'
+code.  The expectation is that spammers will not retry and that others
+will.
+.TP
 .B -f
 prevents relaying from non-trusted networks.
 It also tags messages from non-trusted sites when they deliver mail

+ 6 - 3
sys/man/8/stats

@@ -93,12 +93,15 @@ a midrange value represents a strong signal.
 .PD
 .PP
 The graphs are plotted with time on the horizontal axis.
-The vertical axes range from 0 to 1000, multiplied by the number of processors on the machine
+The vertical axes range from 0 to 1000*sleepsecs, 
+multiplied by the number of processors on the machine
 when appropriate.
 The only exceptions are
-memory
+memory,
 and swap space,
-which display fractions of the total available, and the Ethernet error count,
+which display fractions of the total available, 
+system load, which displays a number between 0 and 1000, 
+idle and intr, which display percentages and the Ethernet error count,
 which goes from 0 to 10..
 If the value of the parameter is too large for the visible range, its value is shown
 in decimal in the upper left corner of the graph.

+ 1 - 0
sys/src/9/alphapc/dat.h

@@ -148,6 +148,7 @@ struct Mach
 	ulong	fairness;		/* for runproc */
 
 	vlong	cpuhz;			/* hwrpb->cfreq */
+	uvlong	cyclefreq;		/* Frequency of user readable cycle counter */
 	ulong	pcclast;
 	uvlong	fastclock;
 	Perf	perf;			/* performance counters */

+ 1 - 0
sys/src/9/alphapc/fns.h

@@ -13,6 +13,7 @@ int		cistrcmp(char*, char*);
 int		cistrncmp(char*, char*, int);
 void		cpuidprint(void);
 void		cserve(ulong, ulong);
+#define cycles(x)
 void		timeradd(Timer *);
 void		timerdel(Timer *);
 int	dmacount(int);

+ 19 - 0
sys/src/9/alphapc/l.s

@@ -173,6 +173,25 @@ tas1:
 tas2:
 	RET
 
+TEXT	_xdec(SB), $-8
+	MOVQ	R0, R1		/* p */
+dec1:
+	MOVLL	(R1), R0		/* *p */
+	SUBL		$1, R0
+	MOVQ	R0, R2
+	MOVLC	R2, (R1)		/* --(*p) */
+	BEQ		R2, dec1		/* write failed, retry */
+	RET
+
+TEXT	_xinc(SB), $-8
+	MOVQ	R0, R1		/* p */
+inc1:
+	MOVLL	(R1), R0		/* *p */
+	ADDL	$1, R0
+	MOVLC	R0, (R1)		/* (*p)++ */
+	BEQ		R0, inc1		/* write failed, retry */
+	RET
+
 TEXT	fpenab(SB), $-8
 	MOVQ	R0, R16
 	CALL_PAL $PALwrfen

+ 2 - 1
sys/src/9/alphapc/mkfile

@@ -18,7 +18,8 @@ PORT=\
 	fault.$O\
 	latin1.$O\
 	log.$O\
-	nulledf.$O\
+	edf.$O\
+	mul64fract.$O\
 	page.$O\
 	parse.$O\
 	pgrp.$O\

+ 0 - 1
sys/src/9/bitsy/bitsy

@@ -14,7 +14,6 @@ dev
 	penmouse
 	pipe
 	proc
-	realtime	realtimesub edf
 	cap
 	srv
 	ssl

+ 1 - 0
sys/src/9/bitsy/dat.h

@@ -145,6 +145,7 @@ struct Mach
 
 	int	cpumhz;			/* speed of cpu */
 	vlong	cpuhz;			/* ... */
+	uvlong	cyclefreq;		/* Frequency of user readable cycle counter */
 
 	/* save areas for exceptions */
 	ulong	sfiq[5];

+ 1 - 0
sys/src/9/bitsy/devpenmouse.c

@@ -50,6 +50,7 @@ struct Mousestate
 
 struct Mouseinfo
 {
+	Lock;
 	Mousestate;
 	ulong	lastcounter;	/* value when /dev/mouse read */
 	Rendez	r;

+ 1 - 0
sys/src/9/bitsy/fns.h

@@ -15,6 +15,7 @@ int	cistrncmp(char*, char*, int);
 void	clockinit(void);
 ulong	clockpower(int);
 #define	coherence()
+#define cycles(x)
 #define	dcflush(a, b)
 void	delay(int);
 void	µcpower(int);

+ 22 - 0
sys/src/9/bitsy/main.c

@@ -529,3 +529,25 @@ getconf(char*)
 {
 	return nil;
 }
+
+long
+_xdec(long *p)
+{
+	int x;
+	long v;
+
+	x = splhi();
+	v = --*p;
+	splx(x);
+	return v;
+}
+
+void
+_xinc(long *p)
+{
+	int x;
+
+	x = splhi();
+	++*p;
+	splx(x);
+}

+ 2 - 1
sys/src/9/bitsy/mkfile

@@ -15,8 +15,10 @@ PORT=\
 	cache.$O\
 	chan.$O\
 	dev.$O\
+	edf.$O\
 	fault.$O\
 	latin1.$O\
+	mul64fract.$O\
 	rebootcmd.$O\
 	page.$O\
 	parse.$O\
@@ -24,7 +26,6 @@ PORT=\
 	portclock.$O\
 	print.$O\
 	proc.$O\
-	nulledf.$O\
 	qio.$O\
 	qlock.$O\
 	segment.$O\

+ 13 - 4
sys/src/9/bitsy/trap.c

@@ -6,6 +6,7 @@
 #include	"io.h"
 #include	"ureg.h"
 #include	"../port/error.h"
+#include	"tos.h"
 
 Intrregs *intrregs;
 
@@ -440,9 +441,14 @@ trap(Ureg *ureg)
 		break;
 	}
 
-	splhi();
-	if(user && (up->procctl || up->nnote))
-		notify(ureg);
+	if(user){
+		if(up->delaysched)
+			sched();
+		splhi();
+		if(up->procctl || up->nnote)
+			notify(ureg);
+	}else
+		splhi();
 }
 
 /*
@@ -570,6 +576,9 @@ syscall(Ureg* ureg)
 	if(scallnr == NOTED)
 		noted(ureg, *(ulong*)(sp+BY2WD));
 
+	if(up->delaysched)
+		sched();
+
 	splhi();
 	if(scallnr != RFORK && (up->procctl || up->nnote))
 		notify(ureg);
@@ -826,7 +835,7 @@ execregs(ulong entry, ulong ssize, ulong nargs)
 	ureg->r13 = (ulong)sp;
 	ureg->pc = entry;
 //print("%lud: EXECREGS pc 0x%lux sp 0x%lux\n", up->pid, ureg->pc, ureg->r13);
-	return USTKTOP-BY2WD;		/* address of user-level clock */
+	return USTKTOP-sizeof(Tos);		/* address of kernel/user shared data */
 }
 
 /*

+ 1 - 1
sys/src/9/boot/paq.c

@@ -8,7 +8,7 @@ char *fparts[] =
 	"add params	0x0040000 0x0080000",
 	"add kernel	0x0080000 0x0140000",
 	"add user	0x0140000 0x0200000",
-	"add ramdisk	0x0200000 0x0800000",
+	"add ramdisk	0x0200000 0x0600000",
 };
 
 void

+ 3 - 3
sys/src/9/ip/devip.c

@@ -730,7 +730,7 @@ setladdr(Conv* c)
 /*
  *  set a local port making sure the quad of raddr,rport,laddr,lport is unique
  */
-static char*
+char*
 setluniqueport(Conv* c, int lport)
 {
 	Proto *p;
@@ -764,7 +764,7 @@ setluniqueport(Conv* c, int lport)
 /*
  *  pick a local port and set it
  */
-static void
+void
 setlport(Conv* c)
 {
 	Proto *p;
@@ -813,7 +813,7 @@ setlport(Conv* c)
  *  set a local address and port from a string of the form
  *	[address!]port[!r]
  */
-static char*
+char*
 setladdrport(Conv* c, char* str, int announcing)
 {
 	char *p;

+ 3 - 5
sys/src/9/ip/tcp.c

@@ -49,7 +49,7 @@ enum
 	DEF_MSS		= 1460,		/* Default mean segment */
 	DEF_MSS6	= 1280,		/* Default mean segment (min) for v6 */
 	DEF_RTT		= 500,		/* Default round trip */
-	DEF_KAT		= 30000,	/* Default time ms) between keep alives */
+	DEF_KAT		= 120000,	/* Default time ms) between keep alives */
 	TCP_LISTEN	= 0,		/* Listen connection */
 	TCP_CONNECT	= 1,		/* Outgoing connection */
 	SYNACK_RXTIMER	= 250,		/* ms between SYNACK retransmits */
@@ -2066,9 +2066,7 @@ reset:
 	seg.wnd <<= tcb->rcv.scale;
 
 	if(tcb->kacounter > 0)
-		tcb->kacounter = MAXBACKMS / (tcb->katimer.start*MSPTICK);
-	if(tcb->kacounter < 3)
-		tcb->kacounter = 3;
+		tcpsetkacounter(tcb);
 
 	switch(tcb->state) {
 	case Closed:
@@ -2667,7 +2665,7 @@ tcpsendka(Conv *s)
 void
 tcpsetkacounter(Tcpctl *tcb)
 {
-	tcb->kacounter = MAXBACKMS / (tcb->katimer.start*MSPTICK);;
+	tcb->kacounter = (12 * 60 * 1000) / (tcb->katimer.start*MSPTICK);
 	if(tcb->kacounter < 3)
 		tcb->kacounter = 3;
 }

+ 1 - 0
sys/src/9/mtx/dat.h

@@ -138,6 +138,7 @@ struct Mach
 	ulong	bushz;
 	ulong	dechz;
 	ulong	tbhz;
+	uvlong	cyclefreq;		/* Frequency of user readable cycle counter */
 
 	ulong	pcclast;
 	uvlong	fastclock;

+ 3 - 2
sys/src/9/mtx/fns.h

@@ -8,10 +8,9 @@ void	clockinit(void);
 void	clockintr(Ureg*);
 void	clockintrsched(void);
 #define coherence()	eieio()
-void	timeradd(Timer *);
-void	timerdel(Timer *);
 void	cpuidentify(void);
 void	cpuidprint(void);
+#define cycles(x)
 void	dcflush(void*, ulong);
 void	delay(int);
 void	dumpregs(Ureg*);
@@ -109,6 +108,8 @@ int	screenprint(char*, ...);			/* debugging */
 int	segflush(void*, ulong);
 void	sync(void);
 int	tas(void*);
+void	timeradd(Timer *);
+void	timerdel(Timer *);
 void	touser(void*);
 void	trapinit(void);
 void	trapvec(void);

+ 20 - 0
sys/src/9/mtx/l.s

@@ -281,6 +281,26 @@ tas0:
 	ISYNC
 	RETURN
 
+TEXT	_xinc(SB),$0	/* void _xinc(long *); */
+	MOVW	R3, R4
+xincloop:
+	DCBF	(R4)	/* fix for 603x bug */
+	LWAR	(R4), R3
+	ADD		$1, R3
+	STWCCC	R3, (R4)
+	BNE		xincloop
+	RETURN
+
+TEXT	_xdec(SB),$0	/* long _xdec(long *); */
+	MOVW	R3, R4
+xdecloop:
+	DCBF	(R4)	/* fix for 603x bug */
+	LWAR	(R4), R3
+	ADD		$-1, R3
+	STWCCC	R3, (R4)
+	BNE		xdecloop
+	RETURN
+
 TEXT	getpvr(SB), $0
 	MOVW	SPR(PVR), R3
 	RETURN

+ 2 - 1
sys/src/9/mtx/mkfile

@@ -15,10 +15,11 @@ PORT=\
 	cache.$O\
 	chan.$O\
 	dev.$O\
+	edf.$O\
 	fault.$O\
 	latin1.$O\
 	log.$O\
-	nulledf.$O\
+	mul64fract.$O\
 	rebootcmd.$O\
 	page.$O\
 	parse.$O\

+ 2 - 1
sys/src/9/mtx/trap.c

@@ -5,6 +5,7 @@
 #include	"fns.h"
 #include	"ureg.h"
 #include	"io.h"
+#include	"tos.h"
 #include	"../port/error.h"
 
 static Lock vctllock;
@@ -536,7 +537,7 @@ execregs(ulong entry, ulong ssize, ulong nargs)
 	ureg->usp = (ulong)sp;
 	ureg->pc = entry;
 	ureg->srr1 &= ~MSR_FP;
-	return USTKTOP-BY2WD;		/* address of user-level clock */
+	return USTKTOP-sizeof(Tos);		/* address of kernel/user shared data */
 }
 
 void

+ 18 - 20
sys/src/9/pc/archmp.c

@@ -54,6 +54,18 @@ mpsearch(void)
 	return mpscan(KADDR(0xF0000), 0x10000);
 }
 
+static int identify(void);
+
+PCArch archmp = {
+.id=		"_MP_",	
+.ident=		identify,
+.reset=		mpshutdown,
+.intrinit=	mpinit,
+.intrenable=	mpintrenable,
+.fastclock=	i8253read,
+.timerset=	lapictimerset,
+};
+
 static int
 identify(void)
 {
@@ -86,6 +98,8 @@ identify(void)
 	if(sum || (pcmp->version != 1 && pcmp->version != 4))
 		return 1;
 
+	if(cpuserver && m->havetsc)
+		archmp.fastclock = tscticks;
 	return 0;
 }
 
@@ -102,37 +116,21 @@ syncclock(void)
 	if(m->machno == 0){
 		wrmsr(0x10, 0);
 		m->tscticks = 0;
-		m->tscoff = 0;
 	} else {
 		x = MACHP(0)->tscticks;
 		while(x == MACHP(0)->tscticks)
 			;
-		m->tscoff = MACHP(0)->tscticks;
-		wrmsr(0x10, 0);
-		m->tscticks = 0;
+		wrmsr(0x10, MACHP(0)->tscticks);
+		m->tscticks = MACHP(0)->tscticks;
 	}
 }
 
 uvlong
 tscticks(uvlong *hz)
 {
-	uvlong t;
-
 	if(hz != nil)
 		*hz = m->cpuhz;
 
-	rdtsc(&t);
-	m->tscticks = t;
-
-	return t+m->tscoff;
+	cycles(&m->tscticks);	/* Uses the rdtsc instruction */
+	return m->tscticks;
 }
-
-PCArch archmp = {
-.id=		"_MP_",	
-.ident=		identify,
-.reset=		mpshutdown,
-.intrinit=	mpinit,
-.intrenable=	mpintrenable,
-.fastclock=	i8253read,
-.timerset=	lapictimerset,
-};

+ 1 - 1
sys/src/9/pc/dat.h

@@ -190,6 +190,7 @@ struct Mach
 
 	Lock	apictimerlock;
 	int	cpumhz;
+	uvlong	cyclefreq;		/* Frequency of user readable cycle counter */
 	uvlong	cpuhz;
 	int	cpuidax;
 	int	cpuiddx;
@@ -198,7 +199,6 @@ struct Mach
 	int	havetsc;
 	int	havepge;
 	uvlong	tscticks;
-	uvlong	tscoff;
 
 	vlong	mtrrcap;
 	vlong	mtrrdef;

+ 7 - 7
sys/src/9/pc/ether8390.c

@@ -28,9 +28,9 @@ enum {					/* NIC core registers */
 	Crda0		= 0x08,		/* current remote DMA address 0 */
 	Crda1		= 0x09,		/* current remote DMA address 1 */
 	Rsr		= 0x0C,		/* receive status register */
-	Cntr0		= 0x0D,		/* frame alignment errors */
-	Cntr1		= 0x0E,		/* CRC errors */
-	Cntr2		= 0x0F,		/* missed packet errors */
+	Ref0		= 0x0D,		/* frame alignment errors */
+	Ref1		= 0x0E,		/* CRC errors */
+	Ref2		= 0x0F,		/* missed packet errors */
 
 					/* Page 0, write */
 	Pstart		= 0x01,		/* page start register */
@@ -594,9 +594,9 @@ interrupt(Ureg*, void* arg)
 		}
 
 		if(isr & Cnt){
-			ether->frames += regr(ctlr, Cntr0);
-			ether->crcs += regr(ctlr, Cntr1);
-			ether->buffs += regr(ctlr, Cntr2);
+			ether->frames += regr(ctlr, Ref0);
+			ether->crcs += regr(ctlr, Ref1);
+			ether->buffs += regr(ctlr, Ref2);
 			regw(ctlr, Isr, Cnt);
 		}
 	}
@@ -719,7 +719,7 @@ attach(Ether* ether)
 	regw(ctlr, Isr, 0xFF);
 	regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
 	regw(ctlr, Rcr, r);
-	r = regr(ctlr, Cntr2);
+	r = regr(ctlr, Ref2);
 	regw(ctlr, Tcr, LpbkNORMAL);
 	iunlock(ctlr);
 	USED(r);

+ 2 - 2
sys/src/9/pc/etherga620.c

@@ -628,7 +628,7 @@ ga620interrupt(Ureg*, void* arg)
 	if(!(csr32r(ctlr, Mhc) & Is))
 		return;
 	if(m->havetsc)
-		rdtsc(&tsc0);
+		cycles(&tsc0);
 
 	ctlr->interrupts++;
 	csr32w(ctlr, Hi, 1);
@@ -661,7 +661,7 @@ ga620interrupt(Ureg*, void* arg)
 	}
 
 	if(m->havetsc)
-		rdtsc(&tsc1);
+		cycles(&tsc1);
 	ctlr->ticks += tsc1-tsc0;
 }
 

+ 79 - 20
sys/src/9/pc/etherigbe.c

@@ -13,6 +13,15 @@
  *	add tuning control via ctl file;
  *	this driver is little-endian specific.
  */
+
+#ifdef FS
+#include "all.h"
+#include "io.h"
+#include "mem.h"
+#include "../ip/ip.h"
+
+#else
+
 #include "u.h"
 #include "../port/lib.h"
 #include "mem.h"
@@ -21,10 +30,22 @@
 #include "io.h"
 #include "../port/error.h"
 #include "../port/netif.h"
+#endif			/* FS */
 
 #include "etherif.h"
 #include "ethermii.h"
-
+#include "compat.h"
+
+/* 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 */
@@ -173,6 +194,8 @@ enum {					/* EEPROM content offsets */
 	Ea		= 0x00,		/* Ethernet Address */
 	Cf		= 0x03,		/* Compatibility Field */
 	Pba		= 0x08,		/* Printed Board Assembly number */
+	/* in fs kernel, Icw1 is defined in io.h; changed it here */
+#define Icw1 Igbe_icw1
 	Icw1		= 0x0A,		/* Initialization Control Word 1 */
 	Sid		= 0x0B,		/* Subsystem ID */
 	Svid		= 0x0C,		/* Subsystem Vendor ID */
@@ -557,6 +580,7 @@ static char* statistics[Nstatistics] = {
 	"TCP Segmentation Context Fail",
 };
 
+#ifndef FS
 static long
 igbeifstat(Ether* edev, void* a, long n, ulong offset)
 {
@@ -568,6 +592,8 @@ igbeifstat(Ether* edev, void* a, long n, ulong offset)
 	ctlr = edev->ctlr;
 	qlock(&ctlr->slock);
 	p = malloc(2*READSTR);
+	if (p == nil)
+		panic("igbeifstat: no mem");
 	l = 0;
 	for(i = 0; i < Nstatistics; i++){
 		r = csr32r(ctlr, Statistics+i*4);
@@ -678,6 +704,7 @@ igbectl(Ether* edev, void* buf, long n)
 
 	return n;
 }
+#endif		/* FS */
 
 static void
 igbepromiscuous(void* arg, int on)
@@ -717,9 +744,7 @@ igberballoc(void)
 static void
 igberbfree(Block* bp)
 {
-	bp->rp = bp->lim - Rbsz;
-	bp->wp = bp->rp;
-
+	BLKRESET(bp);
 	ilock(&igberblock);
 	bp->next = igberbpool;
 	igberbpool = bp;
@@ -742,14 +767,14 @@ igbelim(void* ctlr)
 }
 
 static void
-igbelproc(void* arg)
+igbelproc(PROCARG(void *arg))
 {
 	Ctlr *ctlr;
 	Ether *edev;
 	MiiPhy *phy;
 	int ctrl, r;
 
-	edev = arg;
+	edev = GETARG(arg);
 	ctlr = edev->ctlr;
 	for(;;){
 		if(ctlr->mii == nil || ctlr->mii->curphy == nil)
@@ -911,7 +936,7 @@ igbetransmit(Ether* edev)
 	 */
 	tdt = ctlr->tdt;
 	while(NEXT(tdt, ctlr->ntd) != tdh){
-		if((bp = qget(edev->oq)) == nil)
+		if((bp = etheroq(edev)) == nil)
 			break;
 		td = &ctlr->tdba[tdt];
 		td->addr[0] = PCIWADDR(bp->rp);
@@ -1009,7 +1034,7 @@ igberim(void* ctlr)
 }
 
 static void
-igberproc(void* arg)
+igberproc(PROCARG(void *arg))
 {
 	Rd *rd;
 	Block *bp;
@@ -1017,7 +1042,7 @@ igberproc(void* arg)
 	int r, rdh;
 	Ether *edev;
 
-	edev = arg;
+	edev = GETARG(arg);
 	ctlr = edev->ctlr;
 
 	igberxinit(ctlr);
@@ -1048,7 +1073,7 @@ igberproc(void* arg)
 			if((rd->status & Reop) && rd->errors == 0){
 				bp = ctlr->rb[rdh];
 				ctlr->rb[rdh] = nil;
-				bp->wp += rd->length;
+				INCRPTR(bp, rd->length);
 				bp->next = nil;
 				if(!(rd->status & Ixsm)){
 					ctlr->ixsm++;
@@ -1058,7 +1083,9 @@ igberproc(void* arg)
 						 * (and valid as errors == 0).
 						 */
 						ctlr->ipcs++;
+#ifndef FS
 						bp->flag |= Bipck;
+#endif
 					}
 					if(rd->status & Tcpcs){
 						/*
@@ -1066,12 +1093,16 @@ igberproc(void* arg)
 						 * (and valid as errors == 0).
 						 */
 						ctlr->tcpcs++;
+#ifndef FS
 						bp->flag |= Btcpck|Budpck;
+#endif
 					}
+#ifndef FS
 					bp->checksum = rd->checksum;
 					bp->flag |= Bpktck;
+#endif
 				}
-				etheriq(edev, bp, 1);
+				ETHERIQ(edev, bp, 1);
 			}
 			else if(ctlr->rb[rdh] != nil){
 				freeb(ctlr->rb[rdh]);
@@ -1116,6 +1147,8 @@ igbeattach(Ether* edev)
 
 	ctlr->rb = malloc(ctlr->nrd*sizeof(Block*));
 	ctlr->tb = malloc(ctlr->ntd*sizeof(Block*));
+	if (ctlr->tb == nil)
+		panic("igbeattach: no mem");
 
 	if(waserror()){
 		while(ctlr->nrb > 0){
@@ -1567,20 +1600,22 @@ release:
 static void
 igbedetach(Ctlr* ctlr)
 {
-	int r;
+	int r, s;
 
 	/*
 	 * 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.
 	 */
+	s = splhi();		/* in case reset generates an interrupt */
 	csr32w(ctlr, Imc, ~0);
 	csr32w(ctlr, Rctl, 0);
 	csr32w(ctlr, Tctl, 0);
 
-	delay(10);
+	delay(100);		/* was 10 */
 
 	csr32w(ctlr, Ctrl, Devrst);
+	delay(100);		/* new */
 	while(csr32r(ctlr, Ctrl) & Devrst)
 		;
 
@@ -1599,12 +1634,14 @@ igbedetach(Ctlr* ctlr)
 	}
 
 	csr32w(ctlr, Imc, ~0);
+	delay(100);		/* new */
 	while(csr32r(ctlr, Icr))
 		;
+	splx(s);
 }
 
-static int
-igbereset(Ctlr* ctlr)
+int
+etherigbereset(Ctlr* ctlr)
 {
 	int ctrl, i, pause, r, swdpio, txcw;
 
@@ -1741,27 +1778,46 @@ igbepci(void)
 			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\n", cls*4);
+				print("igbe: unexpected CLS - %d bytes\n",
+					cls*sizeof(long));
 				break;
 			case 0x00:
 			case 0xFF:
-				print("igbe: unusable CLS\n");
-				continue;
+				/* 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));
+		if (ctlr == nil)
+			panic("ibgepci: no mem");
 		ctlr->port = port;
 		ctlr->pcidev = p;
 		ctlr->id = (p->did<<16)|p->vid;
 		ctlr->cls = cls*4;
 		ctlr->nic = KADDR(ctlr->port);
 
-		if(igbereset(ctlr)){
+		if(etherigbereset(ctlr)){
 			free(ctlr);
 			continue;
 		}
@@ -1811,18 +1867,21 @@ igbepnp(Ether* edev)
 	edev->attach = igbeattach;
 	edev->transmit = igbetransmit;
 	edev->interrupt = igbeinterrupt;
+#ifndef FS
 	edev->ifstat = igbeifstat;
 	edev->ctl = igbectl;
 
 	edev->arg = edev;
 	edev->promiscuous = igbepromiscuous;
-
+#endif
 	return 0;
 }
 
+#ifndef FS
 void
 etherigbelink(void)
 {
 	addethercard("i82543", igbepnp);
 	addethercard("igbe", igbepnp);
 }
+#endif

+ 2 - 2
sys/src/9/pc/fns.h

@@ -13,6 +13,7 @@ void	(*coherence)(void);
 void	cpuid(char*, int*, int*);
 int	cpuidentify(void);
 void	cpuidprint(void);
+void	cycles(uvlong*);
 void	delay(int);
 int	dmacount(int);
 int	dmadone(int);
@@ -118,13 +119,12 @@ void	pcmspecialclose(int);
 void	(*_pcmspecialclose)(int);
 void	pcmunmap(int, PCMmap*);
 void	printcpufreq(void);
-#define	procrestore(p)
+void	procrestore(Proc*);
 void	procsave(Proc*);
 void	procsetup(Proc*);
 void	putcr3(ulong);
 void	putcr4(ulong);
 void	rdmsr(int, vlong*);
-void	rdtsc(uvlong*);
 void	screeninit(void);
 int	screenprint(char*, ...);			/* debugging */
 void	(*screenputs)(char*, int);

+ 4 - 4
sys/src/9/pc/i8253.c

@@ -139,13 +139,13 @@ guesscpuhz(int aalcycles)
 		 */
 		outb(Tmode, Latch0);
 		if(m->havetsc)
-			rdtsc(&a);
+			cycles(&a);
 		x = inb(T0cntr);
 		x |= inb(T0cntr)<<8;
 		aamloop(loops);
 		outb(Tmode, Latch0);
 		if(m->havetsc)
-			rdtsc(&b);
+			cycles(&b);
 		y = inb(T0cntr);
 		y |= inb(T0cntr)<<8;
 		x -= y;
@@ -176,6 +176,7 @@ guesscpuhz(int aalcycles)
 		 */
 		m->cpumhz = (b+500000)/1000000L;
 		m->cpuhz = b;
+		m->cyclefreq = b;
 	} else {
 		/*
 		 *  add in possible 0.5% error and convert to MHz
@@ -234,7 +235,6 @@ i8253clock(Ureg* ureg, void*)
 void
 i8253enable(void)
 {
-print("i8253enable...");
 	i8253.enabled = 1;
 	i8253.period = Freq/HZ;
 	intrenable(IrqCLOCK, i8253clock, 0, BUSUNKNOWN, "clock");
@@ -306,6 +306,6 @@ perfticks(void)
 
 	if(!m->havetsc)
 		return m->ticks;
-	rdtsc(&x);
+	cycles(&x);
 	return x;
 }

+ 1 - 0
sys/src/9/pc/io.h

@@ -7,6 +7,7 @@ enum {
 	VectorBPT	= 3,		/* breakpoint */
 	VectorUD	= 6,		/* invalid opcode exception */
 	VectorCNA	= 7,		/* coprocessor not available */
+	Vector2F	= 8,		/* double fault */
 	VectorCSO	= 9,		/* coprocessor segment overrun */
 	VectorPF	= 14,		/* page fault */
 	VectorCERR	= 16,		/* coprocessor error */

+ 131 - 4
sys/src/9/pc/l.s

@@ -11,7 +11,7 @@
 #define CPUID		BYTE $0x0F; BYTE $0xA2	/* CPUID, argument in AX */
 #define WRMSR		BYTE $0x0F; BYTE $0x30	/* WRMSR, argument in AX/DX (lo/hi) */
 #define RDMSR		BYTE $0x0F; BYTE $0x32	/* RDMSR, result in AX/DX (lo/hi) */
-#define RDTSC 		BYTE $0x0F; BYTE $0x31
+#define RDTSC 		BYTE $0x0F; BYTE $0x31	/* RDTSC, result in AX/DX (lo/hi) */
 #define WBINVD		BYTE $0x0F; BYTE $0x09
 #define HLT		BYTE $0xF4
 #define SFENCE		BYTE $0x0F; BYTE $0xAE; BYTE $0xF8
@@ -47,6 +47,31 @@ TEXT _start0x80100020(SB),$0
 TEXT _start0x00100020(SB),$0
 	CLI					/* make sure interrupts are off */
 
+	/* set up the gdt so we have sane plan 9 style gdts. */
+	MOVL	$tgdtptr(SB), AX
+	ANDL	$~KZERO, AX
+	MOVL	(AX), GDTR
+	MOVW	$1, AX
+	MOVW	AX,MSW
+
+	/* clear prefetch queue (weird code to avoid optimizations) */
+	DELAY
+
+	/* set segs to something sane (avoid traps later) */
+	MOVW	$(1<<3),AX
+	MOVW	AX,DS
+	MOVW	AX,SS
+	MOVW	AX,ES
+	MOVW	AX,FS
+	MOVW	AX,GS
+
+/*	JMP	$(2<<3):$mode32bit(SB) /**/
+	 BYTE	$0xEA
+	 LONG	$mode32bit-KZERO(SB)
+	 WORD	$(2<<3)
+TEXT	mode32bit(SB),$0
+	/* At this point, the GDT setup is done. */
+
 	MOVL	$PADDR(CPU0PDB), DI		/* clear 4 pages for the tables etc. */
 	XORL	AX, AX
 	MOVL	$(4*BY2PG), CX
@@ -94,6 +119,33 @@ _setpte:
 	MOVL	DX, CR0				/* turn on paging */
 	JMP*	AX				/* jump to the virtual nirvana */
 
+/*
+ *  gdt to get us to 32-bit/segmented/unpaged mode
+ */
+TEXT	tgdt(SB),$0
+
+	/* null descriptor */
+	LONG	$0
+	LONG	$0
+
+	/* data segment descriptor for 4 gigabytes (PL 0) */
+	LONG	$(0xFFFF)
+	LONG	$(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
+
+	/* exec segment descriptor for 4 gigabytes (PL 0) */
+	LONG	$(0xFFFF)
+	LONG	$(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
+
+/*
+ *  pointer to initial gdt
+ *  Note the -KZERO which puts the physical address in the gdtptr. 
+ *  that's needed as we start executing in physical addresses. 
+ */
+TEXT	tgdtptr(SB),$0
+
+	WORD	$(3*8)
+	LONG	$tgdt-KZERO(SB)
+
 /*
  * Basic machine environment set, can clear BSS and create a stack.
  * The stack starts at the top of the page containing the Mach structure.
@@ -278,17 +330,31 @@ TEXT putcr4(SB), $0
 	MOVL	AX, CR4
 	RET
 
-TEXT rdtsc(SB), $0				/* time stamp counter; cycles since power up */
+TEXT cycles(SB), $0				/* time stamp counter; cycles since power up */
 	RDTSC
-	MOVL	vlong+0(FP), CX			/* &vlong */
+	MOVL	vlong+0(FP), CX	/* &vlong */
 	MOVL	AX, 0(CX)			/* lo */
 	MOVL	DX, 4(CX)			/* hi */
 	RET
 
+TEXT rd0(SB), $0
+	MOVL	vlong+0(FP), CX
+	MOVL	$0, 0(CX)
+	MOVL	$0, 4(CX)
+	RET
+
+TEXT rdmsr10(SB), $0
+	MOVL	$0x10, CX
+	RDMSR
+	MOVL	vlong+0(FP), CX
+	MOVL	AX, 0(CX)
+	MOVL	DX, 4(CX)
+	RET
+
 TEXT rdmsr(SB), $0				/* model-specific register */
 	MOVL	index+0(FP), CX
 	RDMSR
-	MOVL	vlong+4(FP), CX			/* &vlong */
+	MOVL	vlong+4(FP), CX	/* &vlong */
 	MOVL	AX, 0(CX)			/* lo */
 	MOVL	DX, 4(CX)			/* hi */
 	RET
@@ -449,6 +515,7 @@ TEXT splx(SB), $0
 	MOVL	$(MACHADDR+0x04), AX 		/* save PC in m->splpc */
 	MOVL	(SP), BX
 	MOVL	BX, (AX)
+	/* fall through */
 
 TEXT splxpc(SB), $0				/* for iunlock */
 	MOVL	s+0(FP), AX
@@ -474,6 +541,23 @@ TEXT tas(SB), $0
 	XCHGL	AX, (BX)			/* lock->key */
 	RET
 
+TEXT	_xinc(SB),$0	/* void _xinc(long *); */
+	MOVL	l+0(FP),AX
+	LOCK
+	INCL	0(AX)
+	RET
+
+TEXT	_xdec(SB),$0	/* long _xdec(long *); */
+	MOVL	l+0(FP),AX
+	LOCK
+	DECL	0(AX)
+	JZ	iszero
+	MOVL	$1, AX
+	RET
+iszero:
+	MOVL	$0, AX
+	RET
+
 TEXT wbflush(SB), $0
 	CPUID
 	RET
@@ -492,6 +576,49 @@ TEXT xchgl(SB), $0
 	RET
  */
 
+TEXT	mul64fract(SB), $0
+	/* mul64fract(uvlong*r, uvlong a, uvlong b)
+	 *
+	 * multiply uvlong a by uvlong b and return a uvlong result.
+	 *
+	 * One of the input arguments is a uvlong integer,
+	 * the other represents a fractional number with
+	 * the integer portion in the most significant word and
+	 * the fractional portion in the least significant word.
+	 *
+	 * Example: mul64fract(&r, 2ULL, 3ULL << 31) returns 1ULL
+	 *
+	 * The uvlong integer result is returned through r
+	 *
+	 *	ignored		r0 = lo(a0*b0)
+	 *	lsw of result	r1 = hi(a0*b0) +lo(a0*b1) +	lo(a1*b0)
+	 *	msw of result	r2 = 		hi(a0*b1) +	hi(a1*b0) +	lo(a1*b1)
+	 *	ignored		r3 =						hi(a1*b1)
+	 */
+
+	MOVL	r+0(FP), CX
+	XORL	BX, BX		/* BX = 0 */
+
+	MOVL	a+8(FP),AX
+	MULL	b+16(FP)	/* a1*b1 */
+	MOVL	AX, 4(CX)	/* r2 = lo(a1*b1) */
+
+	MOVL	a+8(FP), AX
+	MULL	b+12(FP)	/* a1*b0 */
+	MOVL	AX, 0(CX)	/* r1 = lo(a1*b0) */
+	ADDL	DX, 4(CX)	/* r2 += hi(a1*b0) */
+
+	MOVL	a+4(FP), AX
+	MULL	b+16(FP)	/* a0*b1 */
+	ADDL	AX, 0(CX)	/* r1 += lo(a0*b1) */
+	ADCL	DX, 4(CX)	/* r2 += hi(a0*b1) + carry */
+
+	MOVL	a+4(FP), AX
+	MULL	b+12(FP)	/* a0*b0 */
+	ADDL	DX, 0(CX)	/* r1 += hi(a0*b0) */
+	ADCL	BX, 4(CX)	/* r2 += carry */
+	RET
+
 /*
  *  label consists of a stack pointer and a PC
  */

+ 18 - 1
sys/src/9/pc/main.c

@@ -548,18 +548,35 @@ mathinit(void)
  *  set up floating point for a new process
  */
 void
-procsetup(Proc *p)
+procsetup(Proc*p)
 {
 	p->fpstate = FPinit;
 	fpoff();
 }
 
+void
+procrestore(Proc *p)
+{
+	uvlong t;
+
+	if(p->kp || m->havetsc == 0)
+		return;
+	cycles(&t);
+	p->pcycles -= t;
+}
+
 /*
  *  Save the mach dependent part of the process state.
  */
 void
 procsave(Proc *p)
 {
+	uvlong t;
+
+	if(m->havetsc){
+		cycles(&t);
+		p->pcycles += t;
+	}
 	if(p->fpstate == FPactive){
 		if(p->state == Moribund)
 			fpoff();

+ 5 - 3
sys/src/9/pc/mkfile

@@ -1,5 +1,6 @@
 CONF=pc
-CONFLIST=pc pccpu pcdisk pcauth
+CONFLIST=pc pccpu pcf pccpuf pcdisk pcauth
+CRAPLIST=pccd pccpud pccpusape pcext pcf pcflop pcglenda pcgr pclml pcmartha pcsape pcblast
 
 objtype=386
 </$objtype/mkfile
@@ -17,7 +18,7 @@ PORT=\
 	dev.$O\
 	fault.$O\
 	latin1.$O\
-	nulledf.$O\
+	edf.$O\
 	page.$O\
 	parse.$O\
 	pgrp.$O\
@@ -74,7 +75,7 @@ $p$CONF.gz: $p$CONF
 
 install:V: $p$CONF $p$CONF.gz
 	cp $p$CONF $p$CONF.gz /$objtype/
-	# import lookout / /n/lookout && cp $p$CONF $p$CONF.gz /n/lookout/$objtype/
+	import lookout / /n/lookout && cp $p$CONF $p$CONF.gz /n/lookout/$objtype/
 
 <../boot/bootmkfile
 <../port/portmkfile
@@ -92,6 +93,7 @@ main.$O:			init.h reboot.h
 wavelan.$O:	wavelan.c ../pc/wavelan.c ../pc/wavelan.h
 etherwavelan.$O:	etherwavelan.c  ../pc/wavelan.h
 devusb.$O usbuhci.$O usbohci.$O:	usb.h
+trap.$O:	/sys/include/tos.h
 
 sd53c8xx.i:	sd53c8xx.n
 	aux/na $prereq > $target

+ 4 - 4
sys/src/9/pc/pc

@@ -1,6 +1,7 @@
 dev
 	root
 	cons
+
 	arch
 	pnp		pci
 	env
@@ -14,7 +15,6 @@ dev
 	tls
 	cap
 	kprof
-	realtime	realtimesub edf
 
 	ether		netif
 	ip		arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum386 inferno
@@ -29,7 +29,7 @@ dev
 
 	audio		dma
 	pccard
-	i82365		cis	
+	i82365		cis
 	uart
 	usb
 	tv
@@ -63,7 +63,7 @@ misc
 	archmp		mp apic
 
 	sdata		pci sdscsi
-	sd53c8xx	pci sdscsi
+	sd53c8xx		pci sdscsi
 	sdmylex		pci sdscsi
 
 	uarti8250
@@ -81,6 +81,7 @@ misc
 	vgai81x	+cur
 	vgamach64xx	+cur
 	vgamga2164w	+cur
+	vgamga4xx	+cur
 	vganeomagic	+cur
 	vganvidia	+cur
 	vgargb524	=cur
@@ -89,7 +90,6 @@ misc
 	vgatvp3020	=cur
 	vgatvp3026	=cur
 	vgavmware	+cur
-	vgamga4xx	+cur
 
 ip
 	il

+ 0 - 1
sys/src/9/pc/pccpu

@@ -16,7 +16,6 @@ dev
 	sdp		thwack unthwack
 	cap
 	kprof
-	realtime	realtimesub edf
 
 	ether		netif
 	ip		arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum386 inferno

+ 26 - 1
sys/src/9/pc/pccpuf

@@ -16,11 +16,14 @@ dev
 	sdp		thwack unthwack
 	cap
 	kprof
-	realtime	realtimesub edf
 
 	ether		netif
 	ip		arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum386 inferno
 
+	draw		screen vga vgax
+	mouse		mouse
+	vga
+
 	sd
 	floppy		dma
 
@@ -54,6 +57,28 @@ misc
 	sdata		pci sdscsi
 	sd53c8xx	pci sdscsi
 
+	vga3dfx		+cur
+	vgaark2000pv	+cur
+	vgabt485	=cur
+	vgaclgd542x	+cur
+	vgaclgd546x	+cur
+	vgact65545	+cur
+	vgacyber938x	+cur
+	vgaet4000	+cur
+	vgahiqvideo	+cur
+	vgai81x	+cur
+	vgamach64xx	+cur
+	vgamga2164w	+cur
+	vgamga4xx	+cur
+	vganeomagic	+cur
+	vganvidia	+cur
+	vgargb524	=cur
+	vgas3		+cur vgasavage
+	vgat2r4		+cur
+	vgatvp3020	=cur
+	vgatvp3026	=cur
+	vgavmware	+cur
+
 
 ip
 	il

+ 0 - 2
sys/src/9/pc/pcdisk

@@ -14,7 +14,6 @@ dev
 	tls
 	cap
 	kprof
-	realtime	realtimesub edf
 
 	ether		netif
 	ip		arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum386 inferno
@@ -24,7 +23,6 @@ dev
 	vga
 
 	sd
-	fs
 	floppy		dma
 	lpt
 

+ 0 - 1
sys/src/9/pc/pcf

@@ -14,7 +14,6 @@ dev
 	tls
 	cap
 	kprof
-	realtime	realtimesub edf
 
 	ether		netif
 	ip		arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum386 inferno

+ 3 - 4
sys/src/9/pc/pcflop

@@ -14,7 +14,6 @@ dev
 #	tls
 	cap
 #	kprof
-#	realtime	realtimesub edf
 
 	ether		netif
 	ip		arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum386 inferno
@@ -49,7 +48,7 @@ link
 	etherec2t	ether8390
 	etherelnk3	pci
 	etherga620	pci
-	etherigbe pci ethermii
+	etherigbe	pci ethermii
 #	ethersink
 	ethersmc	devi82365 cis
 	etherwavelan	wavelan devi82365 cis pci
@@ -63,7 +62,7 @@ misc
 #	archmp		mp apic
 
 	sdata		pci sdscsi
-	sd53c8xx		pci sdscsi
+	sd53c8xx	pci sdscsi
 	sdmylex		pci sdscsi
 
 	uarti8250
@@ -77,7 +76,7 @@ misc
 	vgacyber938x	+cur
 	vgaet4000	+cur
 	vgahiqvideo	+cur
-	vgai81x	+cur
+	vgai81x		+cur
 	vgamach64xx	+cur
 	vgamga2164w	+cur
 	vgamga4xx	+cur

+ 3 - 3
sys/src/9/pc/piix4smbus.c

@@ -96,7 +96,7 @@ transact(SMBus *s, int type, int addr, int cmd, uchar *data)
 	for(tries = 0; tries < 1000000; tries++){
 		if((inb(s->base+Hoststatus) & Host_busy) == 0)
 			break;
-		sched();
+		sched(nil);
 	}
 	if(tries >= 1000000){
 		// try aborting current transaction
@@ -104,7 +104,7 @@ transact(SMBus *s, int type, int addr, int cmd, uchar *data)
 		for(tries = 0; tries < 1000000; tries++){
 			if((inb(s->base+Hoststatus) & Host_busy) == 0)
 				break;
-			sched();
+			sched(nil);
 		}
 		if(tries >= 1000000){
 			snprint(err, sizeof(err), "SMBus jammed: %2.2ux", inb(s->base+Hoststatus));
@@ -138,7 +138,7 @@ transact(SMBus *s, int type, int addr, int cmd, uchar *data)
 		status = inb(s->base+Hoststatus);
 		if(status & (Failed|Bus_error|Dev_error|Host_complete))
 			break;
-		sched();
+		sched(nil);
 	}
 	if((status & Host_complete) == 0){
 		snprint(err, sizeof(err), "SMBus request failed: %2.2ux", status);

+ 1 - 0
sys/src/9/pc/sdata.c

@@ -1898,6 +1898,7 @@ atapnp(void)
 		case (0x244B<<16)|0x8086:	/* 82801BA (ICH2, High-End) */
 		case (0x248A<<16)|0x8086:	/* 82801CA (ICH3, Mobile) */
 		case (0x248B<<16)|0x8086:	/* 82801CA (ICH3, High-End) */
+		case (0x24CA<<16)|0x8086:	/* 82801DBM (ICH4, Mobile) */
 		case (0x24CB<<16)|0x8086:	/* 82801DB (ICH4, High-End) */
 		case (0x24DB<<16)|0x8086:	/* 82801EB (ICH5) */
 			break;

+ 96 - 22
sys/src/9/pc/trap.c

@@ -1,4 +1,5 @@
 #include	"u.h"
+#include	"tos.h"
 #include	"../port/lib.h"
 #include	"mem.h"
 #include	"dat.h"
@@ -11,15 +12,16 @@ void	noted(Ureg*, ulong);
 
 static void debugbpt(Ureg*, void*);
 static void fault386(Ureg*, void*);
+static void doublefault(Ureg*, void*);
 
 static Lock vctllock;
 static Vctl *vctl[256];
-ulong *intrtimes[256];
 
 enum
 {
-	Ntimevec = 1000		/* number of time buckets for each intr */
+	Ntimevec = 10		/* number of time buckets for each intr */
 };
+ulong intrtimes[256][Ntimevec];
 
 void
 intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
@@ -58,8 +60,6 @@ intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
 				vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
 		v->next = vctl[vno];
 	}
-	if(intrtimes[vno] == nil)
-		intrtimes[vno] = xalloc(Ntimevec*sizeof(ulong));
 	vctl[vno] = v;
 	iunlock(&vctllock);
 }
@@ -89,7 +89,7 @@ intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
 	v = *pv;
 	*pv = (*pv)->next;	/* Link out the entry */
 	
-	if (vctl[vno] == nil && arch->intrdisable != nil)
+	if(vctl[vno] == nil && arch->intrdisable != nil)
 		arch->intrdisable(irq);
 	iunlock(&vctllock);
 	xfree(v);
@@ -208,6 +208,7 @@ trapinit(void)
 	 */
 	trapenable(VectorBPT, debugbpt, 0, "debugpt");
 	trapenable(VectorPF, fault386, 0, "fault386");
+	trapenable(Vector2F, doublefault, 0, "doublefault");
 
 	nmienable();
 
@@ -256,8 +257,9 @@ void
 intrtime(Mach*, int vno)
 {
 	ulong diff;
-	ulong x = perfticks();
+	ulong x;
 
+	x = perfticks();
 	diff = x - m->perf.intrts;
 	m->perf.intrts = x;
 
@@ -265,13 +267,29 @@ intrtime(Mach*, int vno)
 	if(up == nil && m->perf.inidle > diff)
 		m->perf.inidle -= diff;
 
-	diff /= m->cpumhz;
-	if(diff >= Ntimevec){
+	diff /= m->cpumhz*10;	// quantum = 10µsec
+	if(diff >= Ntimevec)
 		diff = Ntimevec-1;
-	}
 	intrtimes[vno][diff]++;
 }
 
+/* go to user space */
+void
+kexit(Ureg*)
+{
+	uvlong t;
+	Tos *tos;
+
+	/* precise time accounting, kernel exit */
+	tos = (Tos*)(USTKTOP-sizeof(Tos));
+	if(m->havetsc){
+		cycles(&t);
+		tos->kcycles += t - up->kentry;
+	}
+	tos->pcycles = up->pcycles;
+	tos->pid = up->pid;
+}
+
 /*
  *  All traps come here.  It is slower to have all traps call trap()
  *  rather than directly vectoring the handler.  However, this avoids a
@@ -286,12 +304,18 @@ trap(Ureg* ureg)
 	char buf[ERRMAX];
 	Vctl *ctl, *v;
 	Mach *mach;
+	Ureg urcopy;
+	ulong *u;
+
+	urcopy = *ureg;
+	memset(buf, 0, sizeof(buf));
 
 	m->perf.intrts = perfticks();
-	user = 0;
-	if((ureg->cs & 0xFFFF) == UESEL){
-		user = 1;
+	user = (ureg->cs & 0xFFFF) == UESEL;
+	if(user){
 		up->dbgreg = ureg;
+		if (m->havetsc)
+			cycles(&up->kentry);
 	}
 
 	vno = ureg->trap;
@@ -305,8 +329,20 @@ trap(Ureg* ureg)
 		if(ctl->isr)
 			ctl->isr(vno);
 		for(v = ctl; v != nil; v = v->next){
-			if(v->f)
+			if(v->f){
 				v->f(ureg, v->a);
+				if (vno & ~0xff){
+					u = (ulong*)&u;
+					for(i = 0; i < 40; ++i && (u+=4))
+						iprint("0x%lux:	0x%lux	0x%lux	0x%lux	0x%lux\n", u, u[0], u[1], u[2], u[3]);
+					iprint("vno 0x%ux after calling %s\n", vno, v->name);
+					iprint("ureg di si bp nsp bx dx cx ax gs fs es ds trap ecode pc cs flags sp ss\n");
+					u = (ulong*)ureg;
+					for(i = 0; i < 19; i++)
+						iprint("0x%lux ", u[i]);
+					panic("vno");
+				}
+			}
 		}
 		if(ctl->eoi)
 			ctl->eoi(vno);
@@ -363,6 +399,12 @@ trap(Ureg* ureg)
 		}
 		print("\n");
 		m->spuriousintr++;
+		if(user){
+			/* if we delayed sched because we held a lock, sched now */
+			if(up->delaysched)
+				sched();
+			kexit(ureg);
+		}
 		return;
 	}
 	else{
@@ -380,9 +422,15 @@ trap(Ureg* ureg)
 		panic("unknown trap/intr: %d\n", vno);
 	}
 
-	if(user && (up->procctl || up->nnote)){
-		splhi();
-		notify(ureg);
+	if(user){
+		if(up->procctl || up->nnote){
+			splhi();
+			notify(ureg);
+		}
+		/* if we delayed sched because we held a lock, sched now */
+		if(up->delaysched)
+			sched();
+		kexit(ureg);
 	}
 }
 
@@ -509,6 +557,13 @@ debugbpt(Ureg* ureg, void*)
 	postnote(up, 1, buf, NDebug);
 }
 
+static void
+doublefault(Ureg*, void*)
+{
+	panic("double fault");
+}
+
+
 static void
 fault386(Ureg* ureg, void*)
 {
@@ -552,17 +607,25 @@ syscall(Ureg* ureg)
 	char *e;
 	ulong	sp;
 	long	ret;
-	int	i;
+	int	i, s;
 	ulong scallnr;
 
 	if((ureg->cs & 0xFFFF) != UESEL)
 		panic("syscall: cs 0x%4.4luX\n", ureg->cs);
 
+	if (m->havetsc)
+		cycles(&up->kentry);
+
 	m->syscall++;
 	up->insyscall = 1;
 	up->pc = ureg->pc;
 	up->dbgreg = ureg;
 
+	if(up->procctl == Proc_tracesyscall){
+		up->procctl = Proc_stopme;
+		procctl(up);
+	}
+
 	scallnr = ureg->ax;
 	up->scallnr = scallnr;
 	if(scallnr == RFORK && up->fpstate == FPactive){
@@ -599,16 +662,13 @@ syscall(Ureg* ureg)
 			print("syscall %lud error %s\n", scallnr, up->syserrstr);
 	}
 	if(up->nerrlab){
-		print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
+		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
 		for(i = 0; i < NERR; i++)
 			print("sp=%lux pc=%lux\n",
 				up->errlab[i].sp, up->errlab[i].pc);
 		panic("error stack");
 	}
 
-	up->insyscall = 0;
-	up->psstate = 0;
-
 	/*
 	 *  Put return value in frame.  On the x86 the syscall is
 	 *  just another trap and the return value from syscall is
@@ -617,6 +677,16 @@ syscall(Ureg* ureg)
 	 */
 	ureg->ax = ret;
 
+	if(up->procctl == Proc_tracesyscall){
+		up->procctl = Proc_stopme;
+		s = splhi();
+		procctl(up);
+		splx(s);
+	}
+
+	up->insyscall = 0;
+	up->psstate = 0;
+
 	if(scallnr == NOTED)
 		noted(ureg, *(ulong*)(sp+BY2WD));
 
@@ -624,6 +694,10 @@ syscall(Ureg* ureg)
 		splhi();
 		notify(ureg);
 	}
+	/* if we delayed sched because we held a lock, sched now */
+	if(up->delaysched)
+		sched();
+	kexit(ureg);
 }
 
 /*
@@ -814,7 +888,7 @@ execregs(ulong entry, ulong ssize, ulong nargs)
 	ureg = up->dbgreg;
 	ureg->usp = (ulong)sp;
 	ureg->pc = entry;
-	return USTKTOP-BY2WD;		/* address of user-level clock */
+	return USTKTOP-sizeof(Tos);		/* address of kernel/user shared data */
 }
 
 /*

+ 69 - 28
sys/src/9/pc/uarti8250.c

@@ -48,7 +48,7 @@ enum {					/* Iir */
 	Irls		= 0x06,		/* Receiver Line Status */
 	Ictoi		= 0x0C,		/* Character Time-out Indication */
 	IirMASK		= 0x3F,
-	Ife		= 0xC0,		/* FIFOs enabled */
+	Ifena		= 0xC0,		/* FIFOs enabled */
 };
 
 enum {					/* Fcr */
@@ -114,7 +114,8 @@ typedef struct Ctlr {
 	uchar	sticky[8];
 
 	Lock;
-	int	fifo;
+	int	hasfifo;
+	int	checkfifo;
 	int	fena;
 } Ctlr;
 
@@ -194,36 +195,50 @@ i8250status(Uart* uart, void* buf, long n, long offset)
 }
 
 static void
-i8250fifo(Uart* uart, int on)
+i8250fifo(Uart* uart, int level)
 {
-	int i;
 	Ctlr *ctlr;
 
-	/*
-	 * Toggle FIFOs:
-	 * if none, do nothing;
-	 * reset the Rx and Tx FIFOs;
-	 * empty the Rx buffer and clear any interrupt conditions;
-	 * if enabling, try to turn them on.
-	 */
 	ctlr = uart->regs;
+	if(ctlr->hasfifo == 0)
+		return;
 
+	/*
+	 * Changing the FIFOena bit in Fcr flushes data
+	 * from both receive and transmit FIFOs; there's
+	 * no easy way to guarantee not losing data on
+	 * the receive side, but it's possible to wait until
+	 * the transmitter is really empty.
+	 */
 	ilock(ctlr);
-	if(!ctlr->fifo){
-		csr8w(ctlr, Fcr, FIFOtclr|FIFOrclr);
-		for(i = 0; i < 16; i++){
-			csr8r(ctlr, Iir);
-			csr8r(ctlr, Rbr);
-		}
-  
-		ctlr->fena = 0;
-		if(on){
-			csr8w(ctlr, Fcr, FIFO1|FIFOena);
-			if(!(csr8r(ctlr, Iir) & Ife))
-				ctlr->fifo = 1;
-			ctlr->fena = 1;
-		}
+	while(!(csr8r(ctlr, Lsr) & Temt))
+		;
+
+	/*
+	 * Set the trigger level, default is the max.
+	 * value.
+	 * Some UARTs require FIFOena to be set before
+	 * other bits can take effect, so set it twice.
+	 */
+	ctlr->fena = level;
+	switch(level){
+	case 0:
+		break;
+	case 1:
+		level = FIFO1|FIFOena;
+		break;
+	case 4:
+		level = FIFO4|FIFOena;
+		break;
+	case 8:
+		level = FIFO8|FIFOena;
+		break;
+	default:
+		level = FIFO14|FIFOena;
+		break;
 	}
+	csr8w(ctlr, Fcr, level);
+	csr8w(ctlr, Fcr, level);
 	iunlock(ctlr);
 }
 
@@ -533,13 +548,40 @@ i8250enable(Uart* uart, int ie)
 {
 	Ctlr *ctlr;
 
+	ctlr = uart->regs;
+
+	/*
+	 * Check if there is a FIFO.
+	 * Changing the FIFOena bit in Fcr flushes data
+	 * from both receive and transmit FIFOs; there's
+	 * no easy way to guarantee not losing data on
+	 * the receive side, but it's possible to wait until
+	 * the transmitter is really empty.
+	 * Also, reading the Iir outwith i8250interrupt()
+	 * can be dangerous, but this should only happen
+	 * once, before interrupts are enabled.
+	 */
+	ilock(ctlr);
+	if(!ctlr->checkfifo){
+		/*
+		 * Wait until the transmitter is really empty.
+		 */
+		while(!(csr8r(ctlr, Lsr) & Temt))
+			;
+		csr8w(ctlr, Fcr, FIFOena);
+		if(csr8r(ctlr, Iir) & Ifena)
+			ctlr->hasfifo = 1;
+		csr8w(ctlr, Fcr, 0);
+		ctlr->checkfifo = 1;
+	}
+	iunlock(ctlr);
+
 	/*
  	 * Enable interrupts and turn on DTR and RTS.
 	 * Be careful if this is called to set up a polled serial line
 	 * early on not to try to enable interrupts as interrupt-
 	 * -enabling mechanisms might not be set up yet.
 	 */
-	ctlr = uart->regs;
 	if(ie){
 		if(ctlr->iena == 0){
 			intrenable(ctlr->irq, i8250interrupt, uart, ctlr->tbdf, uart->name);
@@ -558,7 +600,6 @@ i8250enable(Uart* uart, int ie)
 	(*uart->phys->dtr)(uart, 1);
 	(*uart->phys->rts)(uart, 1);
 
-
 	/*
 	 * During startup, the i8259 interrupt controller is reset.
 	 * This may result in a lost interrupt from the i8250 uart.
@@ -659,10 +700,10 @@ i8250console(void)
 		break;	
 	}
 
+	(*uart->phys->enable)(uart, 0);
 	uartctl(uart, "b9600 l8 pn s1");
 	if(*cmd != '\0')
 		uartctl(uart, cmd);
-	(*uart->phys->enable)(uart, 0);
 
 	consuart = uart;
 	uart->console = 1;

+ 0 - 22
sys/src/9/port/alarm.c

@@ -51,28 +51,6 @@ checkalarms(void)
 
 	if(p && p->alarm <= now)
 		wakeup(&alarmr);
-
-	if(talarm.list == 0 || !canlock(&talarm))
-		return;
-
-	for(;;) {
-		p = talarm.list;
-		if(p == 0)
-			break;
-
-		if(p->twhen == 0) {
-			talarm.list = p->tlink;
-			p->trend = 0;
-			continue;
-		}
-		if(now < p->twhen)
-			break;
-		wakeup(p->trend);
-		talarm.list = p->tlink;
-		p->trend = 0;
-	}
-
-	unlock(&talarm);
 }
 
 ulong

+ 1 - 1
sys/src/9/port/alloc.c

@@ -112,7 +112,7 @@ punlock(Pool *p)
 
 	memmove(msg, pv->msg, sizeof msg);
 	iunlock(&pv->lk);
-	print("%.*s", sizeof pv->msg, msg);
+	iprint("%.*s", sizeof pv->msg, msg);
 }
 
 void

+ 2 - 2
sys/src/9/port/allocb.c

@@ -80,14 +80,14 @@ iallocb(int size)
 
 	if(ialloc.bytes > conf.ialloc){
 		if((m1++%10000)==0)
-			print("iallocb: limited %lud/%lud\n",
+			iprint("iallocb: limited %lud/%lud\n",
 				ialloc.bytes, conf.ialloc);
 		return 0;
 	}
 
 	if((b = _allocb(size)) == nil){
 		if((m2++%10000)==0)
-			print("iallocb: no memory %lud/%lud\n",
+			iprint("iallocb: no memory %lud/%lud\n",
 				ialloc.bytes, conf.ialloc);
 		return nil;
 	}

+ 9 - 9
sys/src/9/port/chan.c

@@ -93,27 +93,27 @@ isdotdot(char *p)
 	return p[0]=='.' && p[1]=='.' && p[2]=='\0';
 }
 
-int
+long
 incref(Ref *r)
 {
-	int x;
+	long x;
 
-	lock(r);
+	lock(&r->l);
 	x = ++r->ref;
-	unlock(r);
+	unlock(&r->l);
 	return x;
 }
 
-int
+long
 decref(Ref *r)
 {
-	int x;
+	long x;
 
-	lock(r);
+	lock(&r->l);
 	x = --r->ref;
-	unlock(r);
+	unlock(&r->l);
 	if(x < 0)
-		panic("decref, pc=0x%lux", getcallerpc(&r));
+		panic("deccnt pc=0x%lux", getcallerpc(&r));
 
 	return x;
 }

+ 1 - 4
sys/src/9/port/dev.c

@@ -309,10 +309,7 @@ long
 devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen)
 {
 	long m, dsz;
-	struct{
-		Dir;
-		char slop[100];
-	}dir;
+	Dir dir;
 
 	for(m=0; m<n; c->dri++) {
 		switch((*gen)(c, nil, tab, ntab, c->dri, &dir)){

+ 1 - 1
sys/src/9/port/devaudio.c

@@ -603,7 +603,7 @@ waitaudio(void)
 
 	audio.intr = 0;
 	pokeaudio();
-	tsleep(&audio.vous, anybuf, 0, 10*1000);
+	tsleep(&audio.vous, anybuf, 0, 10000);
 	if(audio.intr == 0) {
 /*		print("#A: audio timeout\n");	/**/
 		audio.active = 0;

+ 6 - 0
sys/src/9/port/devcons.c

@@ -54,12 +54,14 @@ static int	writebintime(char*, int);
 
 enum
 {
+	CMhalt,
 	CMreboot,
 	CMpanic,
 };
 
 Cmdtab rebootmsg[] =
 {
+	CMhalt,		"halt",		1,
 	CMreboot,	"reboot",	0,
 	CMpanic,	"panic",	0,
 };
@@ -1000,10 +1002,14 @@ conswrite(Chan *c, void *va, long n, vlong off)
 		}
 		ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
 		switch(ct->index) {
+		case CMhalt:
+			reboot(nil, 0, 0);
+			break;
 		case CMreboot:
 			rebootcmd(cb->nf-1, cb->f+1);
 			break;
 		case CMpanic:
+			*(ulong*)0=0;
 			panic("/dev/reboot");
 		}
 		poperror();

+ 5 - 2
sys/src/9/port/devfs.c

@@ -267,17 +267,20 @@ rdconf(void)
 	cc = nil;
 	USED(cc); // on errors
 	if (strncmp(confstr, Cfgstr, strlen(Cfgstr)) != 0)
-		error("Bad config");
+		error("Bad config: should begin with: fsdev\\n");
 	kstrdup(&c, confstr + strlen(Cfgstr));
 	memset(confstr, 0, sizeof(confstr));
 	for (p = c; p != nil && *p != 0; p = e){
 		e = strchr(p, '\n');
 		if (e == nil)
 			e = p + strlen(p);
+		if (e == p) {
+			e++;
+			continue;
+		}
 		mconfig(p, e - p);
 	}
 	poperror();
-	free(s);	
 }
 
 

+ 7 - 19
sys/src/9/port/devloopback.c

@@ -23,8 +23,6 @@ struct Link
 
 	vlong	delay0ns;	/* nanosec of delay in the link */
 	long	delaynns;	/* nanosec of delay per byte */
-	vlong	delay0;		/* fastticks of delay */
-	long	delayn;
 
 	Block	*tq;		/* transmission queue */
 	Block	*tqtail;
@@ -73,7 +71,7 @@ enum
 	Statelen	= 23*1024,	/* status buffer size */
 
 	Tmsize		= 8,
-	Delayn 		= 10000,	/* default delays */
+	Delayn 		= 10000,	/* default delays in ns */
 	Delay0 		= 2500000,
 
 	Loopqlim	= 32*1024,	/* default size of queues */
@@ -90,14 +88,10 @@ static Dirtab loopdirs[MaxQ];
 
 static Loop	loopbacks[Nloopbacks];
 
-static uvlong	fasthz;
-
 #define TYPE(x) 	(((ulong)(x))&0xff)
 #define ID(x) 		(((ulong)(x))>>8)
 #define QID(x,y) 	((((ulong)(x))<<8)|((ulong)(y)))
 
-#define NS2FASTHZ(t)	((fasthz*(t))/1000000000);
-
 static void	looper(Loop *lb);
 static long	loopoput(Loop *lb, Link *link, Block *bp);
 static void	ptime(uchar *p, vlong t);
@@ -148,8 +142,8 @@ loopbackattach(char *spec)
 
 	lb->ref++;
 	if(lb->ref == 1){
-		fastticks(&fasthz);
 		for(chan = 0; chan < 2; chan++){
+			lb->link[chan].ci.mode = Tabsolute;
 			lb->link[chan].ci.a = &lb->link[chan];
 			lb->link[chan].ci.f = linkintr;
 			lb->link[chan].limit = Loopqlim;
@@ -167,9 +161,7 @@ loopbackattach(char *spec)
 			}
 			lb->link[chan].indrop = 1;
 
-			lb->link[chan].delayn = NS2FASTHZ(Delayn);
 			lb->link[chan].delaynns = Delayn;
-			lb->link[chan].delay0 = NS2FASTHZ(Delay0);
 			lb->link[chan].delay0ns = Delay0;
 		}
 	}
@@ -508,12 +500,8 @@ loopbackwrite(Chan *c, void *va, long n, vlong off)
 			 * it takes about 20000 cycles on a pentium ii
 			 * to run pushlink; perhaps this should be accounted.
 			 */
-			d0 = NS2FASTHZ(d0ns);
-			dn = NS2FASTHZ(dnns);
 
 			ilock(link);
-			link->delay0 = d0;
-			link->delayn = dn;
 			link->delay0ns = d0ns;
 			link->delaynns = dnns;
 			iunlock(link);
@@ -577,7 +565,7 @@ loopoput(Loop *lb, Link *link, Block *volatile bp)
 	if(BLEN(bp) < lb->minmtu)
 		bp = adjustblock(bp, lb->minmtu);
 	poperror();
-	ptime(bp->rp, fastticks(nil));
+	ptime(bp->rp, todget(nil));
 
 	link->packets++;
 	link->bytes += n;
@@ -594,7 +582,7 @@ looper(Loop *lb)
 	vlong t;
 	int chan;
 
-	t = fastticks(nil);
+	t = todget(nil);
 	for(chan = 0; chan < 2; chan++)
 		pushlink(&lb->link[chan], t);
 }
@@ -605,7 +593,7 @@ linkintr(Ureg*, Timer *ci)
 	Link *link;
 
 	link = ci->a;
-	pushlink(link, ci->when);
+	pushlink(link, ci->ns);
 }
 
 /*
@@ -662,7 +650,7 @@ pushlink(Link *link, vlong now)
 		if(link->droprate && nrand(link->droprate) == 0)
 			link->drops++;
 		else{
-			ptime(bp->rp, tout + link->delay0);
+			ptime(bp->rp, tout + link->delay0ns);
 			if(link->tq == nil)
 				link->tq = bp;
 			else
@@ -702,7 +690,7 @@ pushlink(Link *link, vlong now)
 	if(!tin || tin > tout && tout)
 		tin = tout;
 
-	link->ci.when = tin;
+	link->ci.ns = tin;
 	if(tin){
 		if(tin < now)
 			panic("loopback unfinished business");

+ 8 - 8
sys/src/9/port/devmnt.c

@@ -20,15 +20,15 @@
 
 struct Mntrpc
 {
-	Chan*	c;		/* Channel for whom we are working */
+	Chan*	c;			/* Channel for whom we are working */
 	Mntrpc*	list;		/* Free/pending list */
 	Fcall	request;	/* Outgoing file system protocol message */
 	Fcall 	reply;		/* Incoming reply */
-	Mnt*	m;		/* Mount device during rpc */
-	Rendez	r;		/* Place to hang out */
+	Mnt*	m;			/* Mount device during rpc */
+	Rendez	r;			/* Place to hang out */
 	uchar*	rpc;		/* I/O Data buffer */
-	uint		rpclen;	/* len of buffer */
-	Block	*b;		/* reply blocks */
+	uint	rpclen;		/* len of buffer */
+	Block	*b;			/* reply blocks */
 	char	done;		/* Rpc completed */
 	uvlong	stime;		/* start time for mnt statistics */
 	ulong	reqlen;		/* request length for mnt statistics */
@@ -66,15 +66,15 @@ void	mntpntfree(Mnt*);
 void	mntqrm(Mnt*, Mntrpc*);
 Mntrpc*	mntralloc(Chan*, ulong);
 long	mntrdwr(int, Chan*, void*, long, vlong);
-int	mntrpcread(Mnt*, Mntrpc*);
+int		mntrpcread(Mnt*, Mntrpc*);
 void	mountio(Mnt*, Mntrpc*);
 void	mountmux(Mnt*, Mntrpc*);
 void	mountrpc(Mnt*, Mntrpc*);
-int	rpcattn(void*);
+int		rpcattn(void*);
 Chan*	mntchan(void);
 
 char	Esbadstat[] = "invalid directory entry received from server";
-char Enoversion[] = "version not established for mount channel";
+char 	Enoversion[] = "version not established for mount channel";
 
 
 void (*mntstats)(int, Chan*, uvlong, ulong);

+ 9 - 8
sys/src/9/port/devmouse.c

@@ -16,14 +16,15 @@ typedef struct Mousestate	Mousestate;
 
 struct Mousestate
 {
-	Point	xy;			/* mouse.xy */
-	int	buttons;		/* mouse.buttons */
+	Point	xy;		/* mouse.xy */
+	int	buttons;	/* mouse.buttons */
 	ulong	counter;	/* increments every update */
-	ulong	msec;	/* time of last event */
+	ulong	msec;		/* time of last event */
 };
 
 struct Mouseinfo
 {
+	Lock;
 	Mousestate;
 	int	dx;
 	int	dy;
@@ -37,10 +38,10 @@ struct Mouseinfo
 	int	inopen;
 	int	acceleration;
 	int	maxacc;
-	Mousestate 	queue[16];	/* circular buffer of click events */
-	int	ri;	/* read index into queue */
-	int	wi;	/* write index into queue */
-	uchar	qfull;	/* queue is full */
+	Mousestate	queue[16];	/* circular buffer of click events */
+	int	ri;		/* read index into queue */
+	int	wi;		/* write index into queue */
+	uchar	qfull;		/* queue is full */
 };
 
 enum
@@ -54,7 +55,7 @@ static Cmdtab mousectlmsg[] =
 {
 	CMbuttonmap,	"buttonmap",	0,
 	CMswap,		"swap",		1,
-	CMwildcard,	"*",			0,
+	CMwildcard,	"*",		0,
 };
 
 Mouseinfo	mouse;

+ 267 - 22
sys/src/9/port/devproc.c

@@ -1,14 +1,18 @@
 #include	"u.h"
+#include	<trace.h>
+#include	"tos.h"
 #include	"../port/lib.h"
 #include	"mem.h"
 #include	"dat.h"
 #include	"fns.h"
 #include	"../port/error.h"
 #include	"ureg.h"
+#include	"edf.h"
 
 enum
 {
 	Qdir,
+	Qtrace,
 	Qargs,
 	Qctl,
 	Qfd,
@@ -42,11 +46,26 @@ enum
 	CMprofile,
 	CMstart,
 	CMstartstop,
+	CMstartsyscall,
 	CMstop,
 	CMwaitstop,
 	CMwired,
 	CMfair,
 	CMunfair,
+	CMtrace,
+	/* real time */
+	CMperiod,
+	CMdeadline,
+	CMcost,
+	CMsporadic,
+	CMdeadlinenotes,
+	CMadmit,
+	CMexpel,
+};
+
+enum{
+	Nevents = 0x4000,
+	Emask = Nevents - 1,
 };
 
 #define	STATSIZE	(2*KNAMELEN+12+9*12)
@@ -78,23 +97,32 @@ Dirtab procdir[] =
 
 static
 Cmdtab proccmd[] = {
-	CMclose,	"close",	2,
-	CMclosefiles,	"closefiles",	1,
-	CMfixedpri,	"fixedpri",	2,
-	CMhang,		"hang",		1,
-	CMnohang,	"nohang",	1,
-	CMnoswap,	"noswap",	1,
-	CMkill,		"kill",		1,
-	CMpri,		"pri",		2,
-	CMprivate,	"private",	1,
-	CMprofile,	"profile",	1,
-	CMstart,	"start",	1,
-	CMstartstop,	"startstop",	1,
-	CMstop,		"stop",		1,
-	CMwaitstop,	"waitstop",	1,
-	CMwired,	"wired",	2,
-	CMfair,	"fair",	1,
-	CMunfair,	"unfair",	1,
+	CMclose,		"close",		2,
+	CMclosefiles,		"closefiles",		1,
+	CMfixedpri,		"fixedpri",		2,
+	CMhang,			"hang",			1,
+	CMnohang,		"nohang",		1,
+	CMnoswap,		"noswap",		1,
+	CMkill,			"kill",			1,
+	CMpri,			"pri",			2,
+	CMprivate,		"private",		1,
+	CMprofile,		"profile",		1,
+	CMstart,		"start",		1,
+	CMstartstop,		"startstop",		1,
+	CMstartsyscall,		"startsyscall",		1,
+	CMstop,			"stop",			1,
+	CMwaitstop,		"waitstop",		1,
+	CMwired,		"wired",		2,
+	CMfair,			"fair",			1,
+	CMunfair,		"unfair",		1,
+	CMtrace,		"trace",		1,
+	CMperiod,		"period",		2,
+	CMdeadline,		"deadline",		2,
+	CMcost,			"cost",			2,
+	CMsporadic,		"sporadic",		1,
+	CMdeadlinenotes,	"deadlinenotes",	1,
+	CMadmit,		"admit",		1,
+	CMexpel,		"expel",		1,
 };
 
 /* Segment type from portdat.h */
@@ -122,8 +150,31 @@ Segment* txt2data(Proc*, Segment*);
 int	procstopped(void*);
 void	mntscan(Mntwalk*, Proc*);
 
+static Traceevent *tevents;
+static Lock tlock;
+static int topens;
+static int tproduced, tconsumed;
+static Rendez teventr;
+void	(*proctrace)(Proc*, int); 
+
 extern int unfair;
 
+static void
+profclock(Ureg *ur, Timer *)
+{
+	Tos *tos;
+
+	if(up == 0 || up->state != Running)
+		return;
+
+	/* user profiling clock */
+	if(userureg(ur)){
+		tos = (Tos*)(USTKTOP-sizeof(Tos));
+		tos->clock += TK2MS(1);
+		segclock(ur->pc);
+	}
+}
+
 static int
 procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
 {
@@ -140,6 +191,13 @@ procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
 	}
 
 	if(c->qid.path == Qdir){
+		if(s == 0){
+			strcpy(up->genbuf, "trace");
+			mkqid(&qid, Qtrace, -1, QTFILE);
+			devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
+			return 1;
+		}
+
 		if(name != nil){
 			/* ignore s and use name to find pid */
 			pid = strtol(name, &ename, 10);
@@ -148,9 +206,10 @@ procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
 			s = procindex(pid);
 			if(s < 0)
 				return -1;
-		}else
-			if(s >= conf.nproc)
-				return -1;
+		}
+		else if(--s >= conf.nproc)
+			return -1;
+
 		p = proctab(s);
 		pid = p->pid;
 		if(pid == 0)
@@ -165,7 +224,15 @@ procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
 		devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp);
 		return 1;
 	}
-	if(s >= nelem(procdir))
+
+	if(c->qid.path == Qtrace){
+		strcpy(up->genbuf, "trace");
+		mkqid(&qid, Qtrace, -1, QTFILE);
+		devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
+		return 1;
+	}
+
+	if(--s >= nelem(procdir))
 		return -1;
 	if(tab)
 		panic("procgen");
@@ -199,11 +266,34 @@ procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
 	return 1;
 }
 
+static void
+_proctrace(Proc*p, Tevent etype)
+{
+	Traceevent *te;
+
+	if (p->trace == 0 || topens == 0 || 
+			(tproduced - tconsumed >= Nevents))
+		return;
+
+	te = &tevents[tproduced&Emask];
+	te->pid = p->pid;
+	te->etype = etype;
+	te->time = todget(nil);
+	tproduced++;
+
+	/* To avoid circular wakeup when used in combination with 
+	 * EDF scheduling.
+	 */
+	if (teventr.p && teventr.p->state == Wakeme)
+		wakeup(&teventr);
+}
+
 static void
 procinit(void)
 {
 	if(conf.nproc >= (1<<(16-QSHIFT))-1)
 		print("warning: too many procs for devproc\n");
+	addclock0link((void (*)(void))profclock, 113);	/* Relative prime to HZ */
 }
 
 static Chan*
@@ -253,6 +343,33 @@ procopen(Chan *c, int omode)
 	if(c->qid.type & QTDIR)
 		return devopen(c, omode, 0, 0, procgen);
 
+	if(QID(c->qid) == Qtrace){
+		if (omode != OREAD) 
+			error(Eperm);
+		lock(&tlock);
+		if (waserror()){
+			unlock(&tlock);
+			nexterror();
+		}
+		if (topens > 0)
+			error("already open");
+		topens++;
+		if (tevents == nil){
+			tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);
+			if(tevents == nil)
+				error(Enomem);
+			tproduced = tconsumed = 0;
+		}
+		proctrace = _proctrace;
+		unlock(&tlock);
+		poperror();
+
+		c->mode = openmode(omode);
+		c->flag |= COPEN;
+		c->offset = 0;
+		return c;
+	}
+		
 	p = proctab(SLOT(c->qid));
 	qlock(&p->debug);
 	if(waserror()){
@@ -346,6 +463,9 @@ procwstat(Chan *c, uchar *db, int n)
 	if(c->qid.type&QTDIR)
 		error(Eperm);
 
+	if(QID(c->qid) == Qtrace)
+		return devwstat(c, db, n);
+		
 	p = proctab(SLOT(c->qid));
 	nonone(p);
 	d = nil;
@@ -481,6 +601,14 @@ procfds(Proc *p, char *va, int count, long offset)
 static void
 procclose(Chan * c)
 {
+	if(QID(c->qid) == Qtrace){
+		lock(&tlock);
+		if(topens > 0)
+			topens--;
+		if(topens == 0)
+			proctrace = nil;
+		unlock(&tlock);
+	}
 	if(QID(c->qid) == Qns && c->aux != 0)
 		free(c->aux);
 }
@@ -530,10 +658,16 @@ procargs(Proc *p, char *buf, int nbuf)
 	return j;
 }
 
+static int
+eventsavailable(void *)
+{
+	return tproduced > tconsumed;
+}
+
 static long
 procread(Chan *c, void *va, long n, vlong off)
 {
-	int m;
+	int m, navail, ne;
 	long l;
 	Proc *p;
 	Waitq *wq;
@@ -549,6 +683,27 @@ procread(Chan *c, void *va, long n, vlong off)
 	if(c->qid.type & QTDIR)
 		return devdirread(c, a, n, 0, 0, procgen);
 
+	if(QID(c->qid) == Qtrace){
+		if(!eventsavailable(nil))
+			return 0;
+
+		rptr = (uchar*)va;
+		navail = tproduced - tconsumed;
+		if(navail > n / sizeof(Traceevent))
+			navail = n / sizeof(Traceevent);
+		while(navail > 0) {
+			ne = ((tconsumed & Emask) + navail > Nevents)? 
+						Nevents - (tconsumed & Emask): navail;
+			memmove(rptr, &tevents[tconsumed & Emask], 
+						ne * sizeof(Traceevent));
+
+			tconsumed += ne;
+			rptr += ne * sizeof(Traceevent);
+			navail -= ne;
+		}
+		return rptr - (uchar*)va;
+	}
+
 	p = proctab(SLOT(c->qid));
 	if(p->pid != PID(c->qid))
 		error(Eprocdied);
@@ -1090,6 +1245,39 @@ procctlclosefiles(Proc *p, int all, int fd)
 	closefgrp(f);
 }
 
+static char *
+parsetime(vlong *rt, char *s)
+{
+	uvlong ticks;
+	ulong l;
+	char *e, *p;
+	static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
+
+	if (s == nil)
+		return("missing value");
+	ticks=strtoul(s, &e, 10);
+	if (*e == '.'){
+		p = e+1;
+		l = strtoul(p, &e, 10);
+		if(e-p > nelem(p10))
+			return "too many digits after decimal point";
+		if(e-p == 0)
+			return "ill-formed number";
+		l *= p10[e-p-1];
+	}else
+		l = 0;
+	if (*e == '\0' || strcmp(e, "s") == 0){
+		ticks = 1000000000 * ticks + l;
+	}else if (strcmp(e, "ms") == 0){
+		ticks = 1000000 * ticks + l/1000;
+	}else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
+		ticks = 1000 * ticks + l/1000000;
+	}else if (strcmp(e, "ns") != 0)
+		return "unrecognized unit";
+	*rt = ticks;
+	return nil;
+}
+
 void
 procctlreq(Proc *p, char *va, int n)
 {
@@ -1097,6 +1285,8 @@ procctlreq(Proc *p, char *va, int n)
 	int npc, pri;
 	Cmdbuf *cb;
 	Cmdtab *ct;
+	vlong time;
+	char *e;
 
 	if(p->kp)	/* no ctl requests to kprocs */
 		error(Eperm);
@@ -1178,6 +1368,13 @@ procctlreq(Proc *p, char *va, int n)
 		ready(p);
 		procstopwait(p, Proc_traceme);
 		break;
+	case CMstartsyscall:
+		if(p->state != Stopped)
+			error(Ebadctl);
+		p->procctl = Proc_tracesyscall;
+		ready(p);
+		procstopwait(p, Proc_tracesyscall);
+		break;
 	case CMstop:
 		procstopwait(p, Proc_stopme);
 		break;
@@ -1187,6 +1384,54 @@ procctlreq(Proc *p, char *va, int n)
 	case CMwired:
 		procwired(p, atoi(cb->f[1]));
 		break;
+	case CMtrace:
+		p->trace = (p->trace + 1) & 1;
+		break;
+	/* real time */
+	case CMperiod:
+		if(p->edf == nil)
+			edfinit(p);
+		if(e=parsetime(&time, cb->f[1]))
+			error(e);
+		edfstop(p);
+		p->edf->T = time;
+		break;
+	case CMdeadline:
+		if(p->edf == nil)
+			edfinit(p);
+		if(e=parsetime(&time, cb->f[1]))
+			error(e);
+		edfstop(p);
+		p->edf->D = time;
+		break;
+	case CMcost:
+		if(p->edf == nil)
+			edfinit(p);
+		if(e=parsetime(&time, cb->f[1]))
+			error(e);
+		edfstop(p);
+		p->edf->C = time;
+		break;
+	case CMsporadic:
+		if(p->edf == nil)
+			edfinit(p);
+		p->edf->flags |= Sporadic;
+		break;
+	case CMdeadlinenotes:
+		if(p->edf == nil)
+			edfinit(p);
+		p->edf->flags |= Sendnotes;
+		break;
+	case CMadmit:
+		if(p->edf == 0)
+			error("edf params");
+		if(e = edfadmit(p))
+			error(e);
+		break;
+	case CMexpel:
+		if(p->edf)
+			edfstop(p);
+		break;
 	}
 
 	poperror();

+ 7 - 0
sys/src/9/port/devroot.c

@@ -221,6 +221,13 @@ rootread(Chan *c, void *buf, long n, vlong off)
 		return 0;
 	if(offset+n > d->length)
 		n = d->length - offset;
+#ifdef asdf
+print("[%d] kaddr %.8ulx base %.8ulx offset %ld (%.8ulx), n %d %.8ulx %.8ulx %.8ulx\n", 
+		t, buf, data, offset, offset, n,
+		((ulong*)(data+offset))[0],
+		((ulong*)(data+offset))[1],
+		((ulong*)(data+offset))[2]);
+#endif asdf
 	memmove(buf, data+offset, n);
 	return n;
 }

+ 28 - 20
sys/src/9/port/devuart.c

@@ -286,6 +286,21 @@ uartdrained(void* arg)
 	return qlen(p->oq) == 0 && p->op == p->oe;
 }
 
+static void
+uartdrainoutput(Uart *p)
+{
+	if(!p->enabled)
+		return;
+
+	p->drain = 1;
+	if(waserror()){
+		p->drain = 0;
+		nexterror();
+	}
+	sleep(&p->r, uartdrained, p);
+	poperror();
+}
+
 static void
 uartclose(Chan *c)
 {
@@ -308,7 +323,7 @@ uartclose(Chan *c)
 			 */
 			qhangup(p->oq, nil);
 			if(!waserror()){
-				sleep(&p->r, uartdrained, p);
+				uartdrainoutput(p);
 				poperror();
 			}
 			qclose(p->oq);
@@ -361,8 +376,7 @@ uartctl(Uart *p, char *cmd)
 		switch(*f[i]){
 		case 'B':
 		case 'b':
-			if(p->enabled)
-				sleep(&p->r, uartdrained, p);
+			uartdrainoutput(p);
 			if((*p->phys->baud)(p, n) < 0)
 				return -1;
 			break;
@@ -372,8 +386,7 @@ uartctl(Uart *p, char *cmd)
 			break;
 		case 'D':
 		case 'd':
-			if(p->enabled)
-				sleep(&p->r, uartdrained, p);
+			uartdrainoutput(p);
 			(*p->phys->dtr)(p, n);
 			break;
 		case 'E':
@@ -394,27 +407,23 @@ uartctl(Uart *p, char *cmd)
 			break;
 		case 'i':
 		case 'I':
-			if(p->enabled)
-				sleep(&p->r, uartdrained, p);
+			uartdrainoutput(p);
 			(*p->phys->fifo)(p, n);
 			break;
 		case 'K':
 		case 'k':
-			if(p->enabled)
-				sleep(&p->r, uartdrained, p);
+			uartdrainoutput(p);
 			(*p->phys->dobreak)(p, n);
 			break;
 		case 'L':
 		case 'l':
-			if(p->enabled)
-				sleep(&p->r, uartdrained, p);
+			uartdrainoutput(p);
 			if((*p->phys->bits)(p, n) < 0)
 				return -1;
 			break;
 		case 'm':
 		case 'M':
-			if(p->enabled)
-				sleep(&p->r, uartdrained, p);
+			uartdrainoutput(p);
 			(*p->phys->modemctl)(p, n);
 			break;
 		case 'n':
@@ -424,8 +433,7 @@ uartctl(Uart *p, char *cmd)
 			break;
 		case 'P':
 		case 'p':
-			if(p->enabled)
-				sleep(&p->r, uartdrained, p);
+			uartdrainoutput(p);
 			if((*p->phys->parity)(p, *(f[i]+1)) < 0)
 				return -1;
 			break;
@@ -438,14 +446,12 @@ uartctl(Uart *p, char *cmd)
 			break;
 		case 'R':
 		case 'r':
-			if(p->enabled)
-				sleep(&p->r, uartdrained, p);
+			uartdrainoutput(p);
 			(*p->phys->rts)(p, n);
 			break;
 		case 'S':
 		case 's':
-			if(p->enabled)
-				sleep(&p->r, uartdrained, p);
+			uartdrainoutput(p);
 			if((*p->phys->stop)(p, n) < 0)
 				return -1;
 			break;
@@ -618,8 +624,10 @@ uartkick(void *v)
 	(*p->phys->kick)(p);
 	iunlock(&p->tlock);
 
-	if(qisclosed(p->oq) && uartdrained(p))
+	if(p->drain && uartdrained(p)){
+		p->drain = 0;
 		wakeup(&p->r);
+	}
 }
 
 /*

+ 454 - 1014
sys/src/9/port/edf.c

@@ -1,1147 +1,587 @@
 /* EDF scheduling */
-#include	"u.h"
+#include	<u.h>
 #include	"../port/lib.h"
 #include	"mem.h"
 #include	"dat.h"
 #include	"fns.h"
 #include	"../port/error.h"
-#include	"realtime.h"
 #include	"../port/edf.h"
+#include	<trace.h>
 
 /* debugging */
-int			edfprint = 0;
-#define DPRINT	if(edfprint)iprint
-
-char *edfstatename[] = {
-	[EdfUnused] =		"Unused",
-	[EdfExpelled] =		"Expelled",
-	[EdfAdmitted] =	"Admitted",
-	[EdfBestEffort] =	"BestEffort",
-	[EdfIdle] =			"Idle",
-	[EdfAwaitrelease] =	"Awaitrelease",
-	[EdfReleased] =		"Released",
-	[EdfRunning] =		"Running",
-	[EdfExtra] =		"Extra",
-	[EdfPreempted] =	"Preempted",
-	[EdfBlocked] =		"Blocked",
-	[EdfDeadline] =		"Deadline",
-};
-
-static Timer	deadlinetimer[MAXMACH];	/* Time of next deadline */
-static Timer	releasetimer[MAXMACH];		/* Time of next release */
+int	edfprint = 0;
+#define DPRINT	if(edfprint)print
+
+static vlong	now;
+extern ulong	delayedscheds;
+extern Schedq	runq[Nrq];
+extern int		nrdy;
+extern ulong	runvec;
+
+/* Statistics stuff */
+ulong		nilcount;
+ulong		scheds;
+vlong		edfruntime;
+ulong		edfnrun;
+int			misseddeadlines;
 
-static int		initialized;
-static Ticks	now;
-/* Edfschedlock protects modification of sched params, including resources */
+/* Edfschedlock protects modification of admission params */
+int			edfinited;
 QLock		edfschedlock;
-Lock			edflock;
-
-Head		tasks;
-Head		resources;
-int			edfstateupdate;
-int			misseddeadlines;
+static Lock	thelock;
 
 enum{
-	Deadline,	/* Invariant for schedulability test: Deadline < Release */
-	Release,
+	Dl,	/* Invariant for schedulability test: Dl < Rl */
+	Rl,
 };
 
-static int earlierrelease(Task *t1, Task *t2) {return t1->r < t2->r;}
-static int earlierdeadline(Task *t1, Task *t2) {return t1->d < t2->d;}
-static void	edfrelease(Task *t);
-
-/* Tasks waiting for release, head earliest release time */
-Taskq		qwaitrelease =	{{0}, nil, earlierrelease};
-
-/* Released tasks waiting to run, head earliest deadline */
-Taskq		qreleased	=	{{0}, nil, earlierdeadline};
-
-/* Exhausted EDF tasks, append at end */
-Taskq		qextratime;
-
-/* Running/Preempted EDF tasks, head running, one stack per processor */
-Taskq		edfstack[MAXMACH];
-
-static Task *qschedulability;
-
-void (*devrt)(Task*, Ticks, int);
-
-static void		edfresched(Task*);
-static void		setdelta(void);
-static void		testdelta(Task*);
-static void		edfreleaseintr(Ureg*, Timer*);
-static void		edfdeadlineintr(Ureg*, Timer*);
-static char *	edftestschedulability(Task*);
-static void		resrelease(Task*);
-
-static void
-edfinit(void)
-{
-	int i;
-
-	if (initialized)
-		return;
-	ilock(&edflock);
-	if (initialized){
-		iunlock(&edflock);
-		return;
-	}
-	for (i = 0; i < conf.nmach; i++){
-		deadlinetimer[i].f = edfdeadlineintr;
-		deadlinetimer[i].a = &deadlinetimer[i];
-		deadlinetimer[i].when = 0;
-		releasetimer[i].f = edfreleaseintr;
-		releasetimer[i].a = &releasetimer[i];
-		releasetimer[i].when = 0;
-	}
-	initialized = 1;
-	iunlock(&edflock);
-}
+static char *testschedulability(Proc*);
+static Proc *qschedulability;
 
-static int
-isedf(Proc *p)
-{
-	return p && p->task && p->task->state >= EdfIdle;
-}
+enum {
+	Onemicrosecond =	1000ULL,
+	Onemillisecond =	1000000ULL,
+	Onesecond =			1000000000ULL,
+	OneRound = 			Onemillisecond/2LL,
+	MilliRound = 		Onemicrosecond/2LL,
+};
 
 static int
-edfanyready(void)
-{
-	return edfstack[m->machno].head || qreleased.head;
-}
-
-static void
-edfpush(Task *t)
-{
-	Taskq *q;
-
-	DPRINT("%d edfpush, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
-	q = edfstack + m->machno;
-	assert(t->runq.n || (up && up->task == t));
-	if (q->head){
-		assert(q->head->state == EdfRunning);
-		q->head->state = EdfPreempted;
-		if(devrt) devrt(q->head, now, SPreempt);
-	}
-	t->rnext = q->head;
-	if(devrt) devrt(t, now, SRun);
-	q->head = t;
-}
-
-static Task*
-edfpop(void)
+timeconv(Fmt *f)
 {
-	Task *t;
-	Taskq *q;
+	char buf[128], *sign;
+	vlong t;
 
-	DPRINT("%d edfpop\n", m->machno);
-	q = edfstack + m->machno;
-	if (t = q->head){
-		assert(t->state == EdfRunning);
-		q->head = t->rnext;
-		t->rnext = nil;
-		if (q->head){
-			assert(q->head->state == EdfPreempted);
-			q->head->state = EdfRunning;
-			if(devrt) devrt(q->head, now, SRun);
-		}
-	}
-	return t;
-}
-
-static Task*
-edfenqueue(Taskq *q, Task *t)
-{
-	Task *tt, **ttp;
-
-	DPRINT("%d edfenqueue, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
-	t->rnext = nil;
-	if (q->head == nil) {
-		q->head = t;
-		return t;
+	buf[0] = 0;
+	switch(f->r) {
+	case 'U':
+		t = va_arg(f->args, uvlong);
+		break;
+	case 't':		// vlong in nanoseconds
+		t = va_arg(f->args, vlong);
+		break;
+	default:
+		return fmtstrcpy(f, "(timeconv)");
 	}
-	SET(tt);
-	for (ttp = &q->head; *ttp; ttp = &tt->rnext) {
-		tt = *ttp;
-		if (q->before && q->before(t, tt)) {
-			t->rnext = tt;
-			*ttp = t;
-			break;
-		}
+	if (t < 0) {
+		sign = "-";
+		t = -t;
 	}
-	if (*ttp == nil)
-		tt->rnext = t;
-	if (t != q->head)
-		t = nil;
-	return t;
+	else
+		sign = "";
+	if (t > Onesecond){
+		t += OneRound;
+		sprint(buf, "%s%d.%.3ds", sign, (int)(t / Onesecond), (int)(t % Onesecond)/1000000);
+	}else if (t > Onemillisecond){
+		t += MilliRound;
+		sprint(buf, "%s%d.%.3dms", sign, (int)(t / Onemillisecond), (int)(t % Onemillisecond)/1000);
+	}else if (t > Onemicrosecond)
+		sprint(buf, "%s%d.%.3dµs", sign, (int)(t / Onemicrosecond), (int)(t % Onemicrosecond));
+	else
+		sprint(buf, "%s%dns", sign, (int)t);
+	return fmtstrcpy(f, buf);
 }
 
-static Task*
-edfdequeue(Taskq *q)
+void
+edflock(void)
 {
-	Task *t;
-
-	DPRINT("%d edfdequeue\n", m->machno);
-	if (t = q->head){
-		q->head = t->rnext;
-		t->rnext = nil;
-	}
-	return t;
+	ilock(&thelock);
+	now = todget(nil);
 }
 
-static Task*
-edfqremove(Taskq *q, Task *t)
+void
+edfunlock(void)
 {
-	Task **tp;
-
-	DPRINT("%d edfqremove, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
-	for (tp = &q->head; *tp; tp = &(*tp)->rnext){
-		if (*tp == t){
-			*tp = t->rnext;
-			t = (tp == &q->head) ? q->head : nil;
-			return t;
-		}
-	}
-	return nil;
+	edfruntime += todget(nil) - now;
+	edfnrun++;
+	iunlock(&thelock);
 }
 
-			
 void
-edfreleasetimer(void)
+edfinit(Proc*p)
 {
-	Task *t;
-
-	if ((t = qwaitrelease.head) == nil)
-		return;
-	DPRINT("edfreleasetimer clock\n");
-	releasetimer[m->machno].when = t->r;
-	if (releasetimer[m->machno].when <= now)
-		releasetimer[m->machno].when = now;
-	timeradd(&releasetimer[m->machno]);
+	if(!edfinited){
+		fmtinstall('t', timeconv);
+		edfinited++;
+	}
+	now = todget(nil);
+	DPRINT("%t edfinit %lud[%s]\n", now, p->pid, statename[p->state]);
+	p->edf = malloc(sizeof(Edf));
+	if(p->edf == nil)
+		error(Enomem);
+	return;
 }
 
 static void
-edfblock(Proc *p)
+deadlineintr(Ureg*, Timer *t)
 {
-	Task *t, *pt;
-
-	/* The current proc has blocked */
-	ilock(&edflock);
-	t = p->task;
-	assert(t);
-	if (t->state != EdfRunning){
-		/* called by a proc just joining the task */
-		iunlock(&edflock);
-		return;
-	}
-	DPRINT("%d edfblock, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
+	/* Proc reached deadline */
+	extern int panicking;
+	Proc *p;
 
-	if (t->runq.n){
-		/* There's another runnable proc in the running task, leave task where it is */
-		iunlock(&edflock);
+	if(panicking || active.exiting)
 		return;
-	}
-	pt = edfpop();
-	assert(pt == t);
-	t->state = EdfBlocked;
-	if(devrt) devrt(t, now, SBlock);
-	iunlock(&edflock);
-}
 
-static void
-deadline(Proc *p, SEvent why)
-{
-	Task *t, *nt;
-	Ticks used;
-
-	/* Task has reached its deadline, lock must be held */
-	DPRINT("%d deadline, %s, %d\n", m->machno, edfstatename[p->task->state], p->task->runq.n);
-	SET(nt);
-	if (p){
-		nt = p->task;
-		if (nt == nil || nt->state != EdfRunning)
-			return;
-	}
-	t = edfpop();
-
-	if(p != nil && nt != t){
-		iprint("deadline, %s, %d\n", edfstatename[p->task->state], p->task->runq.n);
-		iunlock(&edflock);
-		assert(0 && p == nil || nt == t);
-	}
-	if (deadlinetimer[m->machno].when){
-		timerdel(&deadlinetimer[m->machno]);
-		deadlinetimer[m->machno].when = 0;
+	p = t->ta;
+	DPRINT("%t deadlineintr %lud[%s]\n", todget(nil), p->pid, statename[p->state]);
+	/* If we're interrupting something other than the proc pointed to by t->a,
+	 * we've already achieved recheduling, so we need not do anything
+	 * Otherwise, we must cause a reschedule, but if we call sched()
+	 * here directly, the timer interrupt routine will not finish its business
+	 * Instead, we cause the resched to happen when the interrupted proc
+	 * returns to user space
+	 */
+	if (p == up){
+		up->delaysched++;
+ 		delayedscheds++;
 	}
-	used = now - t->scheduled;
-	t->S -= used;
-	t->scheduled = now;
-	t->total += used;
-	t->aged = (t->aged*31 + t->C - t->S) >> 5;
-	t->d = now;
-	t->state = EdfDeadline;
-	if(devrt) devrt(t, now, why);
-	edfresched(t);
 }
 
 static void
-edfdeadline(Proc *p)
+release(Proc *p)
 {
-	DPRINT("%d edfdeadline\n", m->machno);
-	/* Task has reached its deadline */
-	ilock(&edflock);
-	now = fastticks(nil);
-	deadline(p, SYield);
-	iunlock(&edflock);
-}
-
-static char *
-edfadmit(Task *t)
-{
-	char *err, *p;
-	static char csndump[512];
-	CSN *c;
-
-	/* Called with edfschedlock held */
-	if (t->state != EdfExpelled)
-		return "task state";	/* should never happen */
-
-	/* simple sanity checks */
-	if (t->T == 0)
-		return "T not set";
-	if (t->C == 0)
-		return "C not set";
-	if (t->D > t->T)
-		return "D > T";
-	if (t->D == 0)	/* if D is not set, set it to T */
-		t->D = t->T;
-	if (t->C > t->D)
-		return "C > D";
-
-	resourcetimes(t, &t->csns);
-
-	DEBUG("task %d: T %T, C %T, D %T, tΔ %T\n",
-		t->taskno, ticks2time(t->T), ticks2time(t->C),
-		ticks2time(t->D), ticks2time(t->testDelta));
-	p = seprintresources(csndump, csndump+sizeof csndump);
-	seprintcsn(p, csndump+sizeof csndump, &t->csns);
-	DEBUG("%s\n", csndump);
-
-	if (err = edftestschedulability(t)){
-		return err;
-	}
-	ilock(&edflock);
-	DPRINT("%d edfadmit, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
-	if (t->flags & BestEffort){
-		t->state = EdfBestEffort;
-		iunlock(&edflock);
-		return nil;
-	}
-	now = fastticks(nil);
-
-	t->state = EdfAdmitted;
-	if(devrt) devrt(t, t->d, SAdmit);
-	if (up->task == t){
-		DPRINT("%d edfadmitting self\n", m->machno);
-		/* Admitting self, fake reaching deadline */
-		t->r = now;
-		t->t = now + t->T;
-		t->d = now + t->D;
-		if(devrt) devrt(t, t->d, SDeadline);
-		t->S = t->C;
-		t->scheduled = now;
-		t->state = EdfRunning;
-		t->periods++;
-		if(devrt) devrt(t, now, SRun);
-		setdelta();
-		for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){
-			DEBUG("admit csn: C=%T\n", ticks2time(c->C));
-			c->S = c->C;
+	/* Called with edflock held */
+	Edf *e;
+	void (*pt)(Proc*, int);
+
+	e = p->edf;
+	e->flags &= ~Yield;
+	if (e->d < now){
+		e->periods++;
+		e->r = now;
+		if ((e->flags & Sporadic) == 0){
+			/* Non sporadic processes stay true to their period;
+			 * calculate next release time
+			 */
+			while(e->t <= now)
+				e->t += e->T;
+		}else{
+			/* Sporadic processes may not be released earlier than
+			 * one period after this release
+			 */
+			e->t = e->r + e->T;
 		}
-		assert(t->runq.n > 0 || (up && up->task == t));
-		edfpush(t);
-		deadlinetimer[m->machno].when = t->d;
-		timeradd(&deadlinetimer[m->machno]);
+		e->d = e->r + e->D;
+		e->S = e->C;
+		DPRINT("%t release %lud[%s], r=%t, d=%t, t=%t, S=%t\n",
+			now, p->pid, statename[p->state], e->r, e->d, e->t, e->S);
+		if (pt = proctrace)
+			pt(p, SRelease);
 	}else{
-		if (t->runq.n){
-			if (edfstack[m->machno].head == nil){
-				t->r = now;
-				edfrelease(t);
-				setdelta();
-				edfresched(t);
-			}
-		}
+		DPRINT("%t release %lud[%s], too late t=%t, called from 0x%lux\n",
+			now, p->pid, statename[p->state], e->t, getcallerpc(&p));
 	}
-	iunlock(&edflock);
-	return nil;
 }
 
 static void
-edfexpel(Task *t)
+releaseintr(Ureg*, Timer *t)
 {
-	Task *tt;
-
-	/* Called with edfschedlock held */
-	ilock(&edflock);
-	DPRINT("%d edfexpel, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
-	now = fastticks(nil);
-	switch(t->state){
-	case EdfUnused:
-	case EdfExpelled:
-		/* That was easy */
-		iunlock(&edflock);
-		return;
-	case EdfAdmitted:
-	case EdfIdle:
-		/* Just reset state */
-		break;
-	case EdfAwaitrelease:
-		if (edfqremove(&qwaitrelease, t))
-			edfreleasetimer();
-		break;
-	case EdfReleased:
-		edfqremove(&qreleased, t);
-		break;
-	case EdfRunning:
-		/* Task must be expelling itself */
-		tt = edfpop();
-		assert(t == tt);
-		break;
-	case EdfExtra:
-		edfqremove(&qextratime, t);
-		break;
-	case EdfPreempted:
-		edfqremove(edfstack + m->machno, t);
-		break;
-	case EdfBlocked:
-	case EdfDeadline:
-		break;
-	}
-	t->state = EdfExpelled;
-	if(devrt) devrt(t, now, SExpel);
-	setdelta();
-	iunlock(&edflock);
-	return;
-}
-
-static void
-edfreleaseintr(Ureg*, Timer*)
-{
-	Task *t;
+	Proc *p;
+	Edf *e;
 	extern int panicking;
-
-	DPRINT("%d edfreleaseintr\n", m->machno);
+	Schedq *rq;
 
 	if(panicking || active.exiting)
 		return;
 
-	now = fastticks(nil);
-	ilock(&edflock);
-	while((t = qwaitrelease.head) && t->r <= now){
-		/* There's something waiting to be released and its time has come */
-		edfdequeue(&qwaitrelease);
-		edfreleasetimer();
-		edfrelease(t);
-	}
-	iunlock(&edflock);
-	sched();
-	splhi();
-}
-
-static void
-edfdeadlineintr(Ureg*, Timer *)
-{
-	/* Task reached deadline */
-
-	Ticks used;
-	Task *t;
-	Resource *r;
-	char buf[128];
-	int noted;
-	extern int panicking;
-
-	DPRINT("%d edfdeadlineintr\n", m->machno);
-
-	if(panicking || active.exiting)
+	p = t->ta;
+	e = p->edf;
+	if ((e->flags & Admitted) == 0)
 		return;
-
-	now = fastticks(nil);
-	ilock(&edflock);
-	// If up is not set, we're running inside the scheduler
-	// for non-real-time processes.
-	noted = 0;
-	if (up && isedf(up)) {
-		t = up->task;
-
-		assert(t->state == EdfRunning);
-		assert(t->scheduled > 0);
-	
-		used = now - t->scheduled;
-		t->scheduled = now;
-		t->total += used;
-
-		if (t->r < now){
-			if (t->curcsn){
-				if (t->curcsn->S <= used){
-					t->curcsn->S = 0LL;
-					resrelease(t);
-					r = t->curcsn->i;
-					noted++;
-					snprint(buf, sizeof buf, "sys: deadline miss: resource %s", r->name);
-				}else
-					t->curcsn->S -= used;
-			}
-
-			if (t->S <= used){
-				t->S = 0LL;
-				if (!noted){
-					noted++;
-					snprint(buf, sizeof buf, "sys: deadline miss: runtime");
-				}
-			}else
-				t->S -= used;
-
-			if (t->d <= now || t->S == 0LL || t->curcsn == 0LL){
-				/* Task has reached its deadline/slice, remove from queue */
-				if (t->d <= now){
-					t->missed++;
-					misseddeadlines++;
-				}
-				deadline(up, SSlice);
-
-				while (t = edfstack[m->machno].head){
-					if (now < t->d)
-						break;
-					deadline(nil, SSlice);
-				}	
-			}
+	edflock();
+	DPRINT("%t releaseintr %lud[%s]\n", now, p->pid, statename[p->state]);
+	switch(p->state){
+	default:
+		edfunlock();
+		return;
+	case Ready:
+		/* remove proc from current runq */
+		rq = &runq[p->priority];
+		if (dequeueproc(rq, p) != p){
+			print("releaseintr: can't find proc or lock race\n");
+			release(p);	/* It'll start best effort */
+			edfunlock();
+			return;
 		}
-	}
-	iunlock(&edflock);
-	if (noted)
-		postnote(up, 0, buf, NUser);
-	sched();
-	splhi();
-}
-
-static void
-edfbury(Proc *p)
-{
-	Task *t;
-
-	DPRINT("%d edfbury\n", m->machno);
-	ilock(&edflock);
-	now = fastticks(nil);
-	if ((t = p->task) == nil){
-		/* race condition? */
-		iunlock(&edflock);
-		DPRINT("%d edf bury race, pid %lud\n", m->machno, p->pid);
+		p->state = Waitrelease;
+		/* fall through */
+	case Waitrelease:
+		release(p);
+		edfunlock();
+		ready(p);
+		sched();
+//		if (up){
+//			up->delaysched++;
+ //			delayedscheds++;
+//		}
 		return;
+	case Running:
+		release(p);
+		edfrun(p, 1);
+		break;
 	}
-	assert(edfstack[m->machno].head == t);
-	delist(&t->procs, p);
-	if (t->runq.head == nil){
-		edfpop();
-		t->state = EdfBlocked;
-	}
-	if (t->procs.n == 0){
-		assert(t->runq.head == nil);
-		t->state = EdfIdle;
-	}
-	if(devrt) devrt(t, now, SBlock);
-	p->task = nil;
-	iunlock(&edflock);
+	edfunlock();
 }
 
-static void
-edfready(Proc *p)
+void
+edfrecord(Proc *p)
 {
-	Task *t;
-
-	ilock(&edflock);
-	DPRINT("%d edfready, %s, %d\n", m->machno, edfstatename[p->task->state], p->task->runq.n);
-	if ((t = p->task) == nil){
-		/* Must be a race */
-		iunlock(&edflock);
-		DPRINT("%d edf ready race, pid %lud\n", m->machno, p->pid);
-		return;
-	}
-	p->rnext = 0;
-	p->readytime = m->ticks;
-	p->state = Ready;
-	t->runq.n++;
-	if(t->runq.tail){
-		t->runq.tail->rnext = p;
-		t->runq.tail = p;
-	}else{
-		t->runq.head = p;
-		t->runq.tail = p;
-
-		/* first proc to become runnable in this task */
-		now = fastticks(nil);
-		edfresched(t);
-	}
-	iunlock(&edflock);
+	vlong used;
+	Edf *e;
+	void (*pt)(Proc*, int);
+
+	e = p->edf;
+	edflock();
+	used = now - e->s;
+	if (e->d <= now)
+		e->edfused += used;
+	else
+		e->extraused += used;
+	if (e->S > 0){
+		if (e->S <= used){
+			if(pt = proctrace)
+				pt(p, SDeadline);
+			DPRINT("%t edfrecord slice used up\n", now);
+			e->d = now;
+			e->S = 0;
+		}else
+			e->S -= used;
+	}
+	e->s = now;
+	edfunlock();
 }
 
-static void
-edfresched(Task *t)
+void
+edfrun(Proc *p, int edfpri)
 {
-	Task *xt;
-
-	DPRINT("%d edfresched, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
-	if (t->procs.n == 0){
-		/* No member processes */
-		if (t->state > EdfIdle){
-			t->state = EdfIdle;
-			if(devrt) devrt(t, now, SBlock);
-		}
-		return;
-	}
-	if (t->runq.n == 0 && (up == nil || up->task != t)){
-		/* Member processes but none runnable */
-		DPRINT("%d edfresched, nothing runnable\n", m->machno);
-		if (t->state == EdfRunning)
-			edfpop();
-
-		if (t->state >= EdfIdle && t->state != EdfBlocked){
-			t->state = EdfBlocked;
-			if(devrt) devrt(t, now, SBlock);
-		}
-		return;
-	}
-
-	/* There are runnable processes */
-
-	switch (t->state){
-	case EdfUnused:
-		iprint("%d attempt to schedule unused task\n", m->machno);
-	case EdfExpelled:
-		return;	/* Not admitted */
-	case EdfIdle:
-		/* task was idle, schedule release now or later */
-		if (t->r < now){
-			if (t->t < now)
-				t->t = now + t->T;
-			t->r = t->t;
-		}
-		edfrelease(t);
-		break;
-	case EdfAwaitrelease:
-	case EdfReleased:
-	case EdfExtra:
-	case EdfPreempted:
-		/* dealt with by timer */
-		break;
-	case EdfAdmitted:
-		/* test whether task can be started */
-		if (edfstack[m->machno].head != nil){
+	Edf *e;
+
+	e = p->edf;
+	/* Called with edflock held */
+	if(edfpri){
+		if (e->d <= now || e->S == 0){
+			/* Deadline reached or resources exhausted,
+			 * deschedule forthwith
+			 */
+			p->delaysched++;
+ 			delayedscheds++;
+			e->s = now;
 			return;
 		}
-		/* fall through */
-	case EdfRunning:
-		if (t->r <= now){
-			if (t->t < now){
-				DPRINT("%d edfresched, rerelease\n", m->machno);
-				/* Period passed, rerelease */
-				t->r = now;
-				xt = edfpop();
-				assert(xt == t);
-				edfrelease(t);
-				return;
-			}
-			if (now < t->d){
-				if (t->S > 0){
-					DPRINT("%d edfresched, resume\n", m->machno);
-					/* Running, not yet at deadline, leave it */
-					return;
-				}else
-					t->d = now;
-			}
-			/* Released, but deadline is past, release at t->t */
-			t->r = t->t;
+		p->tns = now + e->S;
+		if (e->d < p->tns)
+			p->tns = e->d;
+		if(p->tt == nil || p->tf != deadlineintr){
+			DPRINT("%t edfrun, deadline=%t\n", now, p->tns);
+		}else{
+			DPRINT("v");
 		}
-		xt = edfpop();
-		assert(xt == t);
-		t->state = EdfAwaitrelease;
-		if (edfenqueue(&qwaitrelease, t))
-			edfreleasetimer();
-		break;
-	case EdfBlocked:
-	case EdfDeadline:
-		if (t->r <= now){
-			if (t->t < now){
-				DPRINT("%d edfresched, rerelease\n", m->machno);
-				/* Period passed, rerelease */
-				t->r = now;
-				edfrelease(t);
-				return;
-			}
-			if ((t->flags & Useblocking) == 0 && now < t->d){
-				if (t->S > 0){
-					DPRINT("%d edfresched, resume\n", m->machno);
-					/* Released, not yet at deadline, release (again) */
-					t->state = EdfReleased;
-					edfenqueue(&qreleased, t);
-					if(devrt) devrt(t, now, SResume);
-					return;
-				}else
-					t->d = now;
-			}
-			/* Released, but deadline is past, release at t->t */
-			t->r = t->t;
-		}
-		t->state = EdfAwaitrelease;
-		if (edfenqueue(&qwaitrelease, t))
-			edfreleasetimer();
-		break;
+		p->tmode = Tabsolute;
+		p->tf = deadlineintr;
+		p->ta = p;
+		timeradd(p);
+	}else{
+		DPRINT("<");
 	}
+	e->s = now;
 }
 
-static void
-edfrelease(Task *t)
+char *
+edfadmit(Proc *p)
 {
-	CSN *c;
+	char *err;
+	Edf *e;
+	int i;
+	Proc *r;
+	void	(*pt)(Proc*, int);
 
-	DPRINT("%d edfrelease, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
-	assert(t->runq.n > 0 || (up && up->task == t));
-	t->t = t->r + t->T;
-	t->d = t->r + t->D;
-	if(devrt) devrt(t, t->d, SDeadline);
-	t->S = t->C;
-	for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){
-		DEBUG("release csn: C=%T\n", ticks2time(c->C));
-		c->S = c->C;
-	}
-	t->state = EdfReleased;
-	edfenqueue(&qreleased, t);
-	if(devrt) devrt(t, now, SRelease);
-}
+	e = p->edf;
+	if (e->flags & Admitted)
+		return "task state";	/* should never happen */
 
-static Proc *
-edfrunproc(void)
-{
-	/* Return an edf proc to run or nil */
-	
-	Task *t, *nt, *xt;
-	Proc *p;
-	Ticks when;
-	static ulong nilcount;
-	int i;
+	/* simple sanity checks */
+	if (e->T == 0)
+		return "T not set";
+	if (e->C == 0)
+		return "C not set";
+	if (e->D > e->T)
+		return "D > T";
+	if (e->D == 0)	/* if D is not set, set it to T */
+		e->D = e->T;
+	if (e->C > e->D)
+		return "C > D";
 
-	if (edfstack[m->machno].head == nil && qreleased.head== nil){
-		// quick way out
-		nilcount++;
-		return nil;
+	qlock(&edfschedlock);
+	if (err = testschedulability(p)){
+		qunlock(&edfschedlock);
+		return err;
 	}
+	edflock();
 
-	/* Figure out if the current proc should be preempted*/
-	ilock(&edflock);
-	now = fastticks(nil);
-
-	/* first candidate is at the top of the stack of running procs */
-	t = edfstack[m->machno].head;
+	e->flags |= Admitted;
 
-	/* check out head of the release queue for a proc with a better deadline */
-	nt = qreleased.head;
+	if(pt = proctrace)
+		pt(p, SAdmit);
 
-	if (t == nil && nt == nil){
-		nilcount++;
-		iunlock(&edflock);
-		return nil;
-	}
-	DPRINT("edfrunproc %lud\n", nilcount);
-	if (nt && (t == nil || (nt->d < t->d && nt->D < t->Delta))){
-		if (conf.nmach > 1){
-			for (i = 0; i < conf.nmach; i++){
-				if (i == m->machno)
-					continue;
-				xt = edfstack[i].head;
-				if (xt && xt->Delta <= nt->D){
-					DPRINT("%d edfrunproc: interprocessor conflict, run current\n", m->machno);
-					if (t)
-						goto runt;
-					nilcount++;
-					iunlock(&edflock);
-					return nil;
-				}
-			}
+	/* Look for another proc with the same period to synchronize to */
+	SET(r);
+	for(i=0; i<conf.nproc; i++) {
+		r = proctab(i);
+		if(r->state == Dead || r == p)
+			continue;
+		if (r->edf == nil || (r->edf->flags & Admitted) == 0)
+			continue;
+		if (r->edf->T == e->T)
+				break;
+	}
+	if (i == conf.nproc){
+		/* Can't synchronize to another proc, release now */
+		e->t = now;
+		e->d = 0;
+		release(p);
+		if (p == up){
+			DPRINT("%t edfadmit self %lud[%s], release now: r=%t d=%t t=%t\n",
+				now, p->pid, statename[p->state], e->r, e->d, e->t);
+			/* We're already running */
+			edfrun(p, 1);
+		}else{
+			/* We're releasing another proc */
+			DPRINT("%t edfadmit other %lud[%s], release now: r=%t d=%t t=%t\n",
+				now, p->pid, statename[p->state], e->r, e->d, e->t);
+			p->ta = p;
+			releaseintr(nil, p);
 		}
-		/* released task is better than current */
-		DPRINT("%d edfrunproc: released\n", m->machno);
-		edfdequeue(&qreleased);
-		assert(nt->runq.n >= 1 || (up && up->task == nt));
-		edfpush(nt);
-		t = nt;
-		t->scheduled = now;
 	}else{
-		DPRINT("%d edfrunproc: current\n", m->machno);
-	}
-runt:
-	assert (t->runq.n);
-
-	/* Get first proc off t's run queue
-	 * No need to lock runq, edflock always held to access runq
-	 */
-	t->state = EdfRunning;
-	t->periods++;
-	p = t->runq.head;
-	if ((t->runq.head = p->rnext) == nil)
-		t->runq.tail = nil;
-	t->runq.n--;
-	p->state = Scheding;
-	if(p->mp != MACHP(m->machno))
-		p->movetime = MACHP(0)->ticks + HZ/10;
-	p->mp = MACHP(m->machno);
-
-	when = now + t->S;
-	if (t->d < when)
-		when = t->d;
-
-	if (when < now){
-		DPRINT("%d edftimer: %T too late\n", m->machno, ticks2time(now-when));
-		when = now;
-	}
-	if(deadlinetimer[m->machno].when == when){
-		iunlock(&edflock);
-		return p;
-	}
-	deadlinetimer[m->machno].when = when;
-	timeradd(&deadlinetimer[m->machno]);
-	iunlock(&edflock);
-	return p;
-}
-
-/* Schedulability testing and its supporting routines */
-
-static void
-setdelta(void)
-{
-	Resource *r;
-	Task *t;
-	int R;
-	List *lr, *l;
-	TaskLink *lt;
-	CSN *c;
-
-	for (lr = resources.next; lr; lr = lr->next){
-		r = lr->i;
-		assert(r);
-		r->Delta = Infinity;
-		R = 1;
-		for (lt = (TaskLink*)r->tasks.next; lt; lt = (TaskLink*)lt->next){
-			t = lt->i;
-			assert(t);
-			if (t->D < r->Delta){
-				r->Delta = t->D;
+		/* Release in synch to something else */
+		e->t = r->edf->t;
+		if (p == up){
+			DPRINT("%t edfadmit self %lud[%s], release at %t\n",
+				now, p->pid, statename[p->state], e->t);
+			edfunlock();
+			qunlock(&edfschedlock);
+			edfyield();
+			return nil;
+		}else{
+			DPRINT("%t edfadmit other %lud[%s], release at %t\n",
+				now, p->pid, statename[p->state], e->t);
+			if(p->tt == nil){
+				p->tf = releaseintr;
+				p->ta = p;
+				p->tns = e->t;
+				p->tmode = Tabsolute;
+				timeradd(p);
 			}
-			if (lt->R == 0){
-				R = 0;
-			}
-		}
-		if (R)
-			r->Delta = Infinity;	/* Read-only resource, no exclusion */
-	}
-
-	/* Enumerate the critical sections */
-	for (l = tasks.next; l ; l = l->next){
-		t = l->i;
-		assert(t);
-		if (t->state <= EdfExpelled)
-			continue;
-		t->Delta = Infinity;
-		for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){
-			r = c->i;
-			assert(r);
-			c->Delta = r->Delta;
-			if (c->p && c->p->Delta < c->Delta)
-				c->Delta = c->p->Delta;
-			if (c->C == t->C && r->Delta < t->Delta)
-				t->Delta = r->Delta;
 		}
 	}
+	edfunlock();
+	qunlock(&edfschedlock);
+	return nil;
 }
 
-static void
-testdelta(Task *thetask)
+void
+edfstop(Proc *p)
 {
-	Resource *r;
-	Task *t;
-	int R;
-	List *lr, *l;
-	TaskLink *lt;
-	CSN *c;
-
-	for (lr = resources.next; lr; lr = lr->next){
-		r = lr->i;
-		assert(r);
-		DEBUG("Resource %s: ", r->name);
-		r->testDelta = Infinity;
-		R = 1;
-		for (lt = (TaskLink*)r->tasks.next; lt; lt = (TaskLink*)lt->next){
-			t = lt->i;
-			assert(t);
-			if (t->D < r->testDelta){
-				r->testDelta = t->D;
-				DEBUG("%d→%T ", t->taskno, ticks2time(t->D));
-			}
-			if (lt->R == 0){
-				DEBUG("%d→X ", t->taskno);
-				R = 0;
-			}
-		}
-		if (R)
-			r->testDelta = Infinity;	/* Read-only resource, no exclusion */
-		DEBUG("tΔ = %T\n", ticks2time(r->testDelta));
-	}
-
-	/* Enumerate the critical sections */
-	for (l = tasks.next; l ; l = l->next){
-		t = l->i;
-		assert(t);
-		if (t->state <= EdfExpelled && t != thetask)
-			continue;
-		t->testDelta = Infinity;
-		for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){
-			r = c->i;
-			assert(r);
-			c->testDelta = r->testDelta;
-			if (c->p && c->p->testDelta < c->testDelta)
-				c->testDelta = c->p->testDelta;
-			if (c->C == t->C && r->testDelta < t->testDelta)
-				t->testDelta = r->testDelta;
-			DEBUG("Task %d Resource %s: tΔ = %T\n",
-				t->taskno, r->name, ticks2time(r->testDelta));
-		}
+	Edf *e;
+	void	(*pt)(Proc*, int);
+
+	if ((e = p->edf) && (e->flags & Admitted)){
+		edflock();
+		DPRINT("%t edfstop %lud[%s]\n", now, p->pid, statename[p->state]);
+		if(pt = proctrace)
+			pt(p, SExpel);
+		e->flags &= ~Admitted;
+		if (p->tt)
+			timerdel(p);
+		edfunlock();
 	}
 }
 
-static Ticks
-blockcost(Ticks ticks, Task *task, Task *thetask)
+void
+edfyield(void)
 {
-	Ticks Cb, Cbt;
-	List *l;
-	Resource *r;
-	CSN *c, *lc;
-	int R;
-	Task *t;
-
-	Cb = 0;
-	/* for each resource in task t, find all CSNs that refer to the
-	 * resource.  If their Δ <= ticks < D and c->C > current CB
-	 * Cb = c->C
-	 */
-	DEBUG("blockcost task %d: ", task->taskno);
-	for (c = (CSN*)task->csns.next; c; c = (CSN*)c->next){
-		r = c->i;
-		assert(r);
+	/* sleep until next release */
+	Edf *e;
+	void	(*pt)(Proc*, int);
+
+	e = up->edf;
+	if(pt = proctrace)
+		pt(up, SYield);
+	now = todget(nil);
+	e->flags |= Yield;
+	e->d = now;
+	DPRINT("%t edfyield %lud\n", now, up->pid);
+	sched();
+}
 
-		DEBUG("%s ", r->name);
-		Cbt = Cb;
-		R = 1;	/* R == 1: resource is only used in read-only mode  */
-		for (l = tasks.next; l; l = l->next){
-			t = l->i;
-			if (t->state <= EdfExpelled && t != thetask)
-				continue;	/* csn belongs to an irrelevant task */
-			for (lc = (CSN*)t->csns.next; lc; lc = (CSN*)lc->next){
-				if (lc->i != r)
-					continue;	/* wrong resource */
-				if (lc->R == 0)
-					R = 0;	/* Resource is used in exclusive mode */
-				DEBUG("(%T≤%T<%T: %T) ",
-					ticks2time(lc->testDelta), ticks2time(ticks), ticks2time(t->D),
-					ticks2time(lc->C));
-				if (lc->testDelta <= ticks && ticks < t->D && Cbt < lc->C)
-					Cbt = lc->C;
-			}
+int
+edfready(Proc *p)
+{
+	Edf *e;
+	Schedq *rq;
+	Proc *l, *pp;
+	void (*pt)(Proc*, int);
+
+	if ((e = p->edf) == nil || (e->flags & Admitted) == 0)
+		return 0;	/* Not an edf process */
+
+	edflock();
+	if (e->d <= now){
+		/* past deadline, arrange for next release */
+		if ((e->flags & Sporadic) == 0){
+			/* Non sporadic processes stay true to their period, calculate next release time */
+			while(e->t < now)
+				e->t += e->T;
 		}
-		if (R == 0){
-			DEBUG("%T, ", ticks2time(Cbt));
-			Cb = Cbt;
+		if (now < e->t){
+			/* Next release is in the future, schedule it */
+			if (p->tt == nil || p->tf != releaseintr){
+				p->tns = e->t;
+				p->tmode = Tabsolute;
+				p->tf = releaseintr;
+				p->ta = p;
+				timeradd(p);
+				DPRINT("%t edfready %lud[%s], release=%t\n",
+					now, p->pid, statename[p->state], e->t);
+			}
+			if(p->state == Running && (e->flags & (Yield|Yieldonblock)) == 0){
+				/* If we were running, we've overrun our CPU allocation
+				 * or missed the deadline, continue running best-effort at low priority
+				 * Otherwise we were blocked.  If we don't yield on block, we continue
+				 * best effort
+				 */
+				DPRINT(">");
+				p->basepri = PriExtra;
+				p->fixedpri = 1;
+				edfunlock();
+				return 0;	/* Stick on runq[PriExtra] */
+			}
+			DPRINT("%t edfready %lud[%s] wait release at %t\n",
+				now, p->pid, statename[p->state], e->t);
+			p->state = Waitrelease;
+			edfunlock();
+			return 1;	/* Make runnable later */
 		}
-		DEBUG("ro, ");
+		DPRINT("%t edfready %lud %s release now\n", now, p->pid, statename[p->state]);
+		/* release now */
+		release(p);
+		if(pt = proctrace)
+			pt(p, SRelease);
+	}
+	DPRINT("^");
+	rq = &runq[PriEdf];
+	/* insert in queue in earliest deadline order */
+	lock(runq);
+	l = nil;
+	for(pp = rq->head; pp; pp = pp->rnext){
+		if(pp->edf->d > e->d)
+			break;
+		l = pp;
 	}
-	DEBUG("Cb = %T\n", ticks2time(Cb));
-	return Cb;
+	p->rnext = pp;
+	if (l == nil)
+		rq->head = p;
+	else
+		l->rnext = p;
+	if(pp == nil)
+		rq->tail = p;
+	rq->n++;
+	nrdy++;
+	runvec |= 1 << PriEdf;
+	p->priority = PriEdf;
+	unlock(runq);
+	p->readytime = m->ticks;
+	p->state = Ready;
+	if(pt = proctrace)
+		pt(p, SReady);
+	edfunlock();
+	return 1;
 }
 
+
 static void
-testenq(Task *t)
+testenq(Proc *p)
 {
-	Task *tt, **ttp;
+	Proc *xp, **xpp;
+	Edf *e;
 
-	t->testnext = nil;
+	e = p->edf;
+	e->testnext = nil;
 	if (qschedulability == nil) {
-		qschedulability = t;
+		qschedulability = p;
 		return;
 	}
-	SET(tt);
-	for (ttp = &qschedulability; *ttp; ttp = &tt->testnext) {
-		tt = *ttp;
-		if (t->testtime < tt->testtime
-		|| (t->testtime == tt->testtime && t->testtype < tt->testtype)){
-			t->testnext = tt;
-			*ttp = t;
+	SET(xp);
+	for (xpp = &qschedulability; *xpp; xpp = &xp->edf->testnext) {
+		xp = *xpp;
+		if (e->testtime < xp->edf->testtime
+		|| (e->testtime == xp->edf->testtime && e->testtype < xp->edf->testtype)){
+			e->testnext = xp;
+			*xpp = p;
 			return;
 		}
 	}
-	assert(tt->testnext == nil);
-	tt->testnext = t;
+	assert(xp->edf->testnext == nil);
+	xp->edf->testnext = p;
 }
 
 static char *
-edftestschedulability(Task *thetask)
+testschedulability(Proc *theproc)
 {
-	Task *t;
-	Ticks H, G, Cb, ticks;
-	int steps;
-	List *l;
+	Proc *p;
+	vlong H, G, Cb, ticks;
+	int steps, i;
 
 	/* initialize */
-	testdelta(thetask);
-	if (thetask && (thetask->flags & Verbose))
-		pprint("schedulability test for task %d\n", thetask->taskno);
+	DPRINT("schedulability test %lud\n", theproc->pid);
 	qschedulability = nil;
-	for (l = tasks.next; l; l = l->next){
-		t = l->i;
-		assert(t);
-		if (t->state <= EdfExpelled && t != thetask && (t->flags & BestEffort) == 0)
+	for(i=0; i<conf.nproc; i++) {
+		p = proctab(i);
+		if(p->state == Dead)
+			continue;
+		if ((p->edf == nil || (p->edf->flags & Admitted) == 0) && p != theproc)
 			continue;
-		t->testtype = Release;
-		t->testtime = 0;
-		if (thetask && (thetask->flags & Verbose))
-			pprint("\tInit: enqueue task %d\n", t->taskno);
-		testenq(t);
+		p->edf->testtype = Rl;
+		p->edf->testtime = 0;
+		DPRINT("\tInit: edfenqueue %lud\n", p->pid);
+		testenq(p);
 	}
 	H=0;
 	G=0;
+	ticks = 0;
 	for(steps = 0; steps < Maxsteps; steps++){
-		t = qschedulability;
-		qschedulability = t->testnext;
-		ticks = t->testtime;
-		switch (t->testtype){
-		case Deadline:
-			H += t->C;
-			Cb = blockcost(ticks, t, thetask);
-			if (thetask && (thetask->flags & Verbose))
-				pprint("\tStep %3d, Ticks %T, task %d, deadline, H += %T → %T, Cb = %T\n",
-					steps, ticks2time(ticks), t->taskno,
-					ticks2time(t->C), ticks2time(H), ticks2time(Cb));
+		p = qschedulability;
+		qschedulability = p->edf->testnext;
+		ticks = p->edf->testtime;
+		switch (p->edf->testtype){
+		case Dl:
+			H += p->edf->C;
+			Cb = 0;
+			DPRINT("\tStep %3d, Ticks %t, pid %lud, deadline, H += %t → %t, Cb = %t\n",
+				steps, ticks, p->pid, p->edf->C, H, Cb);
 			if (H+Cb>ticks){
-				if (thetask && (thetask->flags & Verbose))
-					pprint("task %d not schedulable: H=%T + Cb=%T > ticks=%T\n",
-						thetask->taskno, ticks2time(H), ticks2time(Cb), ticks2time(ticks));
+				DPRINT("not schedulable\n");
 				return "not schedulable";
 			}
-			t->testtime += t->T - t->D;
-			t->testtype = Release;
-			testenq(t);
+			p->edf->testtime += p->edf->T - p->edf->D;
+			p->edf->testtype = Rl;
+			testenq(p);
 			break;
-		case Release:
-			if (thetask && (thetask->flags & Verbose))
-				pprint("\tStep %3d, Ticks %T, task %d, release, G  %T, C%T\n",
-					steps, ticks2time(ticks), t->taskno,
-					ticks2time(t->C), ticks2time(G));
+		case Rl:
+			DPRINT("\tStep %3d, Ticks %t, pid %lud, release, G  %t, C%t\n",
+				steps, ticks, p->pid, p->edf->C, G);
 			if(ticks && G <= ticks){
-				if (thetask && (thetask->flags & Verbose))
-					pprint("task %d schedulable: G=%T <= ticks=%T\n",
-						thetask->taskno, ticks2time(G), ticks2time(ticks));
+				DPRINT("schedulable\n");
 				return nil;
 			}
-			G += t->C;
-			t->testtime += t->D;
-			t->testtype = Deadline;
-			testenq(t);
+			G += p->edf->C;
+			p->edf->testtime += p->edf->D;
+			p->edf->testtype = Dl;
+			testenq(p);
 			break;
 		default:
 			assert(0);
 		}
 	}
+	DPRINT("probably not schedulable\n");
 	return "probably not schedulable";
 }
-
-static void
-resacquire(Task *t, CSN *c)
-{
-	Ticks now, when, used;
-
-	ilock(&edflock);
-	now = fastticks(nil);
-	used = now - t->scheduled;
-	t->scheduled = now;
-	t->total += used;
-	if (t->flags & BestEffort)
-		c->S = c->C;
-	else
-		t->S -= used;
-	if (t->curcsn)
-		t->curcsn->S -= used;
-	when = now + c->S;
-	if (deadlinetimer[m->machno].when == 0 || when < deadlinetimer[m->machno].when){
-		deadlinetimer[m->machno].when = when;
-		timeradd(&deadlinetimer[m->machno]);
-	}
-	t->Delta = c->Delta;
-	t->curcsn = c;
-	t->state = EdfRunning;
-	iunlock(&edflock);
-	if(devrt) devrt(t, now, SResacq);
-	/* priority is going up, no need to reschedule */
-}
-
-static void
-resrelease(Task *t)
-{
-	Ticks now, when, used;
-	CSN *c;
-
-	ilock(&edflock);
-	c = t->curcsn;
-	assert(c);
-	t->curcsn = c->p;
-	now = fastticks(nil);
-	used = now - t->scheduled;
-	t->scheduled = now;
-	t->total += used;
-	if ((t->flags & BestEffort) == 0)
-		t->S -= used;
-	c->S -= used;
-	if (now + t->S > t->d)
-		when = t->d;
-	else
-		when = now + t->S;
-	if (t->curcsn){
-		t->curcsn->S -= c->S;	/* the sins of the fathers shall be visited upon the children */
-		t->Delta = t->curcsn->Delta;
-		if (when > now + t->curcsn->S)
-			when = now + t->curcsn->S;
-	}else{
-		t->Delta = Infinity;
-		if (t->flags & BestEffort)
-			t->state = EdfBestEffort;
-	}
-	c->S = 0LL;	/* don't allow reuse this period */
-	deadlinetimer[m->machno].when = when;
-	timeradd(&deadlinetimer[m->machno]);
-	iunlock(&edflock);
-
-	qunlock(&edfschedlock);
-	if(devrt) devrt(t, now, SResrel);
-	sched();	/* reschedule */
-	qlock(&edfschedlock);
-}
-
-Edfinterface realedf = {
-	.isedf		= isedf,
-	.edfbury		= edfbury,
-	.edfanyready	= edfanyready,
-	.edfready		= edfready,
-	.edfrunproc	= edfrunproc,
-	.edfblock		= edfblock,
-	.edfinit		= edfinit,
-	.edfexpel		= edfexpel,
-	.edfadmit		= edfadmit,
-	.edfdeadline	= edfdeadline,
-	.resacquire	= resacquire,
-	.resrelease	= resrelease,
-};

+ 35 - 152
sys/src/9/port/edf.h

@@ -1,168 +1,51 @@
 enum {
-	Nproc = 8,
-	Nres = 8,
-	Ntask = 8,
-	Maxtasks = 20,
-	Maxresources = 20,
-	Maxsteps = Maxtasks * 2 * 100,	/* 100 periods of maximum # of tasks */
+	Maxsteps = 20 * 2 * 100,	/* 100 periods of 20 procs */
 
 	/* Edf.flags field */
-	Verbose		= 0x1,
-	Useblocking	= 0x2,
-	BestEffort		= 0x4,
+	Admitted		= 0x01,
+	Sporadic		= 0x02,
+	Yieldonblock	= 0x04,
+	Sendnotes		= 0x08,
+	Deadline		= 0x10,
+	Yield			= 0x20,
 
-	Infinity = 0xffffffffffffffffULL,
-
-};
-
-enum Edfstate {
-	EdfUnused,		/* task structure not in use */
-	EdfExpelled,		/* in initialization, not yet admitted */
-	EdfAdmitted,		/* admitted, but not started */
-	EdfBestEffort,		/* admitted, but not RT scheduled */
-
-	EdfIdle,			/* admitted, but no member processes */
-	EdfAwaitrelease,	/* waiting for release (on qwaitrelease) */
-	EdfReleased,		/* released, but not yet scheduled (on qreleased) */
-	EdfRunning,		/* one of this task's procs is running (on stack) */
-	EdfExtra,			/* one of this task's procs is running in extra time (off stack) */
-	EdfPreempted,		/* the running proc was preempted */
-	EdfBlocked,		/* none of the procs are runnable as a result of sleeping */
-	EdfDeadline,		/* none of the procs are runnable as a result of scheduling */
-};
-
-typedef enum Edfstate		Edfstate;
-typedef struct Edf			Edf;
-typedef struct Head			Head;
-typedef struct List			List;
-typedef struct Resource		Resource;
-typedef struct Task			Task;
-typedef struct Taskq			Taskq;
-typedef struct CSN			CSN;
-typedef struct TaskLink		TaskLink;
-
-struct List {
-	List	*	next;		/* next in list */
-	void	*	i;		/* item in list */
+	Infinity = ~0ULL,
 };
 
-struct Head {
-	List	*next;		/* First item in list */
-	int	n;			/* number of items in list */
-};
+typedef struct Edf		Edf;
 
 struct Edf {
 	/* time intervals */
-	Ticks	D;		/* Deadline */
-	Ticks	Delta;	/* Inherited deadline */
-	Ticks	T;		/* period */
-	Ticks	C;		/* Cost */
-	Ticks	S;		/* Slice: time remaining in this period */
+	vlong		D;			/* Deadline */
+	vlong		Delta;		/* Inherited deadline */
+	vlong		T;			/* period */
+	vlong		C;			/* Cost */
+	vlong		S;			/* Slice: time remaining in this period */
 	/* times */
-	Ticks	r;		/* (this) release time */
-	Ticks	d;		/* (this) deadline */
-	Ticks	t;		/* Start of next period, t += T at release */
+	vlong		r;			/* (this) release time */
+	vlong		d;			/* (this) deadline */
+	vlong		t;			/* Start of next period, t += T at release */
+	vlong		s;			/* Time at which this proc was last scheduled */
 	/* for schedulability testing */
-	Ticks	testDelta;
-	int		testtype;	/* Release or Deadline */
-	Ticks	testtime;
-	Task	*	testnext;
-	/* statistics gathering */
-	ulong	periods;	/* number of periods */
-	ulong	missed;	/* number of deadlines missed */
-	ulong	preemptions;
-	Ticks	total;		/* total time used */
-	Ticks	aged;	/* aged time used */
+	vlong		testDelta;
+	int			testtype;	/* Release or Deadline */
+	vlong		testtime;
+	Proc		*testnext;
 	/* other */
-	Edfstate	state;
-};
-
-struct Task {
-	QLock;
-	Ref;					/* ref count for farbage collection */
-	int		taskno;		/* task number in Qid  */
-	Edf;
-	Ticks	scheduled;
-	Schedq	runq;		/* Queue of runnable member procs */
-	Head	procs;		/* List of member procs */
-	Head	csns;			/* List of resources */
-	CSN		*curcsn;		/* Position in CSN tree or nil */
-	char		*user;		/* mallocated */
-	Dirtab	dir;
-	int		flags;		/* e.g., Verbose */
-	Task		*rnext;
+	ushort		flags;
+	/* Stats */
+	vlong		edfused;
+	vlong		extraused;
+	vlong		aged;
+	ulong		periods;
+	ulong		missed;
 };
 
-struct Taskq
-{
-	Lock;
-	Task*	head;
-	int		(*before)(Task*, Task*);	/* ordering function for queue (nil: fifo) */
-};
-
-struct Resource
-{
-	Ref;
-	char	*	name;
-	Head	tasks;
-	Ticks	Delta;
-	/* for schedulability testing */
-	Ticks	testDelta;
-};
-
-struct CSN {
-	List;					/* links and identifies the resource (must be first) */
-	Task			*t;		/* task the CSN belongs to */
-	Ticks		C;		/* cost */
-	int			R;		/* read-only access (as opposed to exclusive access) */
-	Ticks		Delta;	/* of the Tasks critical section */
-	Ticks		testDelta;
-	Ticks		S;		/* Remaining slice */
-	CSN*		p;		/* parent resource items */
-};
-
-struct TaskLink {
-	List;				/* links and identifies the task (must be first) */
-	Ticks		C;	/* cost */
-	int			R;	/* read-only access (as opposed to exclusive access) */
-};
-
-extern QLock		edfschedlock;
-extern Head		tasks;
-extern Head		resources;
-extern int			nresources;
-extern Lock		edflock;
-extern Taskq		qwaitrelease;
-extern Taskq		qreleased;
-extern Taskq		qextratime;
-extern Taskq		edfstack[];
-extern int			edfstateupdate;
-extern void		(*devrt)(Task *, Ticks, int);
-extern char *		edfstatename[];
-
-#pragma	varargck	type	"T"		Time
-#pragma	varargck	type	"U"		Ticks
+extern Lock	edftestlock;	/* for atomic admitting/expelling */
 
-Time		ticks2time(Ticks);
-Ticks	time2ticks(Time);
-int		putlist(Head*, List*);
-int		enlist(Head*, void*);
-int		delist(Head*, void*);
-char *	parsetime(Time*, char*);
-void *	findlist(Head*, void*);
-Task *	findtask(int);
-List *		onlist(Head*, void*);
-int		timeconv(Fmt*);
-void		resourcefree(Resource*);
-Resource*	resource(char*, int);
-void		removetask(Task*);
-void		taskfree(Task*);
-char *	parseresource(Head*, CSN*, char*);
-char *	seprintresources(char*, char*);
-char *	seprintcsn(char*, char*, Head*);
-void		resourcetimes(Task*, Head*);
-char*	dumpq(char*, char*, Taskq*, Ticks);
-char*	seprinttask(char*, char*, Task*, Ticks);
-char*	dumpq(char*, char*, Taskq*, Ticks);
+#pragma	varargck	type	"t"		vlong
+#pragma	varargck	type	"U"		uvlong
 
-#define	DEBUG	if(1){}else iprint
+/* Interface: */
+void		edflock(void);
+void		edfunlock(void);

+ 2 - 0
sys/src/9/port/fault.c

@@ -11,6 +11,8 @@ fault(ulong addr, int read)
 	Segment *s;
 	char *sps;
 
+if(up && up->nlocks.ref) print("fault nlocks %ld\n", up->nlocks.ref);
+
 	sps = up->psstate;
 	up->psstate = "Fault";
 	spllo();

+ 2 - 2
sys/src/9/port/pgrp.c

@@ -151,10 +151,10 @@ pgrpcpy(Pgrp *to, Pgrp *from)
 	/*
 	 * Allocate mount ids in the same sequence as the parent group
 	 */
-	lock(&mountid);
+	lock(&mountid.l);
 	for(m = order; m; m = m->order)
 		m->copy->mountid = mountid.ref++;
-	unlock(&mountid);
+	unlock(&mountid.l);
 	wunlock(&from->ns);
 }
 

+ 90 - 73
sys/src/9/port/portclock.c

@@ -6,8 +6,6 @@
 #include "io.h"
 #include "ureg.h"
 
-typedef struct Timers Timers;
-
 struct Timers
 {
 	Lock;
@@ -20,54 +18,73 @@ ulong intrcount[MAXMACH];
 ulong fcallcount[MAXMACH];
 
 static uvlong
-tadd(Timers *tt, Timer *nt)
+tadd(Timers *tt, Timer *nt, uvlong now)
 {
-	Timer *t, **last, *pt;
+	Timer *t, **last;
 
-	pt = nil;
-	for(last = &tt->head; t = *last; last = &t->next){
-		if(t == nt){
-			/* timer's changing, remove it before putting it back on */
-			*last = t->next;
-			break;
-		}
-		if(t->period == nt->period){
+	/* Called with tt locked */
+	assert(nt->tt == nil);
+	switch(nt->tmode){
+	default:
+		panic("timer");
+		break;
+	case Trelative:
+		assert(nt->tns > 0);
+		nt->twhen = now + ns2fastticks(nt->tns);
+		break;
+	case Tabsolute:
+		nt->twhen = tod2fastticks(nt->tns);
+		break;
+	case Tperiodic:
+		assert(nt->tns > 0);
+		if(nt->twhen == 0){
 			/* look for another timer at same frequency for combining */
-			pt = t;
-		}
+			for(t = tt->head; t; t = t->tnext){
+				if(t->tmode == Tperiodic && t->tns == nt->tns)
+					break;
+			}
+			if (t)
+				nt->twhen = t->twhen;
+			else
+				nt->twhen = now + ns2fastticks(nt->tns);
+		}else
+			nt->twhen = now + ns2fastticks(nt->tns);
+		break;
 	}
 
-	if(nt->when == 0){
-		/* Try to synchronize periods to reduce # of interrupts */
-		assert(nt->period);
-		if(pt)
-			nt->when = pt->when;
-		else
-			nt->when = (uvlong)fastticks(nil) + nt->period;
-	}
-	
-	for(last = &tt->head; t = *last; last = &t->next){
-		if(t->when > nt->when)
+	for(last = &tt->head; t = *last; last = &t->tnext){
+		if(t->twhen > nt->twhen)
 			break;
 	}
-	nt->next = *last;
+	nt->tnext = *last;
 	*last = nt;
+	nt->tt = tt;
 	if(last == &tt->head)
-		return nt->when;
-	else
-		return 0;
+		return nt->twhen;
+	return 0;
 }
 
-/* add of modify a timer */
+/* add or modify a timer */
 void
 timeradd(Timer *nt)
 {
 	Timers *tt;
 	uvlong when;
 
+	if (nt->tmode == Tabsolute){
+		when = todget(nil);
+		if (nt->tns <= when){
+			if (nt->tns + MS2NS(1) <= when)	/* Give it some slack, small deviations will happen */
+				print("timeradd (%lld %lld) %lld too early 0x%lux\n",
+					when, nt->tns, when - nt->tns, getcallerpc(&nt));
+			nt->tns = when;
+		}
+	}
+	if (nt->tt)
+		timerdel(nt);
 	tt = &timers[m->machno];
 	ilock(tt);
-	when = tadd(tt, nt);
+	when = tadd(tt, nt, fastticks(nil));
 	if(when)
 		timerset(when);
 	iunlock(tt);
@@ -79,17 +96,24 @@ timerdel(Timer *dt)
 	Timer *t, **last;
 	Timers *tt;
 
-	tt = &timers[m->machno];
-	ilock(tt);
-	for(last = &tt->head; t = *last; last = &t->next){
-		if(t == dt){
-			*last = t->next;
-			break;
+	while(tt = dt->tt){
+		ilock(tt);
+		if (tt != dt->tt){
+			iunlock(tt);
+			continue;
+		}
+		for(last = &tt->head; t = *last; last = &t->tnext){
+			if(t == dt){
+				assert(dt->tt);
+				dt->tt = nil;
+				*last = t->tnext;
+				break;
+			}
 		}
+		if(last == &tt->head && tt->head)
+			timerset(tt->head->twhen);
+		iunlock(tt);
 	}
-	if(last == &tt->head && tt->head)
-		timerset(tt->head->when);
-	iunlock(tt);
 }
 
 void
@@ -114,23 +138,15 @@ hzclock(Ureg *ur)
 	if((active.machs&(1<<m->machno)) == 0)
 		return;
 
-	if(active.exiting && (active.machs & (1<<m->machno))) {
+	if(active.exiting) {
 		print("someone's exiting\n");
 		exit(0);
 	}
 
 	checkalarms();
 
-	if(up == 0 || up->state != Running)
-		return;
-
-	/* user profiling clock */
-	if(userureg(ur)){
-		(*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1);
-		segclock(ur->pc);
-	}
-
-	hzsched();	/* in proc.c */
+	if(up && up->state == Running)
+		hzsched();	/* in proc.c */
 }
 
 void
@@ -151,7 +167,7 @@ timerintr(Ureg *u, uvlong)
 	now = fastticks(nil);
 	ilock(tt);
 	while(t = tt->head){
-		when = t->when;
+		when = t->twhen;
 		if(when > now){
 			timerset(when);
 			iunlock(tt);
@@ -160,36 +176,36 @@ timerintr(Ureg *u, uvlong)
 				hzclock(u);
 			return;
 		}
-		tt->head = t->next;
+		tt->head = t->tnext;
+		assert(t->tt == tt);
+		t->tt = nil;
 		fcallcount[m->machno]++;
 		iunlock(tt);
-		if(t->f){
-			(*t->f)(u, t);
+		if(t->tf){
+			(*t->tf)(u, t);
 			splhi();
 		} else
 			callhzclock++;
 		ilock(tt);
-		if(t->period){
-			t->when += t->period;
-			tadd(tt, t);
+		if(t->tmode == Tperiodic){
+			t->twhen += ns2fastticks(t->tns);
+			tadd(tt, t, now);
 		}
 	}
 	iunlock(tt);
 }
 
-uvlong hzperiod;
-
 void
 timersinit(void)
 {
 	Timer *t;
 
-	hzperiod = ms2fastticks(1000/HZ);
-
+	todinit();
 	t = malloc(sizeof(*t));
-	t->when = 0;
-	t->period = hzperiod;
-	t->f = nil;
+	t->tmode = Tperiodic;
+	t->tt = nil;
+	t->tns = 1000000000/HZ;
+	t->tf = nil;
 	timeradd(t);
 }
 
@@ -197,20 +213,21 @@ void
 addclock0link(void (*f)(void), int ms)
 {
 	Timer *nt;
+	uvlong ft;
 
-	/* Synchronize this to hztimer: reduces # of interrupts */
+	/* Synchronize to hztimer if ms is 0 */
 	nt = malloc(sizeof(Timer));
-	nt->when = 0;
 	if(ms == 0)
 		ms = 1000/HZ;
-	nt->period = ms2fastticks(ms);
-	nt->f = (void (*)(Ureg*, Timer*))f;
+	nt->tns = (vlong)ms*1000000LL;
+	nt->tmode = Tperiodic;
+	nt->tt = nil;
+	nt->tf = (void (*)(Ureg*, Timer*))f;
+
+	ft = fastticks(nil);
 
 	ilock(&timers[0]);
-	tadd(&timers[0], nt);
-	/* no need to restart timer:
-	 * this one's synchronized with hztimer which is already running
-	 */
+	tadd(&timers[0], nt, ft);
 	iunlock(&timers[0]);
 }
 

+ 83 - 48
sys/src/9/port/portdat.h

@@ -7,7 +7,7 @@ typedef struct Cmdtab	Cmdtab;
 typedef struct Cname	Cname;
 typedef struct Dev	Dev;
 typedef struct Dirtab	Dirtab;
-typedef struct Edfinterface	Edfinterface;
+typedef struct Edf	Edf;
 typedef struct Egrp	Egrp;
 typedef struct Evalue	Evalue;
 typedef struct Fgrp	Fgrp;
@@ -46,6 +46,7 @@ typedef struct Session	Session;
 typedef struct Task	Task;
 typedef struct Talarm	Talarm;
 typedef struct Timer	Timer;
+typedef struct Timers	Timers;		/* defined in portdat.h */
 typedef struct Uart	Uart;
 typedef struct Waitq	Waitq;
 typedef struct Walkqid	Walkqid;
@@ -56,7 +57,7 @@ typedef int    Devgen(Chan*, char*, Dirtab*, int, int, Dir*);
 
 struct Ref
 {
-	Lock;
+	Lock	l;
 	long	ref;
 };
 
@@ -68,10 +69,10 @@ struct Rendez
 
 struct QLock
 {
-	Lock	use;			/* to access Qlock structure */
-	Proc	*head;			/* next process waiting for object */
-	Proc	*tail;			/* last process waiting for object */
-	int	locked;			/* flag */
+	Lock	use;		/* to access Qlock structure */
+	Proc	*head;		/* next process waiting for object */
+	Proc	*tail;		/* last process waiting for object */
+	int	locked;		/* flag */
 };
 
 struct RWlock
@@ -108,7 +109,7 @@ struct Sargs
 enum
 {
 	Aaccess,			/* as in stat, wstat */
-	Abind,			/* for left-hand-side of bind */
+	Abind,				/* for left-hand-side of bind */
 	Atodir,				/* as in chdir */
 	Aopen,				/* for i/o */
 	Amount,				/* to be mounted or mounted upon */
@@ -152,24 +153,25 @@ struct Block
 
 struct Chan
 {
+	Lock;
 	Ref;
 	Chan*	next;			/* allocation */
 	Chan*	link;
 	vlong	offset;			/* in fd */
-	vlong	devoffset;			/* in underlying device; see read */
+	vlong	devoffset;		/* in underlying device; see read */
 	ushort	type;
 	ulong	dev;
 	ushort	mode;			/* read/write */
 	ushort	flag;
 	Qid	qid;
 	int	fid;			/* for devmnt */
-	ulong	iounit;	/* chunk size for i/o; 0==default */
+	ulong	iounit;			/* chunk size for i/o; 0==default */
 	Mhead*	umh;			/* mount point that derived Chan; used in unionread */
 	Chan*	umc;			/* channel in union; held for union read */
 	QLock	umqlock;		/* serialize unionreads */
 	int	uri;			/* union read index */
 	int	dri;			/* devdirread index */
-	uchar*	dirrock;	/* directory entry rock for translations */
+	uchar*	dirrock;		/* directory entry rock for translations */
 	int	nrock;
 	int	mrock;
 	QLock	rockqlock;
@@ -205,7 +207,7 @@ struct Dev
 	void	(*init)(void);
 	void	(*shutdown)(void);
 	Chan*	(*attach)(char*);
-	Walkqid*	(*walk)(Chan*, Chan*, char**, int);
+	Walkqid*(*walk)(Chan*, Chan*, char**, int);
 	int	(*stat)(Chan*, uchar*, int);
 	Chan*	(*open)(Chan*, int);
 	void	(*create)(Chan*, char*, int, ulong);
@@ -244,7 +246,7 @@ enum
 
 struct Mntwalk				/* state for /proc/#/ns */
 {
-	int		cddone;
+	int	cddone;
 	ulong	id;
 	Mhead*	mh;
 	Mount*	cm;
@@ -282,7 +284,7 @@ struct Mnt
 	Mnt	*list;		/* Free list */
 	int	flags;		/* cache */
 	int	msize;		/* data + IOHDRSZ */
-	char	*version;			/* 9P version */
+	char	*version;	/* 9P version */
 	Queue	*q;		/* input queue */
 };
 
@@ -341,6 +343,7 @@ struct Swapalloc
 
 struct Image
 {
+	Lock;
 	Ref;
 	Chan	*c;			/* channel to text file */
 	Qid 	qid;			/* Qid for page cache coherence */
@@ -395,6 +398,7 @@ struct Physseg
 
 struct Segment
 {
+	Lock;
 	Ref;
 	QLock	lk;
 	ushort	steal;		/* Page stealer lock */
@@ -416,9 +420,9 @@ struct Segment
 enum
 {
 	RENDLOG	=	5,
-	RENDHASH =	1<<RENDLOG,		/* Hash to lookup rendezvous tags */
+	RENDHASH =	1<<RENDLOG,	/* Hash to lookup rendezvous tags */
 	MNTLOG	=	5,
-	MNTHASH =	1<<MNTLOG,		/* Hash to walk mount table */
+	MNTHASH =	1<<MNTLOG,	/* Hash to walk mount table */
 	NFD =		100,		/* per process file descriptors */
 	PGHLOG  =	9,
 	PGHSIZE	=	1<<PGHLOG,	/* Page hash for image lookup */
@@ -438,6 +442,7 @@ struct Pgrp
 
 struct Rgrp
 {
+	Lock;
 	Ref;
 	Proc	*rendhash[RENDHASH];	/* Rendezvous tag hash */
 };
@@ -464,6 +469,7 @@ struct Evalue
 
 struct Fgrp
 {
+	Lock;
 	Ref;
 	Chan	**fd;
 	int	nfd;			/* number allocated */
@@ -497,6 +503,28 @@ struct Waitq
 	Waitq	*next;
 };
 
+/*
+ * fasttick timer interrupts
+ */
+enum {
+	/* Mode */
+	Trelative,	/* timer programmed in ns from now */
+	Tabsolute,	/* timer programmed in ns since epoch */
+	Tperiodic,	/* periodic timer, period in ns */
+};
+struct Timer
+{
+	/* Public interface */
+	int	tmode;		/* See above */
+	vlong	tns;		/* meaning defined by mode */
+	void	(*tf)(Ureg*, Timer*);
+	void	*ta;
+	/* Internal */
+	Timers	*tt;		/* Timers queue this timer runs on */
+	uvlong	twhen;		/* ns represented in fastticks */
+	Timer	*tnext;
+};
+
 enum
 {
 	RFNAMEG		= (1<<0),
@@ -535,11 +563,13 @@ enum
 	Broken,
 	Stopped,
 	Rendezvous,
+	Waitrelease,
 
 	Proc_stopme = 1, 	/* devproc requests */
 	Proc_exitme,
 	Proc_traceme,
 	Proc_exitbig,
+	Proc_tracesyscall,
 
 	TUser = 0, 		/* Proc.time */
 	TSys,
@@ -551,11 +581,15 @@ enum
 	NERR = 64,
 	NNOTE = 5,
 
-	Nrq		= 20,	/* number of scheduler priority levels */
-	PriLock		= 0,	/* priority for processes waiting on a lock */
-	PriNormal	= 10,	/* base priority for normal processes */
-	PriKproc	= 13,	/* base priority for kernel processes */
-	PriRoot		= 13,	/* base priority for root processes */
+	Npriq		= 20,		/* number of scheduler priority levels */
+	Nrq		= Npriq+2,	/* number of priority levels including real time */
+	PriRelease	= Npriq,	/* priority of released edf processes */
+	PriEdf		= Npriq+1,	/* priority of active edf processes */
+	PriLock		= 0,		/* priority for processes waiting on a lock */
+	PriExtra	= 1,		/* priority for edf processes in extra time */
+	PriNormal	= 10,		/* base priority for normal processes */
+	PriKproc	= 13,		/* base priority for kernel processes */
+	PriRoot		= 13,		/* base priority for root processes */
 };
 
 typedef uvlong	Ticks;
@@ -571,7 +605,7 @@ struct Schedq
 struct Proc
 {
 	Label	sched;		/* known to l.s */
-	char	*kstack;			/* known to l.s */
+	char	*kstack;	/* known to l.s */
 	Mach	*mach;		/* machine running this proc */
 	char	*text;
 	char	*user;
@@ -603,6 +637,18 @@ struct Proc
 
 	ulong	parentpid;
 	ulong	time[6];	/* User, Sys, Real; child U, S, R */
+
+	uvlong	kentry;		/* Kernel entry time stamp (for profiling) */
+	/*
+	 * pcycles: cycles spent in this process (updated on procsave/restore)
+	 * when this is the current proc and we're in the kernel
+	 * (procrestores outnumber procsaves by one)
+	 * the number of cycles spent in the proc is pcycles + cycles()
+	 * when this is not the current process or we're in user mode
+	 * (procrestores and procsaves balance), it is pcycles.
+	 */
+	vlong	pcycles;
+
 	int	insyscall;
 	int	fpstate;
 
@@ -615,9 +661,9 @@ struct Proc
 	ulong	pc;		/* DEBUG only */
 
 	Lock	rlock;		/* sync sleep/wakeup with postnote */
-	Rendez	*r;		/* rendezvous point slept on */
+	Rendez	*r;			/* rendezvous point slept on */
 	Rendez	sleep;		/* place for syssleep/debug */
-	int	notepending;	/* note issued but not acted on */
+	int	notepending;/* note issued but not acted on */
 	int	kp;		/* true if a kernel process */
 	Proc	*palarm;	/* Next alarm time */
 	ulong	alarm;		/* Time of call */
@@ -628,9 +674,8 @@ struct Proc
 	ulong	rendval;	/* Value for rendezvous */
 	Proc	*rendhash;	/* Hash list for tag values */
 
-	ulong	twhen;
+	Timer;			/* For tsleep and real-time */
 	Rendez	*trend;
-	Proc	*tlink;
 	int	(*tfn)(void*);
 	void	(*kpfun)(void*);
 	void	*kparg;
@@ -660,7 +705,7 @@ struct Proc
 
 	Mach	*wired;
 	Mach	*mp;		/* machine this process last ran on */
-	ulong	nlocks;		/* number of locks held by proc */
+	Ref	nlocks;		/* number of locks held by proc */
 	ulong	delaysched;
 	ulong	priority;	/* priority level */
 	ulong	basepri;	/* base priority level */
@@ -672,7 +717,8 @@ struct Proc
 	int	preempted;	/* true if this process hasn't finished the interrupt
 				 *  that last preempted it
 				 */
-	Task	*task;		/* if non-null, real-time proc, task contains scheduling params */
+	Edf	*edf;		/* if non-null, real-time proc, edf contains scheduling params */
+	int	trace;		/* process being traced? */
 
 	ulong	qpc;		/* pc calling last blocking qlock */
 
@@ -839,6 +885,7 @@ struct Uart
 	uchar	ostage[Stagesize];
 	uchar	*op;
 	uchar	*oe;
+	int	drain;
 
 	int	modem;			/* hardware flow control on */
 	int	xonoff;			/* software flow control on */
@@ -853,31 +900,21 @@ struct Uart
 
 extern	Uart*	consuart;
 
-/*
- * fasttick timer interrupts
- */
-struct Timer
-{
-	uvlong	when;			/* fastticks when f should be called */
-	ulong	period;
-	void	(*f)(Ureg*, Timer*);
-	void	*a;
-	Timer	*next;
-};
-
 struct Edfinterface {
-	int	(*isedf)(Proc*);
+	int		(*isedf)(Proc*);
 	void	(*edfbury)(Proc*);
-	int	(*edfanyready)(void);
+	int		(*edfanyready)(void);
 	void	(*edfready)(Proc*);
 	Proc*	(*edfrunproc)(void);
 	void	(*edfblock)(Proc*);
 	void	(*edfinit)(void);
 	void	(*edfexpel)(Task*);
-	char *	(*edfadmit)(Task*);
-	void	(*edfdeadline)(Proc*);
-	void	(*resacquire)(Task*, CSN*);
-	void	(*resrelease)(Task*);
+	char*	(*edfadmit)(Task*);
+	void	(*edfyield)(Proc*);
+	void	(*edfdump)(void);
+	char*	(*edfstatus)(char*, char*);
+	char*	(*edfaddproc)(Task*, Proc*);
+	char*	(*edfremproc)(Task*, Proc*);
 };
 
 /*
@@ -890,7 +927,7 @@ struct Perf
 	ulong	avg_inintr;	/* avg time per clock tick in interrupt handlers */
 	ulong	inidle;		/* time since last clock tick in idle loop */
 	ulong	avg_inidle;	/* avg time per clock tick in idle loop */
-	ulong	last;			/* value of perfticks() at last clock tick */
+	ulong	last;		/* value of perfticks() at last clock tick */
 	ulong	period;		/* perfticks() per clock tick */
 };
 
@@ -907,8 +944,6 @@ enum
 };
 
 
-extern Edfinterface *edf;
-
 #define DEVDOTDOT -1
 
 #pragma	varargck	argpos	print	1

+ 22 - 4
sys/src/9/port/portfns.h

@@ -7,7 +7,7 @@ void		alarmkproc(void*);
 Block*		allocb(int);
 int		anyhigher(void);
 int		anyready(void);
-#define	assert(x)	if(x){}else _assert("assert(x) failed")
+#define		assert(x)	if(x){}else _assert("assert(x) failed")
 void		_assert(char*);
 Image*		attachimage(int, Chan*, ulong, ulong);
 Page*		auxpage(void);
@@ -56,9 +56,10 @@ void		cunmount(Chan*, Chan*);
 void		cupdate(Chan*, uchar*, int, vlong);
 void		cwrite(Chan*, uchar*, int, vlong);
 ulong		dbgpc(Proc*);
-int		decref(Ref*);
+long		decref(Ref*);
 int		decrypt(void*, void*, int);
 void		delay(int);
+Proc*		dequeueproc(Schedq*, Proc*);
 Chan*		devattach(int, char*);
 Block*		devbread(Chan*, long, ulong);
 long		devbwrite(Chan*, Block*, ulong);
@@ -88,6 +89,13 @@ void		dumpstack(void);
 Fgrp*		dupfgrp(Fgrp*);
 void		duppage(Page*);
 void		dupswap(Page*);
+void		edfinit(Proc*);
+char*		edfadmit(Proc*);
+int		edfready(Proc*);
+void		edfrecord(Proc*);
+void		edfrun(Proc*, int);
+void		edfstop(Proc*);
+void		edfyield(void);
 int		emptystr(char*);
 int		encrypt(void*, void*, int);
 void		envcpy(Egrp*, Egrp*);
@@ -99,6 +107,7 @@ long		execregs(ulong, ulong, ulong);
 void		exhausted(char*);
 void		exit(int);
 uvlong		fastticks(uvlong*);
+uvlong		fastticks2ns(uvlong);
 int		fault(ulong, int);
 void		fdclose(int, int);
 Chan*		fdtochan(int, int, int, int);
@@ -129,7 +138,7 @@ void		iallocsummary(void);
 long		ibrk(ulong, int);
 void		ilock(Lock*);
 void		iunlock(Lock*);
-int		incref(Ref*);
+long		incref(Ref*);
 void		initseg(void);
 int		iprint(char*, ...);
 void		isdir(Chan*);
@@ -163,6 +172,7 @@ long		logread(Log*, void*, ulong, long);
 void		log(Log*, int, char*, ...);
 Cmdtab*		lookupcmd(Cmdbuf*, Cmdtab*, int);
 Page*		lookpage(Image*, ulong);
+#define		MS2NS(n) (((vlong)(n))*1000000LL)
 void		machinit(void);
 void*		mallocz(ulong, int);
 void*		malloc(ulong);
@@ -170,6 +180,7 @@ void		mallocsummary(void);
 Block*		mem2bl(uchar*, int);
 void		mfreeseg(Segment*, ulong, int);
 void		microdelay(int);
+uvlong		mk64fract(uvlong, uvlong);
 void		mkqid(Qid*, vlong, ulong, int);
 void		mmurelease(Proc*);
 void		mmuswitch(Proc*);
@@ -181,6 +192,7 @@ ulong		ms2tk(ulong);
 ulong		msize(void*);
 ulong		ms2tk(ulong);
 uvlong		ms2fastticks(ulong);
+void		mul64fract(uvlong*, uvlong, uvlong);
 void		muxclose(Mnt*);
 Chan*		namec(char*, int, int, ulong);
 void		nameerror(char*, char*);
@@ -198,6 +210,7 @@ void		nexterror(void);
 Cname*		newcname(char*);
 int		notify(Ureg*);
 int		nrand(int);
+uvlong		ns2fastticks(uvlong);
 int		okaddr(ulong, ulong, int);
 int		openmode(ulong);
 Block*		packblock(Block*);
@@ -230,6 +243,7 @@ void		procinit0(void);
 void		procflushseg(Segment*);
 void		procpriority(Proc*, int, int);
 Proc*		proctab(int);
+extern void	(*proctrace)(Proc*, int); 
 void		procwired(Proc*, int);
 Pte*		ptealloc(void);
 Pte*		ptecpy(Pte*);
@@ -330,13 +344,15 @@ void		timerintr(Ureg*, uvlong);
 void		timerset(uvlong);
 ulong		tk2ms(ulong);
 #define		TK2MS(x) ((x)*(1000/HZ))
+uvlong		tod2fastticks(vlong);
 vlong		todget(vlong*);
 void		todfix(void);
 void		todsetfreq(vlong);
 void		todinit(void);
 void		todset(vlong, vlong, int);
 Block*		trimblock(Block*, int, int);
-void		tsleep(Rendez*, int (*)(void*), void*, int);
+void		tnsleep(Rendez*, int (*)(void*), void*, vlong);
+void		tsleep(Rendez*, int (*)(void*), void*, ulong);
 int		uartctl(Uart*, char*);
 int		uartgetc(void);
 void		uartkick(void*);
@@ -382,5 +398,7 @@ void		hnputs(void*, ushort);
 vlong		nhgetv(void*);
 ulong		nhgetl(void*);
 ushort		nhgets(void*);
+void		_xinc(long*);
+long		_xdec(long*);
 
 #pragma varargck argpos iprint 1

+ 2 - 1
sys/src/9/port/portmkfile

@@ -75,7 +75,8 @@ latin1.$O:	../port/latin1.h
 thwack.$O:	../port/thwack.h
 unthwack.$O:	../port/thwack.h
 devsdp.$O:	../port/thwack.h
-devrealtime.$O edf.$O realtime.$O: ../port/edf.h
+devproc.$O sysproc.$O:	/sys/include/tos.h
+devproc.$O edf.$O proc.$O: /sys/include/trace.h
 
 boot$CONF.out: $CONF print.$O $BOOTDIR/boot.c $BOOTLIB
 	$BOOTDIR/mkboot $CONF > boot$CONF.c

+ 96 - 70
sys/src/9/port/proc.c

@@ -1,9 +1,11 @@
-#include	"u.h"
+#include	<u.h>
 #include	"../port/lib.h"
 #include	"mem.h"
 #include	"dat.h"
 #include	"fns.h"
 #include	"../port/error.h"
+#include	"edf.h"
+#include	<trace.h>
 
 int	nrdy;
 Ref	noteidalloc;
@@ -26,9 +28,9 @@ enum
 	DQ=((HZ-Q)/40)*2,
 };
 
-static Schedq	runq[Nrq];
-static ulong	runvec;
-static int	quanta[Nrq] =
+Schedq	runq[Nrq];
+ulong	runvec;
+static int	quanta[Npriq] =
 {
 	Q+19*DQ, Q+18*DQ, Q+17*DQ, Q+16*DQ,
 	Q+15*DQ, Q+14*DQ, Q+13*DQ, Q+12*DQ,
@@ -37,10 +39,6 @@ static int	quanta[Nrq] =
 	Q+ 3*DQ, Q+ 2*DQ, Q+ 1*DQ, Q+ 0*DQ,
 };
 
-extern Edfinterface	nulledf;
-
-Edfinterface *edf = &nulledf;
-
 char *statename[] =
 {	/* BUG: generate automatically */
 	"Dead",
@@ -55,7 +53,7 @@ char *statename[] =
 	"Broken",
 	"Stopped",
 	"Rendez",
-	"Released",
+	"Waitrelease",
 };
 
 static void pidhash(Proc*);
@@ -67,8 +65,12 @@ static void pidunhash(Proc*);
 void
 schedinit(void)		/* never returns */
 {
+	Edf *e;
+
 	setlabel(&m->sched);
 	if(up) {
+		if((e = up->edf) && (e->flags & Admitted))
+			edfrecord(up);
 		m->proc = 0;
 		switch(up->state) {
 		case Running:
@@ -76,8 +78,10 @@ schedinit(void)		/* never returns */
 			break;
 		case Moribund:
 			up->state = Dead;
-			if(edf->isedf(up))
-				edf->edfbury(up);
+			edfstop(up);
+			if (up->edf)
+				free(up->edf);
+			up->edf = nil;
 
 			/*
 			 * Holding locks from pexit:
@@ -114,10 +118,12 @@ sched(void)
 			(up && up->lastilock)?up->lastilock->pc:0, getcallerpc(x+3));
 
 	if(up){
-		if(up->nlocks && up->state != Moribund){
+		if(up->nlocks.ref && up->state != Moribund && up->delaysched < 20){
+			up->delaysched++;
  			delayedscheds++;
 			return;
 		}
+		up->delaysched = 0;
 
 		splhi();
 
@@ -143,7 +149,7 @@ sched(void)
 int
 anyready(void)
 {
-	return runvec || edf->edfanyready();
+	return runvec;
 }
 
 int
@@ -161,10 +167,6 @@ hzsched(void)
 	/* another cycle, another quantum */
 	up->quanta--;
 
-	/* edf scheduler always gets first chance */
-	if(edf->isedf(up))
-		return;
-
 	/* don't bother unless someone is elegible */
 	if(anyhigher() || (!up->fixedpri && anyready())){
 		sched();
@@ -211,11 +213,11 @@ ready(Proc *p)
 {
 	int s, pri;
 	Schedq *rq;
+	void (*pt)(Proc*, int);
 
 	s = splhi();
 
-	if(edf->isedf(p)){
-		edf->edfready(p);
+	if(edfready(p)){
 		splx(s);
 		return;
 	}
@@ -255,6 +257,8 @@ ready(Proc *p)
 	runvec |= 1<<pri;
 	p->readytime = m->ticks;
 	p->state = Ready;
+	pt = proctrace;
+	if(pt) pt(p, SReady);
 	unlock(runq);
 	splx(s);
 }
@@ -262,7 +266,7 @@ ready(Proc *p)
 /*
  *  remove a process from a scheduling queue (called splhi)
  */
-static Proc*
+Proc*
 dequeueproc(Schedq *rq, Proc *tp)
 {
 	Proc *l, *p;
@@ -326,7 +330,7 @@ rebalance(void)
 	Schedq *rq;
 	Proc *p;
 
-	for(rq = runq; rq < &runq[Nrq]; rq++){
+	for(rq = runq; rq < &runq[Npriq]; rq++){
 		p = rq->head;
 		if(p == nil)
 			continue;
@@ -359,12 +363,10 @@ runproc(void)
 	Proc *p;
 	ulong start, now;
 	int i;
+	void (*pt)(Proc*, int);
 
 	start = perfticks();
 
-	if((p = edf->edfrunproc()) != nil)
-		return p;
-
 	/* 10 is completely arbitrary - it interacts with the comparison in rebalance */
 	/* presotto */
 	if(m->fairness++ == 10){
@@ -411,6 +413,13 @@ found:
 	p->state = Scheding;
 	p->mp = MACHP(m->machno);
 
+	if(p->edf && (p->edf->flags & Admitted)){
+		edflock();
+		edfrun(p, rq == &runq[PriEdf]);	/* start deadline timer and do admin */
+		edfunlock();
+	}
+	pt = proctrace;
+	if(pt) pt(p, SRun);
 	return p;
 }
 
@@ -473,7 +482,7 @@ newproc(void)
 	p->syserrstr = p->errbuf1;
 	p->errbuf0[0] = '\0';
 	p->errbuf1[0] = '\0';
-	p->nlocks = 0;
+	p->nlocks.ref = 0;
 	p->delaysched = 0;
 	kstrdup(&p->user, "*nouser");
 	kstrdup(&p->text, "*notext");
@@ -494,7 +503,7 @@ newproc(void)
 	p->wired = 0;
 	procpriority(p, PriNormal, 0);
 
-	p->task = nil;
+	p->edf = nil;
 
 	return p;
 }
@@ -536,8 +545,8 @@ procwired(Proc *p, int bm)
 void
 procpriority(Proc *p, int pri, int fixed)
 {
-	if(pri >= Nrq)
-		pri = Nrq - 1;
+	if(pri >= Npriq)
+		pri = Npriq - 1;
 	else if(pri < 0)
 		pri = 0;
 	p->basepri = pri;
@@ -580,16 +589,17 @@ void
 sleep(Rendez *r, int (*f)(void*), void *arg)
 {
 	int s;
+	void (*pt)(Proc*, int);
 
 	s = splhi();
 
-	if(up->nlocks)
+	if(up->nlocks.ref)
 		print("process %lud sleeps with %lud locks held, last lock 0x%p locked at pc 0x%lux\n",
-			up->pid, up->nlocks, up->lastlock, up->lastlock->pc);
+			up->pid, up->nlocks.ref, up->lastlock, up->lastlock->pc);
 	lock(r);
 	lock(&up->rlock);
 	if(r->p){
-		print("double sleep %lud %lud\n", r->p->pid, up->pid);
+		print("double sleep called from 0x%lux, %lud %lud\n", getcallerpc(&r), r->p->pid, up->pid);
 		dumpstack();
 	}
 
@@ -614,6 +624,8 @@ sleep(Rendez *r, int (*f)(void*), void *arg)
 		 *  now we are committed to
 		 *  change state and call scheduler
 		 */
+		pt = proctrace;
+		if(pt) pt(up, SSleep);
 		up->state = Wakeme;
 		up->r = r;
 
@@ -633,10 +645,6 @@ sleep(Rendez *r, int (*f)(void*), void *arg)
 			 */
 			unlock(&up->rlock);
 			unlock(r);
-
-			if(edf->isedf(up))
-				edf->edfblock(up);
-
 			gotolabel(&m->sched);
 		}
 	}
@@ -657,44 +665,61 @@ tfn(void *arg)
 }
 
 void
-tsleep(Rendez *r, int (*fn)(void*), void *arg, int ms)
+twakeup(Ureg*, Timer *t)
 {
-	ulong when;
-	Proc *f, **l;
-
-	when = ms2tk(ms) + MACHP(0)->ticks;
-
-	lock(&talarm);
-	/* take out of list if checkalarm didn't */
-	if(up->trend) {
-		l = &talarm.list;
-		for(f = *l; f; f = f->tlink) {
-			if(f == up) {
-				*l = up->tlink;
-				break;
-			}
-			l = &f->tlink;
-		}
+	Proc *p;
+
+	p = t->ta;
+	if(p->trend){
+		wakeup(p->trend);
+		p->trend = 0;
 	}
-	/* insert in increasing time order */
-	l = &talarm.list;
-	for(f = *l; f; f = f->tlink) {
-		if(f->twhen >= when)
-			break;
-		l = &f->tlink;
+}
+
+void
+tnsleep(Rendez *r, int (*fn)(void*), void *arg, vlong ns)
+{
+	if (up->tt)
+		timerdel(up);
+	up->tns = ns;
+	up->tf = twakeup;
+	up->tmode = Trelative;
+	up->ta = up;
+	up->trend = r;
+	up->tfn = fn;
+	timeradd(up);
+
+	if(waserror()){
+		timerdel(up);
+		nexterror();
 	}
+	sleep(r, tfn, arg);
+	if (up->tt)
+		timerdel(up);
+	up->twhen = 0;
+	poperror();
+}
+
+void
+tsleep(Rendez *r, int (*fn)(void*), void *arg, ulong ms)
+{
+	if (up->tt)
+		timerdel(up);
+	up->tns = MS2NS(ms);
+	up->tf = twakeup;
+	up->tmode = Trelative;
+	up->ta = up;
 	up->trend = r;
-	up->twhen = when;
 	up->tfn = fn;
-	up->tlink = *l;
-	*l = up;
-	unlock(&talarm);
+	timeradd(up);
 
 	if(waserror()){
-		up->twhen = 0;
+		timerdel(up);
 		nexterror();
 	}
 	sleep(r, tfn, arg);
+	if (up->tt)
+		timerdel(up);
 	up->twhen = 0;
 	poperror();
 }
@@ -835,8 +860,7 @@ addbroken(Proc *p)
 	broken.p[broken.n++] = p;
 	qunlock(&broken);
 
-	if(edf->isedf(up))
-		edf->edfbury(up);
+	edfstop(up);
 	p->state = Broken;
 	p->psstate = 0;
 	sched();
@@ -887,8 +911,13 @@ pexit(char *exitstr, int freemem)
 	Rgrp *rgrp;
 	Pgrp *pgrp;
 	Chan *dot;
+	void (*pt)(Proc*, int);
 
 	up->alarm = 0;
+	if (up->tt)
+		timerdel(up);
+	pt = proctrace;
+	if(pt) pt(up, SDead);
 
 	/* nil out all the resources under lock (free later) */
 	qlock(&up->debug);
@@ -1006,8 +1035,7 @@ pexit(char *exitstr, int freemem)
 	lock(&procalloc);
 	lock(&palloc);
 
-	if(edf->isedf(up))
-		edf->edfbury(up);
+	edfstop(up);
 	up->state = Moribund;
 	sched();
 	panic("pexit");
@@ -1085,7 +1113,7 @@ dumpaproc(Proc *p)
 		s = statename[p->state];
 	print("%3lud:%10s pc %8lux dbgpc %8lux  %8s (%s) ut %ld st %ld bss %lux qpc %lux nl %lud nd %lud lpc %lux pri %lud\n",
 		p->pid, p->text, p->pc, dbgpc(p),  s, statename[p->state],
-		p->time[0], p->time[1], bss, p->qpc, p->nlocks, p->delaysched, p->lastlock ? p->lastlock->pc : 0, p->priority);
+		p->time[0], p->time[1], bss, p->qpc, p->nlocks.ref, p->delaysched, p->lastlock ? p->lastlock->pc : 0, p->priority);
 }
 
 void
@@ -1259,8 +1287,6 @@ procctl(Proc *p)
 		qunlock(&p->debug);
 		splhi();
 		p->state = Stopped;
-		if(edf->isedf(up))
-			edf->edfblock(up);
 		sched();
 		p->psstate = state;
 		splx(s);

+ 2 - 8
sys/src/9/port/qlock.c

@@ -20,8 +20,8 @@ qlock(QLock *q)
 
 	if(m->ilockdepth != 0)
 		print("qlock: %lux: ilockdepth %d", getcallerpc(&q), m->ilockdepth);
-	if(up != nil && up->nlocks)
-		print("qlock: %lux: nlocks %lud", getcallerpc(&q), up->nlocks);
+	if(up != nil && up->nlocks.ref)
+		print("qlock: %lux: nlocks %lud", getcallerpc(&q), up->nlocks.ref);
 
 	if(q->use.key == 0x55555555)
 		panic("qlock: q %p, key 5*\n", q);
@@ -44,8 +44,6 @@ qlock(QLock *q)
 	up->qnext = 0;
 	up->state = Queueing;
 	up->qpc = getcallerpc(&q);
-	if(edf->isedf(up))
-		edf->edfblock(up);
 	unlock(&q->use);
 	sched();
 }
@@ -108,8 +106,6 @@ rlock(RWlock *q)
 	q->tail = up;
 	up->qnext = 0;
 	up->state = QueueingR;
-	if(edf->isedf(up))
-		edf->edfblock(up);
 	unlock(&q->use);
 	sched();
 }
@@ -165,8 +161,6 @@ wlock(RWlock *q)
 	q->tail = up;
 	up->qnext = 0;
 	up->state = QueueingW;
-	if(edf->isedf(up))
-		edf->edfblock(up);
 	unlock(&q->use);
 	sched();
 }

+ 39 - 19
sys/src/9/port/sysfile.c

@@ -382,15 +382,35 @@ unionrewind(Chan *c)
 	qunlock(&c->umqlock);
 }
 
-static void
-dirqid(uchar *p, Qid *q)
+static int
+dirfixed(uchar *p, uchar *e, Dir *d)
 {
-	p += BIT16SZ+BIT16SZ+BIT32SZ;
-	q->type = GBIT8(p);
+	int len;
+
+	len = GBIT16(p)+BIT16SZ;
+	if(p + len > e)
+		return -1;
+
+	p += BIT16SZ;	/* ignore size */
+	d->type = devno(GBIT16(p), 1);
+	p += BIT16SZ;
+	d->dev = GBIT32(p);
+	p += BIT32SZ;
+	d->qid.type = GBIT8(p);
 	p += BIT8SZ;
-	q->vers = GBIT32(p);
+	d->qid.vers = GBIT32(p);
 	p += BIT32SZ;
-	q->path = GBIT64(p);
+	d->qid.path = GBIT64(p);
+	p += BIT64SZ;
+	d->mode = GBIT32(p);
+	p += BIT32SZ;
+	d->atime = GBIT32(p);
+	p += BIT32SZ;
+	d->mtime = GBIT32(p);
+	p += BIT32SZ;
+	d->length = GBIT64(p);
+
+	return len;
 }
 
 static char*
@@ -530,30 +550,28 @@ mountfix(Chan *c, uchar *op, long n, long maxn)
 	uchar *p;
 	int dirlen, rest;
 	long l;
-	Qid q;
 	uchar *buf, *e;
+	Dir d;
 
 	p = op;
 	buf = nil;
 	nbuf = 0;
 	for(e=&p[n]; p+BIT16SZ<e; p+=dirlen){
-		dirlen = BIT16SZ+GBIT16(p);
-		if(p+dirlen > e)
+		dirlen = dirfixed(p, e, &d);
+		if(dirlen < 0)
 			break;
-		dirqid(p, &q);
 		nc = nil;
 		mh = nil;
-		if(findmount(&nc, &mh, c->type, c->dev, q)){
+		if(findmount(&nc, &mh, d.type, d.dev, d.qid)){
 			/*
 			 * If it's a union directory and the original is
 			 * in the union, don't rewrite anything.
 			 */
 			for(m=mh->mount; m; m=m->next)
-				if(eqchantdqid(m->to, c->type, c->dev, q, 1))
+				if(eqchantdqid(m->to, d.type, d.dev, d.qid, 1))
 					goto Norewrite;
 
 			name = dirname(p, &nname);
-		//	print("mnted %.*s\n", utfnlen(name, nname), name);
 			/*
 			 * Do the stat but fix the name.  If it fails, leave old entry.
 			 * BUG: If it fails because there isn't room for the entry,
@@ -1136,17 +1154,19 @@ sysremove(ulong *arg)
 
 	validaddr(arg[0], 1, 0);
 	c = namec((char*)arg[0], Aremove, 0, 0);
-	if(waserror()){
-		c->type = 0;	/* see below */
-		cclose(c);
-		nexterror();
-	}
 	/*
 	 * Removing mount points is disallowed to avoid surprises
 	 * (which should be removed: the mount point or the mounted Chan?).
 	 */
-	if(c->ismtpt)
+	if(c->ismtpt){
+		cclose(c);
 		error(Eismtpt);
+	}
+	if(waserror()){
+		c->type = 0;	/* see below */
+		cclose(c);
+		nexterror();
+	}
 	devtab[c->type]->remove(c);
 	/*
 	 * Remove clunks the fid, but we need to recover the Chan

+ 14 - 4
sys/src/9/port/sysproc.c

@@ -1,9 +1,11 @@
 #include	"u.h"
+#include	"tos.h"
 #include	"../port/lib.h"
 #include	"mem.h"
 #include	"dat.h"
 #include	"fns.h"
 #include	"../port/error.h"
+#include	"edf.h"
 
 #include	<a.out.h>
 
@@ -246,6 +248,7 @@ sysexec(ulong *arg)
 	Fgrp *f;
 	Image *img;
 	ulong magic, text, entry, data, bss;
+	Tos *tos;
 
 	validaddr(arg[0], 1, 0);
 	file = (char*)arg[0];
@@ -316,7 +319,7 @@ sysexec(ulong *arg)
 	/*
 	 * Args: pass 1: count
 	 */
-	nbytes = BY2WD;		/* hole for profiling clock at top of stack */
+	nbytes = sizeof(Tos);		/* hole for profiling clock at top of stack (and more) */
 	nargs = 0;
 	if(indir){
 		argp = progarg;
@@ -363,6 +366,12 @@ sysexec(ulong *arg)
 	/*
 	 * Args: pass 2: assemble; the pages will be faulted in
 	 */
+	tos = (Tos*)(TSTKTOP - sizeof(Tos));
+	tos->cyclefreq = m->cyclefreq;
+	cycles((uvlong*)&tos->pcycles);
+	tos->pcycles = -tos->pcycles;
+	tos->kcycles = tos->pcycles;
+	tos->clock = 0;
 	argv = (char**)(TSTKTOP - ssize);
 	charp = (char*)(TSTKTOP - nbytes);
 	args = charp;
@@ -540,7 +549,10 @@ syssleep(ulong *arg)
 
 	n = arg[0];
 	if(n <= 0) {
-		yield();
+		if (up->edf && (up->edf->flags & Admitted))
+			edfyield();
+		else
+			yield();
 		return 0;
 	}
 	if(n < TK2MS(1))
@@ -839,8 +851,6 @@ sysrendezvous(ulong *arg)
 	*l = up;
 	up->state = Rendezvous;
 	unlock(up->rgrp);
-	if(edf->isedf(up))
-		edf->edfblock(up);
 
 	sched();
 

+ 31 - 7
sys/src/9/port/taslock.c

@@ -4,6 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "../port/error.h"
+#include "edf.h"
 
 struct
 {
@@ -12,6 +13,23 @@ struct
 	ulong	inglare;
 } lockstats;
 
+static void
+inccnt(Ref *r)
+{
+	_xinc(&r->ref);
+}
+
+static int
+deccnt(Ref *r)
+{
+	int x;
+
+	x = _xdec(&r->ref);
+	if(x < 0)
+		panic("decref pc=0x%lux", getcallerpc(&r));
+	return x;
+}
+
 static void
 dumplockmem(char *tag, Lock *l)
 {
@@ -48,7 +66,7 @@ lock(Lock *l)
 
 	lockstats.locks++;
 	if(up)
-		up->nlocks++;	/* prevent being scheded */
+		inccnt(&up->nlocks);	/* prevent being scheded */
 	if(tas(&l->key) == 0){
 		if(up)
 			up->lastlock = l;
@@ -58,20 +76,26 @@ lock(Lock *l)
 		return 0;
 	}
 	if(up)
-		up->nlocks--;	/* didn't get the lock, allow scheding */
+		deccnt(&up->nlocks);
 
 	lockstats.glare++;
 	for(;;){
 		lockstats.inglare++;
 		i = 0;
 		while(l->key){
+			if(up && up->edf && (up->edf->flags & Admitted)){
+				/* priority inversion, yield */
+				print("inversion 0x%lux pc 0x%lux proc %lud held by pc 0x%lux proc %lud\n",
+					l, pc, up ? up->pid : 0, l->pc, l->p ? l->p->pid : 0);
+				edfyield();
+			}
 			if(i++ > 100000000){
 				i = 0;
 				lockloop(l, pc);
 			}
 		}
 		if(up)
-			up->nlocks++;
+			inccnt(&up->nlocks);
 		if(tas(&l->key) == 0){
 			if(up)
 				up->lastlock = l;
@@ -81,7 +105,7 @@ lock(Lock *l)
 			return 1;
 		}
 		if(up)
-			up->nlocks--;
+			deccnt(&up->nlocks);
 	}
 	return 0;	/* For the compiler */
 }
@@ -136,10 +160,10 @@ int
 canlock(Lock *l)
 {
 	if(up)
-		up->nlocks++;
+		inccnt(&up->nlocks);
 	if(tas(&l->key)){
 		if(up)
-			up->nlocks--;
+			deccnt(&up->nlocks);
 		return 0;
 	}
 
@@ -164,7 +188,7 @@ unlock(Lock *l)
 	coherence();
 
 	if(up)
-		--up->nlocks;
+		deccnt(&up->nlocks);
 }
 
 void

+ 139 - 51
sys/src/9/port/tod.c

@@ -5,57 +5,64 @@
 #include	"fns.h"
 #include	"../port/error.h"
 
-// compute nanosecond epoch time from the fastest ticking clock
-// on the system.  converting the time to nanoseconds requires
-// the following formula
-//
-//	t = (((1000000000<<31)/f)*ticks)>>31
-//
-//  where
-//
-//	'f'		is the clock frequency
-//	'ticks'		are clock ticks
-//
-//  to avoid too much calculation in todget(), we calculate
-//
-//	mult = (1000000000<<31)/f
-//
-//  each time f is set.  f is normally set by a user level
-//  program writing to /dev/fastclock.
-//
-//  We assume that the cpu's of a multiprocessor are synchronized.
-//  This assumption needs to be questioned with each new architecture.
-
+/* compute nanosecond epoch time from the fastest ticking clock
+ * on the system.  converting the time to nanoseconds requires
+ * the following formula
+ *
+ *	t = (((1000000000<<31)/f)*ticks)>>31
+ *
+ *  where
+ *
+ *	'f'		is the clock frequency
+ *	'ticks'		are clock ticks
+ *
+ *  to avoid too much calculation in todget(), we calculate
+ *
+ *	mult = (1000000000<<32)/f
+ *
+ *  each time f is set.  f is normally set by a user level
+ *  program writing to /dev/fastclock.  mul64fract will then
+ *  take that fractional multiplier and a 64 bit integer and
+ *  return the resulting integer product.
+ *
+ *  We assume that the cpu's of a multiprocessor are synchronized.
+ *  This assumption needs to be questioned with each new architecture.
+ */
 
-// frequency of the tod clock
+/* frequency of the tod clock */
 #define TODFREQ	1000000000ULL
 
 struct {
+	int		init;		// true if initialized
 	ulong	cnt;
 	Lock;
-	vlong	multiplier;	// t = off + (multiplier*ticks)>>31
+	uvlong	multiplier;	// t = off + (multiplier*ticks)>>31
+	uvlong	divider;	// ticks = (divider*(ticks-off))>>31
 	vlong	hz;		// frequency of fast clock
 	vlong	last;		// last reading of fast clock
 	vlong	off;		// offset from epoch to last
 	vlong	lasttime;	// last return value from todget
-	vlong	delta;	// add 'delta' each slow clock tick from sstart to send
-	ulong	sstart;	// ...
-	ulong	send;	// ...
+	vlong	delta;		// add 'delta' each slow clock tick from sstart to send
+	ulong	sstart;		// ...
+	ulong	send;		// ...
 } tod;
 
 void
 todinit(void)
 {
+	if(tod.init)
+		return;
 	ilock(&tod);
 	tod.last = fastticks((uvlong*)&tod.hz);
 	iunlock(&tod);
 	todsetfreq(tod.hz);
+	tod.init = 1;
 	addclock0link(todfix, 100);
 }
 
-//
-//  calculate multiplier
-//
+/*
+ *  calculate multiplier
+ */
 void
 todsetfreq(vlong f)
 {
@@ -63,17 +70,21 @@ todsetfreq(vlong f)
 	tod.hz = f;
 
 	/* calculate multiplier for time conversion */
-	tod.multiplier = (TODFREQ<<31)/f;
+	tod.multiplier = mk64fract(TODFREQ, f);
+	tod.divider = mk64fract(f, TODFREQ);
 
 	iunlock(&tod);
 }
 
-//
-//  Set the time of day struct
-//
+/*
+ *  Set the time of day struct
+ */
 void
 todset(vlong t, vlong delta, int n)
 {
+	if(!tod.init)
+		todinit();
+
 	ilock(&tod);
 	if(t >= 0){
 		tod.off = t;
@@ -97,9 +108,9 @@ todset(vlong t, vlong delta, int n)
 	iunlock(&tod);
 }
 
-//
-//  get time of day
-//
+/*
+ *  get time of day
+ */
 vlong
 todget(vlong *ticksp)
 {
@@ -107,14 +118,15 @@ todget(vlong *ticksp)
 	vlong ticks, diff;
 	ulong t;
 
-	if(tod.hz == 0)
-		ticks = fastticks((uvlong*)&tod.hz);
-	else
-		ticks = fastticks(nil);
+	if(!tod.init)
+		todinit();
 
-	// since 64 bit loads are not atomic, we have to lock around them
+	// we don't want time to pass twixt the measuring of fastticks
+	// and grabbing tod.last.  Also none of the vlongs are atomic so
+	// we have to look at them inside the lock.
 	ilock(&tod);
 	tod.cnt++;
+	ticks = fastticks(nil);
 
 	// add in correction
 	if(tod.sstart != tod.send){
@@ -127,8 +139,10 @@ todget(vlong *ticksp)
 
 	// convert to epoch
 	diff = ticks - tod.last;
-	x = (diff * tod.multiplier) >> 31;
-	x = x + tod.off;
+	if(diff < 0)
+		diff = 0;
+	mul64fract(&x, diff, tod.multiplier);
+	x += tod.off;
 
 	// time can't go backwards
 	if(x < tod.lasttime)
@@ -144,9 +158,24 @@ todget(vlong *ticksp)
 	return x;
 }
 
-//
-//  called regularly to avoid calculation overflows
-//
+/*
+ *  convert time of day to ticks
+ */
+uvlong
+tod2fastticks(vlong ns)
+{
+	uvlong x;
+
+	ilock(&tod);
+	mul64fract(&x, ns-tod.off, tod.divider);
+	x += tod.last;
+	iunlock(&tod);
+	return x;
+}
+
+/*
+ *  called regularly to avoid calculation overflows
+ */
 void
 todfix(void)
 {
@@ -160,9 +189,9 @@ todfix(void)
 		ilock(&tod);
 	
 		// convert to epoch
-		x = diff * tod.multiplier;
-		x = x >> 31;
-		x = x + tod.off;
+		mul64fract(&x, diff, tod.multiplier);
+if(x > 30000000000ULL) print("todfix %llud\n", x);
+		x += tod.off;
 	
 		// protect against overflows
 		tod.last = ticks;
@@ -189,7 +218,66 @@ seconds(void)
 uvlong
 ms2fastticks(ulong ms)
 {
-	if(tod.hz == 0)
-		fastticks((uvlong*)&tod.hz);
+	if(!tod.init)
+		todinit();
 	return (tod.hz*ms)/1000ULL;
 }
+
+/*
+ *  convert nanoseconds to fast ticks
+ */
+uvlong
+ns2fastticks(uvlong ns)
+{
+	uvlong res;
+
+	if(!tod.init)
+		todinit();
+	mul64fract(&res, ns, tod.divider);
+	return res;
+}
+
+/*
+ *  convert fast ticks to ns
+ */
+uvlong
+fastticks2ns(uvlong ticks)
+{
+	uvlong res;
+
+	if(!tod.init)
+		todinit();
+	mul64fract(&res, ticks, tod.multiplier);
+	return res;
+}
+
+/*
+ * Make a 64 bit fixed point number that has a decimal point
+ * to the left of the low order 32 bits.  This is used with
+ * mul64fract for converting twixt nanoseconds and fastticks.
+ *
+ *	multiplier = (to<<32)/from
+ */
+uvlong
+mk64fract(uvlong to, uvlong from)
+{
+/*
+	int shift;
+
+	if(to == 0ULL)
+		return 0ULL;
+
+	shift = 0;
+	while(shift < 32 && to < (1ULL<<(32+24))){
+		to <<= 8;
+		shift += 8;
+	}
+	while(shift < 32 && to < (1ULL<<(32+31))){
+		to <<= 1;
+		shift += 1;
+	}
+
+	return (to/from)<<(32-shift);
+*/
+	return (to<<32)/from;
+}

+ 2 - 3
sys/src/9/ppc/blast

@@ -13,7 +13,6 @@ dev
 	kprof
 	uart
 	irq
-	realtime	realtimesub edf
 
 	ether		netif
 	ip		arp chandial ip ipv6 ipaux iproute netif netlog nullmedium pktmedium ptclbsum inferno
@@ -39,8 +38,8 @@ port
 	int cpuserver = 1;
 
 boot cpu
-	tcp
 	il
+	tcp
 
 bootdir
 	/power/bin/rc
@@ -54,8 +53,8 @@ bootdir
 	/power/bin/echo
 	/power/bin/mount
 	/power/bin/sleep
-	/power/bin/auth/factotum
 	/power/bin/ip/ipconfig
+	/power/bin/auth/factotum
 	/power/bin/ls
 	/power/bin/ps
 	/power/bin/auth/wrkey

+ 12 - 13
sys/src/9/ppc/dat.h

@@ -98,7 +98,6 @@ struct PMMU
 {
 	int		mmupid;
 	Ureg	*	mmureg;		/* pointer to ureg structure */
-	ulong	mmuinstr;	/* last miss was an instruction miss */
 };
 
 /*
@@ -125,33 +124,33 @@ typedef	void		KMap;
 struct Mach
 {
 	/* OFFSETS OF THE FOLLOWING KNOWN BY l.s */
-/*0x00*/	int		machno;			/* physical id of processor */
-/*0x04*/	ulong	splpc;			/* pc that called splhi() */
-/*0x08*/	Proc	*	proc;			/* current process on this processor */
+/*0x00*/	int		machno;	/* physical id of processor */
+/*0x04*/	ulong	splpc;	/* pc that called splhi() */
+/*0x08*/	Proc	*	proc;	/* current process on this processor */
 	/* Debugging/statistics for software TLB in l.s (therefore, also known by l.s) */
-/*0x0c*/	ulong	tlbfault;			/* type of last miss */
-/*0x10*/	ulong	imiss;			/* number of instruction misses */
-/*0x14*/	ulong	dmiss;			/* number of data misses */
+/*0x0c*/	ulong	tlbfault;	/* type of last miss */
+/*0x10*/	ulong	imiss;	/* number of instruction misses */
+/*0x14*/	ulong	dmiss;	/* number of data misses */
 
 	/* ordering from here on irrelevant */
 
 	Imap*	imap;
-	uchar*	flash;
 
-	ulong	ticks;			/* of the clock since boot time */
-	Label	sched;			/* scheduler wakeup */
-	Lock		alarmlock;		/* access to alarm list */
-	void	*	alarm;			/* alarms bound to this clock */
+	ulong	ticks;		/* of the clock since boot time */
+	Label	sched;		/* scheduler wakeup */
+	Lock		alarmlock;	/* access to alarm list */
+	void	*	alarm;		/* alarms bound to this clock */
 	int		inclockintr;
 	int		cputype;
 	ulong	loopconst;
-	Perf	perf;			/* performance counters */
+	Perf	perf;				/* performance counters */
 
 	ulong	fairness;		/* for runproc */
 
 	ulong	clkin;		/* basic clock frequency */
 	ulong	vco_out;
 	vlong	cpuhz;
+	uvlong	cyclefreq;		/* Frequency of user readable cycle counter */
 	ulong	bushz;
 	ulong	dechz;
 	ulong	tbhz;

+ 10 - 11
sys/src/9/ppc/devirq.c

@@ -3,8 +3,7 @@
 #include	"mem.h"
 #include	"dat.h"
 #include	"fns.h"
-#include "io.h"
-#include "m8260.h"
+#include	"m8260.h"
 #include	"../port/error.h"
 
 enum{
@@ -79,7 +78,7 @@ ticmstimer(Ureg*, Timer *t)
 {
 	Irqconfig *ic;
 
-	ic = t->a;
+	ic = t->ta;
  	ic->interrupts++;
 	wakeup(&ic->r);
 }
@@ -92,9 +91,9 @@ irqenable(Irqconfig *ic, int irq)
 	if (ic->intenable)
 		return;
 	if (irq == Qmstimer){
-		if (ic->period == 0)
-			ic->period = ms2fastticks(ic->mode);
-		ic->when = 0;
+		if (ic->tstatus == Tidle)
+			ic->tns = MS2NS(ic->mode);
+		ic->tmode = Tperiodic;
 		timeradd(&ic->Timer);
 	}else{
 		if (irqconfig[irq]){
@@ -157,8 +156,8 @@ irqopen(Chan *c, int omode)
 	irq = (ulong)c->qid.path;
 	if(irq != Qdir){
 		ic = mallocz(sizeof(Irqconfig), 1);
-		ic->f = ticmstimer;
-		ic->a = ic;
+		ic->tf = ticmstimer;
+		ic->ta = ic;
 		if (irq == Qmstimer)
 			ic->mode = 1000;
 		c->aux = ic;
@@ -263,11 +262,11 @@ irqwrite(Chan *c, void *a, long n, vlong)
 		if (irq == Qmstimer){
 			ic->mode = strtol(cb->f[1], nil, 0);
 			if (ic->mode <= 0){
-				ic->period = ms2fastticks(1000);
+				ic->tns = MS2NS(1000);
 				ic->mode = 1000;
 				error(Ebadarg);
 			}
-			ic->period = ms2fastticks(ic->mode);
+			ic->tns = MS2NS(ic->mode);
 		}else if (strcmp(cb->f[1], "level") == 0){
 			ic->mode = 0;
 			iomem->siexr &= ~(0x8000 >> irq);
@@ -310,9 +309,9 @@ interrupt(Ureg*, void *arg)
 		print("Unexpected interrupt: %d\n", irq);
 		return;
 	}
+	ilock(&irqlock);
 	if (irq <= Qirq7)
 		iomem->sipnr_h |= 0x8000 >> irq;	/* Clear the interrupt */
-	ilock(&irqlock);
 	for(ic = *pic; ic; ic = ic->next){
 		ic->interrupts++;
 		wakeup(&ic->r);

+ 8 - 1
sys/src/9/ppc/fns.h

@@ -9,6 +9,7 @@ void	clockintr(Ureg*);
 void	clockintrsched(void);
 void	cpuidentify(void);
 void	cpuidprint(void);
+void	cycles(uvlong*);
 void	dbgputc(int c);
 void	dcacheenb(void);
 void	dcflush(void*, ulong);
@@ -160,4 +161,10 @@ void pciclrbme(Pcidev*);
 uchar pciipin(Pcidev *, uchar);
 Pcidev* pcimatch(Pcidev*, int, int);
 Pcidev* pcimatchtbdf(int);
-#define procrestore(p)
+void	procrestore(Proc*);
+
+#ifdef ucuconf
+extern ulong getpll(void);
+extern ulong getl2cr(void);
+extern void putl2cr(ulong);
+#endif

+ 226 - 11
sys/src/9/ppc/l.s

@@ -6,6 +6,14 @@
 #define	SAVELR	SPRG2
 #define	SAVEXX	SPRG3
 
+#ifdef ucuconf
+/* These only exist on the PPC 755: */
+#define	SAVER4	SPRG4
+#define	SAVER5	SPRG5
+#define	SAVER6	SPRG6
+#define	SAVER7	SPRG7
+#endif /* ucuconf */
+
 /* special instruction definitions */
 #define	BDNZ	BC	16,0,
 #define	BDNE	BC	0,2,
@@ -30,9 +38,8 @@
 	 * enable machine check
 	 */
 	MOVW	MSR, R3
-	MOVW	$(MSR_EE|MSR_IP), R4
+	MOVW	$(MSR_ME|MSR_EE|MSR_IP), R4
 	ANDN	R4, R3
-	OR		$(MSR_ME), R3
 	SYNC
 	MOVW	R3, MSR
 	MSRSYNC
@@ -45,7 +52,46 @@
 	MOVW	$KZERO, R3
 	ANDN	R3, R2
 
+	/* before this we're not running above KZERO */
 	BL		mmuinit0(SB)
+	/* after this we are */
+
+#ifdef ucuconf
+	MOVW	$0x2000000, R4		/* size */
+	MOVW	$0, R3			/* base address */
+	RLWNM	$0, R3, $~(CACHELINESZ-1), R5
+	CMP		R4, $0
+	BLE		_dcf1
+	SUB		R5, R3
+	ADD		R3, R4
+	ADD		$(CACHELINESZ-1), R4
+	SRAW	$CACHELINELOG, R4
+	MOVW	R4, CTR
+_dcf0:	DCBF	(R5)
+	ADD		$CACHELINESZ, R5
+	BDNZ	_dcf0
+_dcf1:
+	SYNC
+
+	/* BAT0,3 unused, copy of BAT2 */
+	MOVW	SPR(IBATL(2)), R3
+	MOVW	R3, SPR(IBATL(0))
+	MOVW	SPR(IBATU(2)), R3
+	MOVW	R3, SPR(IBATU(0))
+	MOVW	SPR(DBATL(2)), R3
+	MOVW	R3, SPR(DBATL(0))
+	MOVW	SPR(DBATU(2)), R3
+	MOVW	R3, SPR(DBATU(0))
+
+	MOVW	SPR(IBATL(2)), R3
+	MOVW	R3, SPR(IBATL(3))
+	MOVW	SPR(IBATU(2)), R3
+	MOVW	R3, SPR(IBATU(3))
+	MOVW	SPR(DBATL(2)), R3
+	MOVW	R3, SPR(DBATL(3))
+	MOVW	SPR(DBATU(2)), R3
+	MOVW	R3, SPR(DBATU(3))
+#endif /* ucuconf */
 
 	/* running with MMU on!! */
 
@@ -63,12 +109,85 @@
 
 	RETURN		/* not reached */
 
-#ifdef ucuconf
-#include "lucu.h"
-#endif
-#ifdef blastconf
-#include "lblast.h"
-#endif
+/*
+ * on return from this function we will be running in virtual mode.
+ * We set up the Block Address Translation (BAT) registers thus:
+ * 1) first 3 BATs are 256M blocks, starting from KZERO->0
+ * 2) remaining BAT maps last 256M directly
+ */
+TEXT	mmuinit0(SB), $0
+	/* reset all the tlbs */
+	MOVW	$64, R3
+	MOVW	R3, CTR
+	MOVW	$0, R4
+
+tlbloop:
+	TLBIE	R4
+	SYNC
+	ADD		$BIT(19), R4
+	BDNZ	tlbloop
+	TLBSYNC
+
+#ifndef ucuconf
+	/* BATs 0 and 1 cover memory from 0x00000000 to 0x20000000 */
+
+	/* KZERO -> 0, IBAT and DBAT, 256 MB */
+	MOVW	$(KZERO|(0x7ff<<2)|2), R3
+	MOVW	$(PTEVALID|PTEWRITE), R4	/* PTEVALID => Cache coherency on */
+	MOVW	R3, SPR(IBATU(0))
+	MOVW	R4, SPR(IBATL(0))
+	MOVW	R3, SPR(DBATU(0))
+	MOVW	R4, SPR(DBATL(0))
+
+	/* KZERO+256M -> 256M, IBAT and DBAT, 256 MB */
+	ADD		$(1<<28), R3
+	ADD		$(1<<28), R4
+	MOVW	R3, SPR(IBATU(1))
+	MOVW	R4, SPR(IBATL(1))
+	MOVW	R3, SPR(DBATU(1))
+	MOVW	R4, SPR(DBATL(1))
+
+	/* FPGABASE -> FPGABASE, DBAT, 16 MB */
+	MOVW	$(FPGABASE|(0x7f<<2)|2), R3
+	MOVW	$(FPGABASE|PTEWRITE|PTEUNCACHED), R4	/* FPGA memory, don't cache */
+	MOVW	R3, SPR(DBATU(2))
+	MOVW	R4, SPR(DBATL(2))
+
+	/* IBAT 2 unused */
+	MOVW	R0, SPR(IBATU(2))
+	MOVW	R0, SPR(IBATL(2))
+
+	/* direct map last block, uncached, (not guarded, doesn't work for BAT), DBAT only */
+	MOVW	$(INTMEM|(0x7ff<<2)|2), R3
+	MOVW	$(INTMEM|PTEWRITE|PTEUNCACHED), R4	/* Don't set PTEVALID here */
+	MOVW	R3, SPR(DBATU(3))
+	MOVW	R4, SPR(DBATL(3))
+
+	/* IBAT 3 unused */
+	MOVW	R0, SPR(IBATU(3))
+	MOVW	R0, SPR(IBATL(3))
+#else /* ucuconf */
+	/* BAT 2 covers memory from 0x00000000 to 0x10000000 */
+
+	/* KZERO -> 0, IBAT2 and DBAT2, 256 MB */
+	MOVW	$(KZERO|(0x7ff<<2)|2), R3
+	MOVW	$(PTEVALID|PTEWRITE), R4	/* PTEVALID => Cache coherency on */
+	MOVW	R3, SPR(DBATU(2))
+	MOVW	R4, SPR(DBATL(2))
+	MOVW	R3, SPR(IBATU(2))
+	MOVW	R4, SPR(IBATL(2))
+#endif /* ucuconf */
+
+	/* enable MMU */
+	MOVW	LR, R3
+	OR		$KZERO, R3
+	MOVW	R3, SPR(SRR0)	/* Stored PC for RFI instruction */
+	MOVW	MSR, R4
+	OR		$(MSR_IR|MSR_DR|MSR_RI|MSR_FP), R4
+	MOVW	R4, SPR(SRR1)
+	RFI		/* resume in kernel mode in caller */
+
+	RETURN
 
 TEXT	kfpinit(SB), $0
 	MOVFL	$0,FPSCR(7)
@@ -184,7 +303,8 @@ TEXT	dczap(SB), $-4	/* dczap(virtaddr, count) */
 	ADD		$(CACHELINESZ-1), R4
 	SRAW	$CACHELINELOG, R4
 	MOVW	R4, CTR
-dcz0:	DCBI	(R5)
+dcz0:
+	DCBI	(R5)
 	ADD		$CACHELINESZ, R5
 	BDNZ	dcz0
 dcz1:
@@ -241,6 +361,26 @@ tas0:
 	SYNC
 	RETURN
 
+TEXT	_xinc(SB),$0	/* void _xinc(long *); */
+	MOVW	R3, R4
+xincloop:
+	DCBF	(R4)	/* fix for 603x bug */
+	LWAR	(R4), R3
+	ADD		$1, R3
+	STWCCC	R3, (R4)
+	BNE		xincloop
+	RETURN
+
+TEXT	_xdec(SB),$0	/* long _xdec(long *); */
+	MOVW	R3, R4
+xdecloop:
+	DCBF	(R4)	/* fix for 603x bug */
+	LWAR	(R4), R3
+	ADD		$-1, R3
+	STWCCC	R3, (R4)
+	BNE		xdecloop
+	RETURN
+
 TEXT	tlbflushall(SB), $0
 	MOVW	$TLBENTRIES, R3
 	MOVW	R3, CTR
@@ -324,7 +464,7 @@ TEXT	dmiss(SB), $-4
 	MOVW	R3, 0xc(R1)
 	MOVW	0x14(R1), R3		/* count m->dmiss */
 	ADD		$1, R3
-	MOVW	R3, 0x20(R1)
+	MOVW	R3, 0x14(R1)
 	/* Real work */
 	MOVW	SPR(HASH1), R1	/* (phys) pointer into the hash table */
 	ADD		$BY2PTEG, R1, R2	/* end pointer */
@@ -354,7 +494,7 @@ dmiss2:
 	RFI
 
 /*
- * When a trap sets the TGPR bit (TLB miss traps on the 8260 do this),
+ * When a trap sets the TGPR bit (TLB miss traps do this),
  * registers get remapped: R0-R31 are temporarily inaccessible,
  * and Temporary Registers TR0-TR3 are mapped onto R0-R3.
  * While this bit is set, R4-R31 cannot be used.
@@ -765,6 +905,12 @@ TEXT	icacheenb(SB), $0
 	SYNC
 	RETURN
 
+#ifdef ucuconf
+TEXT getpll(SB),$0
+	MOVW	SPR(1009),R3
+	ISYNC
+	RETURN
+
 TEXT getl2pm(SB),$0
 	MOVW	SPR(1016),R3
 	RETURN
@@ -839,3 +985,72 @@ TEXT setdbat0(SB),$0
 	MOVW	4(R3),R4
 	MOVW	R4,SPR(DBATL(0))
 	RETURN
+#endif /* ucuconf */
+
+TEXT mmudisable(SB),$0
+	/* disable MMU */
+	MOVW	LR, R4
+	MOVW	$KZERO, R5
+	ANDN	R5, R4
+	MOVW	R4, SPR(SRR0)			/* Stored PC for RFI instruction */
+
+	MOVW	MSR, R4
+	MOVW	$(MSR_IR|MSR_DR|MSR_RI|MSR_FP), R5
+	ANDN	R5, R4
+	MOVW	R4, SPR(SRR1)
+
+	MOVW	SPR(HID0), R4			/* Get HID0 and clear unwanted bits */
+	MOVW	$(HID_ICE|HID_DCE), R5
+	ANDN	R5, R4
+	MOVW	R4, SPR(HID0)			/* Cache disable */
+	RFI		/* resume caller with MMU off */
+	RETURN
+
+TEXT kreboot(SB),$0
+	BL		mmudisable(SB)
+	MOVW	R3, LR
+	RETURN
+
+/* mul64fract(uvlong*r, uvlong a, uvlong b)
+ *
+ * multiply uvlong a by uvlong b and return a uvlong result.
+ *
+ * One of the input arguments is a uvlong integer,
+ * the other represents a fractional number with
+ * the integer portion in the most significant word and
+ * the fractional portion in the least significant word.
+ *
+ * Example: mul64fract(&r, 2ULL, 3ULL << 31) returns 1ULL
+ *
+ * The uvlong integer result is returned through r
+ *
+ *	ignored			r0 = lo(a0*b0)
+ *	lsw of result	r1 = hi(a0*b0) +lo(a0*b1) +	lo(a1*b0)
+ *	msw of result	r2 = 			hi(a0*b1) +	hi(a1*b0) +	lo(a1*b1)
+ *	ignored			r3 =									hi(a1*b1)
+ */
+
+TEXT	mul64fract(SB), $0
+	MOVW	a0+8(FP), R9
+	MOVW	a1+4(FP), R10
+	MOVW	b0+16(FP), R4
+	MOVW	b1+12(FP), R5
+
+	MULLW	R10,R5,R13	/* c2 = lo(a1*b1) */
+
+	MULLW	R10,R4,R12	/* c1 = lo(a1*b0) */
+	MULHWU	R10,R4,R7	/* hi(a1*b0) */
+	ADD		R7, R13		/* c2 += hi(a1*b0) */
+
+	MULLW	R9,R5,R6	/* lo(a0*b1) */
+	MULHWU	R9,R5,R7	/* hi(a0*b1) */
+	ADDC	R6, R12		/* c1 += lo(a0*b1) */
+	ADDE	R7, R13		/* c2 += hi(a0*b1) + carry */
+
+	MULHWU	R9,R4,R7	/* hi(a0*b0) */
+	ADDC	R7, R12		/* c1 += hi(a0*b0) */
+	ADDE	R0,	R13		/* c2 += carry */
+
+	MOVW	R12, 4(R3)
+	MOVW	R13, 0(R3)
+	RETURN

+ 2 - 2
sys/src/9/ppc/mkfile

@@ -1,5 +1,5 @@
 CONF=ucu
-CONFLIST=ucu
+CONFLIST=blast ucu
 
 loadaddr = 0x80100000
 
@@ -17,11 +17,11 @@ PORT=\
 	cache.$O\
 	chan.$O\
 	dev.$O\
+	edf.$O\
 	fault.$O\
 	latin1.$O\
 	log.$O\
 	rebootcmd.$O\
-	nulledf.$O\
 	page.$O\
 	parse.$O\
 	pgrp.$O\

+ 3 - 3
sys/src/9/ppc/ucu

@@ -11,10 +11,10 @@ dev
 	cap
 	kprof
 	uart
-	realtime	realtimesub edf
 
 	ether		netif
 	ip		arp chandial ip ipv6 ipaux iproute netif netlog nullmedium pktmedium ptclbsum inferno
+	ce
 
 link
 	ethersaturn
@@ -37,9 +37,9 @@ ip
 port
 	int cpuserver = 1;
 
-boot boot #S/sdC0/
+boot cpu
 	il
-	local
+	tcp
 
 bootdir
 	/power/bin/rc

+ 0 - 21
sys/src/cmd/1a/lex.c

@@ -919,27 +919,6 @@ outhist(void)
 	}
 }
 
-void
-praghjdicks(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
-void
-pragvararg(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
-void
-pragfpround(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
 #include "../cc/lexbody"
 #include "../cc/macbody"
 #include "../cc/compat"

+ 0 - 21
sys/src/cmd/2a/lex.c

@@ -924,27 +924,6 @@ outhist(void)
 	}
 }
 
-void
-praghjdicks(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
-void
-pragvararg(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
-void
-pragfpround(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
 #include "../cc/lexbody"
 #include "../cc/macbody"
 #include "../cc/compat"

+ 0 - 21
sys/src/cmd/5a/lex.c

@@ -673,27 +673,6 @@ outhist(void)
 	}
 }
 
-void
-praghjdicks(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
-void
-pragvararg(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
-void
-pragfpround(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
 #include "../cc/lexbody"
 #include "../cc/macbody"
 #include "../cc/compat"

+ 3 - 0
sys/src/cmd/5c/list.c

@@ -78,6 +78,9 @@ Pconv(Fmt *fp)
 	if(a == ADATA)
 		sprint(str, "	%A	%D/%d,%D", a, &p->from, p->reg, &p->to);
 	else
+	if(p->as == ATEXT)
+		sprint(str, "	%A	%D,%d,%D", a, &p->from, p->reg, &p->to);
+	else
 	if(p->reg == NREG)
 		sprint(str, "	%A%s	%D,%D", a, sc, &p->from, &p->to);
 	else

+ 2 - 0
sys/src/cmd/5c/txt.c

@@ -1098,7 +1098,9 @@ gpseudo(int a, Sym *s, Node *n)
 	p->as = a;
 	p->from.type = D_OREG;
 	p->from.sym = s;
+	p->reg = (profileflg ? 0 : NOPROF);
 	p->from.name = D_EXTERN;
+	p->reg = (profileflg ? 0 : NOPROF);
 	if(s->class == CSTATIC)
 		p->from.name = D_STATIC;
 	naddr(n, &p->to);

+ 1 - 0
sys/src/cmd/5i/stats.c

@@ -5,6 +5,7 @@
 #include "arm.h"
 
 #define Percent(num, max)	((max)?((num)*100)/(max):0)
+#define prof prof5i
 
 extern	Inst	itab[];
 Inst *tables[] = { itab, 0 };

+ 0 - 21
sys/src/cmd/6a/lex.c

@@ -638,27 +638,6 @@ outhist(void)
 	}
 }
 
-void
-praghjdicks(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
-void
-pragvararg(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
-void
-pragfpround(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
 #include "../cc/lexbody"
 #include "../cc/macbody"
 #include "../cc/compat"

+ 5 - 1
sys/src/cmd/6c/list.c

@@ -51,13 +51,17 @@ Pconv(Fmt *fp)
 		sprint(str, "(%ld)	%A	%D/%d,%D",
 			p->lineno, p->as, &p->from, p->from.scale, &p->to);
 	else
+	if(p->as == ATEXT)
+		sprint(str, "(%ld)	%A	%D,%d,%D",
+			p->lineno, p->as, &p->from, p->from.scale, &p->to);
+	else
 	if(p->type != D_NONE) {
 		if(p->type >= D_R0 && p->type < D_R0+32)
 			sprint(str, "(%ld)	%A	%D,%R,%D",
 				p->lineno, p->as, &p->from, (int)p->type, &p->to);
 		else
 		if(p->type == D_CONST)
-			sprint(str, "(%ld)	%A	%D,$%d,%D",
+			sprint(str, "(%ld)	%A	%D,%d,%D",
 				p->lineno, p->as, &p->from, p->offset, &p->to);
 		else
 			sprint(str, "(%ld)	%A	%D,gok(%d),%D",

Some files were not shown because too many files changed in this diff