Plan 9 from Bell Labs 1990-03-12
34 files changed, 8120 insertions(+), 1337 deletions(-) M gnot/boot.c M gnot/boot.h M gnot/clock.c M gnot/dat.h M gnot/devcons.c A gnot/devdk.c A gnot/devincon.c M gnot/devmnt.c M gnot/devpipe.c M gnot/errno.h M gnot/fault.c M gnot/fns.h M gnot/lock.c M gnot/main.c M gnot/proc.c M gnot/stream.c A gnot/sturp.c M gnot/sysproc.c M gnot/trap.c M port/devcons.c A port/devdk.c M port/devlance.c M port/devmnt.c M port/devpipe.c M port/fault.c M port/page.c M port/proc.c M port/stream.c M port/sturp.c M power/dat.h M power/devhs.c M power/errno.h M power/fns.h M power/main.c
M gnot/boot.c => gnot/boot.c +116 -14
@@ 6,7 6,8 @@ Fcall hdr; char buf[100]; void error(char *); void error(char*); void sendmsg(int, char*); main(int argc, char *argv[]) { @@ 18,22 19,123 @@ main(int argc, char *argv[]) open("#c/cons", OWRITE); open("#c/cons", OWRITE); do{ print("user: "); n = read(0, buf, sizeof buf); }while(n==0 || n==1); fd = open("#c/user", 0); if(fd < 0) error("#c/user"); n = read(fd, buf, sizeof buf-1); if(n < 0) error("can't read #c/cons; please reboot"); buf[n-1] = 0; error("can't read #c/user; please reboot"); buf[n] = 0; print("hello %s!\n", buf); if(pipe(p) == -1) error("pipe"); if(write(p[1], "hohoHO!", 8) != 8) close(fd); /* * grab the incon, * push the dk multiplexor onto it, * and use line 1 as the signalling channel. */ cfd = open("#i/ctl", 2); if(cfd < 0) error("opening #i/ctl"); sendmsg(cfd, "push dkmux"); sendmsg(cfd, "config 1 16"); print("dkmux configured\n"); /* * open a datakit channel and call ken via r70, leave the * incon ctl channel open */ fd = open("#k/2/data", 2); if(fd < 0) error("opening #k/2/data"); cfd = open("#k/2/ctl", 2); if(cfd < 0) error("opening #k/2/ctl"); print("#k/2/ctl open\n"); sendmsg(cfd, "connect r70.nonet!bootes!fs"); print("connected to r70.nonet!bootes!fs\n"); close(cfd); /* for(;;){ print("ding\n"); sleep(10000); } /**/ /* * talk to the file server */ print("nop..."); hdr.type = Tnop; n = convS2M(&hdr, buf); if(write(fd, buf, n) != n) error("write nop"); n = read(fd, buf, sizeof buf); if(n <= 0) error("read nop"); if(convM2S(buf, &hdr, n) == 0) { print("n = %d; buf = %.2x %.2x %.2x %.2x\n", n, buf[0], buf[1], buf[2], buf[3]); error("format nop"); } if(hdr.type != Rnop) error("not Rnop"); print("session..."); hdr.type = Tsession; hdr.lang = 'v'; n = convS2M(&hdr, buf); if(write(fd, buf, n) != n) error("write session"); n = read(fd, buf, sizeof buf); if(n <= 0) error("read session"); if(convM2S(buf, &hdr, n) == 0) error("format session"); if(hdr.type != Rsession) error("not Rsession"); if(hdr.err){ print("error %d;", hdr.err); error("remote error"); } print("post..."); sprint(buf, "#s/%s", "bootes"); f = create(buf, 1, 0666); if(f < 0) error("create"); sprint(buf, "%d", fd); if(write(f, buf, strlen(buf)) != strlen(buf)) error("write"); if(read(p[0], buf, 8) != 8) error("read"); print("%s\n", buf); for(;;); close(f); sprint(buf, "#s/%s", "bootes"); f = create("#s/boot", 1, 0666); if(f < 0) error("create"); sprint(buf, "%d", fd); if(write(f, buf, strlen(buf)) != strlen(buf)) error("write"); close(f); print("mount..."); if(bind("/", "/", MREPL) < 0) error("bind"); if(mount(fd, "/", MAFTER|MCREATE, "") < 0) error("mount"); print("success\n"); execl("/68020/init", "init", 0); error("/68020/init"); } void sendmsg(int fd, char *msg) { int n; n = strlen(msg); if(write(fd, msg, n) != n) error(msg); } void
M gnot/boot.h => gnot/boot.h +2197 -819
@@ 1,7 1,7 @@ ulong bootcode[]={ 0x00000107, 0x00000d9c, 0x000001bc, 0x0000207a, 0x00000464, 0x00000130, 0x00000000, 0x00002020, @@ 9,894 9,2102 @@ ulong bootcode[]={ 0x00000000, 0x2f012f00, 0x2c7c0000, 0xbffe610c, 0xdffe610c, 0x2f006100, 0x01604fef, 0x04ce4fef, 0x000c4e75, 0x4fefffc8, 0x42a7486e, 0x81126100, 0x0d664878, 0x20444878, 0x0001486e, 0x811a6100, 0x0d5a4878, 0x20384878, 0x0001486e, 0x81226100, 0x0d4e486e, 0x812a6100, 0x017a4878, 0x202c42a7, 0x486e812a, 0x61002022, 0x2f400050, 0x4aaf0050, 0x6c0a486e, 0x81326100, 0x0404588f, 0x4878001b, 0x486f002c, 0x2f2f0058, 0x61002004, 0x240042e7, 0x2f40005a, 0x44df6c0e, 0x486e813a, 0x610003de, 0x242f005c, 0x588f4237, 0x29200034, 0x486f0034, 0x486e815c, 0x61000496, 0x2f2f0064, 0x61001fac, 0x48780002, 0x486e8167, 0x61001fbe, 0x2f400074, 0x4aaf0074, 0x6c0a486e, 0x816e6100, 0x03a0588f, 0x486e817d, 0x2f2f0078, 0x61000362, 0x486e8188, 0x2f2f0080, 0x61000356, 0x486e8194, 0x6100044e, 0x48780002, 0x486e81a6, 0x61001f7e, 0x4a8042e7, 0x2f40008e, 0x44df6c0a, 0x486e81b0, 0x6100035e, 0x588f4878, 0x0002486e, 0x81c26100, 0x1f5c4a80, 0x42e72f40, 0x009a44df, 0x6c0a486e, 0x81cb6100, 0x033c588f, 0x486e81dc, 0x61000402, 0x486e81eb, 0x2f2f00a0, 0x610002f6, 0x486e8207, 0x610003ee, 0x2f2f00a8, 0x61001f04, 0x486e8229, 0x610003de, 0x422e854e, 0x486f0084, 0x486e854e, 0x61000fba, 0x2f002f40, 0x00b4486f, 0x00902f2f, 0x00bc6100, 0x1f04b0af, 0x00bc670a, 0x486e8230, 0x610002de, 0x588f4878, 0x001c486f, 0x002842a7, 0x61000d3e, 0x24004a82, 0x4fef0010, 0x67e07001, 0xb08267da, 0x4a8242e7, 0x2f420046, 0x44df6c0c, 0x486e8131, 0x6178242f, 0x0048588f, 0x42372920, 0x001f486f, 0x0020486e, 0x81536100, 0x0132486f, 0x00206100, 0x0ce472ff, 0xb2806608, 0x486e815e, 0x614c588f, 0x48780008, 0x486e8163, 0x2f2f0030, 0x61000ce4, 0x7208b280, 0x6708486e, 0x816b612e, 0x009c2f2f, 0x00c86100, 0x1ede2f40, 0x00c84aaf, 0x00c86e0a, 0x486e823a, 0x610002ba, 0x588f2f2f, 0x00c8486e, 0x854e486f, 0x00ac6100, 0x170a4a80, 0x6638102f, 0x00b349c0, 0x2f00102f, 0x00b649c0, 0x2f00102f, 0x00b949c0, 0x2f00102f, 0x00bc49c0, 0x2f002f2f, 0x00e4486e, 0x82436100, 0x0348486e, 0x82666100, 0x02704fef, 0x001c0c2e, 0x0001854e, 0x670a486e, 0x82716100, 0x025c588f, 0x486e827a, 0x61000322, 0x1d7c0002, 0x854e1d7c, 0x00768558, 0x486f00b4, 0x486e854e, 0x61000ef6, 0x2f002f40, 0x00e4486f, 0x00c02f2f, 0x00ec6100, 0x1e40b0af, 0x00ec670a, 0x486e8285, 0x6100021a, 0x588f4878, 0x0008486f, 0x003c2f2f, 0x00386100, 0x0cc07208, 0xb2806708, 0x486e8171, 0x6110588f, 0x486f0044, 0x486e8176, 0x610000d4, 0x60fe4fef, 0xffc04857, 0x42a76100, 0x0c8c486f, 0x00082f2f, 0x0050486e, 0x817a4878, 0x00026100, 0x011a42a7, 0x61744fef, 0x005c4e75, 0x598f4281, 0x001c486f, 0x00cc2f2f, 0x00f86100, 0x1e1a2f40, 0x00f84aaf, 0x00f86e0a, 0x486e8293, 0x610001f6, 0x588f2f2f, 0x00f8486e, 0x854e486f, 0x00dc6100, 0x16464a80, 0x660a486e, 0x82a06100, 0x01d8588f, 0x0c2e0003, 0x854e670a, 0x486e82af, 0x610001c6, 0x588f4a6e, 0x8552671c, 0x302e8552, 0x48c02f00, 0x486e82bc, 0x6100027e, 0x486e82c6, 0x610001a6, 0x4fef000c, 0x486e82d3, 0x6100026a, 0x486e82e1, 0x486e82db, 0x486f00ec, 0x6100032a, 0x487801b6, 0x48780001, 0x486f00f8, 0x61001d6e, 0x4a8042e7, 0x2f40011a, 0x44df6c0a, 0x486e82e8, 0x61000166, 0x588f2f2f, 0x0124486e, 0x82ef486f, 0x01046100, 0x02f4486f, 0x01086100, 0x0dea588f, 0x2f00486f, 0x010c2f2f, 0x012c6100, 0x1d542f00, 0x486f0118, 0x61000dd0, 0x588f221f, 0xb280670a, 0x486e82f2, 0x61000122, 0x588f2f2f, 0x01306100, 0x1d06486e, 0x82fe486e, 0x82f8486f, 0x01206100, 0x02a84878, 0x01b64878, 0x0001486e, 0x83056100, 0x1cec4a80, 0x42e72f40, 0x014e44df, 0x6c0a486e, 0x830d6100, 0x00e4588f, 0x2f2f0158, 0x486e8314, 0x486f0138, 0x61000272, 0x486f013c, 0x61000d68, 0x588f2f00, 0x486f0140, 0x2f2f0160, 0x61001cd2, 0x2f00486f, 0x014c6100, 0x0d4e588f, 0x221fb280, 0x670a486e, 0x83176100, 0x00a0588f, 0x2f2f0164, 0x61001c84, 0x486e831d, 0x6100015e, 0x42a7486e, 0x8328486e, 0x83266100, 0x0d364a80, 0x6c08486e, 0x832a6174, 0x588f486e, 0x83314878, 0x0006486e, 0x832f2f2f, 0x01906100, 0x1c664a80, 0x6c08486e, 0x83326154, 0x588f486e, 0x83386100, 0x011c42a7, 0x486e834d, 0x486e8341, 0x61000cc8, 0x486e8352, 0x61364fef, 0x01b04e75, 0x598f2f2f, 0x000c6100, 0x0cc62f00, 0x2f400008, 0x2f2f0014, 0x2f2f0014, 0x61001c2e, 0xb0af0010, 0x67082f2f, 0x001c6108, 0x588f4fef, 0x00144e75, 0x4fefffc0, 0x485742a7, 0x61001bf0, 0x486f0008, 0x2f2f0050, 0x486e835e, 0x48780002, 0x6100011a, 0x42a76174, 0x4fef005c, 0x4e75598f, 0x42817021, 0xb0816f1e, 0x4ab61d20, 0x8466660e, 0x2daf0008, 0x1d208466, 0x7001588f, 0x4e755281, 0x7021b081, 0x6f1e4ab6, 0x1d2081be, 0x660e2daf, 0x00081d20, 0x81be7001, 0x6ee24280, 0x588f4e75, 0x52817021, 0xb0816ee2, 0x4280588f, 0x4e75598f, 0x206f0008, 0x42827021, 0xb0826f18, 0x20362d20, 0x81beb088, 0x660642b6, 0x2d2081be, 0x52827021, 0xb0826ee8, 0x598f206f, 0x00084282, 0x7021b082, 0x6f182036, 0x2d208466, 0xb0886606, 0x42b62d20, 0x84665282, 0x7021b082, 0x6ee8588f, 0x4e754aaf, 0x00046606, 0x42a7610c, 0x588f486e, 0x83ae6104, 0x588f4e75, 0x4aaf0004, 0x660642a7, 0x610c588f, 0x486e81a6, 0x6104588f, 0x4e75518f, 0x72204a81, 0x6d222eb6, 0x1d2081be, 0x4a976712, 0x2f410004, 0x42b61d20, 0x81be4eb7, 0x0151222f, 0x00045381, 0x4a816cde, 0x2f2f000c, 0x61000bc8, 0x4fef000c, 0x4e754fef, 0xeff841ef, 0x100c5888, 0x2f082f2f, 0x101041ef, 0x0010d1fc, 0x00001000, 0x2f08486f, 0x00146100, 0x01402200, 0x41ef0018, 0x92882f01, 0x486f001c, 0x48780001, 0x61000ba0, 0x240042e7, 0x2f40001e, 0x44df6c1a, 0x52ae800e, 0x700ab0ae, 0x800e6e0e, 0x48780001, 0x6100ff5a, 0x242f0020, 0x588f2002, 0x4fef1024, 0x4e754fef, 0xeff841ef, 0x10105888, 0x2f082f2f, 0x101441ef, 0x0010d1fc, 0x00001000, 0x2f08486f, 0x00146100, 0x00d82200, 0x41ef0018, 0x92882f01, 0x486f001c, 0x2f2f1024, 0x61000b38, 0x240042e7, 0x2f40001e, 0x44df6c1a, 0x52ae800e, 0x700ab0ae, 0x800e6e0e, 0x48780001, 0x6100fef2, 0x242f0020, 0x588f2002, 0x4fef1024, 0x4e75518f, 0x226f000c, 0x2eae8012, 0x518f7220, 0x4a816d22, 0x2eb61d20, 0x84664a97, 0x67122f41, 0x000442b6, 0x1d208466, 0x4eb70151, 0x222f0004, 0x53814a81, 0x6cde2f2f, 0x000c6100, 0x1b204fef, 0x000c4e75, 0x4fefeff8, 0x41ef100c, 0x58882f08, 0x2f2f1010, 0x41ef0010, 0xd1fc0000, 0x10002f08, 0x486f0014, 0x61000140, 0x220041ef, 0x00189288, 0x2f01486f, 0x001c4878, 0x00016100, 0x1b102400, 0x42e72f40, 0x001e44df, 0x6c1a52ae, 0x800e700a, 0xb0ae800e, 0x6e0e4878, 0x00016100, 0xff5a242f, 0x0020588f, 0x20024fef, 0x10244e75, 0x4fefeff8, 0x41ef1010, 0x58882f08, 0x2f2f0014, 0x48691000, 0x2f096174, 0x2d6f0010, 0x801290af, 0x001c4fef, 0x00184e75, 0x142f0007, 0xc43c007f, 0x100249c0, 0x4a360920, 0x8092661e, 0x701eb0ae, 0x80166e04, 0x70014e75, 0x202e8016, 0x120249c1, 0x1d801920, 0x809252ae, 0x2f2f1014, 0x41ef0010, 0xd1fc0000, 0x10002f08, 0x486f0014, 0x610000d8, 0x220041ef, 0x00189288, 0x2f01486f, 0x001c2f2f, 0x10246100, 0x1aa82400, 0x42e72f40, 0x001e44df, 0x6c1a52ae, 0x800e700a, 0xb0ae800e, 0x6e0e4878, 0x00016100, 0xfef2242f, 0x0020588f, 0x20024fef, 0x10244e75, 0x518f226f, 0x000c2eae, 0x801241ef, 0x00105888, 0x2f082f2f, 0x00144869, 0x10002f09, 0x61742d6f, 0x00108012, 0x90af001c, 0x4fef0018, 0x4e75142f, 0x0007c43c, 0x007f1002, 0x49c04a36, 0x09208092, 0x661e701e, 0xb0ae8016, 0x6e047001, 0x4e75202e, 0x80161202, 0x49c11036, 0x19208092, 0x49c02daf, 0x00080d20, 0x801a4280, 0x4e75206f, 0x00042f2f, 0x000c2f2f, 0x000c4868, 0x04002f08, 0x61064fef, 0x00104e75, 0x4fefffe4, 0x226f0028, 0x2f6e8006, 0x00042eae, 0x80022d6f, 0x00208006, 0x202f0024, 0x53802d40, 0x80021019, 0x49c02400, 0x7025b082, 0x675a4a82, 0x661a4236, 0x01618006, 0x202e8006, 0x2d6f0004, 0x80062d57, 0x80024fef, 0x001c4e75, 0x202e8006, 0xb0ae8002, 0x640a1d82, 0x01618006, 0x52ae8006, 0x52ae8012, 0x700ab082, 0x660642ae, 0x801260b2, 0x7009b082, 0x66ac7007, 0xd0ae8012, 0xc0bcffff, 0xfff82d40, 0x8012609a, 0x428474ff, 0x2a0242af, 0x00101419, 0x49c22f49, 0x00284283, 0x702db082, 0x660c7401, 0x26021419, 0x49c22f49, 0x00287030, 0xb0826e08, 0x7039b082, 0x6c0000b6, 0x4a836702, 0x4484702e, 0xb082676a, 0x4a826606, 0x53892f49, 0x00282f2f, 0x00102f05, 0x2f45001c, 0x2f042f44, 0x00242f2f, 0x0038727f, 0xc2821036, 0x49c11d80, 0x19208092, 0x49c02076, 0x52ae8016, 0x120249c1, 0x10361920, 0x809249c0, 0x2daf0008, 0x0d20801a, 0x4e90226f, 0x00382a2f, 0x0024282f, 0x00282400, 0x6c164482, 0x85af0020, 0x42804e75, 0x206f0004, 0x2f2f000c, 0x2f2f000c, 0x48680400, 0x2f086106, 0x4fef0010, 0x4e754fef, 0xffe4226f, 0x00282f6e, 0x80060004, 0x2eae8002, 0x2d6f0020, 0x8006202f, 0x00245380, 0x2d408002, 0x101949c0, 0x24007025, 0xb082675a, 0x4a82661a, 0x42360161, 0x8006202e, 0x80062d6f, 0x00048006, 0x2d578002, 0x4fef001c, 0x4e75202e, 0x8006b0ae, 0x8002640a, 0x1d820161, 0x800652ae, 0x800652ae, 0x8012700a, 0xb0826606, 0x42ae8012, 0x60b27009, 0xb08266ac, 0x7007d0ae, 0x8012c0bc, 0xfffffff8, 0x2d408012, 0x609a4284, 0x74ff2a02, 0x42af0010, 0x141949c2, 0x2f490028, 0x4283702d, 0xb082660c, 0x74012602, 0x141949c2, 0x20022f49, 0x00384fef, 0x001060a8, 0x202f003c, 0xd0822f40, 0x003c4fef, 0x00106000, 0xfef21019, 0x49c02400, 0x2f490028, 0x7030b082, 0x6e867039, 0xb0826d80, 0x4a856c02, 0x42852005, 0x2205d281, 0xd281d081, 0xd080d082, 0x90bc0000, 0x00302a00, 0x6e087039, 0xb0826c00, 0x00b64a83, 0x67024484, 0x702eb082, 0x676a4a82, 0x66065389, 0x2f490028, 0x2f2f0010, 0x2f052f45, 0x001c2f04, 0x2f440024, 0x2f2f0038, 0x727fc282, 0x10361920, 0x809249c0, 0x20760d20, 0x801a4e90, 0x226f0038, 0x2a2f0024, 0x282f0028, 0x24006c16, 0x448285af, 0x00201419, 0x49c22002, 0x2f490038, 0x4fef0010, 0x60a8202f, 0x003cd082, 0x2f40003c, 0x4fef0010, 0x6000fef2, 0x101949c0, 0x24002f49, 0x002860cc, 0x20042204, 0x00287030, 0xb0826e86, 0x7039b082, 0x6d804a85, 0x6c024285, 0x20052205, 0xd281d281, 0xd081d080, 0xd08290bc, 0x00000030, 0x28001019, 0x2a001019, 0x49c02400, 0x2f490028, 0x6000ff1c, 0x4fefffc4, 0x282f004c, 0x226f0040, 0x2a2f0050, 0x206f0048, 0x262f0004, 0x4286700f, 0xc0847201, 0xb0816d00, 0x00f27209, 0xb0816e00, 0x00ea3036, 0x0b208190, 0x4efb0000, 0x7004c084, 0x66044a83, 0x6d72422f, 0x0039741c, 0x20034c45, 0x00012801, 0x7030d880, 0x7039b084, 0x6c047027, 0xd8802202, 0x1f842920, 0x001c7002, 0xb0826f2a, 0x4a86670a, 0x53821fbc, 0x002d2920, 0x001c4878, 0xffff2f2f, 0x00484877, 0x29200024, 0x610000e0, 0x202f0018, 0x4fef0048, 0x4e752003, 0x60cc2004, 0x2204d281, 0xd281d081, 0xd080d082, 0x90bc0000, 0x00302800, 0x101949c0, 0x24002f49, 0x00286000, 0xff1c4fef, 0xffc4282f, 0x004c226f, 0x00402a2f, 0x0050206f, 0x0048262f, 0x00044286, 0x700fc084, 0x7201b081, 0x6d0000f2, 0x7209b081, 0x6e0000ea, 0x30360b20, 0x83984efb, 0x00007004, 0xc0846604, 0x4a836d72, 0x422f0039, 0x741c2003, 0x4c450001, 0x2600b0fc, 0x00006d08, 0x701e9088, 0xb0826f04, 0x4a836fbc, 0x53826094, 0x44837c01, 0x60882611, 0x70042f40, 0x000c4a83, 0x6c044483, 0x7c01422f, 0x0039741c, 0x28017030, 0xd8807039, 0xb0846c04, 0x7027d880, 0x22021f84, 0x2920001c, 0x7002b082, 0x6f2a4a86, 0x670a5382, 0x1fbc002d, 0x2920001c, 0x4878ffff, 0x2f2f0048, 0x48772920, 0x00246100, 0x00e0202f, 0x00184fef, 0x00484e75, 0x20034c45, 0x08012801, 0x7030d880, 0x7039b084, 0x6c047027, 0xd8802202, 0x1f842920, 0x001c7002, 0xb0826e00, 0xff782003, 0x4c450801, 0x2600b0fc, 0x00006d08, 0x701e9088, 0xb0826f06, 0x4a836f00, 0xff5c5382, 0x60ba2611, 0x70042f40, 0x000c6000, 0xff182611, 0x34034283, 0x36027004, 0x2f40000c, 0x6000ff06, 0x00012600, 0xb0fc0000, 0x6d08701e, 0x9088b082, 0x6f044a83, 0x6fbc5382, 0x60944483, 0x7c016088, 0x26117004, 0x2f40000c, 0x6000fefa, 0x4a836c04, 0x44837c01, 0x422f0039, 0x741c2003, 0x4c450801, 0x28017030, 0xd8807039, 0xb0846c04, 0x7027d880, 0x22021f84, 0x2920001c, 0x7002b082, 0x6e00ff78, 0x20034c45, 0x08012600, 0xb0fc0000, 0x6d08701e, 0x9088b082, 0x6f064a83, 0x6f00ff5c, 0x538260ba, 0x26117004, 0x2f40000c, 0x6000feee, 0x6000ff18, 0x26113403, 0x360248c3, 0x42833602, 0x70042f40, 0x000c6000, 0xfedc2611, 0xff062611, 0x70042f40, 0x000c6000, 0xfed04fef, 0xfff4242f, 0x0010282f, 0x0014262f, 0x0018226e, 0x8002206e, 0x80064281, 0x24424a1a, 0x67065281, 0x4a1a66fa, 0x4a846d1e, 0x2001b284, 0x6c18b1c9, 0x640810fc, 0x00202d48, 0x800652ae, 0x80125281, 0x2001b284, 0x6de82442, 0x101a49c0, 0x24006726, 0x4a8367f4, 0xb1c96406, 0x10c22d48, 0x800652ae, 0x8012700a, 0xb0826636, 0x42ae8012, 0x5383101a, 0xfefa2611, 0x70042f40, 0x000c6000, 0xfeee2611, 0x34033602, 0x48c37004, 0x2f40000c, 0x6000fedc, 0x26117004, 0x2f40000c, 0x6000fed0, 0x4feffff4, 0x242f0010, 0x282f0014, 0x262f0018, 0x226e8002, 0x206e8006, 0x42812442, 0x4a1a6706, 0x52814a1a, 0x66fa4a84, 0x6d1e2001, 0xb2846c18, 0xb1c96408, 0x10fc0020, 0x2d488006, 0x52ae8012, 0x52812001, 0xb2846de8, 0x2442101a, 0x49c02400, 0x66da4a84, 0x6c1e2404, 0x4482b282, 0x6c16b1c9, 0x640810fc, 0x00202d48, 0x800652ae, 0x80125281, 0xb2826dea, 0x4fef000c, 0x4e757009, 0xb08266c8, 0x7007d0ae, 0x8012c0bc, 0xfffffff8, 0x2d408012, 0x60b64878, 0xffff42a7, 0x486e818a, 0x6100ff3c, 0x42804fef, 0x67264a83, 0x67f4b1c9, 0x640610c2, 0x2d488006, 0x52ae8012, 0x700ab082, 0x663642ae, 0x80125383, 0x101a49c0, 0x240066da, 0x4a846c1e, 0x24044482, 0xb2826c16, 0xb1c96408, 0x10fc0020, 0x2d488006, 0x52ae8012, 0x5281b282, 0x6dea4fef, 0x000c4e75, 0x598f2037, 0x01610008, 0x1e80422f, 0x00014878, 0xffff2f2f, 0x0010486f, 0x00086100, 0xff167004, 0x4fef0010, 0x4e754878, 0x000a2f2f, 0x00142f2f, 0x00142f2f, 0x00142f2f, 0x00146100, 0xfd8c4fef, 0x00144e75, 0x70fe4e75, 0x7001c0af, 0x00106704, 0x70f84e75, 0x70ff4e75, 0x48780008, 0x2f2f0014, 0x2f2f0014, 0x2f2f0014, 0x2f2f0014, 0x6100fd5a, 0x4fef0014, 0x4e752f2f, 0x000c2f2f, 0x000c2f37, 0x0161000c, 0x6100feac, 0x7009b082, 0x66c87007, 0xd0ae8012, 0xc0bcffff, 0xfff82d40, 0x801260b6, 0x4878ffff, 0x42a7486e, 0x83726100, 0xff3c4280, 0x4fef000c, 0x4e75598f, 0x20370161, 0x00081e80, 0x422f0001, 0x4878ffff, 0x2f2f0010, 0x486f0008, 0x6100ff16, 0x70044fef, 0x000c4e75, 0x70fc4e75, 0x48780010, 0x00104e75, 0x4878000a, 0x2f2f0014, 0x2f2f0014, 0x2f2f0014, 0x2f2f0014, 0x6100fd1e, 0x6100fd8c, 0x4fef0014, 0x4e75202e, 0x8006b0ae, 0x8002640c, 0x1dbc0025, 0x01618006, 0x52ae8006, 0x42804e75, 0x4fefff80, 0x2e2f0090, 0x42af000c, 0xf22f543a, 0x0084f293, 0x0016f22f, 0x54000084, 0xf200001a, 0xf22f7400, 0x008452af, 0x000c42af, 0x001cf23c, 0x40000000, 0x0000f200, 0x0100f22f, 0x4e7570fe, 0x4e757001, 0xc0af0010, 0x670470f8, 0x4e7570ff, 0x4e754878, 0x00082f2f, 0x00142f2f, 0x00142f2f, 0x00142f2f, 0x00146100, 0xfd5a4fef, 0x00144e75, 0x2f2f000c, 0x2f2f000c, 0x2f370161, 0x000c6100, 0xfeac7004, 0x4fef000c, 0x4e7570fc, 0x4e754878, 0x00102f2f, 0x00142f2f, 0x00142f2f, 0x00142f2f, 0x00146100, 0xfd1e4fef, 0x00144e75, 0x202e8006, 0xb0ae8002, 0x640c1dbc, 0x00250161, 0x800652ae, 0x80064280, 0x4e754fef, 0xff802e2f, 0x009042af, 0x000cf22f, 0x543a0084, 0xf28100ee, 0x486f001c, 0xf2930016, 0xf22f5400, 0x0088f227, 0x74006100, 0x0412f22f, 0x40000028, 0xf23c5423, 0x3fd34413, 0x55475a32, 0xf22f6000, 0x0028202f, 0x0028e280, 0x2f400024, 0x44802f00, 0x6100053a, 0xf22f5423, 0x0094f22f, 0x74000030, 0x0084f200, 0x001af22f, 0x74000084, 0x52af000c, 0x42af001c, 0xf23c4000, 0x00000000, 0xf2000100, 0xf22f543a, 0x0084f281, 0x00ee486f, 0x001cf22f, 0x54000088, 0xf2277400, 0x61000412, 0xf22f4000, 0x0028f23c, 0x54233fd3, 0x44135547, 0x5a32f22f, 0x60000028, 0x202f0028, 0x90af002c, 0xe2802f40, 0x00244480, 0x2f006100, 0x05202e2f, 0x00a4f22f, 0x54230034, 0xf2000100, 0x053af22f, 0x54230094, 0xf22f7400, 0x0030202f, 0x002890af, 0x002c2f00, 0x61000520, 0x2e2f00a4, 0xf22f5423, 0x0034f200, 0x0100f23c, 0x40000000, 0x0001f200, 0x0838f295, 0x003453af, 0x0030202f, 0x002c90af, 0x00302f00, 0x610004f0, 0x2e2f00a8, 0xf22f5423, 0x0038f200, 0x0100f23c, 0x40000000, 0x0001f200, 0x0838588f, 0xf292ffd0, 0xf23c4000, 0x00000001, 0x0000000a, 0xf2000838, 0xf2950034, 0x53af0030, 0x202f002c, 0x90af0030, 0x4fef0014, 0xf2920034, 0x52af001c, 0x202f0018, 0x90af001c, 0x2f006100, 0x04f02e2f, 0x00a8f22f, 0x54230038, 0x04aa2e2f, 0x0094f22f, 0x54230024, 0xf2000100, 0xf23c4000, 0x00000001, 0x0000000a, 0xf2000838, 0x588ff292, 0xffd0f23c, 0x40000000, 0x000af200, 0x08384fef, 0x0014f292, 0x003452af, 0x001c202f, 0x001890af, 0x001c2f00, 0x610004aa, 0x2e2f0094, 0xf22f5423, 0x0024f200, 0x0100f23c, 0x40000000, 0x000af200, 0x0838588f, 0xf295ffd0, 0x4a876c02, 0x7e087067, 0x588ff295, 0xffd04a87, 0x6c027e08, 0x7067b0af, 0x00986606, 0x4a876e00, 0x02ac701e, 0xb0876c02, 0x7e1e7402, 0xd4872f47, 0x00907066, 0xb0af0098, 0x66064a87, 0x6e0002ac, 0x701eb087, 0x6c027e1e, 0x7402d487, 0x6616202f, 0x001cd480, 0x6e0e7401, 0xf23c4000, 0x00000000, 0xf2000100, 0x7020b082, 0x6e187065, 0xb0af0098, 0x66067eff, 0x2f470090, 0x7066b0af, 0x00986616, 0x202f001c, 0xd4806e0e, 0x7401f23c, 0x40000000, 0x0000f200, 0x01007020, 0xb0826e18, 0x7065b0af, 0x00986606, 0x7eff2f47, 0x00907065, 0x2f400098, 0x6000fe9c, 0x4284b882, 0x6c3cf203, 0x6100f203, 0x4000f200, 0x0838f295, 0x00045383, 0x70652f40, 0x00986000, 0xfe9c4284, 0xb8826c3c, 0xf2036100, 0xf2034000, 0xf2000128, 0x7030d083, 0x22041f80, 0x49200059, 0xf2000880, 0xf23c4123, 0x0000000a, 0xf2000800, 0x5284b882, 0x6dc47605, 0x70ffd082, 0x24004a82, 0x6d382002, 0x41f72920, 0x00591010, 0x49c0d083, 0x10804283, 0x0c370039, 0xf2000838, 0xf2950004, 0x5383f203, 0x4000f200, 0x01287030, 0xd0832204, 0x1f804920, 0x0059f200, 0x0880f23c, 0x41230000, 0x000af200, 0x08005284, 0xb8826dc4, 0x760570ff, 0xd0822400, 0x4a826d38, 0x200241f7, 0x29200059, 0x6f162002, 0x41f72920, 0x00591010, 0x49c090bc, 0x0000000a, 0x10805283, 0x53824a82, 0x6cc87a01, 0x4a83670c, 0x1f7c0031, 0x005852af, 0x001c4285, 0x42824aaf, 0x000c670a, 0x1fbc002d, 0x29200030, 0x52824283, 0x7801d887, 0x2c077067, 0xb0af0098, 0x661270fb, 0xb0af001c, 0x6e0a202f, 0x001cb087, 0x6f00017a, 0x7066b0af, 0x0098661a, 0x262f001c, 0x44836c02, 0x4283b687, 0x6f022604, 0x202f001c, 0xd8806c02, 0x42844a83, 0x6f222003, 0xd084b086, 0x660a1fbc, 0x002e2920, 0x101049c0, 0xd0831080, 0x42830c37, 0x00392920, 0x00596f16, 0x200241f7, 0x29200059, 0x101049c0, 0x90bc0000, 0x000a1080, 0x52835382, 0x4a826cc8, 0x7a014a83, 0x670c1f7c, 0x00310058, 0x52af001c, 0x42854282, 0x4aaf000c, 0x670a1fbc, 0x002d2920, 0x00305282, 0x1fbc0030, 0x29200030, 0x52825383, 0x4a836ede, 0x4a846f28, 0x42837801, 0xd8872c07, 0x7067b0af, 0x00986612, 0x70fbb0af, 0x001c6e0a, 0x202f001c, 0xb0876f00, 0x017a7066, 0xb0af0098, 0x661a262f, 0x001c4483, 0x6c024283, 0xb6876f02, 0x2604202f, 0x001cd880, 0x6c024284, 0x4a836f22, 0x2003d084, 0xb086660a, 0x1fbc002e, 0x29200030, 0x52822202, 0x1fb75920, 0x00582920, 0x52821fbc, 0x00302920, 0x00305282, 0x52855384, 0x4a846ed8, 0x7067b0af, 0x53834a83, 0x6ede4a84, 0x6f282003, 0xd084b086, 0x660a1fbc, 0x002e2920, 0x00305282, 0x22021fb7, 0x59200058, 0x29200030, 0x52825285, 0x53844a84, 0x6ed87067, 0xb0af0098, 0x670000c2, 0x7068b0af, 0x00986700, 0x00c27068, 0x00b87065, 0xb0af0098, 0x670000b8, 0x7065b0af, 0x00986726, 0x7067b0af, 0x0098671e, 0x42372920, 0x00304878, 0xffff2f2f, 0x0090486f, 0x00386100, 0xfb5e7008, 0x4fef008c, 0x4e751fbc, 0x00652920, 0x00305282, 0x1fbc002b, 0x67267067, 0xb0af0098, 0x671e4237, 0x29200030, 0x5282262f, 0x001c6c0a, 0x1fbc002d, 0x2920002f, 0x44837064, 0xb0836e26, 0x20034c7c, 0x08010000, 0x0064d0bc, 0x00000030, 0x22021f80, 0x4878ffff, 0x2f2f0090, 0x486f0038, 0x6100fb5e, 0x70084fef, 0x008c4e75, 0x1fbc0065, 0x29200030, 0x52822003, 0x52821fbc, 0x002b2920, 0x00305282, 0x262f001c, 0x6c0a1fbc, 0x002d2920, 0x002f4483, 0x7064b083, 0x6e262003, 0x4c7c0801, 0x00000064, 0x26012003, 0x4c7c0801, 0x0000000a, 0xd0bc0000, 0x00302202, 0x1f802920, 0x00305282, 0x20034c7c, 0x08010000, 0x000a2001, 0xd0bc0000, 0x00301f80, 0x00642601, 0x20034c7c, 0x08010000, 0x000ad0bc, 0x00000030, 0x22021f80, 0x29200030, 0x52822003, 0x4c7c0801, 0x0000000a, 0x2001d0bc, 0x00000030, 0x1f802920, 0x00305282, 0x6000ff5c, 0x76ffd682, 0x4a836d0a, 0x0c370030, 0x39200030, 0x67242803, 0x4a846d00, 0xff320c37, 0x002e4920, 0x0030660e, 0x2403b883, 0x6700ff20, 0x52826000, 0xff5c76ff, 0xd6824a83, 0x6d0a0c37, 0x00303920, 0x00306724, 0x28034a84, 0x6d00ff32, 0x0c37002e, 0x49200030, 0x660e2403, 0xb8836700, 0xff205282, 0x6000ff1a, 0x538460de, 0x538360ca, 0x76ff96af, 0x001c6c02, 0x42832c07, 0x9caf001c, 0x70682f40, 0x00986000, 0xfe705387, 0x6000fd52, 0x48780065, 0xff1a5384, 0x60de5383, 0x60ca76ff, 0x96af001c, 0x6c024283, 0x2c079caf, 0x001c7068, 0x2f400098, 0x6000fe70, 0x53876000, 0xfd524878, 0x00652f2f, 0x00142f2f, 0x00142f2f, 0x0014f237, 0x54000161, 0x0014f227, 0x74006100, 0xfbee4fef, 0x00184e75, 0x48780066, 0x2f2f0014, 0x2f2f0014, 0x2f2f0014, 0xf2375400, 0x01610014, 0xf2277400, 0x6100fbee, 0x6100fbc8, 0x4fef0018, 0x4e754878, 0x00662f2f, 0x00672f2f, 0x00142f2f, 0x00142f2f, 0x0014f237, 0x54000161, 0x0014f227, 0x74006100, 0xfbc84fef, 0xfba24fef, 0x00184e75, 0x48780067, 0x2f2f0014, 0x2f2f0014, 0x2f2f0014, 0xf2375400, 0x01610014, 0xf2277400, 0x6100fba2, 0x4fef0018, 0x518ff22f, 0x5500000c, 0x206f0014, 0xf200083a, 0xf28e0010, 0x4290f23c, 0x40000000, 0x0000508f, 0x4e75f217, 0x75002017, 0x7214e2a0, 0xc0bc0000, 0x07ff90bc, 0x000003fe, 0x20800297, 0x800fffff, 0x00973fe0, 0x0000f217, 0x5400508f, 0x4e75518f, 0xf22f5500, 0x000c206f, 0x000c242f, 0x0014f200, 0x083af28e, 0x00104290, 0xf23c4000, 0x00000000, 0x508f4e75, 0xf2177500, 0x20177214, 0xe2a0c0bc, 0x000ef23c, 0x40000000, 0x0000508f, 0x4e75f217, 0x75002017, 0x7214e2a0, 0xc0bc0000, 0x07ffd480, 0x6e0cf23c, 0x40000000, 0x0000508f, 0x4e750c82, 0x000007ff, 0x90bc0000, 0x03fe2080, 0x0297800f, 0xffff0097, 0x3fe00000, 0x6d0c7022, 0x2d40800a, 0x243c0000, 0x07ff0297, 0x800fffff, 0x20027214, 0xe3a08197, 0xf2175400, 0x508f4e75, 0x518ff22f, 0x5500000c, 0x242f0014, 0xf200083a, 0xf28e000e, 0xf23c4000, 0x00000000, 0x508f4e75, 0xf2177500, 0x20177214, 0xe2a0c0bc, 0x000007ff, 0xd4806e0c, 0xf23c4000, 0x00000000, 0x508f4e75, 0x0c820000, 0x07ff6d0c, 0x70222d40, 0x800a243c, 0x4feffff4, 0x206f0018, 0xf22f5500, 0x0010f23c, 0x40000000, 0x0001f200, 0x0838f295, 0x0018f23c, 0x40000000, 0x0000f210, 0x7400f200, 0x08004fef, 0x000c4e75, 0xf22f7500, 0x0004242f, 0x00047214, 0xe2a2c4bc, 0x000007ff, 0x0297800f, 0xffff2002, 0x7214e3a0, 0x8197f217, 0x5400508f, 0x4e754fef, 0xfff4206f, 0x0018f22f, 0x55000010, 0xf23c4000, 0x00000001, 0xf2000838, 0xf2950018, 0xf23c4000, 0x00000000, 0x94bc0000, 0x03fe7015, 0xb0826d2c, 0x203c001f, 0xffffe4a0, 0x4680c1af, 0x000442af, 0x0008f22f, 0x54000004, 0xf2107400, 0xf2000800, 0xf22f5428, 0x00044fef, 0x000c4e75, 0x7035b082, 0x6de072ea, 0xd282203c, 0x7fffffff, 0xe2a04680, 0xc1af0008, 0x60ccf22f, 0x40120004, 0x4e7541ef, 0x00045888, 0x2f082f2f, 0x00086100, 0x0f68508f, 0x4e75226f, 0x00044a19, 0x670c2449, 0x4a1966fc, 0x93ca2009, 0x4e757000, 0x4e757002, 0x4e404e75, 0x598f226f, 0x0008206f, 0x000c10d1, 0x101149c0, 0x4201b001, 0x6d0005f0, 0x7227b001, 0x6e0005e8, 0x30360b20, 0x83c64efb, 0x00002008, 0x90af000c, 0x588f4e75, 0x30290002, 0x10803029, 0x000248c0, 0xe0801140, 0x00015488, 0x30290004, 0x10803029, 0x000448c0, 0xe0801140, 0x00015488, 0x2029000a, 0x10802029, 0x000ae080, 0x11400001, 0x548860ba, 0x30290002, 0x10803029, 0x000248c0, 0xe0801140, 0x00015488, 0x20290006, 0x10802029, 0x0006e080, 0x11400001, 0x20290006, 0x7210e2a0, 0x11400002, 0x20290006, 0x7218e2a0, 0x11400003, 0x42280004, 0x42280005, 0x42280006, 0x42280007, 0x50882029, 0x000a1080, 0x2029000a, 0xe0801140, 0x00015488, 0x52882f29, 0x000a2f29, 0x000e2f08, 0x2f48000c, 0x61000df2, 0x206f000c, 0x20370162, 0x0014000a, 0xd1c04fef, 0x000c6000, 0xff323029, 0x00021080, 0x30290002, 0x48c0e080, 0x11400001, 0x54883029, 0x00041080, 0x30290004, 0x48c0e080, 0x11400001, 0x54882029, 0x000a1080, 0x2029000a, 0xe0801140, 0x00015488, 0x52882f29, 0x000a2f29, 0x000e2f08, 0x2f48000c, 0x61000d8e, 0x206f000c, 0x20370162, 0x0014000a, 0xd1c04fef, 0x000c6000, 0xfece3029, 0x00021080, 0x30290002, 0x48c0e080, 0x11400001, 0x54882029, 0x00061080, 0x20290006, 0xe0801140, 0x00012029, 0x00067210, 0xe2a01140, 0x00022029, 0x00067218, 0xe2a01140, 0x00034228, 0x00044228, 0x00054228, 0x00064228, 0x00075088, 0x2029000a, 0x10802029, 0x000ae080, 0x11400001, 0x54886000, 0xfe6a3029, 0x00021080, 0x30290002, 0x48c0e080, 0x11400001, 0x54883029, 0x00041080, 0x30290004, 0x48c0e080, 0x11400001, 0x54884878, 0x001c4869, 0x00062f08, 0x2f48000c, 0x61000cda, 0x206f000c, 0x701cd1c0, 0x4fef000c, 0x4e75f22f, 0x75000004, 0x242f0004, 0x7214e2a2, 0xc4bc0000, 0x07ff94bc, 0x000003fe, 0x7015b082, 0x6d2c203c, 0x001fffff, 0xe4a04680, 0xc1af0004, 0x42af0008, 0xf22f5400, 0x0004f210, 0x7400f200, 0x0800f22f, 0x54280004, 0x6000fe20, 0x30290002, 0x10803029, 0x000248c0, 0xe0801140, 0x00015488, 0x30290006, 0x10803029, 0x000648c0, 0xe0801140, 0x00015488, 0x6000fdf4, 0x30290002, 0x10803029, 0x000248c0, 0xe0801140, 0x00015488, 0x30290004, 0x10803029, 0x000448c0, 0xe0801140, 0x00015488, 0x48780040, 0x48690006, 0x2f082f48, 0x000c6100, 0x0c64206f, 0x000c7040, 0xd1c04fef, 0x000c6000, 0xfdaa3029, 0x00021080, 0x30290002, 0x48c0e080, 0x11400001, 0x54883029, 0x00041080, 0x30290004, 0x48c0e080, 0x11400001, 0x54886000, 0xfd7e3029, 0x00021080, 0x30290002, 0x48c0e080, 0x11400001, 0x54883029, 0x00041080, 0x30290004, 0x48c0e080, 0x11400001, 0x54886000, 0xfd523029, 0x00021080, 0x30290002, 0x48c0e080, 0x11400001, 0x54884878, 0x00404869, 0x00062f08, 0x2f48000c, 0x61000bd6, 0x206f000c, 0x7040d1c0, 0x4fef000c, 0x4e757035, 0xb0826de0, 0x72ead282, 0x203c7fff, 0xffffe2a0, 0x4680c1af, 0x000860cc, 0xf22f4012, 0x6000fd1c, 0x30290002, 0x10803029, 0x000248c0, 0xe0801140, 0x00015488, 0x30290004, 0x10803029, 0x000448c0, 0xe0801140, 0x00015488, 0x48780040, 0x48690006, 0x2f082f48, 0x000c6100, 0x0b8c206f, 0x000c7040, 0xd1c04fef, 0x000c6000, 0xfcd23029, 0x00021080, 0x30290002, 0x48c0e080, 0x11400001, 0x54886000, 0xfcba6000, 0xff3a3029, 0x00021080, 0x30290002, 0x48c0e080, 0x11400001, 0x54884878, 0x001c4869, 0x000a2f08, 0x2f48000c, 0x61000b3a, 0x206f000c, 0x701cd1c0, 0x4fef000c, 0x6000fc80, 0x60c460aa, 0x6000fc82, 0x30290002, 0x10803029, 0x000248c0, 0xe0801140, 0x00015488, 0x20290006, 0x10802029, 0x0006e080, 0x11400001, 0x20290006, 0x7210e2a0, 0x11400002, 0x20290006, 0x7218e2a0, 0x11400003, 0x42280004, 0x42280005, 0x42280006, 0x42280007, 0x50882029, 0x000a1080, 0x2029000a, 0xe0801140, 0x00015488, 0x2f29000a, 0x2f29000e, 0x2f082f48, 0x000c6100, 0x0ab0206f, 0x000c2037, 0x01620014, 0x000ad1c0, 0x4fef000c, 0x6000fbf0, 0x30290002, 0x10803029, 0x000248c0, 0xe0801140, 0x00015488, 0x30290004, 0x10803029, 0x000448c0, 0xe0801140, 0x00015488, 0x2029000a, 0x10802029, 0x000ae080, 0x11400001, 0x54882f29, 0x000a2f29, 0x000e2f08, 0x2f48000c, 0x61000a4e, 0x206f000c, 0x20370162, 0x0014000a, 0xd1c04fef, 0x000c6000, 0xfb8e6000, 0xfcbe3029, 0x00021080, 0x30290002, 0x48c0e080, 0x11400001, 0x54883029, 0x00041080, 0x30290004, 0x48c0e080, 0x11400001, 0x54882029, 0x000c1080, 0x2029000c, 0xe0881140, 0x00012029, 0x000c7210, 0xe2a81140, 0x00022029, 0x000c7218, 0xe2a81140, 0x00035888, 0x6000fb34, 0x30290002, 0x10803029, 0x000248c0, 0xe0801140, 0x00015488, 0x4878001c, 0x4869000a, 0x2f082f48, 0x000c6100, 0x09b8226f, 0x0014206f, 0x000c701c, 0xd1c02029, 0x00061080, 0x20290006, 0xe0801140, 0x00012029, 0x00067210, 0xe2a01140, 0x00022029, 0x00067218, 0xe2a01140, 0x00035888, 0x10e90026, 0x4fef000c, 0x6000facc, 0x6000ff40, 0x30290002, 0x10803029, 0x000248c0, 0xe0801140, 0x00015488, 0x10e90026, 0x6000faac, 0x60de6000, 0xfdf26000, 0xfe243029, 0x00021080, 0x30290002, 0x48c0e080, 0x11400001, 0x54883029, 0x00081080, 0x30290008, 0x48c0e080, 0x11400001, 0x54886000, 0xfa763029, 0x00021080, 0x30290002, 0x48c0e080, 0x11400001, 0x54884878, 0x001c4869, 0x00062f08, 0x2f48000c, 0x610008fa, 0x701cd1af, 0x000c4878, 0x001c4877, 0x01620018, 0x00222f2f, 0x00146100, 0x08e0206f, 0x0018701c, 0xd1c04fef, 0x00186000, 0xfa261011, 0x49c02f00, 0x486e837a, 0x6100ee02, 0x42804fef, 0x000c4e75, 0x30290004, 0x10803029, 0x000448c0, 0xe0801140, 0x00015488, 0x6000f9f8, 0x10e9000a, 0x6000f9f0, 0x6000f9ec, 0x60fa598f, 0x206f000c, 0x4878001c, 0x2f2f000c, 0x2f082f48, 0x000c6100, 0x087c226f, 0x0014206f, 0x000c701c, 0xd1c02029, 0x001c1080, 0x2029001c, 0xe0801140, 0x00012029, 0x001c7210, 0xe2a01140, 0x00022029, 0x001c7218, 0xe2a01140, 0x00035888, 0x58882029, 0x00241080, 0x20290024, 0xe0801140, 0x00012029, 0x00247210, 0xe2a01140, 0x00022029, 0x00247218, 0xe2a01140, 0x00035888, 0x20290028, 0x10802029, 0x0028e080, 0x11400001, 0x20290028, 0x7210e2a0, 0x11400002, 0x20290028, 0x7218e2a0, 0x11400003, 0x58882029, 0x002c1080, 0x2029002c, 0xe0801140, 0x00012029, 0x002c7210, 0xe2a01140, 0x00022029, 0x002c7218, 0xe2a01140, 0x00035888, 0x20290034, 0x10802029, 0x0034e080, 0x11400001, 0x20290034, 0x7210e2a0, 0x11400002, 0x20290034, 0x7218e2a0, 0x11400003, 0x42280004, 0x42280005, 0x42280006, 0x42280007, 0x50883029, 0x00381080, 0x30290038, 0x48c0e080, 0x11400001, 0x54883029, 0x003a1080, 0x3029003a, 0x48c0e080, 0x11400001, 0x54883029, 0x00201080, 0x30290020, 0x48c0e080, 0x11400001, 0x54883029, 0x00221080, 0x30290022, 0x48c0e080, 0x11400001, 0x54882008, 0x90af0018, 0x4fef0010, 0x4e75598f, 0x226f000c, 0x206f0008, 0x12981011, 0x49c04201, 0xb0016d00, 0x057e7227, 0xb0016e00, 0x05763036, 0x0b208416, 0x4efb0000, 0x202f0008, 0xd0af0010, 0xb0886608, 0x202f0010, 0x588f4e75, 0x4280588f, 0x4e754280, 0x10104281, 0x12280001, 0xe1818081, 0x33400002, 0x54884280, 0x10104281, 0x12280001, 0xe1818081, 0x33400004, 0x54884280, 0x10104281, 0x12280001, 0xe1818081, 0x2340000a, 0x548860a8, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00025488, 0x42801010, 0x42811228, 0x0001e181, 0x80814281, 0x12280002, 0x7410e5a1, 0x80814281, 0x12280003, 0x7418e5a1, 0x80812340, 0x00065088, 0x42801010, 0x42811228, 0x0001e181, 0x80812340, 0x000a5488, 0x52882348, 0x000e2029, 0x000ad1c0, 0x6000ff46, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00025488, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00045488, 0x42801010, 0x42811228, 0x0001e181, 0x80812340, 0x000a5488, 0x52882348, 0x000e2029, 0x000ad1c0, 0x6000fefa, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00025488, 0x42801010, 0x42811228, 0x0001e181, 0x80814281, 0x12280002, 0x7410e5a1, 0x80814281, 0x12280003, 0x7418e5a1, 0x80812340, 0x00065088, 0x42801010, 0x42811228, 0x0001e181, 0x80812340, 0x000a5488, 0x6000fea2, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00025488, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00045488, 0x4878001c, 0x2f082f48, 0x00084869, 0x00066100, 0x056c206f, 0x000c701c, 0xd1c04fef, 0x000c6000, 0xfe584280, 0x10104281, 0x12280001, 0xe1818081, 0x33400002, 0x54884280, 0x10104281, 0x12280001, 0xe1818081, 0x33400006, 0x54886000, 0xfe2c4280, 0x10104281, 0x12280001, 0xe1818081, 0x33400002, 0x54884280, 0x10104281, 0x12280001, 0xe1818081, 0x33400004, 0x54884878, 0x00402f08, 0x2f480008, 0x48690006, 0x610004f6, 0x206f000c, 0x7040d1c0, 0x4fef000c, 0x6000fde2, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00025488, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00045488, 0x6000fdb6, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00025488, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00045488, 0x6000fd8a, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00025488, 0x48780040, 0x2f082f48, 0x00084869, 0x00066100, 0x0468206f, 0x000c7040, 0xd1c04fef, 0x000c6000, 0xfd544280, 0x10104281, 0x12280001, 0xe1818081, 0x33400002, 0x54884280, 0x10104281, 0x12280001, 0xe1818081, 0x33400004, 0x54884878, 0x00402f08, 0x2f480008, 0x48690006, 0x6100041e, 0x206f000c, 0x7040d1c0, 0x4fef000c, 0x6000fd0a, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00025488, 0x6000fcf2, 0x6000ff3a, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00025488, 0x4878001c, 0x2f082f48, 0x00084869, 0x000a6100, 0x03cc206f, 0x000c701c, 0xd1c04fef, 0x000c6000, 0xfcb860c4, 0x60aa6000, 0xfcca4280, 0x10104281, 0x12280001, 0xe1818081, 0x33400002, 0x54884280, 0x10104281, 0x12280001, 0xe1818081, 0x42811228, 0x00027410, 0xe5a18081, 0x42811228, 0x00037418, 0xe5a18081, 0x23400006, 0x50884280, 0x10104281, 0x12280001, 0xe1818081, 0x2340000a, 0x54882348, 0x000e2029, 0x000ad1c0, 0x6000fc4e, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00025488, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00045488, 0x42801010, 0x42811228, 0x0001e181, 0x80812340, 0x000a5488, 0x2348000e, 0x2029000a, 0xd1c06000, 0xfc046000, 0xfd084280, 0x10104281, 0x12280001, 0xe1818081, 0x33400002, 0x54884280, 0x10104281, 0x12280001, 0xe1818081, 0x33400004, 0x54884280, 0x10104281, 0x12280001, 0xe1818081, 0x42811228, 0x00027410, 0xe5a18081, 0x42811228, 0x00037418, 0xe5a18081, 0x2340000c, 0x58886000, 0xfba84280, 0x10104281, 0x12280001, 0xe1818081, 0x33400002, 0x54884878, 0x001c2f08, 0x2f480008, 0x4869000a, 0x61000286, 0x226f0018, 0x206f000c, 0x701cd1c0, 0x42801010, 0x42811228, 0x0001e181, 0x80814281, 0x12280002, 0x7410e5a1, 0x80814281, 0x12280003, 0x7418e5a1, 0x80812340, 0x00065888, 0x13580026, 0x4fef000c, 0x6000fb3e, 0x6000ff3c, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00025488, 0x13580026, 0x6000fb1e, 0x60de6000, 0xfe2c6000, 0xfe5e4280, 0x10104281, 0x12280001, 0xe1818081, 0x33400002, 0x54884280, 0x10104281, 0x12280001, 0xe1818081, 0x33400008, 0x54886000, 0xfae84280, 0x10104281, 0x12280001, 0xe1818081, 0x33400002, 0x54884878, 0x001c2f08, 0x2f480008, 0x48690006, 0x610001c6, 0x701cd1af, 0x000c4878, 0x001c2f2f, 0x00104877, 0x01620020, 0x00226100, 0x01ac206f, 0x0018701c, 0xd1c04fef, 0x00186000, 0xfa981011, 0x49c02f00, 0x486e8388, 0x6100e6ce, 0x42804fef, 0x000c4e75, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00045488, 0x6000fa6a, 0x1358000a, 0x6000fa62, 0x6000fa5e, 0x60fa598f, 0x206f0008, 0x4878001c, 0x2f082f48, 0x00082f2f, 0x00146100, 0x0148226f, 0x0018206f, 0x000c701c, 0xd1c04280, 0x10104281, 0x12280001, 0xe1818081, 0x42811228, 0x00027410, 0xe5a18081, 0x42811228, 0x00037418, 0xe5a18081, 0x2340001c, 0x58885888, 0x42801010, 0x42811228, 0x0001e181, 0x80814281, 0x12280002, 0x7410e5a1, 0x80814281, 0x12280003, 0x7418e5a1, 0x80812340, 0x00245888, 0x42801010, 0x42811228, 0x0001e181, 0x80814281, 0x12280002, 0x7410e5a1, 0x80814281, 0x12280003, 0x7418e5a1, 0x80812340, 0x00285888, 0x42801010, 0x42811228, 0x0001e181, 0x80814281, 0x12280002, 0x7410e5a1, 0x80814281, 0x12280003, 0x7418e5a1, 0x80812340, 0x002c5888, 0x42801010, 0x42811228, 0x0001e181, 0x80814281, 0x12280002, 0x7410e5a1, 0x80814281, 0x12280003, 0x7418e5a1, 0x80812340, 0x00345088, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00385488, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x003a5488, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00205488, 0x42801010, 0x42811228, 0x0001e181, 0x80813340, 0x00225488, 0x200890af, 0x00144fef, 0x00104e75, 0x202f000c, 0x6720246f, 0x0004226f, 0x00082209, 0x828082af, 0x0004c27c, 0x0003671e, 0xb5c9620c, 0x14d95380, 0x66fa202f, 0x00044e75, 0x70154e40, 0x4e757008, 0xd3c0d5c0, 0x15215380, 0x66fa200a, 0x4e75b5c9, 0x620c24d9, 0x598066fa, 0x202f0004, 0x4e75d3c0, 0xd5c02521, 0x598066fa, 0x200a4e75, 0x70084e40, 0x4e757004, 0x4e404e75, 0x70164e40, 0x4e757006, 0x4e404e75, 0x70064e40, 0x4e75700e, 0x70074e40, 0x4e75700d, 0x4e404e75, 0x700f4e40, 0x4e757014, 0x700e4e40, 0x4e75700f, 0x4e404e75, 0x70144e40, 0x4e750000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000d, 0x000026f6, 0x0000270c, 0x00002732, 0x00002750, 0x00002754, 0x00002764, 0x00002782, 0x0000279c, 0x000027a0, 0x000027be, 0x00002bcc, 0x00002bf2, 0x00002c18, 0x000d0000, 0x2a640000, 0x2a7a0000, 0x2aa00000, 0x2abe0000, 0x2ac20000, 0x2ad20000, 0x2af00000, 0x2b0a0000, 0x2b0e0000, 0x2b2c0000, 0x2f3a0000, 0x2f600000, 0x2f860000, 0x00000000, 0x00000000, 0x00000000, @@ 922,8 2130,8 @@ ulong bootcode[]={ 0x00000000, 0x00000000, 0x00000000, 0x00000009, 0x00000000, 0x00090000, 0x00000000, 0x00000000, 0x00000000, @@ 938,57 2146,227 @@ ulong bootcode[]={ 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x020a0b0c, 0x03000000, 0x04000005, 0x00000006, 0x00070000, 0x08000000, 0x0001020a, 0x0b0c0300, 0x00000400, 0x00050000, 0x00060007, 0x00000800, 0x00000000, 0x23632f63, 0x6f6e7300, 0x23632f63, 0x6f6e7300, 0x23632f63, 0x6f6e7300, 0x75736572, 0x3a200063, 0x616e2774, 0x20726561, 0x64202363, 0x00002363, 0x2f636f6e, 0x733b2070, 0x6c656173, 0x65207265, 0x626f6f74, 0x0068656c, 0x6c6f2025, 0x73210a00, 0x70697065, 0x00686f68, 0x6f484f21, 0x73002363, 0x2f636f6e, 0x73002363, 0x2f636f6e, 0x73002363, 0x2f757365, 0x72002363, 0x2f757365, 0x72006361, 0x6e277420, 0x72656164, 0x2023632f, 0x75736572, 0x3b20706c, 0x65617365, 0x20726562, 0x6f6f7400, 0x68656c6c, 0x6f202573, 0x210a0023, 0x692f6374, 0x6c006f70, 0x656e696e, 0x67202369, 0x2f63746c, 0x00707573, 0x6820646b, 0x6d757800, 0x636f6e66, 0x69672031, 0x20313600, 0x646b6d75, 0x7820636f, 0x6e666967, 0x75726564, 0x0a00236b, 0x2f322f64, 0x61746100, 0x6f70656e, 0x696e6720, 0x236b2f32, 0x2f646174, 0x6100236b, 0x2f322f63, 0x746c006f, 0x70656e69, 0x6e672023, 0x6b2f322f, 0x63746c00, 0x236b2f32, 0x2f63746c, 0x206f7065, 0x6e0a0063, 0x6f6e6e65, 0x63742072, 0x37302e6e, 0x6f6e6574, 0x21626f6f, 0x74657321, 0x66730063, 0x6f6e6e65, 0x63746564, 0x20746f20, 0x7237302e, 0x6e6f6e65, 0x7421626f, 0x6f746573, 0x2166730a, 0x006e6f70, 0x2e2e2e00, 0x77726974, 0x65206e6f, 0x70007265, 0x6164206e, 0x6f70006e, 0x203d2025, 0x643b2062, 0x7566203d, 0x20252e32, 0x7820252e, 0x32782025, 0x2e327820, 0x252e3278, 0x0a00666f, 0x726d6174, 0x206e6f70, 0x006e6f74, 0x20526e6f, 0x70007365, 0x7373696f, 0x6e2e2e2e, 0x00777269, 0x74650072, 0x65616400, 0x25730a00, 0x74652073, 0x65737369, 0x6f6e0072, 0x65616420, 0x73657373, 0x696f6e00, 0x666f726d, 0x61742073, 0x65737369, 0x6f6e006e, 0x6f742052, 0x73657373, 0x696f6e00, 0x6572726f, 0x72202564, 0x3b007265, 0x6d6f7465, 0x20657272, 0x6f720070, 0x6f73742e, 0x2e2e0023, 0x732f2573, 0x00626f6f, 0x74657300, 0x63726561, 0x74650025, 0x64007772, 0x69746500, 0x23732f25, 0x7300626f, 0x6f746573, 0x0023732f, 0x626f6f74, 0x3a202573, 0x3a202573, 0x00637265, 0x61746500, 0x25640077, 0x72697465, 0x006d6f75, 0x6e742e2e, 0x2e002f00, 0x2f006269, 0x6e64002f, 0x00006d6f, 0x756e7400, 0x73756363, 0x6573730a, 0x002f3638, 0x3032302f, 0x696e6974, 0x00696e69, 0x74002f36, 0x38303230, 0x2f696e69, 0x7400626f, 0x6f743a20, 0x25733a20, 0x25730a00, 0x00000000, 0x00002a2a, 0x2a000000, 0x00006261, 0x64207479, 0x70653a20, 0x25640a00, 0x62616420, 0x74797065, 0x3a202564, 0x0a000000, 0x2a2a2a00, 0x00000000, 0x01280116, 0x00e0010a, 0x00fe00ec, 0x00e000e0, 0x00840000, 0x6e6f6e2d, 0x7a65726f, 0x20657869, 0x74207374, 0x61747573, 0x00000000, 0x0000f78, 0x00000128, 0x011600e0, 0x010a00fe, 0x00ec00e0, 0x00e00084, 0x00006e6f, 0x6e2d7a65, 0x726f2065, 0x78697420, 0x73746174, 0x75730000, 0x00000618, 0x0614060c, 0x05f405de, 0x05de05de, 0x05de05de, 0x05de058e, 0x05580562, 0x055e055a, 0x0558053c, 0x053804d0, 0x047a0476, 0x0414038c, 0x03880386, 0x0384034e, 0x034a0332, 0x02e802b2, 0x0286025a, 0x021001e4, 0x019a0136, 0x00d20048, 0x000c05a6, 0x05a2059a, 0x0582056c, 0x056c056c, 0x056c056c, 0x056c051c, 0x04e604f0, 0x04ec04e8, 0x04e604ca, 0x04c6045c, 0x04040400, 0x03b60354, 0x0350034e, 0x034c0316, 0x031202fa, 0x02b0027a, 0x024e0222, 0x01d801ac, 0x0162010a, 0x00be005a, 0x001c0000, 0x00024fe, 0x, };
M gnot/clock.c => gnot/clock.c +3 -1
@@ 98,8 98,10 @@ clock(Ureg *ur) SYNCREG[1] = 0x5F; /* clear interrupt */ m->ticks++; p = m->proc; if(p) if(p){ p->pc = ur->pc; p->time[p->insyscall]++; } if(canlock(&m->alarmlock)){ if(m->alarm){ a = m->alarm;
M gnot/dat.h => gnot/dat.h +2 -2
@@ 281,7 281,6 @@ struct Seg struct Proc { Label sched; Lock; Mach *mach; /* machine running this proc */ char text[NAMELEN]; Proc *rnext; /* next process in run queue */ @@ 422,7 421,8 @@ struct Stream { #define STREAMTYPE(x) ((x)&0x1f) #define STREAMID(x) (((x)&~CHDIR)>>5) #define STREAMQID(i,t) (((i)<<5)|(t)) #define PUTNEXT(q,b) (*(q)->next->put)((q)->next, bp) #define PUTNEXT(q,b) (*(q)->next->put)((q)->next, b) #define BLEN(b) ((b)->wptr - (b)->rptr) /* * stream file qid's & high water mark
M gnot/devcons.c => gnot/devcons.c +9 -3
@@ 248,7 248,8 @@ readnum(ulong off, char *buf, ulong n, ulong val, int size) numbconv(&op, 10); tmp[size-1] = ' '; off %= size; if(off >= size) return 0; if(off+n > size) n = size-off; memcpy(buf, tmp+off, n); @@ 261,7 262,8 @@ readstr(ulong off, char *buf, ulong n, char *str) int size; size = strlen(str); off %= size; if(off >= size) return 0; if(off+n > size) n = size-off; memcpy(buf, str+off, n); @@ 380,7 382,9 @@ consread(Chan *c, void *buf, long n) return i; case Qcputime: k = c->offset % sizeof tmp; k = c->offset; if(k >= sizeof tmp) return 0; if(k+n > sizeof tmp) n = sizeof tmp - k; /* easiest to format in a separate buffer and copy out */ @@ 513,8 517,10 @@ typedef struct Incon{ unsigned char send; unsigned char u7; }Incon; /* inconintr(Ureg *ur) { int x; x = ((Incon*)0x40700000)->status; } */
A gnot/devdk.c => gnot/devdk.c +1462 -0
@@ 0,0 1,1462 @@ #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "errno.h" #define NOW (MACHP(0)->ticks) #define DPRINT if(0) enum { /* * configuration parameters */ Ndk = 2, /* max dks */ /* * relative or immutable */ Nline = 256, /* max lines per dk */ Ndir = Nline + 1, /* entries in the dk directory */ Nsubdir = 5, /* entries in the sub directory */ }; typedef struct Dkmsg Dkmsg; typedef struct Line Line; typedef struct Dk Dk; /* * types of possible dkcalls */ enum { Dial, Announce, Redial }; /* * format of messages to/from the datakit controller on the common * signalling line */ struct Dkmsg { uchar type; uchar srv; uchar param0l; uchar param0h; uchar param1l; uchar param1h; uchar param2l; uchar param2h; uchar param3l; uchar param3h; uchar param4l; uchar param4h; }; /* * message codes (T_xxx == dialin.type, D_xxx == dialin.srv) */ #define T_SRV 1 /* service request */ #define D_SERV 1 /* (host to dkmux) announce a service */ #define D_DIAL 2 /* (host to dkmux) connect to a service */ #define D_XINIT 7 /* (dkmux to host) line has been spliced */ #define T_REPLY 2 /* reply to T_SRV/D_SERV or T_SRV/D_DIAL */ #define D_OK 1 /* not used */ #define D_OPEN 2 /* (dkmux to host) connection established */ #define D_FAIL 3 /* (dkmux to host) connection failed */ #define T_CHG 3 /* linege the status of a connection */ #define D_CLOSE 1 /* close the connection */ #define D_ISCLOSED 2 /* (dkmux to host) confirm a close */ #define D_CLOSEALL 3 /* (dkmux to host) close all connections */ #define D_REDIAL 6 /* (host to dkmux) redial a call */ #define T_ALIVE 4 /* (host to dkmux) keep alive message */ #define D_CONTINUE 0 /* host has not died since last msg */ #define D_RESTART 1 /* host has restarted */ #define D_MAXCHAN 2 /* request maximum line number */ #define T_RESTART 8 /* (dkmux to host) datakit restarted */ /* * macros for cracking/forming the window negotiation parameter */ #define MIN(x,y) (x < y ? x : y) #define W_WINDOW(o,d,t) ((o<<8) | (d<<4) | t | 0100000) #define W_VALID(x) ((x) & 0100000) #define W_ORIG(x) (((x)>>8) & 017) #define W_DEST(x) (((x)>>4) & 017) #define W_TRAF(x) ((x) & 017) #define W_DESTMAX(x,y) (W_WINDOW(W_ORIG(x),MIN(W_DEST(x),y),W_TRAF(x))) #define W_LIMIT(x,y) (W_WINDOW(MIN(W_ORIG(x),y),MIN(W_DEST(x),y),W_TRAF(x))) #define W_VALUE(x) (1<<((x)+4)) #define WS_2K 7 /* * one per datakit line */ struct Line { QLock; Rendez r; /* wait here for dial */ int state; /* dial state */ int err; /* dialing error (if non zero) */ int window; /* negotiated window */ int timestamp; /* timestamp of last call received on this line */ int calltolive; /* multiple of 15 seconds for dialing state to last */ Queue *rq; char addr[64]; char raddr[64]; char ruser[32]; char other[64]; Dk *dp; /* interface contianing this line */ }; /* * a dkmux dk. one exists for every stream that a * dkmux line discipline is pushed onto. */ struct Dk { QLock; int ref; char name[64]; /* dk name */ Queue *wq; /* dk output queue */ int lines; /* number of lines */ int ncsc; /* csc line number */ Chan *csc; /* common signalling line */ Line line[Nline]; }; static Dk dk[Ndk]; /* * conversation states (for Line.state) */ typedef enum { Lclosed=0, Lopened, /* opened but no call out */ Lconnected, /* opened and a call set up on htis line */ Lrclose, /* remote end has closed down */ Llclose, /* local end has closed down */ Ldialing, /* dialing a new call */ Llistening, /* this line listening for calls */ Lackwait, /* incoming call waiting for ack/nak */ Laccepting, /* waiting for user to accept or reject the call */ } Lstate; /* * datakit error to errno */ enum { DKok, DKbusy, DKnetotl, DKdestotl, DKbadnet, DKnetbusy, DKinuse, DKreject, }; int dkerr[]={ [DKok]Egreg, [DKbusy]Einuse, /* destination busy */ [DKnetotl]Enetotl, /* network not answering */ [DKdestotl]Edestotl, /* destination not answering */ [DKbadnet]Ebadnet, /* unassigned destination */ [DKnetbusy]Enetbusy, /* network overload */ [DKinuse]Einuse, /* server already exists */ [DKreject]Erejected /* call rejected by destination */ }; #define DKERRS sizeof(dkerr)/sizeof(int) /* * imported */ extern Qinfo urpinfo; /* * predeclared */ Chan* dkattach(char*); static void dkmuxconfig(Dk*, Block*); static int dkmesg(Dk*, int, int, int, int); static void dkcsckproc(void*); static int dklisten(Chan*); static void dkanswer(Chan*, int, int); static void dkwindow(Chan*); static void dkcall(int, Chan*, char*, char*, char*); static void dktimer(void*); static void dkchgmesg(Dk*, Dkmsg*, int); static void dkreplymesg(Dk*, Dkmsg*, int); Chan* dkopen(Chan*, int); /* * the datakit multiplexor stream module definition */ static void dkmuxopen(Queue *, Stream *); static void dkmuxclose(Queue *); static void dkmuxoput(Queue *, Block *); static void dkmuxiput(Queue *, Block *); Qinfo dkmuxinfo = { dkmuxiput, dkmuxoput, dkmuxopen, dkmuxclose, "dkmux" }; /* * a new dkmux. find a free dk structure and assign it to this queue. */ static void dkmuxopen(Queue *q, Stream *s) { Dk *dp; int i; for(dp = dk; dp < &dk[Ndk]; dp++){ if(dp->wq == 0){ qlock(dp); if(dp->wq) { /* someone was faster than us */ qunlock(dp); continue; } q->ptr = q->other->ptr = (void *)dp; dp->csc = 0; dp->ncsc = 4; dp->lines = 16; dp->name[0] = 0; dp->wq = WR(q); qunlock(dp); return; } } error(0, Enoifc); } /* * close down a dkmux */ static void dkmuxclose(Queue *q) { Dk *dp; dp = (Dk *)q->ptr; qlock(dp); if(dp->csc) close(dp->csc); dp->wq = 0; qunlock(dp); } /* * handle configuration */ static void dkmuxoput(Queue *q, Block *bp) { Dk *dp; dp = (Dk *)q->ptr; if(bp->type != M_DATA){ if(streamparse("config", bp)) dkmuxconfig(dp, bp); else PUTNEXT(q, bp); return; } PUTNEXT(q, bp); } /* * gather a message and send it up the appropriate stream * * The first two bytes of each message contains the channel * number, low order byte first. * * Simplifying assumption: one put == one message && the channel number * is in the first block. If this isn't true, demultiplexing will not * work. */ static void dkmuxiput(Queue *q, Block *bp) { Dk *dp; Line *lp; int line; dp = (Dk *)q->ptr; if(bp->type != M_DATA){ PUTNEXT(q, bp); return; } line = bp->rptr[0] | (bp->rptr[1]<<8); bp->rptr += 2; if(line<0 || line>=dp->lines){ print("dkmuxiput bad line %d\n", line); freeb(bp); return; } lp = &dp->line[line]; if(canqlock(lp)){ if(lp->rq) PUTNEXT(lp->rq, bp); else{ print("dkmuxiput unopened line %d\n", line); freeb(bp); } qunlock(lp); } else { print("dkmuxiput unopened line %d\n", line); freeb(bp); } } /* * the datakit line stream module definition */ static void dkstopen(Queue *, Stream *); static void dkstclose(Queue *); static void dkoput(Queue *, Block *); static void dkiput(Queue *, Block *); Qinfo dkinfo = { dkiput, dkoput, dkstopen, dkstclose, "dk" }; /* * open and save a pointer to the conversation */ static void dkstopen(Queue *q, Stream *s) { Dk *dp; Line *lp; dp = &dk[s->dev]; q->other->ptr = q->ptr = lp = &dp->line[s->id]; lp->dp = dp; lp->rq = q; } /* * close down a datakit conversation */ static void dkstclose(Queue *q) { Dk *dp; Line *lp; lp = (Line *)q->ptr; dp = lp->dp; /* * shake hands with dk */ switch(lp->state){ case Lclosed: case Llclose: break; case Lrclose: dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Lclosed; break; case Lackwait: dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Llclose; break; case Llistening: dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Llclose; break; case Lconnected: dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Llclose; break; case Lopened: lp->state = Lclosed; } qlock(lp); lp->rq = 0; qunlock(lp); } /* * this is only called by hangup */ static void dkiput(Queue *q, Block *bp) { PUTNEXT(q, bp); } /* * we assume that each put is a message. * * add a 2 byte channel number to the start of each message */ static void dkoput(Queue *q, Block *bp) { Line *lp; Dk *dp; int line; if(bp->type != M_DATA){ freeb(bp); error(0, Ebadarg); } lp = (Line *)q->ptr; dp = lp->dp; line = lp - dp->line; if(bp->base && bp->rptr - bp->base >= 2) bp->rptr -= 2; bp->rptr[0] = line; bp->rptr[1] = line>>8; PUTNEXT(dp->wq, bp); } /* * configure a datakit multiplexor. this takes 3 arguments separated * by spaces: * the line number of the common signalling channel (must be > 0) * the number of lines in the device (optional) * the name of the dk (optional) * * we can configure only once */ static void dkmuxconfig(Dk *dp, Block *bp) { Chan *c; char *fields[3]; int n; char buf[64]; static int dktimeron; if(dp->csc != 0){ freeb(bp); error(0, Ebadarg); } /* * parse */ n = getfields((char *)bp->rptr, fields, 3, ' '); switch(n){ case 3: strncpy(dp->name, fields[2], sizeof(dp->name)); case 2: dp->lines = strtoul(fields[1], 0, 0); case 1: dp->ncsc = strtoul(fields[0], 0, 0); break; default: freeb(bp); error(0, Ebadarg); } freeb(bp); if(dp->ncsc <= 0 || dp->lines <= dp->ncsc){ dp->lines = 16; error(0, Ebadarg); } /* * open a stream for the csc and push urp onto it */ c = 0; if(waserror()){ if(c) close(c); nexterror(); } c = dkattach(dp->name); c->qid = STREAMQID(dp->ncsc, Sdataqid); dkopen(c, ORDWR); dp->csc = c; /* * start a process to deal with it */ sprint(buf, "**csckproc%d**", dp->ncsc); kproc(buf, dkcsckproc, dp); poperror(); /* * start a keepalive process if one doesn't exist */ if(dktimeron == 0){ dktimeron = 1; kproc("**dktimer**", dktimer, 0); } } /* * qid's */ enum { /* * per line */ Daddrqid, Dlistenqid, Draddrqid, Duserqid, Dotherqid, Dlineqid, /* * per device */ Dcloneqid, }; /* * the dk directory */ Dirtab dkdir[Ndir]; /* * the per stream directory structure */ Dirtab dksubdir[]={ "addr", Daddrqid, 0, 0600, "listen", Dlistenqid, 0, 0600, "other", Dotherqid, 0, 0600, "raddr", Draddrqid, 0, 0600, "ruser", Duserqid, 0, 0600, }; /* * dk file system. most of the calls use dev.c to access the dk * directory and stream.c to access the dk devices. */ void dkreset(void) { } /* * create the dk directory. the files are `clone' and stream * directories '1' to '32' (or whatever Nline is in decimal) */ void dkinit(void) { int i; /* * create the directory. */ /* * the circuits */ for(i = 1; i < Nline; i++) { sprint(dkdir[i].name, "%d", i); dkdir[i].qid = CHDIR|STREAMQID(i, Dlineqid); dkdir[i].length = 0; dkdir[i].perm = 0600; } /* * the clone device */ strcpy(dkdir[0].name, "clone"); dkdir[0].qid = Dcloneqid; dkdir[0].length = 0; dkdir[0].perm = 0600; } Chan* dkattach(char *spec) { Chan *c; Dk *dp; print("attach\n"); /* * find a multiplexor with the same name */ for(dp = dk; dp < &dk[Ndk]; dp++){ qlock(dp); print("name %s %lux\n", dp->name, dp->wq); if(dp->wq && strcmp(spec, dp->name)==0) { dp->ref++; qunlock(dp); break; } qunlock(dp); } if(dp == &dk[Ndk]) error(0, Enoifc); c = devattach('k', spec); c->dev = dp - dk; print("attach done\n"); return c; } Chan* dkclone(Chan *c, Chan *nc) { Dk *dp; dp = &dk[c->dev]; qlock(dp); dp->ref++; qunlock(dp); return devclone(c, nc); } int dkwalk(Chan *c, char *name) { if(c->qid == CHDIR) return devwalk(c, name, dkdir, dk[c->dev].lines, devgen); else return devwalk(c, name, dksubdir, Nsubdir, streamgen); } void dkstat(Chan *c, char *dp) { if(c->qid == CHDIR) devstat(c, dp, dkdir, dk[c->dev].lines, devgen); else devstat(c, dp, dksubdir, Nsubdir, streamgen); } /* * opening a dk device allocates a Line. Opening the `clone' * device is a ``macro'' for finding a free Line and opening * it's ctl file. * * opening the `listen' sub device is a macro for listening for * a new call. Lile `clone' the ctl file of the new channel is * returned. */ Chan* dkopen(Chan *c, int omode) { extern Qinfo dkinfo; Stream *s; Line *lp, *end; Dk *dp; int line; if(c->qid == Dcloneqid){ /* * get an unused device and open it's control file */ dp = &dk[c->dev]; end = &dp->line[dp->lines]; for(lp = &dp->line[dp->ncsc+1]; lp < end; lp++){ if(lp->state == Lclosed && canqlock(lp)){ if(lp->state != Lclosed){ qunlock(lp); continue; } c->qid = STREAMQID(lp-dp->line, Sctlqid); qunlock(lp); break; } } if(lp == end) error(0, Enodev); streamopen(c, &dkinfo); pushq(c->stream, &urpinfo); } else if(STREAMTYPE(c->qid) == Dlistenqid){ /* * listen for a call and open the control file for the * channel on which the call arrived. */ line = dklisten(c); c->qid = STREAMQID(line, Sctlqid); streamopen(c, &dkinfo); pushq(c->stream, &urpinfo); dkwindow(c); } else if(c->qid != CHDIR){ /* * open whatever c points to, make sure it has an urp */ streamopen(c, &dkinfo); if(strcmp(c->stream->procq->next->info->name, "urp")!=0) pushq(c->stream, &urpinfo); } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } void dkcreate(Chan *c, char *name, int omode, ulong perm) { error(0, Eperm); } void dkclose(Chan *c) { Dk *dp; /* real closing happens in lancestclose */ if(c->qid != CHDIR) streamclose(c); dp = &dk[c->dev]; qlock(dp); dp->ref--; qunlock(dp); } long dkread(Chan *c, void *a, long n) { int t; Line *lp; t = STREAMTYPE(c->qid); if(t>=Slowqid || t==Dlineqid) return streamread(c, a, n); if(c->qid == CHDIR) return devdirread(c, a, n, dkdir, dk[c->dev].lines, devgen); lp = &dk[c->dev].line[STREAMID(c->qid)]; switch(t){ case Daddrqid: return stringread(c, a, n, lp->addr); case Draddrqid: return stringread(c, a, n, lp->raddr); case Duserqid: return stringread(c, a, n, lp->ruser); } error(0, Eperm); } long dkwrite(Chan *c, void *a, long n) { int t; char buf[256]; char *field[5]; int m; t = STREAMTYPE(c->qid); /* * get data dispatched as quickly as possible */ if(t == Sdataqid) return streamwrite(c, a, n, 0); /* * easier to do here than in dkoput */ if(t == Sctlqid){ strncpy(buf, a, sizeof buf); m = getfields(buf, field, 5, ' '); if(strcmp(field[0], "connect")==0){ if(m < 2) error(0, Ebadarg); dkcall(Dial, c, field[1], 0, 0); } else if(strcmp(field[0], "announce")==0){ if(m < 2) error(0, Ebadarg); dkcall(Announce, c, field[1], 0, 0); } else if(strcmp(field[0], "redial")==0){ if(m < 4) error(0, Ebadarg); dkcall(Redial, c, field[1], field[2], field[3]); } else if(strcmp(field[0], "accept")==0){ if(m < 2) error(0, Ebadarg); dkanswer(c, strtoul(field[1], 0, 0), 0); } else if(strcmp(field[0], "reject")==0){ if(m < 3) error(0, Ebadarg); dkanswer(c, strtoul(field[1], 0, 0), strtoul(field[2], 0, 0)); } else return streamwrite(c, a, n, 0); return n; } if(t >= Slowqid) return streamwrite(c, a, n, 0); error(0, Eperm); } void dkremove(Chan *c) { error(0, Eperm); } void dkwstat(Chan *c, char *dp) { error(0, Eperm); } void dkerrstr(Error *e, char *buf) { rooterrstr(e, buf); } void dkuserstr(Error *e, char *buf) { extern consuserstr(Error *, char *); consuserstr(e, buf); } /* * send a message to the datakit on the common signaling line */ static int dkmesg(Dk *dp, int type, int srv, int p0, int p1) { Dkmsg d; Block *bp; if(dp->csc == 0) return -1; if(waserror()) return -1; d.type = type; d.srv = srv; d.param0l = p0; d.param0h = p0>>8; d.param1l = p1; d.param1h = p1>>8; d.param2l = 0; d.param2h = 0; d.param3l = 0; d.param3h = 0; d.param4l = 0; d.param4h = 0; streamwrite(dp->csc, (char *)&d, sizeof(Dkmsg), 1); poperror(); return 0; } /* * call out on a datakit */ static int calldone(void *a) { Line *lp; lp = (Line *)a; return lp->state != Ldialing; } static void dkcall(int type, Chan *c, char *addr, char *nuser, char *machine) { char dialstr[66]; int line; char dialtone; int t_val, d_val; Dk *dp; Line *lp; Chan *dc; line = STREAMID(c->qid); dp = &dk[c->dev]; lp = &dp->line[line]; /* * only dial on virgin lines */ if(lp->state != Lclosed) error(0, Ebadarg); DPRINT("dkcall(line=%d, type=%d, dest=%s)\n", line, type, addr); /* * build dial string (guard against new lines) */ if(strchr(addr, '\n')) error(0, Ebadarg); if(strlen(addr)+strlen(u->p->pgrp->user)+2 >= sizeof(dialstr)) error(0, Ebadarg); strcpy(dialstr, addr); switch(type){ case Dial: t_val = T_SRV; d_val = D_DIAL; strcat(dialstr, "\n"); strcat(dialstr, u->p->pgrp->user); strcat(dialstr, "\n"); break; case Announce: t_val = T_SRV; d_val = D_SERV; break; case Redial: t_val = T_CHG; d_val = D_REDIAL; strcat(dialstr, "\n"); strcat(dialstr, nuser); strcat(dialstr, "\n"); strcat(dialstr, machine); strcat(dialstr, "\n"); break; } /* * open the data file */ dc = dkattach(dp->name); if(waserror()){ close(dc); nexterror(); } dc->qid = STREAMQID(line, Sdataqid); dkopen(dc, ORDWR); lp->calltolive = 4; lp->state = Ldialing; /* * tell the controller we want to make a call */ DPRINT("dialout\n"); dkmesg(dp, t_val, d_val, line, W_WINDOW(WS_2K,WS_2K,2)); /* * if redial, wait for a dial tone (otherwise we might send * the dialstr to the previous other end and not the controller) */ if(type==Redial){ if(streamread(dc, &dialtone, 1L) != 1L){ lp->state = Lconnected; error(0, Ebadarg); } } /* * make the call */ DPRINT("dialstr %s\n", dialstr); streamwrite(dc, dialstr, (long)strlen(dialstr), 1); close(dc); poperror(); /* * redial's never get a reply, assume it worked */ if(type == Redial) { lp->state = Lconnected; return; } /* * wait for a reply */ DPRINT("reply wait\n"); sleep(&lp->r, calldone, lp); /* * if there was an error, translate it to a plan 9 * errno and report it to the user. */ DPRINT("got reply %d\n", lp->state); if(lp->state != Lconnected) { if(lp->err >= DKERRS) error(0, dkerr[0]); else error(0, dkerr[lp->err]); } /* * linege state if serving */ if(type == D_SERV){ lp->state = Llistening; } DPRINT("connected!\n"); /* * decode the window size */ if (W_VALID(lp->window)){ /* * a 1127 window negotiation */ lp->window = W_VALUE(W_DEST(lp->window)); } else if(lp->window>2 && lp->window<31){ /* * a generic window negotiation */ lp->window = 1<<lp->window; } else lp->window = 0; /* * tag the connection */ strncpy(lp->addr, addr, sizeof(lp->addr)-1); strncpy(lp->raddr, addr, sizeof(lp->raddr)-1); /* * reset the protocol */ dkwindow(c); } /* * listen for a call, reflavor the */ static int dklisten(Chan *c) { char dialstr[512]; char *line[12]; char *field[8]; Line *lp; Dk *dp; int n, lineno, ts, window; Chan *dc; dp = &dk[c->dev]; /* * open the data file */ dc = dkattach(dp->name); if(waserror()){ close(dc); nexterror(); } dc->qid = STREAMQID(STREAMID(c->qid), Sdataqid); dkopen(dc, ORDWR); /* * wait for a call in */ for(;;){ /* * read the dialstring and null terminate it */ n = streamread(dc, dialstr, sizeof(dialstr)-1); DPRINT("returns %d\n", n); if(n <= 0) error(0, Eio); dialstr[n] = 0; DPRINT("dialstr = %s\n", dialstr); /* * break the dial string into lines */ n = getfields(dialstr, line, 12, '\n'); if (n < 2) { DPRINT("bad dialstr from dk (1 line)\n"); error(0, Eio); } /* * line 0 is `line.tstamp.traffic[.urpparms.window]' */ window = 0; switch(getfields(line[0], field, 5, '.')){ case 5: /* * generic way of passing window */ window = strtoul(field[4], 0, 0); if(window > 0 && window <31) window = 1<<window; else window = 0; /* * intentional fall through */ case 3: /* * 1127 way of passing window */ if(window == 0){ window = strtoul(field[2], 0, 0); if(W_VALID(window)) window = W_VALUE(W_ORIG(window)); else window = 0; } break; default: print("bad message from dk(bad first line)\n"); continue; } lineno = strtoul(field[0], 0, 0); if(lineno >= dp->lines){ print("dklisten: illegal line %d\n", lineno); continue; } lp = &dp->line[lineno]; ts = strtoul(field[1], 0, 0); /* * this could be a duplicate request */ if(ts == lp->timestamp){ print("dklisten: repeat timestamp %d\n", lineno); continue; } /* * take care of glare (datakit picked an inuse channel * for the call to come in on). */ if(!canqlock(lp)){ print("DKbusy1\n"); dkanswer(c, lineno, DKbusy); continue; } else { if(lp->state != Lclosed){ qunlock(lp); print("DKbusy2 %ux\n", lp->state); dkanswer(c, lineno, DKbusy); continue; } } lp->window = window; /* * Line 1 is `my-dk-name.service[.more-things]'. * Special characters are escaped by '\'s. */ strncpy(lp->addr, line[1], sizeof(lp->addr)-1); /* * the rest is variable length */ switch(n) { case 2: /* no more lines */ lp->ruser[0] = 0; lp->raddr[0] = 0; break; case 3: /* line 2 is `source.user.param1.param2' */ getfields(line[2], field, 3, '.'); strncpy(lp->raddr, field[0], sizeof(lp->raddr)-1); strncpy(lp->ruser, field[1], sizeof(lp->ruser)-1); break; case 4: /* line 2 is `user.param1.param2' */ getfields(line[2], field, 2, '.'); strncpy(lp->ruser, field[0], sizeof(lp->ruser)-1); /* line 3 is `source.node.mod.line' */ strncpy(lp->raddr, line[3], sizeof(lp->raddr)-1); break; default: print("bad message from dk(>4 line)\n"); qunlock(lp); error(0, Ebadarg); } sprint(lp->other, "w(%d)", W_TRAF(lp->window)); DPRINT("src(%s)user(%s)dest(%s)other(%s)\n", lp->raddr, lp->ruser, lp->addr, lp->other); lp->timestamp = ts; lp->state = Lconnected; qunlock(lp); close(dc); poperror(); DPRINT("dklisten returns %d\n", lineno); return lineno; } } /* * answer a call */ static void dkanswer(Chan *c, int line, int code) { char reply[64]; Dk *dp; Chan *dc; Line *lp; dp = &dk[c->dev]; lp = &dp->line[line]; /* * open the data file (c is a control file) */ dc = dkattach(dp->name); if(waserror()){ close(dc); nexterror(); } dc->qid = STREAMQID(STREAMID(c->qid), Sdataqid); dkopen(dc, ORDWR); /* * send the reply */ sprint(reply, "%ud.%ud.%ud", line, lp->timestamp, code); DPRINT("dkanswer %s\n", reply); streamwrite(dc, reply, strlen(reply), 1); close(dc); poperror(); } /* * set the window size and reset the protocol */ static void dkwindow(Chan *c) { char buf[64]; long wins; Line *lp; lp = &dk[c->dev].line[STREAMID(c->qid)]; if(lp->window == 0) lp->window = 64; sprint(buf, "init %d %d", lp->window, Streamhi); streamwrite(c, buf, strlen(buf), 1); } /* * hangup a datakit connection */ static void dkhangup(Line *lp) { Block *bp; qlock(lp); if(lp->rq){ bp = allocb(0); bp->type = M_HANGUP; PUTNEXT(lp->rq, bp); } qunlock(lp); } /* * A process which listens to all input on a csc line */ static void dkcsckproc(void *a) { long n; Dk *dp; Dkmsg d; int line; int i; dp = (Dk *)a; /* * loop forever listening */ for(;;){ n = streamread(dp->csc, (char *)&d, (long)sizeof(d)); if(n != sizeof(d)){ print("strange csc message %d\n", n); continue; } line = (d.param0h<<8) + d.param0l; /* print("t(%d)s(%d)l(%d)\n", d.type, d.srv, line); /**/ switch (d.type) { case T_CHG: /* controller wants to close a line */ dkchgmesg(dp, &d, line); break; case T_REPLY: /* reply to a dial request */ dkreplymesg(dp, &d, line); break; case T_SRV: /* ignore it, it's useless */ print("dksrvmesg(%d)\n", line); break; case T_RESTART: /* datakit reboot */ print("dk restart\n"); if(line >=0 && line<dp->lines){ print("maxlines=%d\n", line+1); dp->lines=line+1; } break; default: DPRINT("unrecognized csc message %o(%o)\n", d.type, line); break; } } } /* * datakit requests or confirms closing a line */ static void dkchgmesg(Dk *dp, Dkmsg *dialp, int line) { Line *lp; if (line <= 0 || line >= dp->lines) { /* tell controller this line is not in use */ dkmesg(dp, T_CHG, D_CLOSE, line, 0); return; } lp = &dp->line[line]; switch (dialp->srv) { case D_CLOSE: /* remote shutdown */ switch (lp->state) { case Ldialing: /* simulate a failed connection */ dkreplymesg(dp, (Dkmsg *)0, line); lp->state = Lrclose; break; case Lrclose: case Lconnected: case Llistening: case Lackwait: dkhangup(lp); lp->state = Lrclose; break; case Lopened: dkmesg(dp, T_CHG, D_CLOSE, line, 0); break; case Llclose: case Lclosed: dkhangup(lp); dkmesg(dp, T_CHG, D_CLOSE, line, 0); lp->state = Lclosed; break; } break; case D_ISCLOSED: /* acknowledging a local shutdown */ switch (lp->state) { case Llclose: case Lclosed: lp->state = Lclosed; break; case Lrclose: case Lconnected: case Llistening: case Lackwait: break; } break; default: print("unrecognized T_CHG\n"); } } /* * datakit replies to a dialout. capture reply code and traffic parameters */ static void dkreplymesg(Dk *dp, Dkmsg *dialp, int line) { Proc *p; Line *lp; DPRINT("dkreplymesg(%d)\n", line); if(line < 0 || line >= dp->lines) return; lp=&dp->line[line]; if(lp->state != Ldialing) return; if(dialp){ /* * a reply from the dk */ lp->state = (dialp->srv==D_OPEN) ? Lconnected : Lrclose; lp->err = (dialp->param1h<<8) + dialp->param1l; lp->window = lp->err; DPRINT("dkreplymesg: %d\n", lp->state); } else { /* * a local abort */ lp->state = Lrclose; lp->err = 0; } if(lp->state==Lrclose){ dkhangup(lp); } wakeup(&lp->r); } /* * 15-second timer for all interfaces */ static Rendez dkt; static int fuckit(void *a) { return 0; } static void dktimer(void *a) { int dki, i; Dk *dp; Line *lp; waserror(); for(;;){ /* * loop through the active dks */ for(dki=0; dki<Ndk; dki++){ dp = &dk[dki]; if(dp->csc==0) continue; /* * send keep alive */ dkmesg(dp, T_ALIVE, D_CONTINUE, 0, 0); /* * remind controller of dead lines and * timeout calls that take to long */ for (i=0; i<dp->lines; i++){ lp = &dp->line[i]; switch(lp->state){ case Llclose: dkmesg(dp, T_CHG, D_CLOSE, i, 0); break; case Ldialing: if(lp->calltolive==0 || --lp->calltolive!=0) break; dkreplymesg(dp, (Dkmsg *)0, i); break; } } } tsleep(&dkt, fuckit, 0, 7500); } }
A gnot/devincon.c => gnot/devincon.c +764 -0
@@ 0,0 1,764 @@ #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "errno.h" #include "devtab.h" #include "io.h" typedef struct Incon Incon; typedef struct Device Device; #define NOW (MACHP(0)->ticks*MS2HZ) #define DPRINT if(0) enum { Minstation= 2, /* lowest station # to poll */ Maxstation= 15, /* highest station # to poll */ Nincon= 1, /* number of incons */ Nraw= 1024, /* size of raw input buffer */ }; /* * incon datakit board */ struct Device { uchar cdata; #define cpolln cdata uchar u0; uchar cstatus; uchar u1; uchar creset; uchar u2; uchar csend; uchar u3; ushort data_cntl; /* data is high byte, cntl is low byte */ uchar status; #define cmd status uchar u5; uchar reset; uchar u6; uchar send; uchar u7; }; #define INCON ((Device *)0x40700000) struct Incon { QLock; QLock xmit; /* transmit lock */ QLock reslock; /* reset lock */ Device *dev; int station; /* station number */ int state; /* chip state */ Rendez r; /* output process */ Rendez kr; /* input kernel process */ ushort chan; /* current input channel */ Queue *rq; /* read queue */ uchar buf[1024]; /* bytes being collected */ uchar *wptr; /* pointer into buf */ int kstarted; /* true if kernel process started */ ushort raw[Nraw]; ushort *rp; ushort *wp; /* statistics */ ulong overflow; /* overflow errors */ ulong pack0; /* channel 0 */ ulong crc; /* crc errors */ ulong in; /* bytes in */ ulong out; /* bytes out */ }; Incon incon[Nincon]; /* * chip state */ enum { Selecting, Selected, Dead, }; /* * internal chip registers */ #define sel_polln 0 #define sel_station 1 #define sel_poll0 2 #define sel_rcv_cnt 3 #define sel_rcv_tim 4 #define sel_tx_cnt 5 /* * CSR bits */ #define INCON_RUN 0x80 #define INCON_STOP 0x00 #define ENABLE_IRQ 0x40 #define ENABLE_TX_IRQ 0x20 #define INCON_ALIVE 0x80 #define TX_FULL 0x10 #define TX_EMPTY 0x08 #define RCV_EMPTY 0x04 #define OVERFLOW 0x02 #define CRC_ERROR 0x01 /* * polling constants */ #define HT_GNOT 0x30 #define ST_UNIX 0x04 #define NCHAN 16 static void inconkproc(void*); /* * incon stream module definition */ static void inconoput(Queue*, Block*); static void inconstopen(Queue*, Stream*); static void inconstclose(Queue*); Qinfo inconinfo = { nullput, inconoput, inconstopen, inconstclose, "incon" }; /* * set the incon parameters */ void inconset(Incon *ip, int cnt, int delay) { Device *dev; if (cnt<1 || cnt>14 || delay<1 || delay>15) error(0, Ebadarg); dev = ip->dev; dev->cmd = sel_rcv_cnt | INCON_RUN; *(uchar *)&dev->data_cntl = cnt; dev->cmd = sel_rcv_tim | INCON_RUN; *(uchar *)&dev->data_cntl = delay; dev->cmd = INCON_RUN | ENABLE_IRQ; } static void nop(void) { } /* * poll for a station number */ void inconpoll(Incon *ip, int station) { ulong timer; Device *dev; dev = ip->dev; /* * get us to a known state */ ip->state = Dead; dev->cmd = INCON_STOP; /* * try a station number */ dev->cmd = sel_station; *(uchar *)&dev->data_cntl = station; dev->cmd = sel_poll0; *(uchar *)&dev->data_cntl = HT_GNOT; dev->cmd = sel_rcv_cnt; *(uchar *)&dev->data_cntl = 3; dev->cmd = sel_rcv_tim; *(uchar *)&dev->data_cntl = 15; dev->cmd = sel_tx_cnt; *(uchar *)&dev->data_cntl = 1; dev->cmd = sel_polln; *(uchar *)&dev->data_cntl = 0x00; *(uchar *)&dev->data_cntl = ST_UNIX; *(uchar *)&dev->data_cntl = NCHAN; *(uchar *)&dev->data_cntl = 'g'; *(uchar *)&dev->data_cntl = 'n'; *(uchar *)&dev->data_cntl = 'o'; *(uchar *)&dev->data_cntl = 't'; dev->cpolln = 0; /* * poll and wait for ready (or 1/4 second) */ ip->state = Selecting; dev->cmd = INCON_RUN | ENABLE_IRQ; timer = NOW + 250; while (NOW < timer) { nop(); if(dev->status & INCON_ALIVE){ ip->station = station; ip->state = Selected; break; } } } /* * reset the chip and find a new staion number */ void inconrestart(Incon *ip) { Device *dev; int i; if(!canqlock(&ip->reslock)) return; /* * poll for incon station numbers */ for(i = Minstation; i <= Maxstation; i++){ inconpoll(ip, i); if(ip->state == Selected) break; } switch(ip->state) { case Selecting: print("incon[%d] not polled\n", ip-incon); break; case Selected: print("incon[%d] station %d\n", ip-incon, ip->station); inconset(ip, 8, 9); break; default: print("incon[%d] bollixed\n", ip-incon); break; } qunlock(&ip->reslock); } /* * reset all incon chips. */ void inconreset(void) { int i; Incon *ip; incon[0].dev = INCON; incon[0].state = Selected; incon[0].rp = incon[0].wp = incon[0].raw; for(i=1; i<Nincon; i++){ incon[i].dev = INCON+i; incon[i].state = Dead; incon[i].dev->cmd = INCON_STOP; incon[i].rp = incon[i].wp = incon[i].raw; } } void inconinit(void) { } /* * enable the device for interrupts, spec is the device number */ Chan* inconattach(char *spec) { Incon *ip; int i; Chan *c; i = strtoul(spec, 0, 0); if(i >= Nincon) error(0, Ebadarg); ip = &incon[i]; if(ip->state != Selected) inconrestart(ip); c = devattach('i', spec); c->dev = i; c->qid = CHDIR; return c; } Chan* inconclone(Chan *c, Chan *nc) { return devclone(c, nc); } int inconwalk(Chan *c, char *name) { return devwalk(c, name, 0, 0, streamgen); } void inconstat(Chan *c, char *dp) { devstat(c, dp, 0, 0, streamgen); } Chan* inconopen(Chan *c, int omode) { if(c->qid == CHDIR){ if(omode != OREAD) error(0, Eperm); }else streamopen(c, &inconinfo); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } void inconcreate(Chan *c, char *name, int omode, ulong perm) { error(0, Eperm); } void inconclose(Chan *c) { if(c->qid != CHDIR) streamclose(c); } long inconread(Chan *c, void *buf, long n) { return streamread(c, buf, n); } long inconwrite(Chan *c, void *buf, long n) { return streamwrite(c, buf, n, 0); } void inconremove(Chan *c) { error(0, Eperm); } void inconwstat(Chan *c, char *dp) { error(0, Eperm); } void inconuserstr(Error *e, char *buf) { consuserstr(e, buf); } void inconerrstr(Error *e, char *buf) { rooterrstr(e, buf); } /* * the stream routines */ /* * create the kernel process for input */ static void inconstopen(Queue *q, Stream *s) { Incon *ip; char name[32]; ip = &incon[s->dev]; sprint(name, "**incon%d**", s->dev); q->ptr = q->other->ptr = ip; ip->rq = q; kproc(name, inconkproc, ip); } /* * kill off the kernel process */ static int kDead(void *arg) { Incon *ip; ip = (Incon *)arg; return ip->kstarted == 0; } static void inconstclose(Queue * q) { Incon *ip; ip = (Incon *)q->ptr; qlock(ip); ip->rq = 0; qunlock(ip); wakeup(&ip->kr); sleep(&ip->r, kDead, ip); } /* * free all blocks of a message in `q', `bp' is the first block * of the message */ static void freemsg(Queue *q, Block *bp) { for(; bp; bp = getq(q)){ if(bp->flags & S_DELIM){ freeb(bp); return; } freeb(bp); } } /* * output a block * * the first 2 bytes of every message are the channel number, * low order byte first. the third is a possible trailing control * character. */ void inconoput(Queue *q, Block *bp) { Device *dev; Incon *ip; ulong end; int chan; int ctl; int n, size; if(bp->type != M_DATA){ freeb(bp); return; } /* * get a whole message before handing bytes to the device */ if(!putq(q, bp)) return; /* * one transmitter at a time */ ip = (Incon *)q->ptr; qlock(&ip->xmit); dev = ip->dev; /* * parse message */ bp = getq(q); if(bp->wptr - bp->rptr < 3){ freemsg(q, bp); qunlock(&ip->xmit); return; } chan = bp->rptr[0] | (bp->rptr[1]<<8); ctl = bp->rptr[2]; bp->rptr += 3; /* * make sure there's an incon out there */ if(!(dev->status&INCON_ALIVE) || ip->state==Dead){ inconrestart(ip); freemsg(q, bp); qunlock(&ip->xmit); return; } /* * send the 8 bit data */ for(;;){ /* * spin till there is room */ for(end = NOW+1000; dev->status & TX_FULL;){ nop(); /* make sure we don't optimize too much */ if(NOW > end){ print("incon output stuck\n"); freemsg(q, bp); qunlock(&ip->xmit); return; } } /* * put in next packet */ n = bp->wptr - bp->rptr; if(n > 16) n = 16; size = n; dev->cdata = chan; DPRINT("CH|%uo->\n", chan); while(n--){ DPRINT("->%uo\n", *bp->rptr); *(uchar *)&dev->data_cntl = *bp->rptr++; } /* * get next block */ if(bp->rptr >= bp->wptr){ if(bp->flags & S_DELIM){ freeb(bp); break; } freeb(bp); bp = getq(q); if(bp==0) break; } /* * end packet */ dev->cdata = 0; } /* * send the control byte if there is one */ if(ctl){ if(size >= 16){ dev->cdata = 0; DPRINT("CH|%uo->\n", chan); dev->cdata = chan; } DPRINT("CTL|%uo->\n", ctl); dev->cdata = ctl; } dev->cdata = 0; qunlock(&ip->xmit); return; } /* * return true if the raw fifo is non-empty */ static int notempty(void *arg) { Incon *ip; ip = (Incon *)arg; return ip->wp!=ip->rp; } /* * fill a block with what is currently buffered and send it upstream */ static void upstream(Incon *ip, unsigned int ctl) { int n; Block *bp; n = ip->wptr - ip->buf; bp = allocb(3 + n); bp->wptr[0] = ip->chan; bp->wptr[1] = ip->chan>>8; bp->wptr[2] = ctl; if(n) memcpy(&bp->wptr[3], ip->buf, n); bp->wptr += 3 + n; bp->flags |= S_DELIM; PUTNEXT(ip->rq, bp); ip->wptr = ip->buf; } /* * Read bytes from the raw input circular buffer. */ static void inconkproc(void *arg) { Incon *ip; unsigned int c; uchar *lim; ushort *p, *e; ip = (Incon *)arg; ip->kstarted = 1; ip->wptr = ip->buf; e = &ip->raw[Nraw]; for(;;){ /* * die if the device is closed */ qlock(ip); if(ip->rq == 0){ qunlock(ip); ip->kstarted = 0; wakeup(&ip->r); return; } /* * sleep if input fifo empty */ while(!notempty(ip)) sleep(&ip->kr, notempty, ip); p = ip->rp; /* * get channel number */ c = (*p++)>>8; if(p == e) p = ip->raw; DPRINT("<-CH|%uo\n", c); if(ip->chan != c){ if(ip->wptr - ip->buf != 0) upstream(ip, 0); ip->chan = c; } /* * null byte marks end of packet */ for(lim = &ip->buf[sizeof ip->buf];;){ if((c=*p++)&1) { /* * data byte, put in local buffer */ c = *ip->wptr++ = c>>8; DPRINT("<-%uo\n", c); if(ip->wptr >= lim) upstream(ip, 0); } else if (c>>=8) { /* * control byte ends block */ DPRINT("<-CTL|%uo\n", c); upstream(ip, c); } else { /* end of packet */ break; } if(p == e) p = ip->raw; } ip->rp = p; qunlock(ip); } } /* * read the packets from the device into the raw input buffer. * we have to do this at interrupt tevel to turn off the interrupts. */ static rdpackets(Incon *ip) { Device *dev; unsigned int c; ushort *p, *e; int n; dev = ip->dev; while(!(dev->status & RCV_EMPTY)){ n = ip->rp - ip->wp; if(n <= 0) n += Nraw; if(n < 19){ /* * no room in the raw queue, throw it away */ c = (dev->data_cntl)>>8; for(c=0;c<18;c++){ if(dev->data_cntl == 0) break; } } else { /* * put packet in the raw queue */ p = ip->wp; e = &ip->raw[Nraw]; *p++ = dev->data_cntl; if(p == e) p = ip->raw; do { *p++ = c = dev->data_cntl; if(p == e) p = ip->raw; } while(c); ip->wp = p; } } wakeup(&ip->kr); } /* * Receive an incon interrupt. One entry point * for all types of interrupt. Until we figure out * how to use more than one incon, this routine only * is for incon[0]. */ inconintr(Ureg *ur) { uchar status; Incon *ip; ip = &incon[0]; status = ip->dev->status; if(!(status & RCV_EMPTY)) rdpackets(ip); /* check for exceptional conditions */ if(status&(OVERFLOW|CRC_ERROR)){ if(status&OVERFLOW){ print("incon overflow\n"); ip->overflow++; } if(status&CRC_ERROR){ print("incon crc error\n"); ip->crc++; } } /* see if it died underneath us */ if(!(status&INCON_ALIVE)){ switch(ip->state){ case Selected: ip->dev->cmd = INCON_STOP; print("Incon died\n"); break; case Selecting: print("rejected\n"); break; default: ip->dev->cmd = INCON_STOP; break; } ip->state = Dead; } }
M gnot/devmnt.c => gnot/devmnt.c +2 -0
@@ 382,6 382,7 @@ mntclose(Chan *c) if(c == m->mntpt) m->mntpt = 0; if(decref(m) == 0){ /* BUG: need to hang up all pending i/o */ print("close mount table %d\n", m->mntid); qlock(m); close(m->msg); m->msg = 0; @@ 467,6 468,7 @@ mntremove(Chan *c) mhfree(mh); nexterror(); } decref(m); mh->thdr.type = Tremove; mh->thdr.fid = c->fid; mntxmit(m, mh);
M gnot/devpipe.c => gnot/devpipe.c +1 -1
@@ 129,7 129,7 @@ pipewrite(Chan *c, void *va, long n) postnote(u->p, 1, "sys: write on closed pipe", NExit); error(0, Egreg); } return streamwrite(c, va, n); return streamwrite(c, va, n, 0); } void
M gnot/errno.h => gnot/errno.h +6 -1
@@ 36,10 36,15 @@ enum{ Etoosmall, /* read or write too small */ Ehungup, /* write to hungup stream */ Ebadnet, /* illegal network address */ Enoifc, /* no free nonet interface slots */ Enoifc, /* no free interface slots */ Enodev, /* no free devices */ Ebadctl, /* bad process control request */ Enonote, /* note overflow */ Eintr, /* interrupted */ Edestbusy, /* datakit destination busy */ Enetbusy, /* datakit controller busy */ Edestotl, /* datakit destination out to lunch */ Enetotl, /* datakit controller out to lunch */ Erejected, /* datakit destination rejected call */ Egreg, /* it's all greg's fault */ };
M gnot/fault.c => gnot/fault.c +3 -1
@@ 83,6 83,7 @@ fault(Ureg *ur, FFrame *f) read = (f->ssw&READ) && !(f->ssw&RM); else read = f->ssw&(FB|FC); /* print("fault pc=%lux addr=%lux read %d\n", ur->pc, badvaddr, read); /**/ s = seg(u->p, addr); if(s == 0){ @@ 272,9 273,10 @@ validaddr(ulong addr, ulong len, int write) Seg *s; if((long)len < 0) panic("validaddr len %lux\n", len); goto Err; s = seg(u->p, addr); if(s==0 || addr+len>s->maxva || (write && (s->o->flag&OWRPERM)==0)){ Err: pprint("invalid address in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp); postnote(u->p, 1, "bad address", NDebug); error(0, Ebadarg);
M gnot/fns.h => gnot/fns.h +9 -2
@@ 4,6 4,7 @@ Block *allocb(ulong); void append(List**, List*); void cancel(Alarm*); int canlock(Lock*); int canqlock(QLock*); void chaninit(void); void chandevreset(void); void chandevinit(void); @@ 47,7 48,9 @@ void freepage(Orig*); void freepte(Orig*); void freesegs(int); void freealarm(Alarm*); Block *getq(Queue *); Block *getb(Blist*); int getfields(char*, char**, int, char); Block *getq(Queue*); void gotolabel(Label*); void growpte(Orig*, ulong); void *ialloc(ulong, int); @@ 55,6 58,7 @@ int incref(Ref*); void insert(List**, List*, List*); void isdir(Chan*); void kbdchar(int); void kproc(char*, void(*)(void*), void*); void lock(Lock*); void lockinit(void); Orig *lookorig(ulong, ulong, int, Chan*); @@ 86,6 90,8 @@ void printinit(void); void printslave(void); void procinit0(void); Proc *proctab(int); Queue* pushq(Stream*, Qinfo*); void putbq(Blist*, Block*); void putkmmu(ulong, ulong); void putmmu(ulong, ulong); int putq(Queue*, Block*); @@ 118,10 124,11 @@ Devgen streamgen; void streamclose(Chan*); void streaminit(void); long streamread(Chan*, void*, long); long streamwrite(Chan*, void*, long); long streamwrite(Chan*, void*, long, int); Stream* streamnew(Chan*, Qinfo*); void streamopen(Chan*, Qinfo*); int streamparse(char*, Block*); long stringread(Chan*, void*, long, char*); long syscall(Ureg*); int tas(char*); void touser(void);
M gnot/lock.c => gnot/lock.c +6 -0
@@ 66,6 66,12 @@ qlock(QLock *q) sched(); } int canqlock(QLock *q) { return canlock(&q->use); } void qunlock(QLock *q) {
M gnot/main.c => gnot/main.c +24 -2
@@ 7,10 7,24 @@ #include "ureg.h" #include "init.h" typedef struct Boot{ long station; long traffic; char user[NAMELEN]; char server[64]; char line[64]; }Boot; #define BOOT ((Boot*)0) char protouser[NAMELEN]; void unloadboot(void); void main(void) { Lock l; unloadboot(); machinit(); mmuinit(); confinit(); @@ 28,6 42,12 @@ main(void) } void unloadboot(void) { strncpy(protouser, BOOT->user, NAMELEN); } void machinit(void) { int n; @@ 87,7 107,7 @@ userinit(void) p = newproc(); p->pgrp = newpgrp(); strcpy(p->text, "*init*"); strcpy(p->pgrp->user, "bootes"); strcpy(p->pgrp->user, protouser); /* savefpregs(&initfp); /**/ /* p->fpstate = FPinit; /**/ @@ 219,7 239,7 @@ confinit(void) conf.npage = (2*1024*1024)/BY2PG; conf.npte = 500; conf.nmod = 50; conf.nalarm = 50; conf.nalarm = 1000; conf.norig = 50; conf.nchan = 100; conf.nenv = 50; @@ 228,6 248,8 @@ confinit(void) conf.nmtab = 50; conf.nmount = 100; conf.nmntdev = 5; conf.nmntbuf = 10; conf.nmnthdr = 10; conf.nstream = 64; conf.nqueue = 5 * conf.nstream; conf.nblock = 16 * conf.nstream;
M gnot/proc.c => gnot/proc.c +59 -0
@@ 172,6 172,8 @@ loop: unlock(&pidalloc); if(p->pid == 0) panic("pidalloc"); print("allocate process %d\n", p->pid); DEBUG(); return p; } unlock(&procalloc); @@ 523,3 525,60 @@ DEBUG() p->time[0], p->time[1]); } } void kproc(char *name, void (*func)(void *), void *arg) { Proc *p; int n; ulong upa; int lastvar; /* used to compute stack address */ User *up; /* * Kernel stack */ p = newproc(); p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF)); upa = p->upage->pa|KZERO; up = (User *)upa; /* * Save time: only copy u-> data and useful stack */ memcpy((void*)upa, u, sizeof(User)); n = USERADDR+BY2PG - (ulong)&lastvar; n = (n+32) & ~(BY2WD-1); /* be safe & word align */ memcpy((void*)(upa+BY2PG-n), (void*)((u->p->upage->pa|KZERO)+BY2PG-n), n); ((User *)upa)->p = p; /* * Refs */ incref(up->dot); for(n=0; n<=up->maxfd; n++) up->fd[n] = 0; up->maxfd = 0; /* * Sched */ if(setlabel(&p->sched)){ u->p = p; p->state = Running; p->mach = m; m->proc = p; spllo(); strncpy(p->text, name, sizeof p->text); (*func)(arg); pexit(0, 1); } p->pgrp = u->p->pgrp; incref(p->pgrp); p->nchild = 0; p->parent = 0; memset(p->time, 0, sizeof(p->time)); p->time[TReal] = MACHP(0)->ticks; ready(p); flushmmu(); }
M gnot/stream.c => gnot/stream.c +154 -26
@@ 7,12 7,23 @@ #include "errno.h" #include "devtab.h" /* * process end line discipline */ static void stputq(Queue*, Block*); Qinfo procinfo = { stputq, nullput, 0, 0, "process" } ; /*extern Qinfo noetherinfo; */ Qinfo procinfo = { stputq, nullput, 0, 0, "process" }; /* * line disciplines that can be pushed * * WARNING: this table should be the result of configuration */ extern Qinfo noetherinfo; extern Qinfo dkmuxinfo; extern Qinfo urpinfo; static Qinfo *lds[] = { /* &noetherinfo, */ &dkmuxinfo, &urpinfo, 0 }; @@ 34,7 45,9 @@ static Lock garbagelock; */ typedef struct { int size; Queue; Blist; QLock; /* qlock for sleepers on r */ Rendez r; /* sleep here waiting for blocks */ } Bclass; Bclass bclass[Nclass]={ { 0 }, @@ 108,7 121,9 @@ allocb(ulong size) while(bcp->first == 0){ unlock(bcp); print("waiting for blocks\n"); qlock(bcp); sleep(&bcp->r, isblock, (void *)bcp); qunlock(bcp); lock(bcp); } bp = bcp->first; @@ 128,25 143,33 @@ allocb(ulong size) } /* * Free a block. Poison its pointers so that someone trying to access * it after freeing will cause a dump. * Free a block (or list of blocks). Poison its pointers so that * someone trying to access it after freeing will cause a dump. */ void freeb(Block *bp) { Bclass *bcp; int tries; bcp = &bclass[bp->flags & S_CLASS]; bp->rptr = bp->wptr = 0; lock(bcp); bp->rptr = bp->wptr = 0; if(bcp->first) bcp->last->next = bp; else bcp->first = bp; tries = 0; while(bp->next){ if(++tries > 10){ dumpstack(); panic("freeb"); } bp = bp->next; } bcp->last = bp; bp->next = 0; wakeup(&bcp->r); unlock(bcp); wakeup(&bcp->r); } /* @@ 269,11 292,11 @@ putq(Queue *q, Block *bp) q->last->next = bp; else q->first = bp; q->len += bp->wptr - bp->rptr; q->len += BLEN(bp); delim = bp->flags & S_DELIM; while(bp->next) { bp = bp->next; q->len += bp->wptr - bp->rptr; q->len += BLEN(bp); delim |= bp->flags & S_DELIM; } q->last = bp; @@ 292,22 315,21 @@ putb(Blist *q, Block *bp) q->last->next = bp; else q->first = bp; q->len += bp->wptr - bp->rptr; q->len += BLEN(bp); delim = bp->flags & S_DELIM; while(bp->next) { bp = bp->next; q->len += bp->wptr - bp->rptr; q->len += BLEN(bp); delim |= bp->flags & S_DELIM; } q->last = bp; bp->next = 0; return delim; } /* * add a block to the start of a queue */ static void void putbq(Blist *q, Block *bp) { lock(q); @@ 316,12 338,12 @@ putbq(Blist *q, Block *bp) else q->last = bp; q->first = bp; q->len += bp->wptr - bp->rptr; q->len += BLEN(bp); unlock(q); } /* * remove the first block from a queue * remove the first block from a queue */ Block * getq(Queue *q) @@ 334,7 356,7 @@ getq(Queue *q) q->first = bp->next; if(q->first == 0) q->last = 0; q->len -= bp->wptr - bp->rptr; q->len -= BLEN(bp); if((q->flag&QHIWAT) && q->len < Streamhi/2){ wakeup(&q->other->next->other->r); q->flag &= ~QHIWAT; @@ 344,6 366,10 @@ getq(Queue *q) unlock(q); return bp; } /* * remove the first block from a list of blocks */ Block * getb(Blist *q) { @@ 354,13 380,87 @@ getb(Blist *q) q->first = bp->next; if(q->first == 0) q->last = 0; q->len -= bp->wptr - bp->rptr; q->len -= BLEN(bp); bp->next = 0; } return bp; } /* * make sure the first block has n bytes */ Block * pullup(Block *bp, int n) { Block *nbp; int i; /* * this should almost always be true, the rest it * just for to avoid every caller checking. */ if(BLEN(bp) >= n) return bp; /* * if not enough room in the first block, * add another to the front of the list. if(bp->lim - bp->rptr < n){ nbp = allocb(n); nbp->next = bp; bp = nbp; } /* * copy bytes from the trailing blocks into the first */ n -= BLEN(bp); while(nbp = bp->next){ i = BLEN(nbp); if(i > n) { memcpy(bp->wptr, nbp->rptr, n); bp->wptr += n; nbp->rptr += n; return bp; } else { memcpy(bp->wptr, nbp->rptr, i); bp->wptr += i; bp->next = nbp->next; nbp->next = 0; freeb(nbp); } } freeb(bp); return 0; } /* * grow the front of a list of blocks by n bytes */ Block * prepend(Block *bp, int n) { Block *nbp; if(bp->base && (bp->rptr - bp->base)>=n){ /* * room for channel number in first block of message */ bp->rptr -= n; return bp; } else { /* * make new block, put message number at end */ nbp = allocb(2); nbp->next = bp; nbp->wptr = nbp->lim; nbp->rptr = nbp->wptr - n; return nbp; } } /* * put a block into the bit bucket */ void @@ 415,7 515,7 @@ streamparse(char *name, Block *bp) int len; len = strlen(name); if(bp->wptr - bp->rptr < len) if(BLEN(bp) < len) return 0; if(strncmp(name, (char *)bp->rptr, len)==0){ if(bp->rptr[len] == ' ') @@ 622,14 722,19 @@ stputq(Queue *q, Block *bp) freeb(bp); q->flag |= QHUNGUP; q->other->flag |= QHUNGUP; wakeup(&q->other->r); } else { lock(q); if(q->first) q->last->next = bp; else q->first = bp; q->len += BLEN(bp); while(bp->next) { bp = bp->next; q->len += BLEN(bp); } q->last = bp; q->len += bp->wptr - bp->rptr; if(q->len >= Streamhi) q->flag |= QHIWAT; unlock(q); @@ 651,8 756,7 @@ stringread(Chan *c, uchar *buf, long n, char *str) n = i; if(n<0) return 0; memcpy(buf + c->offset, str, n); c->offset += n; memcpy(buf, str + c->offset, n); return n; } @@ 716,7 820,7 @@ streamread(Chan *c, void *vbuf, long n) continue; } i = bp->wptr - bp->rptr; i = BLEN(bp); if(i <= left){ memcpy(buf, bp->rptr, i); left -= i; @@ 806,7 910,7 @@ flowctl(Queue *q) * send the request as a single delimited block */ long streamwrite(Chan *c, void *a, long n) streamwrite(Chan *c, void *a, long n, int docopy) { Stream *s; Block *bp; @@ 846,7 950,7 @@ streamwrite(Chan *c, void *a, long n) if(q->other->flag & QHUNGUP) error(0, Ehungup); if(GLOBAL(a) || n==0){ if((GLOBAL(a) && !docopy) || n==0){ /* * `a' is global to the whole system, just create a * pointer to it and pass it on. @@ 887,3 991,27 @@ streamwrite(Chan *c, void *a, long n) poperror(); return n; } /* * like andrew's getmfields but no hidden state */ int getfields(char *lp, /* to be parsed */ char **fields, /* where to put pointers */ int n, /* number of pointers */ char sep /* separator */ ) { int i; for(i=0; lp && *lp && i<n; i++){ while(*lp == sep) *lp++=0; if(*lp == 0) break; fields[i]=lp; while(*lp && *lp != sep) lp++; } return i; }
A gnot/sturp.c => gnot/sturp.c +845 -0
@@ 0,0 1,845 @@ #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "errno.h" enum { Nurp= 32, MSrexmit= 1000, Nmask= 0x7, }; #define DPRINT print typedef struct Urp Urp; #define NOW (MACHP(0)->ticks*MS2HZ) /* * URP status */ struct urpstat { ulong input; /* bytes read from urp */ ulong output; /* bytes output to urp */ ulong rxmit; /* retransmit rejected urp msg */ ulong rjtrs; /* reject, trailer size */ ulong rjpks; /* reject, packet size */ ulong rjseq; /* reject, sequence number */ ulong levelb; /* unknown level b */ ulong enqsx; /* enqs sent */ ulong enqsr; /* enqs rcved */ } urpstat; struct Urp { QLock; short state; /* flags */ Rendez r; /* process waiting for close */ /* input */ Queue *rq; /* input queue */ uchar iseq; /* last good input sequence number */ uchar lastecho; /* last echo/rej sent */ uchar trbuf[3]; /* trailer being collected */ short trx; /* # bytes in trailer being collected */ /* output */ QLock xmit; /* output lock, only one process at a time */ Queue *wq; /* output queue */ int maxout; /* maximum outstanding unacked blocks */ int maxblock; /* max block size */ int next; /* next block to send */ int unechoed; /* first unechoed block */ int unacked; /* first unacked block */ int nxb; /* next xb to use */ Block *xb[8]; /* the xmit window buffer */ QLock xl[8]; ulong timer; /* timeout for xmit */ int kstarted; }; #define WINDOW(u) ((u->unechoed + u->maxout - u->next)%8) #define IN(x, f, n) (f<=n ? x>=f && x<n : x<n || x>=f) #define NEXT(x) (((x)+1)&Nmask) /* * Protocol control bytes */ #define SEQ 0010 /* sequence number, ends trailers */ #undef ECHO #define ECHO 0020 /* echos, data given to next queue */ #define REJ 0030 /* rejections, transmission error */ #define ACK 0040 /* acknowledgments */ #define BOT 0050 /* beginning of trailer */ #define BOTM 0051 /* beginning of trailer, more data follows */ #define BOTS 0052 /* seq update algorithm on this trailer */ #define SOU 0053 /* start of unsequenced trailer */ #define EOU 0054 /* end of unsequenced trailer */ #define ENQ 0055 /* xmitter requests flow/error status */ #define CHECK 0056 /* xmitter requests error status */ #define INITREQ 0057 /* request initialization */ #define INIT0 0060 /* disable trailer processing */ #define INIT1 0061 /* enable trailer procesing */ #define AINIT 0062 /* response to INIT0/INIT1 */ #undef DELAY #define DELAY 0100 /* real-time printing delay */ #define BREAK 0110 /* Send/receive break (new style) */ #define REJECTING 0x1 #define INITING 0x2 #define HUNGUP 0x4 #define OPEN 0x8 #define CLOSING 0x10 Urp urp[Nurp]; /* * predeclared */ static void urpciput(Queue*, Block*); static void urpiput(Queue*, Block*); static void urpoput(Queue*, Block*); static void urpopen(Queue*, Stream*); static void urpclose(Queue *); static void output(Urp*); static void sendblock(Urp*, int); static void rcvack(Urp*, int); static void flushinput(Urp*); static void sendctl(Urp*, int); static void initoutput(Urp*, int); static void initinput(Urp*, int); static void urpkproc(void *arg); Qinfo urpinfo = { urpciput, urpoput, urpopen, urpclose, "urp" }; static void urpopen(Queue *q, Stream *s) { Urp *up; int i; char name[128]; DPRINT("urpopen\n"); /* * find a free urp structure */ for(up = urp; up < &urp[Nurp]; up++){ qlock(up); if(up->state == 0) break; qunlock(up); } if(up == &urp[Nurp]) error(0, Egreg); q->ptr = q->other->ptr = up; up->rq = q; up->wq = q->other; up->state = OPEN; qunlock(up); initinput(up, 0); initoutput(up, 0); /* * start the ack/(re)xmit process */ if(up->kstarted == 0){ up->kstarted = 1; sprint(name, "**urp%d**", up - urp); kproc(name, urpkproc, up); } } /* * Shut down the connection and kill off the kernel process */ static int isflushed(void *a) { Urp *up; up = (Urp *)a; return (up->state&HUNGUP) || (up->unechoed==up->next && up->wq->len==0); } static int isdead(void *a) { Urp *up; up = (Urp *)a; return up->kstarted == 0; } static void urpclose(Queue *q) { Block *bp; Urp *up; int i; up = (Urp *)q->ptr; /* * wait for all outstanding messages to drain, tell kernel * process we're closing. */ up->state |= CLOSING; sleep(&up->r, isflushed, up); /* * ack all outstanding messages */ qlock(&up->xmit); up->state |= HUNGUP; i = up->next - 1; if(i < 0) i = 7; rcvack(up, ECHO+i); qunlock(&up->xmit); DPRINT("urpclose(%ux)\n", up); /* * kill off the kernel process */ wakeup(&up->rq->r); DPRINT("urpclosed(%ux)\n", up); } /* * upstream control messages */ static void urpctliput(Urp *up, Queue *q, Block *bp) { switch(bp->type){ case M_HANGUP: up->state |= HUNGUP; wakeup(&up->r); wakeup(&up->rq->r); break; } PUTNEXT(q, bp); } /* * character mode input. * * the first byte in every message is a ctl byte (which belongs at the end). */ void urpciput(Queue *q, Block *bp) { Urp *up; int i; int ctl; up = (Urp *)q->ptr; if(bp->type != M_DATA){ urpctliput(up, q, bp); return; } /* * get the control character */ ctl = *bp->rptr++; if(ctl < 0) return; /* * take care of any data */ if(BLEN(bp)>0 && q->next->len<Streamhi) PUTNEXT(q, bp); else freeb(bp); /* * handle the control character */ switch(ctl){ case 0: break; case ENQ: urpstat.enqsr++; sendctl(up, up->lastecho); sendctl(up, ACK+up->iseq); break; case CHECK: sendctl(up, ACK+up->iseq); break; case AINIT: up->state &= ~INITING; flushinput(up); wakeup(&up->rq->r); break; case INIT0: case INIT1: sendctl(up, AINIT); if(ctl == INIT1) q->put = urpiput; initinput(up, 0); break; case INITREQ: initoutput(up, 0); break; case BREAK: break; case REJ+0: case REJ+1: case REJ+2: case REJ+3: case REJ+4: case REJ+5: case REJ+6: case REJ+7: rcvack(up, ctl); break; case ACK+0: case ACK+1: case ACK+2: case ACK+3: case ACK+4: case ACK+5: case ACK+6: case ACK+7: case ECHO+0: case ECHO+1: case ECHO+2: case ECHO+3: case ECHO+4: case ECHO+5: case ECHO+6: case ECHO+7: rcvack(up, ctl); break; case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3: case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7: i = ctl & Nmask; if(q->next->len < Streamhi) sendctl(up, up->lastecho = ECHO+i); up->iseq = i; break; } } /* * block mode input. * * the first byte in every message is a ctl byte (which belongs at the end). * * Simplifying assumption: one put == one message && the control byte * is in the first block. If this isn't true, strange bytes will be * used as control bytes. */ void urpiput(Queue *q, Block *bp) { Urp *up; int i; int ctl; up = (Urp *)q->ptr; if(bp->type != M_DATA){ urpctliput(up, q, bp); return; } /* * get the control character */ ctl = *bp->rptr++; /* * take care of any block count(trx) */ while(up->trx){ if(BLEN(bp)<=0) break; switch (up->trx) { case 1: case 2: up->trbuf[up->trx++] = *bp->rptr++; continue; default: up->trx = 0; break; } } /* * queue the block(s) */ if(BLEN(bp) > 0){ putq(q, bp); q->last->flags &= ~S_DELIM; if(q->len > 4*1024){ flushinput(up); return; } } else freeb(bp); /* * handle the control character */ switch(ctl){ case 0: break; case ENQ: print("rENQ %uo %uo\n", up->lastecho, ACK+up->iseq); urpstat.enqsr++; sendctl(up, up->lastecho); sendctl(up, ACK+up->iseq); flushinput(up); break; case CHECK: sendctl(up, ACK+up->iseq); break; case AINIT: up->state &= ~INITING; flushinput(up); wakeup(&up->rq->r); break; case INIT0: case INIT1: sendctl(up, AINIT); if(ctl == INIT0) q->put = urpciput; initinput(up, 0); break; case INITREQ: initoutput(up, 0); break; case BREAK: break; case BOT: case BOTS: case BOTM: up->trx = 1; up->trbuf[0] = ctl; break; case REJ+0: case REJ+1: case REJ+2: case REJ+3: case REJ+4: case REJ+5: case REJ+6: case REJ+7: print("rREJ\n"); rcvack(up, ctl); break; case ACK+0: case ACK+1: case ACK+2: case ACK+3: case ACK+4: case ACK+5: case ACK+6: case ACK+7: case ECHO+0: case ECHO+1: case ECHO+2: case ECHO+3: case ECHO+4: case ECHO+5: case ECHO+6: case ECHO+7: rcvack(up, ctl); break; /* * if the seuence number is the next expected * and te trailer length == 3 * and the block count matches the bytes received * then send the bytes upstream. */ case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3: case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7: i = ctl & Nmask; if(up->trx != 3){ urpstat.rjtrs++; flushinput(up); print("sREJ1 %d\n", up->iseq); sendctl(up, up->lastecho = REJ+up->iseq); break; } else if(q->len != up->trbuf[1] + (up->trbuf[2]<<8)){ urpstat.rjpks++; flushinput(up); print("sREJ2 %d\n", up->iseq); sendctl(up, up->lastecho = REJ+up->iseq); break; } else if(i != ((up->iseq+1)&Nmask)) { urpstat.rjseq++; flushinput(up); print("sREJ3 %d %d\n", i, up->iseq); sendctl(up, up->lastecho = REJ+up->iseq); break; } /* * send data upstream */ if(q->first) { if(up->trbuf[0] != BOTM) q->last->flags |= S_DELIM; while(bp = getq(q)) PUTNEXT(q, bp); } else { bp = allocb(0); bp->flags |= S_DELIM; PUTNEXT(q, bp); } up->trx = 0; /* * acknowledge receipt */ if(q->next->len < Streamhi){ sendctl(up, ECHO+i); up->lastecho = ECHO+i; wakeup(&up->rq->r); } up->iseq = i; break; } } /* * downstream control */ static void urpctloput(Urp *up, Queue *q, Block *bp) { char *fields[2]; int n; int inwin=0, outwin=0; switch(bp->type){ case M_CTL: if(streamparse("init", bp)){ switch(getfields((char *)bp->rptr, fields, 2, ' ')){ case 2: inwin = strtoul(fields[1], 0, 0); case 1: outwin = strtoul(fields[0], 0, 0); } /* initinput(up, inwin); */ DPRINT("initoutput %d\n", outwin); initoutput(up, outwin); freeb(bp); return; } } PUTNEXT(q, bp); } /* * accept data from a writer */ static void urpoput(Queue *q, Block *bp) { Urp *up; up = (Urp *)q->ptr; if(bp->type != M_DATA){ urpctloput(up, q, bp); return; } urpstat.output += BLEN(bp); putq(q, bp); output(up); } /* * start output */ static void output(Urp *up) { Block *bp, *nbp; ulong now; Queue *q; int n; if(!canqlock(&up->xmit)) return; if(waserror()){ print("urp output error\n"); qunlock(&up->xmit); nexterror(); } /* * if still initing and it's time to rexmit, send an INIT1 */ now = NOW; if(up->state & INITING){ if(now > up->timer){ sendctl(up, INIT1); up->timer = now + MSrexmit; } qunlock(&up->xmit); poperror(); return; } /* * fill the transmit buffers */ q = up->wq; for(bp = getq(q); bp && up->xb[up->nxb]==0; up->nxb = NEXT(up->nxb)){ if(BLEN(bp) > up->maxblock){ nbp = up->xb[up->nxb] = allocb(0); nbp->rptr = bp->rptr; nbp->wptr = bp->rptr = bp->rptr + up->maxblock; } else { up->xb[up->nxb] = bp; bp = getq(q); } } if(bp) putbq(q, bp); /* print("output w(%d) up->xb[%d](%ux) up->nxb(%d) up->state(%ux)\n", WINDOW(up), up->next, up->xb[up->next], up->nxb, up->state); /**/ /* * if a retransmit time has elapsed since a transmit, send an ENQ */ if(up->unechoed != up->next && NOW > up->timer){ print("sENQ\n"); up->timer = NOW + MSrexmit; up->state &= ~REJECTING; sendctl(up, ENQ); qunlock(&up->xmit); poperror(); return; } /* * if there's a window open, push some blocks out */ while(WINDOW(up)>0 && up->xb[up->next]!=0 && canqlock(&up->xl[up->next])){ if(up->xb[up->next]) sendblock(up, up->next); qunlock(&up->xl[up->next]); up->next = NEXT(up->next); } qunlock(&up->xmit); poperror(); } /* * send a control byte, put the byte at the end of the allocated * space in case a lower layer needs header room. */ static void sendctl(Urp *up, int ctl) { Block *bp; if(up->wq->next->len > Streamhi) return; bp = allocb(1); bp->wptr = bp->lim; bp->rptr = bp->lim-1; *bp->rptr = ctl; bp->flags |= S_DELIM; PUTNEXT(up->wq, bp); } /* * send a block. */ static void sendblock(Urp *up, int bn) { Block *bp, *m, *nbp; int n; up->timer = NOW + MSrexmit; if(up->wq->next->len > Streamhi) return; /* * message 1, the BOT and the data */ bp = up->xb[bn]; m = allocb(1); m->rptr = m->lim - 1; m->wptr = m->lim; *m->rptr = (bp->flags & S_DELIM) ? BOT : BOTM; nbp = m->next = allocb(0); nbp->rptr = bp->rptr; nbp->wptr = bp->wptr; nbp->flags |= S_DELIM; PUTNEXT(up->wq, m); /* * message 2, the block length and the SEQ */ m = allocb(3); m->rptr = m->lim - 3; m->wptr = m->lim; n = BLEN(bp); m->rptr[0] = SEQ | bn; m->rptr[1] = n; m->rptr[2] = n<<8; m->flags |= S_DELIM; PUTNEXT(up->wq, m); } /* * receive an acknowledgement */ static void rcvack(Urp *up, int msg) { int seqno; int next; seqno = msg&Nmask; next = NEXT(seqno); /* * release any acknowledged blocks */ if(IN(seqno, up->unacked, up->next)){ for(; up->unacked != next; up->unacked = NEXT(up->unacked)){ qlock(&up->xl[up->unacked]); if(up->xb[up->unacked]) freeb(up->xb[up->unacked]); up->xb[up->unacked] = 0; qunlock(&up->xl[up->unacked]); } } switch(msg & 0370){ case ECHO: if(IN(seqno, up->unechoed, up->next)) { up->unechoed = next; } /* * the next reject at the start of a window starts a * retransmission. */ up->state &= ~REJECTING; break; case REJ: if(IN(seqno, up->unechoed, up->next)) up->unechoed = next; /* * ... FALL THROUGH ... */ case ACK: /* * start a retransmission if we aren't retransmitting * and this is the start of a window. */ if(up->unechoed==next && !(up->state & REJECTING)){ up->state |= REJECTING; up->next = next; } break; } wakeup(&up->rq->r); } /* * throw away any partially collected input */ static void flushinput(Urp *up) { Block *bp; while (bp = getq(up->rq)) freeb(bp); up->trx = 0; } /* * initialize output */ static void initoutput(Urp *up, int window) { int i; /* * set output window */ up->maxblock = window/4; if(up->maxblock < 64) up->maxblock = 64; if(up->maxblock > Streamhi/4) up->maxblock = Streamhi/4; up->maxblock -= 4; up->maxout = 3; /* * set sequence varialbles */ up->unechoed = 1; up->unacked = 1; up->next = 1; up->nxb = 1; /* * free any outstanding blocks */ for(i = 0; i < 8; i++){ qlock(&up->xl[i]); if(up->xb[i]) freeb(up->xb[i]); qunlock(&up->xl[i]); } /* * tell the other side we've inited */ up->state |= INITING; up->timer = NOW + MSrexmit; sendctl(up, INIT1); } /* * initialize input */ static void initinput(Urp *up, int window) { /* * restart all sequence parameters */ up->trx = 0; up->iseq = 0; up->lastecho = ECHO+0; flushinput(up); } /* * do retransmissions etc */ static int todo(void *arg) { Urp *up; up = (Urp *)arg; return (WINDOW(up)>0 && up->wq->len>0 && !(up->state&INITING)); } static void urpkproc(void *arg) { Urp *up; up = (Urp *)arg; print("urpkproc started\n"); for(;;){ if(up->state & (HUNGUP|CLOSING)){ if(isflushed(up)) wakeup(&up->r); if(up->state & HUNGUP) break; } if((up->lastecho&Nmask)!=up->iseq && up->rq->next->len<Streamhi) sendctl(up, up->lastecho = ECHO+up->iseq); output(up); tsleep(&up->rq->r, todo, up, MSrexmit/2); } DPRINT("urpkproc exiting %ux\n", up); up->kstarted = 0; up->state = 0; }
M gnot/sysproc.c => gnot/sysproc.c +11 -5
@@ 51,7 51,7 @@ sysfork(ulong *arg) s = &p->seg[SSEG]; s->proc = p; on = (s->maxva-s->minva)>>PGSHIFT; usp = ((Ureg*)UREGADDR)->sp; usp = ((Ureg*)UREGADDR)->usp; if(usp >= USTKTOP) panic("fork bad usp %lux", usp); if(usp < u->p->seg[SSEG].minva) @@ 174,21 174,27 @@ sysexec(ulong *arg) } if(!indir) strcpy(elem, u->elem); print("offset %lux\n", tc->offset); n = (*devtab[tc->type].read)(tc, &exec, sizeof(Exec)); if(n < 2) if(n < 2){ print("short read\n"); Err: error(0, Ebadexec); } if(n==sizeof(Exec) && exec.magic==A_MAGIC){ if((exec.text&KZERO) || (ulong)exec.entry < UTZERO+sizeof(Exec) || (ulong)exec.entry >= UTZERO+sizeof(Exec)+exec.text) || (ulong)exec.entry >= UTZERO+sizeof(Exec)+exec.text){ print("bad header sizes\n"); goto Err; } goto Binary; } /* * Process #! /bin/sh args ... */ print("do #! magic=%lux size=%d\n", exec.magic, n); memcpy(line, &exec, sizeof(Exec)); if(indir || line[0]!='#' || line[1]!='!') goto Err; @@ 347,10 353,10 @@ sysexec(ulong *arg) unlock(o); flushmmu(); ((Ureg*)UREGADDR)->pc = exec.entry - 4; ((Ureg*)UREGADDR)->pc = exec.entry; sp = (ulong*)(USTKTOP - ssize); *--sp = nargs; ((Ureg*)UREGADDR)->sp = (ulong)sp; ((Ureg*)UREGADDR)->usp = (ulong)sp; lock(&p->debug); u->nnote = 0; u->notify = 0;
M gnot/trap.c => gnot/trap.c +1 -0
@@ 244,6 244,7 @@ syscall(Ureg *aur) u->p->insyscall = 1; ur = aur; u->p->pc = ur->pc; if(ur->sr & SUPER) panic("recursive system call"); #ifdef asdf
M port/devcons.c => port/devcons.c +7 -3
@@ 323,7 323,8 @@ readnum(ulong off, char *buf, ulong n, ulong val, int size) numbconv(&op, 10); tmp[size-1] = ' '; off %= size; if(off >= size) return 0; if(off+n > size) n = size-off; memcpy(buf, tmp+off, n); @@ 336,7 337,8 @@ readstr(ulong off, char *buf, ulong n, char *str) int size; size = strlen(str); off %= size; if(off >= size) return 0; if(off+n > size) n = size-off; memcpy(buf, str+off, n); @@ 455,7 457,9 @@ consread(Chan *c, void *buf, long n) return i; case Qcputime: k = c->offset % sizeof tmp; k = c->offset; if(k >= sizeof tmp) return 0; if(k+n > sizeof tmp) n = sizeof tmp - k; /* easiest to format in a separate buffer and copy out */
A port/devdk.c => port/devdk.c +1459 -0
@@ 0,0 1,1459 @@ #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "errno.h" #define NOW (MACHP(0)->ticks) #define DPRINT if(0) enum { /* * configuration parameters */ Ndk = 2, /* max dks */ /* * relative or immutable */ Nline = 256, /* max lines per dk */ Ndir = Nline + 1, /* entries in the dk directory */ Nsubdir = 5, /* entries in the sub directory */ }; typedef struct Dkmsg Dkmsg; typedef struct Line Line; typedef struct Dk Dk; /* * types of possible dkcalls */ enum { Dial, Announce, Redial }; /* * format of messages to/from the datakit controller on the common * signalling line */ struct Dkmsg { uchar type; uchar srv; uchar param0l; uchar param0h; uchar param1l; uchar param1h; uchar param2l; uchar param2h; uchar param3l; uchar param3h; uchar param4l; uchar param4h; }; /* * message codes (T_xxx == dialin.type, D_xxx == dialin.srv) */ #define T_SRV 1 /* service request */ #define D_SERV 1 /* (host to dkmux) announce a service */ #define D_DIAL 2 /* (host to dkmux) connect to a service */ #define D_XINIT 7 /* (dkmux to host) line has been spliced */ #define T_REPLY 2 /* reply to T_SRV/D_SERV or T_SRV/D_DIAL */ #define D_OK 1 /* not used */ #define D_OPEN 2 /* (dkmux to host) connection established */ #define D_FAIL 3 /* (dkmux to host) connection failed */ #define T_CHG 3 /* linege the status of a connection */ #define D_CLOSE 1 /* close the connection */ #define D_ISCLOSED 2 /* (dkmux to host) confirm a close */ #define D_CLOSEALL 3 /* (dkmux to host) close all connections */ #define D_REDIAL 6 /* (host to dkmux) redial a call */ #define T_ALIVE 4 /* (host to dkmux) keep alive message */ #define D_CONTINUE 0 /* host has not died since last msg */ #define D_RESTART 1 /* host has restarted */ #define D_MAXCHAN 2 /* request maximum line number */ #define T_RESTART 8 /* (dkmux to host) datakit restarted */ /* * macros for cracking/forming the window negotiation parameter */ #define MIN(x,y) (x < y ? x : y) #define W_WINDOW(o,d,t) ((o<<8) | (d<<4) | t | 0100000) #define W_VALID(x) ((x) & 0100000) #define W_ORIG(x) (((x)>>8) & 017) #define W_DEST(x) (((x)>>4) & 017) #define W_TRAF(x) ((x) & 017) #define W_DESTMAX(x,y) (W_WINDOW(W_ORIG(x),MIN(W_DEST(x),y),W_TRAF(x))) #define W_LIMIT(x,y) (W_WINDOW(MIN(W_ORIG(x),y),MIN(W_DEST(x),y),W_TRAF(x))) #define W_VALUE(x) (1<<((x)+4)) #define WS_2K 7 /* * one per datakit line */ struct Line { QLock; Rendez r; /* wait here for dial */ int state; /* dial state */ int err; /* dialing error (if non zero) */ int window; /* negotiated window */ int timestamp; /* timestamp of last call received on this line */ int calltolive; /* multiple of 15 seconds for dialing state to last */ Queue *rq; char addr[64]; char raddr[64]; char ruser[32]; char other[64]; Dk *dp; /* interface contianing this line */ }; /* * a dkmux dk. one exists for every stream that a * dkmux line disilpline is pushed onto. */ struct Dk { QLock; int ref; char name[64]; /* dk name */ Queue *wq; /* dk output queue */ int lines; /* number of lines */ int ncsc; /* csc line number */ Chan *csc; /* common signalling line */ Line line[Nline]; }; static Dk dk[Ndk]; /* * conversation states (for Line.state) */ typedef enum { Lclosed=0, Lopened, /* opened but no call out */ Lconnected, /* opened and a call set up on htis line */ Lrclose, /* remote end has closed down */ Llclose, /* local end has closed down */ Ldialing, /* dialing a new call */ Llistening, /* this line listening for calls */ Lackwait, /* incoming call waiting for ack/nak */ Laccepting, /* waiting for user to accept or reject the call */ } Lstate; /* * datakit error to errno */ enum { DKok, DKbusy, DKnetotl, DKdestotl, DKbadnet, DKnetbusy, DKinuse, DKreject, }; int dkerr[]={ [DKok]Egreg, [DKbusy]Einuse, /* destination busy */ [DKnetotl]Enetotl, /* network not answering */ [DKdestotl]Edestotl, /* destination not answering */ [DKbadnet]Ebadnet, /* unassigned destination */ [DKnetbusy]Enetbusy, /* network overload */ [DKinuse]Einuse, /* server already exists */ [DKreject]Erejected /* call rejected by destination */ }; #define DKERRS sizeof(dkerr)/sizeof(int) /* * imported */ extern Qinfo urpinfo; /* * predeclared */ Chan* dkattach(char*); static void dkmuxconfig(Dk*, Block*); static int dkmesg(Dk*, int, int, int, int); static void dkcsckproc(void*); static int dklisten(Chan*); static void dkanswer(Chan*, int, int); static void dkwindow(Chan*); static void dkcall(int, Chan*, char*, char*, char*); static void dktimer(void*); static void dkchgmesg(Dk*, Dkmsg*, int); static void dkreplymesg(Dk*, Dkmsg*, int); Chan* dkopen(Chan*, int); /* * the datakit multiplexor stream module definition */ static void dkmuxopen(Queue *, Stream *); static void dkmuxclose(Queue *); static void dkmuxoput(Queue *, Block *); static void dkmuxiput(Queue *, Block *); Qinfo dkmuxinfo = { dkmuxiput, dkmuxoput, dkmuxopen, dkmuxclose, "dkmux" }; /* * a new dkmux. find a free dk structure and assign it to this queue. */ static void dkmuxopen(Queue *q, Stream *s) { Dk *dp; int i; for(dp = dk; dp < &dk[Ndk]; dp++){ if(dp->wq == 0){ qlock(dp); if(dp->wq) { /* someone was faster than us */ qunlock(dp); continue; } q->ptr = q->other->ptr = (void *)dp; dp->csc = 0; dp->ncsc = 4; dp->lines = 16; dp->name[0] = 0; dp->wq = WR(q); qunlock(dp); return; } } error(0, Enoifc); } /* * close down a dkmux */ static void dkmuxclose(Queue *q) { Dk *dp; dp = (Dk *)q->ptr; qlock(dp); if(dp->csc) close(dp->csc); dp->wq = 0; qunlock(dp); } /* * handle configuration */ static void dkmuxoput(Queue *q, Block *bp) { Dk *dp; dp = (Dk *)q->ptr; if(bp->type != M_DATA){ if(streamparse("config", bp)) dkmuxconfig(dp, bp); else PUTNEXT(q, bp); return; } PUTNEXT(q, bp); } /* * gather a message and send it up the appropriate stream * * The first two bytes of each message contains the channel * number, low order byte first. * * Simplifying assumption: one put == one message && the channel number * is in the first block. If this isn't true, demultiplexing will not * work. */ static void dkmuxiput(Queue *q, Block *bp) { Dk *dp; Line *lp; int line; dp = (Dk *)q->ptr; if(bp->type != M_DATA){ PUTNEXT(q, bp); return; } line = *bp->rptr++ | (*bp->rptr++<<8); if(line<0 || line>=dp->lines){ print("dkmuxiput bad line %d\n", line); freeb(bp); return; } lp = &dp->line[line]; if(canqlock(lp)){ if(lp->rq) PUTNEXT(lp->rq, bp); else{ print("dkmuxiput unopened line %d\n", line); freeb(bp); } qunlock(lp); } else { print("dkmuxiput unopened line %d\n", line); freeb(bp); } } /* * the datakit line stream module definition */ static void dkstopen(Queue *, Stream *); static void dkstclose(Queue *); static void dkoput(Queue *, Block *); static void dkiput(Queue *, Block *); Qinfo dkinfo = { dkiput, dkoput, dkstopen, dkstclose, "dk" }; /* * open and save a pointer to the conversation */ static void dkstopen(Queue *q, Stream *s) { Dk *dp; Line *lp; dp = &dk[s->dev]; q->other->ptr = q->ptr = lp = &dp->line[s->id]; lp->dp = dp; lp->rq = q; } /* * close down a datakit conversation */ static void dkstclose(Queue *q) { Dk *dp; Line *lp; lp = (Line *)q->ptr; dp = lp->dp; /* * shake hands with dk */ switch(lp->state){ case Lclosed: case Llclose: break; case Lrclose: dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Lclosed; break; case Lackwait: dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Llclose; break; case Llistening: dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Llclose; break; case Lconnected: dkmesg(dp, T_CHG, D_CLOSE, lp - dp->line, 0); lp->state = Llclose; break; case Lopened: lp->state = Lclosed; } qlock(lp); lp->rq = 0; qunlock(lp); } /* * this is only called by hangup */ static void dkiput(Queue *q, Block *bp) { PUTNEXT(q, bp); } /* * we assume that each put is a message. * * add a 2 byte channel number to the start of each message */ static void dkoput(Queue *q, Block *bp) { Line *lp; Dk *dp; int line; if(bp->type != M_DATA){ freeb(bp); error(0, Ebadarg); } lp = (Line *)q->ptr; dp = lp->dp; line = lp - dp->line; if(bp->base && bp->rptr - bp->base >= 2) bp->rptr -= 2; bp->rptr[0] = line; bp->rptr[1] = line>>8; PUTNEXT(dp->wq, bp); } /* * configure a datakit multiplexor. this takes 3 arguments separated * by spaces: * the line number of the common signalling channel (must be > 0) * the number of lines in the device (optional) * the name of the dk (optional) * * we can configure only once */ static void dkmuxconfig(Dk *dp, Block *bp) { Chan *c; char *fields[3]; int n; char buf[64]; static int dktimeron; if(dp->csc != 0){ freeb(bp); error(0, Ebadarg); } /* * parse */ n = getfields((char *)bp->rptr, fields, 3, ' '); switch(n){ case 3: strncpy(dp->name, fields[2], sizeof(dp->name)); case 2: dp->lines = strtoul(fields[1], 0, 0); case 1: dp->ncsc = strtoul(fields[0], 0, 0); break; default: freeb(bp); error(0, Ebadarg); } freeb(bp); if(dp->ncsc <= 0 || dp->lines <= dp->ncsc){ dp->lines = 16; error(0, Ebadarg); } /* * open a stream for the csc and push urp onto it */ c = 0; if(waserror()){ if(c) close(c); nexterror(); } c = dkattach(dp->name); c->qid = STREAMQID(dp->ncsc, Sdataqid); dkopen(c, ORDWR); dp->csc = c; /* * start a process to deal with it */ sprint(buf, "**csckproc%d**", dp->ncsc); kproc(buf, dkcsckproc, dp); poperror(); /* * start a keepalive process if one doesn't exist */ if(dktimeron == 0){ dktimeron = 1; kproc("**dktimer**", dktimer, 0); } } /* * qid's */ enum { /* * per line */ Daddrqid, Dlistenqid, Draddrqid, Duserqid, Dotherqid, Dlineqid, /* * per device */ Dcloneqid, }; /* * the dk directory */ Dirtab dkdir[Ndir]; /* * the per stream directory structure */ Dirtab dksubdir[]={ "addr", Daddrqid, 0, 0600, "listen", Dlistenqid, 0, 0600, "other", Dotherqid, 0, 0600, "raddr", Draddrqid, 0, 0600, "ruser", Duserqid, 0, 0600, }; /* * dk file system. most of the calls use dev.c to access the dk * directory and stream.c to access the dk devices. */ void dkreset(void) { } /* * create the dk directory. the files are `clone' and stream * directories '1' to '32' (or whatever Nline is in decimal) */ void dkinit(void) { int i; /* * create the directory. */ /* * the circuits */ for(i = 1; i < Nline; i++) { sprint(dkdir[i].name, "%d", i); dkdir[i].qid = CHDIR|STREAMQID(i, Dlineqid); dkdir[i].length = 0; dkdir[i].perm = 0600; } /* * the clone device */ strcpy(dkdir[0].name, "clone"); dkdir[0].qid = Dcloneqid; dkdir[0].length = 0; dkdir[0].perm = 0600; } Chan* dkattach(char *spec) { Chan *c; Dk *dp; /* * find a multiplexor with the same name */ for(dp = dk; dp < &dk[Ndk]; dp++){ qlock(dp); if(dp->wq && strcmp(spec, dp->name)==0) { dp->ref++; qunlock(dp); break; } qunlock(dp); } if(dp == &dk[Ndk]) error(0, Enoifc); c = devattach('k', spec); c->dev = dp - dk; return c; } Chan* dkclone(Chan *c, Chan *nc) { Dk *dp; dp = &dk[c->dev]; qlock(dp); dp->ref++; qunlock(dp); return devclone(c, nc); } int dkwalk(Chan *c, char *name) { if(c->qid == CHDIR) return devwalk(c, name, dkdir, dk[c->dev].lines, devgen); else return devwalk(c, name, dksubdir, Nsubdir, streamgen); } void dkstat(Chan *c, char *dp) { if(c->qid == CHDIR) devstat(c, dp, dkdir, dk[c->dev].lines, devgen); else devstat(c, dp, dksubdir, Nsubdir, streamgen); } /* * opening a dk device allocates a Line. Opening the `clone' * device is a ``macro'' for finding a free Line and opening * it's ctl file. * * opening the `listen' sub device is a macro for listening for * a new call. Lile `clone' the ctl file of the new channel is * returned. */ Chan* dkopen(Chan *c, int omode) { extern Qinfo dkinfo; Stream *s; Line *lp, *end; Dk *dp; int line; if(c->qid == Dcloneqid){ /* * get an unused device and open it's control file */ dp = &dk[c->dev]; end = &dp->line[dp->lines]; for(lp = &dp->line[dp->ncsc+1]; lp < end; lp++){ if(lp->state == Lclosed && canqlock(lp)){ if(lp->state != Lclosed){ qunlock(lp); continue; } c->qid = STREAMQID(lp-dp->line, Sctlqid); qunlock(lp); break; } } if(lp == end) error(0, Enodev); streamopen(c, &dkinfo); pushq(c->stream, &urpinfo); } else if(STREAMTYPE(c->qid) == Dlistenqid){ /* * listen for a call and open the control file for the * channel on which the call arrived. */ line = dklisten(c); c->qid = STREAMQID(line, Sctlqid); streamopen(c, &dkinfo); pushq(c->stream, &urpinfo); dkwindow(c); } else if(c->qid != CHDIR){ /* * open whatever c points to, make sure it has an urp */ streamopen(c, &dkinfo); if(strcmp(c->stream->procq->next->info->name, "urp")!=0) pushq(c->stream, &urpinfo); } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } void dkcreate(Chan *c, char *name, int omode, ulong perm) { error(0, Eperm); } void dkclose(Chan *c) { Dk *dp; /* real closing happens in lancestclose */ if(c->qid != CHDIR) streamclose(c); dp = &dk[c->dev]; qlock(dp); dp->ref--; qunlock(dp); } long dkread(Chan *c, void *a, long n) { int t; Line *lp; t = STREAMTYPE(c->qid); if(t>=Slowqid || t==Dlineqid) return streamread(c, a, n); if(c->qid == CHDIR) return devdirread(c, a, n, dkdir, dk[c->dev].lines, devgen); lp = &dk[c->dev].line[STREAMID(c->qid)]; switch(t){ case Daddrqid: return stringread(c, a, n, lp->addr); case Draddrqid: return stringread(c, a, n, lp->raddr); case Duserqid: return stringread(c, a, n, lp->ruser); } error(0, Eperm); } long dkwrite(Chan *c, void *a, long n) { int t; char buf[256]; char *field[5]; int m; t = STREAMTYPE(c->qid); /* * get data dispatched as quickly as possible */ if(t == Sdataqid) return streamwrite(c, a, n, 0); /* * easier to do here than in dkoput */ if(t == Sctlqid){ strncpy(buf, a, sizeof buf); m = getfields(buf, field, 5, ' '); if(strcmp(field[0], "connect")==0){ if(m < 2) error(0, Ebadarg); dkcall(Dial, c, field[1], 0, 0); } else if(strcmp(field[0], "announce")==0){ if(m < 2) error(0, Ebadarg); dkcall(Announce, c, field[1], 0, 0); } else if(strcmp(field[0], "redial")==0){ if(m < 4) error(0, Ebadarg); dkcall(Redial, c, field[1], field[2], field[3]); } else if(strcmp(field[0], "accept")==0){ if(m < 2) error(0, Ebadarg); dkanswer(c, strtoul(field[1], 0, 0), 0); } else if(strcmp(field[0], "reject")==0){ if(m < 3) error(0, Ebadarg); dkanswer(c, strtoul(field[1], 0, 0), strtoul(field[2], 0, 0)); } else return streamwrite(c, a, n, 0); return n; } if(t >= Slowqid) return streamwrite(c, a, n, 0); error(0, Eperm); } void dkremove(Chan *c) { error(0, Eperm); } void dkwstat(Chan *c, char *dp) { error(0, Eperm); } void dkerrstr(Error *e, char *buf) { rooterrstr(e, buf); } void dkuserstr(Error *e, char *buf) { extern consuserstr(Error *, char *); consuserstr(e, buf); } /* * send a message to the datakit on the common signaling line */ static int dkmesg(Dk *dp, int type, int srv, int p0, int p1) { Dkmsg d; Block *bp; if(dp->csc == 0) return -1; if(waserror()) return -1; d.type = type; d.srv = srv; d.param0l = p0; d.param0h = p0>>8; d.param1l = p1; d.param1h = p1>>8; d.param2l = 0; d.param2h = 0; d.param3l = 0; d.param3h = 0; d.param4l = 0; d.param4h = 0; streamwrite(dp->csc, (char *)&d, sizeof(Dkmsg), 1); poperror(); return 0; } /* * call out on a datakit */ static int calldone(void *a) { Line *lp; lp = (Line *)a; return lp->state != Ldialing; } static void dkcall(int type, Chan *c, char *addr, char *nuser, char *machine) { char dialstr[66]; int line; char dialtone; int t_val, d_val; Dk *dp; Line *lp; Chan *dc; line = STREAMID(c->qid); dp = &dk[c->dev]; lp = &dp->line[line]; /* * only dial on virgin lines */ if(lp->state != Lclosed) error(0, Ebadarg); DPRINT("dkcall(line=%d, type=%d, dest=%s)\n", line, type, addr); /* * build dial string (guard against new lines) */ if(strchr(addr, '\n')) error(0, Ebadarg); if(strlen(addr)+strlen(u->p->pgrp->user)+2 >= sizeof(dialstr)) error(0, Ebadarg); strcpy(dialstr, addr); switch(type){ case Dial: t_val = T_SRV; d_val = D_DIAL; strcat(dialstr, "\n"); strcat(dialstr, u->p->pgrp->user); strcat(dialstr, "\n"); break; case Announce: t_val = T_SRV; d_val = D_SERV; break; case Redial: t_val = T_CHG; d_val = D_REDIAL; strcat(dialstr, "\n"); strcat(dialstr, nuser); strcat(dialstr, "\n"); strcat(dialstr, machine); strcat(dialstr, "\n"); break; } /* * open the data file */ dc = dkattach(dp->name); if(waserror()){ close(dc); nexterror(); } dc->qid = STREAMQID(line, Sdataqid); dkopen(dc, ORDWR); lp->calltolive = 4; lp->state = Ldialing; /* * tell the controller we want to make a call */ DPRINT("dialout\n"); dkmesg(dp, t_val, d_val, line, W_WINDOW(WS_2K,WS_2K,2)); /* * if redial, wait for a dial tone (otherwise we might send * the dialstr to the previous other end and not the controller) */ if(type==Redial){ if(streamread(dc, &dialtone, 1L) != 1L){ lp->state = Lconnected; error(0, Ebadarg); } } /* * make the call */ DPRINT("dialstr %s\n", dialstr); streamwrite(dc, dialstr, (long)strlen(dialstr), 1); close(dc); poperror(); /* * redial's never get a reply, assume it worked */ if(type == Redial) { lp->state = Lconnected; return; } /* * wait for a reply */ DPRINT("reply wait\n"); sleep(&lp->r, calldone, lp); /* * if there was an error, translate it to a plan 9 * errno and report it to the user. */ DPRINT("got reply %d\n", lp->state); if(lp->state != Lconnected) { if(lp->err >= DKERRS) error(0, dkerr[0]); else error(0, dkerr[lp->err]); } /* * linege state if serving */ if(type == D_SERV){ lp->state = Llistening; } DPRINT("connected!\n"); /* * decode the window size */ if (W_VALID(lp->window)){ /* * a 1127 window negotiation */ lp->window = W_VALUE(W_DEST(lp->window)); } else if(lp->window>2 && lp->window<31){ /* * a generic window negotiation */ lp->window = 1<<lp->window; } else lp->window = 0; /* * tag the connection */ strncpy(lp->addr, addr, sizeof(lp->addr)-1); strncpy(lp->raddr, addr, sizeof(lp->raddr)-1); /* * reset the protocol */ dkwindow(c); } /* * listen for a call, reflavor the */ static int dklisten(Chan *c) { char dialstr[512]; char *line[12]; char *field[8]; Line *lp; Dk *dp; int n, lineno, ts, window; Chan *dc; dp = &dk[c->dev]; /* * open the data file */ dc = dkattach(dp->name); if(waserror()){ close(dc); nexterror(); } dc->qid = STREAMQID(STREAMID(c->qid), Sdataqid); dkopen(dc, ORDWR); /* * wait for a call in */ for(;;){ /* * read the dialstring and null terminate it */ n = streamread(dc, dialstr, sizeof(dialstr)-1); DPRINT("returns %d\n", n); if(n <= 0) error(0, Eio); dialstr[n] = 0; DPRINT("dialstr = %s\n", dialstr); /* * break the dial string into lines */ n = getfields(dialstr, line, 12, '\n'); if (n < 2) { DPRINT("bad dialstr from dk (1 line)\n"); error(0, Eio); } /* * line 0 is `line.tstamp.traffic[.urpparms.window]' */ window = 0; switch(getfields(line[0], field, 5, '.')){ case 5: /* * generic way of passing window */ window = strtoul(field[4], 0, 0); if(window > 0 && window <31) window = 1<<window; else window = 0; /* * intentional fall through */ case 3: /* * 1127 way of passing window */ if(window == 0){ window = strtoul(field[2], 0, 0); if(W_VALID(window)) window = W_VALUE(W_ORIG(window)); else window = 0; } break; default: print("bad message from dk(bad first line)\n"); continue; } lineno = strtoul(field[0], 0, 0); if(lineno >= dp->lines){ print("dklisten: illegal line %d\n", lineno); continue; } lp = &dp->line[lineno]; ts = strtoul(field[1], 0, 0); /* * this could be a duplicate request */ if(ts == lp->timestamp){ print("dklisten: repeat timestamp %d\n", lineno); continue; } /* * take care of glare (datakit picked an inuse channel * for the call to come in on). */ if(!canqlock(lp)){ print("DKbusy1\n"); dkanswer(c, lineno, DKbusy); continue; } else { if(lp->state != Lclosed){ qunlock(lp); print("DKbusy2 %ux\n", lp->state); dkanswer(c, lineno, DKbusy); continue; } } lp->window = window; /* * Line 1 is `my-dk-name.service[.more-things]'. * Special characters are escaped by '\'s. */ strncpy(lp->addr, line[1], sizeof(lp->addr)-1); /* * the rest is variable length */ switch(n) { case 2: /* no more lines */ lp->ruser[0] = 0; lp->raddr[0] = 0; break; case 3: /* line 2 is `source.user.param1.param2' */ getfields(line[2], field, 3, '.'); strncpy(lp->raddr, field[0], sizeof(lp->raddr)-1); strncpy(lp->ruser, field[1], sizeof(lp->ruser)-1); break; case 4: /* line 2 is `user.param1.param2' */ getfields(line[2], field, 2, '.'); strncpy(lp->ruser, field[0], sizeof(lp->ruser)-1); /* line 3 is `source.node.mod.line' */ strncpy(lp->raddr, line[3], sizeof(lp->raddr)-1); break; default: print("bad message from dk(>4 line)\n"); qunlock(lp); error(0, Ebadarg); } sprint(lp->other, "w(%d)", W_TRAF(lp->window)); DPRINT("src(%s)user(%s)dest(%s)other(%s)\n", lp->raddr, lp->ruser, lp->addr, lp->other); lp->timestamp = ts; lp->state = Lconnected; qunlock(lp); close(dc); poperror(); DPRINT("dklisten returns %d\n", lineno); return lineno; } } /* * answer a call */ static void dkanswer(Chan *c, int line, int code) { char reply[64]; Dk *dp; Chan *dc; Line *lp; dp = &dk[c->dev]; lp = &dp->line[line]; /* * open the data file (c is a control file) */ dc = dkattach(dp->name); if(waserror()){ close(dc); nexterror(); } dc->qid = STREAMQID(STREAMID(c->qid), Sdataqid); dkopen(dc, ORDWR); /* * send the reply */ sprint(reply, "%ud.%ud.%ud", line, lp->timestamp, code); DPRINT("dkanswer %s\n", reply); streamwrite(dc, reply, strlen(reply), 1); close(dc); poperror(); } /* * set the window size and reset the protocol */ static void dkwindow(Chan *c) { char buf[64]; long wins; Line *lp; lp = &dk[c->dev].line[STREAMID(c->qid)]; if(lp->window == 0) lp->window = 64; sprint(buf, "init %d %d", lp->window, Streamhi); streamwrite(c, buf, strlen(buf), 1); } /* * hangup a datakit connection */ static void dkhangup(Line *lp) { Block *bp; qlock(lp); if(lp->rq){ bp = allocb(0); bp->type = M_HANGUP; PUTNEXT(lp->rq, bp); } qunlock(lp); } /* * A process which listens to all input on a csc line */ static void dkcsckproc(void *a) { long n; Dk *dp; Dkmsg d; int line; int i; dp = (Dk *)a; /* * loop forever listening */ for(;;){ n = streamread(dp->csc, (char *)&d, (long)sizeof(d)); if(n != sizeof(d)){ print("strange csc message %d\n", n); continue; } line = (d.param0h<<8) + d.param0l; /* print("t(%d)s(%d)l(%d)\n", d.type, d.srv, line); /**/ switch (d.type) { case T_CHG: /* controller wants to close a line */ dkchgmesg(dp, &d, line); break; case T_REPLY: /* reply to a dial request */ dkreplymesg(dp, &d, line); break; case T_SRV: /* ignore it, it's useless */ print("dksrvmesg(%d)\n", line); break; case T_RESTART: /* datakit reboot */ print("dk restart\n"); if(line >=0 && line<dp->lines){ print("maxlines=%d\n", line+1); dp->lines=line+1; } break; default: DPRINT("unrecognized csc message %o(%o)\n", d.type, line); break; } } } /* * datakit requests or confirms closing a line */ static void dkchgmesg(Dk *dp, Dkmsg *dialp, int line) { Line *lp; if (line <= 0 || line >= dp->lines) { /* tell controller this line is not in use */ dkmesg(dp, T_CHG, D_CLOSE, line, 0); return; } lp = &dp->line[line]; switch (dialp->srv) { case D_CLOSE: /* remote shutdown */ switch (lp->state) { case Ldialing: /* simulate a failed connection */ dkreplymesg(dp, (Dkmsg *)0, line); lp->state = Lrclose; break; case Lrclose: case Lconnected: case Llistening: case Lackwait: dkhangup(lp); lp->state = Lrclose; break; case Lopened: dkmesg(dp, T_CHG, D_CLOSE, line, 0); break; case Llclose: case Lclosed: dkhangup(lp); dkmesg(dp, T_CHG, D_CLOSE, line, 0); lp->state = Lclosed; break; } break; case D_ISCLOSED: /* acknowledging a local shutdown */ switch (lp->state) { case Llclose: case Lclosed: lp->state = Lclosed; break; case Lrclose: case Lconnected: case Llistening: case Lackwait: break; } break; default: print("unrecognized T_CHG\n"); } } /* * datakit replies to a dialout. capture reply code and traffic parameters */ static void dkreplymesg(Dk *dp, Dkmsg *dialp, int line) { Proc *p; Line *lp; DPRINT("dkreplymesg(%d)\n", line); if(line < 0 || line >= dp->lines) return; lp=&dp->line[line]; if(lp->state != Ldialing) return; if(dialp){ /* * a reply from the dk */ lp->state = (dialp->srv==D_OPEN) ? Lconnected : Lrclose; lp->err = (dialp->param1h<<8) + dialp->param1l; lp->window = lp->err; DPRINT("dkreplymesg: %d\n", lp->state); } else { /* * a local abort */ lp->state = Lrclose; lp->err = 0; } if(lp->state==Lrclose){ dkhangup(lp); } wakeup(&lp->r); } /* * 15-second timer for all interfaces */ static Rendez dkt; static int fuckit(void *a) { return 0; } static void dktimer(void *a) { int dki, i; Dk *dp; Line *lp; waserror(); for(;;){ /* * loop through the active dks */ for(dki=0; dki<Ndk; dki++){ dp = &dk[dki]; if(dp->csc==0) continue; /* * send keep alive */ dkmesg(dp, T_ALIVE, D_CONTINUE, 0, 0); /* * remind controller of dead lines and * timeout calls that take to long */ for (i=0; i<dp->lines; i++){ lp = &dp->line[i]; switch(lp->state){ case Llclose: dkmesg(dp, T_CHG, D_CLOSE, i, 0); break; case Ldialing: if(lp->calltolive==0 || --lp->calltolive!=0) break; dkreplymesg(dp, (Dkmsg *)0, i); break; } } } tsleep(&dkt, fuckit, 0, 7500); } }
M port/devlance.c => port/devlance.c +2 -2
@@ 362,7 362,7 @@ lanceoput(Queue *q, Block *bp ) */ len = 0; while(bp = getq(q)){ if(sizeof(Pkt) - len >= (n = bp->wptr - bp->rptr)){ if(sizeof(Pkt) - len >= (n = BLEN(bp))){ memcpy(((uchar *)p)+len, bp->rptr, n); len += n; } else @@ 704,7 704,7 @@ lanceread(Chan *c, void *a, long n) long lancewrite(Chan *c, void *a, long n) { return streamwrite(c, a, n); return streamwrite(c, a, n, 0); } void
M port/devmnt.c => port/devmnt.c +1 -0
@@ 468,6 468,7 @@ mntremove(Chan *c) mhfree(mh); nexterror(); } decref(m); mh->thdr.type = Tremove; mh->thdr.fid = c->fid; mntxmit(m, mh);
M port/devpipe.c => port/devpipe.c +1 -1
@@ 129,7 129,7 @@ pipewrite(Chan *c, void *va, long n) postnote(u->p, 1, "sys: write on closed pipe", NExit); error(0, Egreg); } return streamwrite(c, va, n); return streamwrite(c, va, n, 0); } void
M port/fault.c => port/fault.c +3 -1
@@ 138,6 138,7 @@ fault(Ureg *ur, int user, int code) * Add to mod list */ pte = newmod(); o->nmod++; pte->proc = u->p; pte->page = opte->page; pte->page->ref++; @@ 210,9 211,10 @@ validaddr(ulong addr, ulong len, int write) Seg *s; if((long)len < 0) panic("validaddr len %lux\n", len); goto Err; s = seg(u->p, addr); if(s==0 || addr+len>s->maxva || (write && (s->o->flag&OWRPERM)==0)){ Err: pprint("invalid address in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp); postnote(u->p, 1, "bad address", NDebug); error(0, Ebadarg);
M port/page.c => port/page.c +5 -0
@@ 287,6 287,7 @@ loop: o->nproc = 1; o->npage = 0; o->chan = c; o->nmod = 0; if(c){ o->type = c->type; o->qid = c->qid; @@ 350,6 351,8 @@ loop: } unlock(&modalloc); print("no mods\n"); DEBUG(); panic("mods"); if(u == 0) panic("newmod"); u->p->state = Wakeme; @@ 376,6 379,7 @@ forkmod(Seg *old, Seg *new, Proc *p) if(pte->page==0) panic("forkmod zero page"); if(pte->proc != u->p) panic("forkmod wrong page"); npte = newmod(); o->nmod++; npte->proc = p; npte->page = pte->page; pte->page->ref++; @@ 435,6 439,7 @@ freesegs(int save) } pg->ref--; o->npage--; o->nmod--; old = (PTEA*)pte; pte = pte->nextva; lock(&modalloc);
M port/proc.c => port/proc.c +9 -2
@@ 518,16 518,23 @@ proctab(int i) #include <ureg.h> DEBUG() { int i; int i, j; Proc *p; Orig *o; print("DEBUG\n"); for(i=0; i<conf.nproc; i++){ p = procalloc.arena+i; if(p->state != Dead) if(p->state != Dead){ print("%d:%s upc %lux %s ut %ld st %ld\n", p->pid, p->text, p->pc, statename[p->state], p->time[0], p->time[1]); for(j=0; j<NSEG; j++){ o = p->seg[j].o; if(o) print(" s%d %d %d\n", j, o->nmod, o->npte); } } } }
M port/stream.c => port/stream.c +154 -25
@@ 7,12 7,24 @@ #include "errno.h" #include "devtab.h" /* * process end line discipline */ static void stputq(Queue*, Block*); Qinfo procinfo = { stputq, nullput, 0, 0, "process" } ; extern Qinfo noetherinfo; Qinfo procinfo = { stputq, nullput, 0, 0, "process" }; /* * line disciplines that can be pushed * * WARNING: this table should be the result of configuration */ extern Qinfo noetherinfo; extern Qinfo dkmuxinfo; extern Qinfo urpinfo; static Qinfo *lds[] = { &noetherinfo, &dkmuxinfo, &urpinfo, 0 }; @@ 34,7 46,9 @@ static Lock garbagelock; */ typedef struct { int size; Queue; Blist; QLock; /* qlock for sleepers on r */ Rendez r; /* sleep here waiting for blocks */ } Bclass; Bclass bclass[Nclass]={ { 0 }, @@ 108,7 122,9 @@ allocb(ulong size) while(bcp->first == 0){ unlock(bcp); print("waiting for blocks\n"); qlock(bcp); sleep(&bcp->r, isblock, (void *)bcp); qunlock(bcp); lock(bcp); } bp = bcp->first; @@ 128,25 144,33 @@ allocb(ulong size) } /* * Free a block. Poison its pointers so that someone trying to access * it after freeing will cause a dump. * Free a block (or list of blocks). Poison its pointers so that * someone trying to access it after freeing will cause a dump. */ void freeb(Block *bp) { Bclass *bcp; int tries; bcp = &bclass[bp->flags & S_CLASS]; bp->rptr = bp->wptr = 0; lock(bcp); bp->rptr = bp->wptr = 0; if(bcp->first) bcp->last->next = bp; else bcp->first = bp; tries = 0; while(bp->next){ if(++tries > 10){ dumpstack(); panic("freeb"); } bp = bp->next; } bcp->last = bp; bp->next = 0; wakeup(&bcp->r); unlock(bcp); wakeup(&bcp->r); } /* @@ 269,11 293,11 @@ putq(Queue *q, Block *bp) q->last->next = bp; else q->first = bp; q->len += bp->wptr - bp->rptr; q->len += BLEN(bp); delim = bp->flags & S_DELIM; while(bp->next) { bp = bp->next; q->len += bp->wptr - bp->rptr; q->len += BLEN(bp); delim |= bp->flags & S_DELIM; } q->last = bp; @@ 292,22 316,21 @@ putb(Blist *q, Block *bp) q->last->next = bp; else q->first = bp; q->len += bp->wptr - bp->rptr; q->len += BLEN(bp); delim = bp->flags & S_DELIM; while(bp->next) { bp = bp->next; q->len += bp->wptr - bp->rptr; q->len += BLEN(bp); delim |= bp->flags & S_DELIM; } q->last = bp; bp->next = 0; return delim; } /* * add a block to the start of a queue */ static void void putbq(Blist *q, Block *bp) { lock(q); @@ 316,12 339,12 @@ putbq(Blist *q, Block *bp) else q->last = bp; q->first = bp; q->len += bp->wptr - bp->rptr; q->len += BLEN(bp); unlock(q); } /* * remove the first block from a queue * remove the first block from a queue */ Block * getq(Queue *q) @@ 334,7 357,7 @@ getq(Queue *q) q->first = bp->next; if(q->first == 0) q->last = 0; q->len -= bp->wptr - bp->rptr; q->len -= BLEN(bp); if((q->flag&QHIWAT) && q->len < Streamhi/2){ wakeup(&q->other->next->other->r); q->flag &= ~QHIWAT; @@ 344,6 367,10 @@ getq(Queue *q) unlock(q); return bp; } /* * remove the first block from a list of blocks */ Block * getb(Blist *q) { @@ 354,13 381,87 @@ getb(Blist *q) q->first = bp->next; if(q->first == 0) q->last = 0; q->len -= bp->wptr - bp->rptr; q->len -= BLEN(bp); bp->next = 0; } return bp; } /* * make sure the first block has n bytes */ Block * pullup(Block *bp, int n) { Block *nbp; int i; /* * this should almost always be true, the rest it * just for to avoid every caller checking. */ if(BLEN(bp) >= n) return bp; /* * if not enough room in the first block, * add another to the front of the list. if(bp->lim - bp->rptr < n){ nbp = allocb(n); nbp->next = bp; bp = nbp; } /* * copy bytes from the trailing blocks into the first */ n -= BLEN(bp); while(nbp = bp->next){ i = BLEN(nbp); if(i > n) { memcpy(bp->wptr, nbp->rptr, n); bp->wptr += n; nbp->rptr += n; return bp; } else { memcpy(bp->wptr, nbp->rptr, i); bp->wptr += i; bp->next = nbp->next; nbp->next = 0; freeb(nbp); } } freeb(bp); return 0; } /* * grow the front of a list of blocks by n bytes */ Block * prepend(Block *bp, int n) { Block *nbp; if(bp->base && (bp->rptr - bp->base)>=n){ /* * room for channel number in first block of message */ bp->rptr -= n; return bp; } else { /* * make new block, put message number at end */ nbp = allocb(2); nbp->next = bp; nbp->wptr = nbp->lim; nbp->rptr = nbp->wptr - n; return nbp; } } /* * put a block into the bit bucket */ void @@ 415,7 516,7 @@ streamparse(char *name, Block *bp) int len; len = strlen(name); if(bp->wptr - bp->rptr < len) if(BLEN(bp) < len) return 0; if(strncmp(name, (char *)bp->rptr, len)==0){ if(bp->rptr[len] == ' ') @@ 622,14 723,19 @@ stputq(Queue *q, Block *bp) freeb(bp); q->flag |= QHUNGUP; q->other->flag |= QHUNGUP; wakeup(&q->other->r); } else { lock(q); if(q->first) q->last->next = bp; else q->first = bp; q->len += BLEN(bp); while(bp->next) { bp = bp->next; q->len += BLEN(bp); } q->last = bp; q->len += bp->wptr - bp->rptr; if(q->len >= Streamhi) q->flag |= QHIWAT; unlock(q); @@ 651,8 757,7 @@ stringread(Chan *c, uchar *buf, long n, char *str) n = i; if(n<0) return 0; memcpy(buf + c->offset, str, n); c->offset += n; memcpy(buf, str + c->offset, n); return n; } @@ 716,7 821,7 @@ streamread(Chan *c, void *vbuf, long n) continue; } i = bp->wptr - bp->rptr; i = BLEN(bp); if(i <= left){ memcpy(buf, bp->rptr, i); left -= i; @@ 806,7 911,7 @@ flowctl(Queue *q) * send the request as a single delimited block */ long streamwrite(Chan *c, void *a, long n) streamwrite(Chan *c, void *a, long n, int docopy) { Stream *s; Block *bp; @@ 846,7 951,7 @@ streamwrite(Chan *c, void *a, long n) if(q->other->flag & QHUNGUP) error(0, Ehungup); if(GLOBAL(a) || n==0){ if((GLOBAL(a) && !docopy) || n==0){ /* * `a' is global to the whole system, just create a * pointer to it and pass it on. @@ 887,3 992,27 @@ streamwrite(Chan *c, void *a, long n) poperror(); return n; } /* * like andrew's getmfields but no hidden state */ int getfields(char *lp, /* to be parsed */ char **fields, /* where to put pointers */ int n, /* number of pointers */ char sep /* separator */ ) { int i; for(i=0; lp && *lp && i<n; i++){ while(*lp == sep) *lp++=0; if(*lp == 0) break; fields[i]=lp; while(*lp && *lp != sep) lp++; } return i; }
M port/sturp.c => port/sturp.c +381 -347
@@ 1,23 1,23 @@ #include "syslibc.h" #include "lock.h" #include "chan.h" #include "proc.h" #include "user.h" #include "errno.h" #include "lint.h" #include "mem.h" #include "mempool.h" #include "stream.h" #include "dkparam.h" #include "misc.h" #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "errno.h" enum { Nurp= 32, MSrexmit= 1000, Nmask= 0x7, }; #define DPRINT if(0) typedef struct Urp Urp; #define NOW (MACHP(0)->ticks*MS2HZ) /* * URP status */ @@ 34,12 34,13 @@ struct urpstat { } urpstat; struct Urp { Qlock; QLock; short state; /* flags */ Rendez r; /* process waiting for close */ /* input */ ulong iwindow; /* input window */ Queue *rq; /* input queue */ uchar iseq; /* last good input sequence number */ uchar lastecho; /* last echo/rej sent */ uchar trbuf[3]; /* trailer being collected */ @@ 47,22 48,23 @@ struct Urp { /* output */ Queue *rq; Queue *wq; int XW; /* blocks per xmit window */ QLock xmit; /* output lock, only one process at a time */ Queue *wq; /* output queue */ int maxout; /* maximum outstanding unacked blocks */ int maxblock; /* max block size */ int timeout; /* a timeout has occurred */ int WS; /* start of current window */ int WACK; /* first non-acknowledged message */ int WNX; /* next message to be sent */ Rendez r; /* process waiting in urpoput */ Rendez kr; /* process waiting in urpoput */ int next; /* next block to send */ int unechoed; /* first unechoed block */ int unacked; /* first unacked block */ int nxb; /* next xb to use */ Block *xb[8]; /* the xmit window buffer */ uchar timer; /* timeout for xmit */ QLock xl[8]; ulong timer; /* timeout for xmit */ int kstarted; }; #define WINDOW(u) ((u->WS + u->XW - u->WNX)%8) #define BETWEEN(x, s, n) (s<=n ? x>=s && x<n : x<n || x>=s) #define UNACKED(x, u) (BETWEEN(x, u->WACK, u->WNX) #define WINDOW(u) ((u->unechoed + u->maxout - u->next)%8) #define IN(x, f, n) (f<=n ? x>=f && x<n : x<n || x>=f) #define NEXT(x) (((x)+1)&Nmask) /* * Protocol control bytes @@ 87,33 89,39 @@ struct Urp { #define DELAY 0100 /* real-time printing delay */ #define BREAK 0110 /* Send/receive break (new style) */ #define REXMITING 0001 #define REXMIT 0002 #define INITING 0004 #define REJECTING 0x1 #define INITING 0x2 #define HUNGUP 0x4 #define OPEN 0x8 #define CLOSING 0x10 Urp urp[Nurp]; /* * predeclared */ static void urpiput(Queue*, Block*, Rendez*); static void urpoput(Queue*, Block*, Rendez*); static void urpciput(Queue*, Block*); static void urpiput(Queue*, Block*); static void urpoput(Queue*, Block*); static void urpopen(Queue*, Stream*); static void urpclose(Queue *); static void output(Urp*); static void sendblock(Urp*, int); static void rcvack(Urp*, int); static void flushinput(Urp*); static void sendctl(Queue*, int); static void queuectl(Urp*, int); static void sendctl(Urp*, int); static void initoutput(Urp*, int); static void initinput(Urp*, int); static void urpkproc(void *arg); Qinfo urpinfo = { urpiput, urpoput, urpopen, urpclose, "urp" }; Qinfo urpinfo = { urpciput, urpoput, urpopen, urpclose, "urp" }; int static void urpopen(Queue *q, Stream *s) { Urp *up; int i; char name[128]; /* * find a free urp structure @@ 127,26 135,44 @@ urpopen(Queue *q, Stream *s) if(up == &urp[Nurp]) error(0, Egreg); q->ptr = = q->other->ptr = up; q->ptr = q->other->ptr = up; up->rq = q; up->wq = WR(q); q->put = urpciput; up->wq = q->other; up->state = OPEN; qunlock(up); initinput(up, 0); initoutput(up, 0); /* * start the ack/(re)xmit process */ if(up->kstarted == 0){ up->kstarted = 1; sprint(name, "**urp%d**", up - urp); kproc(name, urpkproc, up); } } /* * Shut it down. * Shut down the connection and kill off the kernel process */ static int allacked(void *a) isflushed(void *a) { Urp *up; up = (Urp *)a; return up->WACK == up->WNX; return (up->state&HUNGUP) || (up->unechoed==up->next && up->wq->len==0); } static int isdead(void *a) { Urp *up; up = (Urp *)a; return up->kstarted == 0; } static void urpclose(Queue *q) { Block *bp; @@ 154,14 180,31 @@ urpclose(Queue *q) int i; up = (Urp *)q->ptr; up->state |= LCLOSE; /* * wait for output to get acked * wait for all outstanding messages to drain, tell kernel * process we're closing. */ while(!urpdone(up)) sleep(&up->r, urpdone, up); up->state = 0; up->state |= CLOSING; sleep(&up->r, isflushed, up); /* * ack all outstanding messages */ qlock(&up->xmit); up->state |= HUNGUP; i = up->next - 1; if(i < 0) i = 7; rcvack(up, ECHO+i); qunlock(&up->xmit); DPRINT("urpclose(%ux)\n", up); /* * kill off the kernel process */ wakeup(&up->rq->r); DPRINT("urpclosed(%ux)\n", up); } /* @@ 172,29 215,25 @@ urpctliput(Urp *up, Queue *q, Block *bp) { switch(bp->type){ case M_HANGUP: /* * ack all outstanding messages */ lock(up); up->state &= ~(INITING); up->state |= RCLOSE; unlock(up); if(up->WS<up->WNX) urprack(up, ECHO+((up->WNX-1)&07)); up->state |= HUNGUP; wakeup(&up->r); wakeup(&up->rq->r); break; } PUTNEXT(q, bp); } /* * character mode input. the last character in EVERY block is * a control character. * character mode input. * * the first byte in every message is a ctl byte (which belongs at the end). */ void urpciput(Queue *q, Block *bp, Rendez *rp) urpciput(Queue *q, Block *bp) { Urp *up; int i, full; Block *nbp; int i; int ctl; up = (Urp *)q->ptr; if(bp->type != M_DATA){ @@ 205,15 244,14 @@ urpciput(Queue *q, Block *bp, Rendez *rp) /* * get the control character */ if(bp->wptr > bp->rptr) ctl = *(--bp->wptr); else ctl = 0; ctl = *bp->rptr++; if(ctl < 0) return; /* * send the block upstream * take care of any data */ if(bp->wptr > bp->rptr) if(BLEN(bp)>0 && q->next->len<Streamhi) PUTNEXT(q, bp); else freeb(bp); @@ 224,29 262,27 @@ urpciput(Queue *q, Block *bp, Rendez *rp) switch(ctl){ case 0: break; case ENQ: urpstat.enqsr++; queuectl(up, up->lastecho); queuectl(up, ACK+up->iseq); flushinput(up); sendctl(up, up->lastecho); sendctl(up, ACK+up->iseq); break; case CHECK: queuectl(up, ACK+up->iseq); sendctl(up, ACK+up->iseq); break; case AINIT: up->state &= ~INITING; flushinput(up); wakeup(&cp->kr); wakeup(&up->rq->r); break; case INIT0: case INIT1: queuectl(up, AINIT); if(*bp->rptr == INIT1) q->put = urpbiput; sendctl(up, AINIT); if(ctl == INIT1) q->put = urpiput; initinput(up, 0); break; @@ 257,6 293,11 @@ urpciput(Queue *q, Block *bp, Rendez *rp) case BREAK: break; case REJ+0: case REJ+1: case REJ+2: case REJ+3: case REJ+4: case REJ+5: case REJ+6: case REJ+7: rcvack(up, ctl); break; case ACK+0: case ACK+1: case ACK+2: case ACK+3: case ACK+4: case ACK+5: case ACK+6: case ACK+7: case ECHO+0: case ECHO+1: case ECHO+2: case ECHO+3: @@ 266,29 307,29 @@ urpciput(Queue *q, Block *bp, Rendez *rp) case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3: case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7: /* * acknowledge receipt */ ctl = ctl & 07; if(q->next->len < Streamhi){ queuectl(up, ECHO+ctl); up->lastecho = ECHO+ctl; wakeup(&cp->kr); } up->iseq = ctl; i = ctl & Nmask; if(q->next->len < Streamhi) sendctl(up, up->lastecho = ECHO+i); up->iseq = i; break; } } /* * block mode input. the last character in EVERY block is a control character. * block mode input. * * the first byte in every message is a ctl byte (which belongs at the end). * * Simplifying assumption: one put == one message && the control byte * is in the first block. If this isn't true, strange bytes will be * used as control bytes. */ void urpbiput(Queue *q, Block *bp, Rendez *rp) urpiput(Queue *q, Block *bp) { Urp *up; int i, full; Block *nbp; int i; int ctl; up = (Urp *)q->ptr; if(bp->type != M_DATA){ @@ 299,15 340,14 @@ urpbiput(Queue *q, Block *bp, Rendez *rp) /* * get the control character */ if(bp->wptr > bp->rptr) ctl = *(--bp->wptr); else ctl = 0; ctl = *bp->rptr++; /* * take care of any block count(trx) */ while(bp->wptr > bp->rptr && up->trx){ while(up->trx){ if(BLEN(bp)<=0) break; switch (up->trx) { case 1: case 2: @@ 315,21 355,20 @@ urpbiput(Queue *q, Block *bp, Rendez *rp) continue; default: up->trx = 0; case 0: break; } } /* * queue the block * queue the block(s) */ if(bp->wptr > bp->rptr){ if(q->len > up->iwindow){ if(BLEN(bp) > 0){ putq(q, bp); q->last->flags &= ~S_DELIM; if(q->len > 4*1024){ flushinput(up); freeb(bp); return; } putq(q, bp); } else freeb(bp); @@ 340,26 379,27 @@ urpbiput(Queue *q, Block *bp, Rendez *rp) case 0: break; case ENQ: print("rENQ\n"); urpstat.enqsr++; queuectl(up, up->lastecho); queuectl(up, ACK+up->iseq); sendctl(up, up->lastecho); sendctl(up, ACK+up->iseq); flushinput(up); break; case CHECK: queuectl(WR(q)->next, ACK+up->iseq); sendctl(up, ACK+up->iseq); break; case AINIT: up->state &= ~INITING; flushinput(up); wakeup(&cp->kr); wakeup(&up->rq->r); break; case INIT0: case INIT1: queuectl(up, AINIT); if(*bp->rptr == INIT0) sendctl(up, AINIT); if(ctl == INIT0) q->put = urpciput; initinput(up, 0); break; @@ 380,6 420,7 @@ urpbiput(Queue *q, Block *bp, Rendez *rp) case REJ+0: case REJ+1: case REJ+2: case REJ+3: case REJ+4: case REJ+5: case REJ+6: case REJ+7: print("rREJ\n"); rcvack(up, ctl); break; @@ 391,22 432,31 @@ urpbiput(Queue *q, Block *bp, Rendez *rp) break; /* * this case is extremely ugliferous * if the seuence number is the next expected * and te trailer length == 3 * and the block count matches the bytes received * then send the bytes upstream. */ case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3: case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7: i = ctl & 07; i = ctl & Nmask; if(up->trx != 3){ urpstat.rjtrs++; flushinput(up); print("sREJ\n"); sendctl(up, up->lastecho = REJ+up->iseq); break; } else if(q->len != up->trbuf[1] + (up->trbuf[2]<<8)){ urpstat.rjpks++; flushinput(up); print("sREJ\n"); sendctl(up, up->lastecho = REJ+up->iseq); break; } else if(i != ((up->iseq+1)&07))) { } else if(i != ((up->iseq+1)&Nmask)) { urpstat.rjseq++; flushinput(up); print("sREJ\n"); sendctl(up, up->lastecho = REJ+up->iseq); break; } @@ 414,26 464,26 @@ urpbiput(Queue *q, Block *bp, Rendez *rp) * send data upstream */ if(q->first) { q->first->flags |= S_DELIM; if(up->trbuf[0] != BOTM) q->last->flags |= S_DELIM; while(bp = getq(q)) PUTNEXT(q, nbp); PUTNEXT(q, bp); } else { bp = allocb(0); bp->flag |= S_DELIM; bp->flags |= S_DELIM; PUTNEXT(q, bp); { } up->trx = 0; /* * acknowledge receipt */ ctl = ctl & 07; if(q->next->len < Streamhi){ queuectl(up, ECHO+ctl); up->lastecho = ECHO+ctl; wakeup(&cp->kr); sendctl(up, ECHO+i); up->lastecho = ECHO+i; wakeup(&up->rq->r); } up->iseq = ctl; up->iseq = i; break; } } @@ 444,20 494,21 @@ urpbiput(Queue *q, Block *bp, Rendez *rp) static void urpctloput(Urp *up, Queue *q, Block *bp) { int fields[2]; char *fields[2]; int n; int inwin=0, outwin=0; switch(bp->type){ case M_CTL: if(streamparse("init", bp)){ switch(getfields(bp->rptr, fields, 2, ' ')){ switch(getfields((char *)bp->rptr, fields, 2, ' ')){ case 2: inwin = strtoul(fields[1], 0, 0); case 1: outwin = strtoul(fields[0], 0, 0); } initinput(up, inwin); /* initinput(up, inwin); */ DPRINT("initoutput %d\n", outwin); initoutput(up, outwin); freeb(bp); return; @@ 467,8 518,9 @@ urpctloput(Urp *up, Queue *q, Block *bp) } /* * accept data from writer * accept data from a writer */ static void urpoput(Queue *q, Block *bp) { Urp *up; @@ 480,192 532,148 @@ urpoput(Queue *q, Block *bp) return; } urpstat.output + = bp->wptr - bp->rptr; for(;;){ } urpstat.output += BLEN(bp); putq(q, bp); output(up); } /* * wait for an AINIT * start output */ void urpopenwait(Urp *up, Queue *q) static void output(Urp *up) { while((up->state&ISOPENING) && !(up->state&RCLOSE)) { proc->state = Waiting; up->proc = proc; putctl1(q->next, M_RDATA, INIT1); if((up->state&ISOPENING) == 0){ up->proc = 0; if(proc->state == Waiting){ proc->state = Running; return; } } sched(); up->proc = 0; } } Block *bp, *nbp; ulong now; Queue *q; int n; /* * wait till transmission is complete */ void urpxmitwait(Urp *up, Queue *q) { Block *bp; int debug; if(!canqlock(&up->xmit)) return; debug = (q->flag&QDEBUG); if(waserror()){ print("urp output error\n"); qunlock(&up->xmit); nexterror(); } up->timeout = 0; while(!EMPTY(q) || up->WS<up->WNX){ /* * clean up if the channel closed */ if (up->state & RCLOSE) { while(bp = getq(q)) freeb(bp); up->WACK = up->WS = up->WNX; } /* * free acked blocks */ urpfreeacked(up); /* * retransmit if requested */ if(up->state&REXMIT) urprexmit(up, q); /* * fill up the window */ if(!EMPTY(q) && WINDOW(up)) urpfillwindow(up, q); /* * ask other end for its status */ if(up->timeout){ urpstat.enqsx++; putctl1(q->next, M_RDATA, ENQ); up->timeout = 0; /* * if still initing and it's time to rexmit, send an INIT1 */ now = NOW; if(up->state & INITING){ if(now > up->timer){ sendctl(up, INIT1); up->timer = now + MSrexmit; } lock(up->olock); if((up->state&RCLOSE) == 0 && up->WS! = up->WNX) { proc->state = Waiting; up->proc = proc; unlock(up->olock); sched(); } else unlock(up->olock); qunlock(&up->xmit); poperror(); return; } urpfreeacked(up); up->WS = up->WACK = up->WF = up->WNX = up->WNX&07; } /* * fill up the urp output window */ void urpfillwindow(Urp *up, Queue *q) { Block *bp, *xbp; int debug; debug = (q->flag&QDEBUG); /* * now process any thing that fits in the flow control window * fill the transmit buffers */ while (WINDOW(up)) { bp = getq(q); if (bp == NULL) break; /* force MAXBLOCK length segments */ if (bp->rptr+up->maxblock < bp->wptr) { xbp = allocb(0); if (xbp == NULL) { putbq(q, bp); break; } xbp->rptr = bp->rptr; bp->rptr + = up->maxblock; xbp->wptr = bp->rptr; putbq(q, bp); bp = xbp; } /* * put new block in the block array. if something is already * there, it should be because we haven't gotten around to freeing * it yet. If not, complain. */ if (up->xb[up->WNX&07]) { urpfreeacked(up); if (up->xb[up->WNX&07]) { uprint(up, "urpfillwindow: overlap"); freeb(up->xb[up->WNX&07]); } q = up->wq; for(bp = getq(q); bp && up->xb[up->nxb]==0; up->nxb = NEXT(up->nxb)){ if(BLEN(bp) > up->maxblock){ nbp = up->xb[up->nxb] = allocb(0); nbp->rptr = bp->rptr; nbp->wptr = bp->rptr = bp->rptr + up->maxblock; } else { up->xb[up->nxb] = bp; bp = getq(q); } up->xb[up->WNX&07] = bp; up->WNX++; urpxmit(q, bp, up->WNX-1); } if(bp) putbq(q, bp); /* print("output w(%d) up->xb[%d](%ux) up->nxb(%d) up->state(%ux)\n", WINDOW(up), up->next, up->xb[up->next], up->nxb, up->state); /**/ /* * if a retransmit time has elapsed since a transmit, send an ENQ */ if(up->unechoed != up->next && NOW > up->timer){ print("sENQ\n"); up->timer = NOW + MSrexmit; up->state &= ~REJECTING; sendctl(up, ENQ); qunlock(&up->xmit); poperror(); return; } /* * if there's a window open, push some blocks out */ while(WINDOW(up)>0 && up->xb[up->next]!=0 && canqlock(&up->xl[up->next])){ if(up->xb[up->next]) sendblock(up, up->next); qunlock(&up->xl[up->next]); up->next = NEXT(up->next); } qunlock(&up->xmit); poperror(); } /* * Send out a message, with trailer. * send a control byte, put the byte at the end of the allocated * space in case a lower layer needs header room. */ void urpxmit(Queue *q, Block *bp, int seqno) static void sendctl(Urp *up, int ctl) { Urp *up = (Urp *)q->ptr; int size; Block *xbp; int debug; Block *bp; if (bp == NULL) { print("null bp in urpxmit\n"); if(up->wq->next->len > Streamhi) return; } debug = (q->flag&QDEBUG); size = bp->wptr - bp->rptr; seqno & = 07; /* send ptr to block, if non-empty */ if (size) { if ((xbp = allocb(0)) == NULL){ print("can't xmit\n"); return; } xbp->rptr = bp->rptr; xbp->wptr = bp->wptr; xbp->type = bp->type; PUTNEXT(q, xbp); } /* send trailer */ if ((xbp = allocb(3)) == NULL){ print("can't xmit2\n"); return; } xbp->type = M_RDATA; *xbp->wptr++ = (bp->class&S_DELIM) ? BOT: BOTM; *xbp->wptr++ = size; *xbp->wptr++ = size >> 8; PUTNEXT(q, xbp); putctl1(q->next, M_RDATA, SEQ + seqno); up->timer = DKPTIME; bp = allocb(1); bp->wptr = bp->lim; bp->rptr = bp->lim-1; *bp->rptr = ctl; bp->flags |= S_DELIM; PUTNEXT(up->wq, bp); } void urprexmit(Urp *up, Queue *q) /* * send a block. */ static void sendblock(Urp *up, int bn) { int i; Block *bp, *m, *nbp; int n; for (i = up->WACK; i<up->WNX; i++) { urpxmit(q, up->xb[i&07], i); urpstat.rxmit++; } up->state & = ~REXMIT; up->timer = NOW + MSrexmit; if(up->wq->next->len > Streamhi) return; /* * message 1, the BOT and the data */ bp = up->xb[bn]; m = allocb(1); m->rptr = m->lim - 1; m->wptr = m->lim; *m->rptr = (bp->flags & S_DELIM) ? BOT : BOTM; nbp = m->next = allocb(0); nbp->rptr = bp->rptr; nbp->wptr = bp->wptr; nbp->flags |= S_DELIM; PUTNEXT(up->wq, m); /* * message 2, the block length and the SEQ */ m = allocb(3); m->rptr = m->lim - 3; m->wptr = m->lim; n = BLEN(bp); m->rptr[0] = SEQ | bn; m->rptr[1] = n; m->rptr[2] = n<<8; m->flags |= S_DELIM; PUTNEXT(up->wq, m); } /* @@ 677,30 685,52 @@ rcvack(Urp *up, int msg) int seqno; int next; seqno = msg&07; next = (seqno+1) & 0x7 seqno = msg&Nmask; next = NEXT(seqno); lock(up); if(BETWEEN(seqno, up->WACK, up->WNX)) up->WACK = next; /* * release any acknowledged blocks */ if(IN(seqno, up->unacked, up->next)){ for(; up->unacked != next; up->unacked = NEXT(up->unacked)){ qlock(&up->xl[up->unacked]); if(up->xb[up->unacked]) freeb(up->xb[up->unacked]); up->xb[up->unacked] = 0; qunlock(&up->xl[up->unacked]); } } switch(msg & 0370){ case ECHO: up->timer = MSrexmit; /* push off ENQ timeout */ if(BETWEEN(seqno, up->WS, up->WNX)){ up->WS = next; wakeup(&up->r); if(IN(seqno, up->unechoed, up->next)) { up->unechoed = next; } /* * the next reject at the start of a window starts a * retransmission. */ up->state &= ~REJECTING; break; case REJ: if(IN(seqno, up->unechoed, up->next)) up->unechoed = next; /* * ... FALL THROUGH ... */ case ACK: if(up->WACK == next){ up->state |= REXMIT; wakeup(&up->r); /* * start a retransmission if we aren't retransmitting * and this is the start of a window. */ if(up->unechoed==next && !(up->state & REJECTING)){ up->state |= REJECTING; up->next = next; } break; } unlock(up); wakeup(&up->rq->r); } /* @@ 717,54 747,12 @@ flushinput(Urp *up) } /* * send a control character down stream */ static void sendctl(Queue *q, int x) { Block *bp; /* * send anything queued */ while(bp = getq(q)) PUTNEXT(q, bp); /* * send the new byte */ bp = allocb(1); *bp->wptr++ = x; PUTNEXT(q, bp); } /* * queue a control character to be sent down stream */ static void queuectl(Urp *up, int x) { Block *bp; Queue *q; q = up->wq; bp = allocb(1); *bp->wptr++ = x; putq(q, bp); wakeup(&up->r); } /* * initialize output */ static void initoutput(Urp *up, int window) { /* * ack any outstanding blocks */ if(up->WS<up->WNX) urprack(up, ECHO+((up->WNX-1)&07)); int i; /* * set output window @@ 774,21 762,33 @@ initoutput(Urp *up, int window) up->maxblock = 64; if(up->maxblock > Streamhi/4) up->maxblock = Streamhi/4; up->XW = 4; up->maxblock -= 4; up->maxout = 3; /* * set sequence varialbles */ up->WS = 1; up->WACK = 1; up->WNX = 1; up->unechoed = 1; up->unacked = 1; up->next = 1; up->nxb = 1; /* * free any outstanding blocks */ for(i = 0; i < 8; i++){ qlock(&up->xl[i]); if(up->xb[i]) freeb(up->xb[i]); qunlock(&up->xl[i]); } /* * tell the other side we've inited */ up->state |= ISOPENING; up->timer = MSrexmit; sendctl(q->next, INIT1); up->state |= INITING; up->timer = NOW + MSrexmit; sendctl(up, INIT1); } /* @@ 803,6 803,40 @@ initinput(Urp *up, int window) up->trx = 0; up->iseq = 0; up->lastecho = ECHO+0; up->WF = 1; flushinput(up); } /* * do retransmissions etc */ static int todo(void *arg) { Urp *up; up = (Urp *)arg; return (WINDOW(up)>0 && up->wq->len>0 && !(up->state&INITING)); } static void urpkproc(void *arg) { Urp *up; up = (Urp *)arg; for(;;){ if(up->state & (HUNGUP|CLOSING)){ if(isflushed(up)) wakeup(&up->r); if(up->state & HUNGUP) break; } if((up->lastecho&Nmask)!=up->iseq && up->rq->next->len<Streamhi) sendctl(up, up->lastecho = ECHO+up->iseq); output(up); tsleep(&up->rq->r, todo, up, MSrexmit/2); } DPRINT("urpkproc exiting %ux\n", up); up->kstarted = 0; up->state = 0; }
M power/dat.h => power/dat.h +3 -1
@@ 242,6 242,7 @@ struct Orig ulong mqid; ulong minca; /* base of region in chan */ ulong maxca; /* end of region in chan */ int nmod; }; struct Page @@ 439,7 440,8 @@ struct Stream { #define STREAMTYPE(x) ((x)&0x1f) #define STREAMID(x) (((x)&~CHDIR)>>5) #define STREAMQID(i,t) (((i)<<5)|(t)) #define PUTNEXT(q,b) (*(q)->next->put)((q)->next, bp) #define PUTNEXT(q,b) (*(q)->next->put)((q)->next, b) #define BLEN(b) ((b)->wptr - (b)->rptr) /* * stream file qid's & high water mark
M power/devhs.c => power/devhs.c +410 -75
@@ 8,17 8,54 @@ #include "io.h" typedef struct Hsvme Hsvme; typedef struct Device Device; enum { Maxtxburst= 1024, /* maximum transmit burst size */ Maxburst= 1023, /* maximum transmit burst size */ Vmevec= 0xd0, /* vme vector for interrupts */ Intlevel= 5, /* level to interrupt on */ Nhsvme= 1, }; struct hsvmestats { ulong parity; ulong rintr; ulong tintr; } hsvmestats; /* * hsvme datakit board */ struct Device { ushort version; ushort pad0x02; ushort vector; ushort pad0x06; ushort csr; ushort pad0x0A; ushort data; }; #define HSVME VMEA24SUP(Device, 0xF90000) struct Hsvme { QLock; QLock xmit; Device *addr; int vec; /* interupt vector */ Rendez r; /* output process */ Rendez kr; /* input kernel process */ int chan; /* current input channel */ Queue *rq; /* read queue */ uchar buf[1024]; /* bytes being collected */ uchar *wptr; /* pointer into buf */ int kstarted; /* true if kernel process started */ /* statistics */ ulong parity; /* parity errors */ ulong rintr; /* rcv interrupts */ ulong tintr; /* transmit interrupts */ ulong in; /* bytes in */ ulong out; /* bytes out */ }; Hsvme hsvme[Nhsvme]; #define ALIVE 0x0001 #define IENABLE 0x0004 @@ 42,21 79,30 @@ struct hsvmestats { #define TXEOD 0x0400 #define NND 0x8000 Rendez hsvmer; #define DELAY(n) { \ register int N = 12*(n); \ while (--N > 0); \ } static void hsvmeintr(int); static void hsvmekproc(void*); /* * hsvme stream module definition */ static void hsvmeoput(Queue*, Block*); static void hsvmestopen(Queue*, Stream*); static void hsvmestclose(Queue*); Qinfo hsvmeinfo = { nullput, hsvmeoput, hsvmestopen, hsvmestclose, "hsvme" }; /* * restart a VME board */ void hsvmerestart(struct hsvme *addr) hsvmerestart(Hsvme *hp) { Device *addr; addr = hp->addr; addr->csr = RESET; wbflush(); DELAY(20000); delay(20); /* * set interrupt vector @@ 64,29 110,32 @@ hsvmerestart(struct hsvme *addr) * set forcew to a known value * interrupt on level `Intlevel' */ addr->vector = 0xd0; addr->vector = hp->vec; addr->csr = NORESET|IPL(Intlevel)|IENABLE|ALIVE; wbflush(); DELAY(500); delay(1); addr->csr = NORESET|IPL(Intlevel)|FORCEW|IENABLE|ALIVE; wbflush(); DELAY(500); delay(1); } /* * reset all vme boards */ void hsvmereset(void) { struct hsvme *addr; addr = HSVME; addr->csr = RESET; int i; Hsvme *hp; for(i=0; i<Nhsvme; i++){ hsvme[i].addr = HSVME+i; hsvme[i].vec = Vmevec+i; hsvme[i].addr->csr = RESET; setvmevec(hsvme[i].vec, hsvmeintr); } wbflush(); DELAY(20000); /* * routine to call on interrupt */ setvmevec(Vmevec, hsvmeintr); delay(20); } void @@ 95,23 144,26 @@ hsvmeinit(void) } /* * enable the device for interrupts * enable the device for interrupts, spec is the device number */ static int never(void *arg) { return 0; } Chan* hsvmeattach(char *spec) { struct hsvme *addr; addr = HSVME; hsvmerestart(addr); print("hsvme csr %ux\n", addr->csr); return devattach('h', spec); Hsvme *hp; int i; Chan *c; i = strtoul(spec, 0, 0); if(i >= Nhsvme) error(0, Ebadarg); hp = &hsvme[i]; hsvmerestart(hp); print("hsvme [%d] csr %ux\n", i, hp->addr->csr); c = devattach('h', spec); c->dev = i; c->qid = CHDIR; return c; } Chan* @@ 123,25 175,23 @@ hsvmeclone(Chan *c, Chan *nc) int hsvmewalk(Chan *c, char *name) { if(c->qid != CHDIR) return 0; if(strcmp(name, "hsvme") == 0){ c->qid = 1; return 1; } return 0; return devwalk(c, name, 0, 0, streamgen); } void hsvmestat(Chan *c, char *dp) { print("hsvmestat\n"); error(0, Egreg); devstat(c, dp, 0, 0, streamgen); } Chan* hsvmeopen(Chan *c, int omode) { if(c->qid == CHDIR){ if(omode != OREAD) error(0, Eperm); }else streamopen(c, &hsvmeinfo); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; @@ 157,20 207,20 @@ hsvmecreate(Chan *c, char *name, int omode, ulong perm) void hsvmeclose(Chan *c) { if(c->qid != CHDIR) streamclose(c); } long hsvmeread(Chan *c, void *buf, long n) { error(0, Egreg); return 0; return streamread(c, buf, n); } long hsvmewrite(Chan *c, void *buf, long n) { error(0, Egreg); return 0; return streamwrite(c, buf, n, 0); } void @@ 197,31 247,316 @@ hsvmeerrstr(Error *e, char *buf) rooterrstr(e, buf); } /* * the stream routines */ /* * create the kernel process for input */ static void hsvmestopen(Queue *q, Stream *s) { Hsvme *hp; char name[32]; hp = &hsvme[s->dev]; sprint(name, "**hsvme%d**", s->dev); q->ptr = q->other->ptr = hp; hp->rq = q; kproc(name, hsvmekproc, hp); } /* * kill off the kernel process */ static int kdead(void *arg) { Hsvme *hp; hp = (Hsvme *)arg; return hp->kstarted == 0; } static void hsvmeintr(int vec) hsvmestclose(Queue * q) { ushort csr; struct hsvme *addr; Hsvme *hp; hp = (Hsvme *)q->ptr; qlock(hp); hp->rq = 0; qunlock(hp); wakeup(&hp->kr); sleep(&hp->r, kdead, hp); } print("hsvme intr\n"); addr = HSVME; wbflush(); csr = addr->csr; do { if (addr->csr & REF) { hsvmestats.rintr++; print("hsvme rintr\n"); /* * free all blocks of a message in `q', `bp' is the first block * of the message */ static void freemsg(Queue *q, Block *bp) { for(; bp; bp = getq(q)){ if(bp->flags & S_DELIM){ freeb(bp); return; } if (addr->csr & XHF) { hsvmestats.tintr++; print("hsvme tintr\n"); freeb(bp); } } /* * return true if the output fifo is at least half empty. * the implication is that it can take at least another 1000 byte burst. */ static int halfempty(void *arg) { Device *addr; addr = (Device*)arg; return addr->csr & XHF; } /* * output a block * * the first 2 bytes of every message are the channel number, * low order byte first. the third is a possible trailing control * character. */ void hsvmeoput(Queue *q, Block *bp) { Device *addr; Hsvme *hp; int burst; int chan; int ctl; int n; if(bp->type != M_DATA){ freeb(bp); return; } /* * get a whole message before handing bytes to the device */ if(!putq(q, bp)) return; /* * one transmitter at a time */ hp = (Hsvme *)q->ptr; qlock(&hp->xmit); addr = hp->addr; /* * parse message */ bp = getq(q); if(bp->wptr - bp->rptr < 3){ freemsg(q, bp); qunlock(&hp->xmit); return; } chan = CHNO | *bp->rptr++ | (*bp->rptr++<<8); ctl = *bp->rptr++; /* * send the 8 bit data, burst are up to Maxburst (9-bit) bytes long */ if(!(addr->csr & XHF)) sleep(&hp->r, halfempty, addr); /* print("->%.2uo\n", CHNO|chan);/**/ addr->data = CHNO|chan; burst = Maxburst; while(bp){ if(burst == 0){ addr->data = TXEOD; /* print("->%.2uo\n", TXEOD); /**/ if(!(addr->csr & XHF)) sleep(&hp->r, halfempty, addr); /* print("->%.2uo\n", CHNO|chan); /**/ addr->data = CHNO|chan; burst = Maxburst; } if ((csr^XFF) & (XFF|EROFLOW|EFRAME|EPARITY|EXOFLOW)) { hsvmestats.parity++; hsvmerestart(addr); print("hsvme %ux: reset, csr = 0x%x\n", HSVME, csr); n = bp->wptr - bp->rptr; if(n > burst) n = burst; burst -= n; while(n--){ /* print("->%.2uo\n", *bp->rptr); /**/ addr->data = *bp->rptr++; } wbflush(); } while ((csr = addr->csr) & REF); if(bp->rptr >= bp->wptr){ if(bp->flags & S_DELIM){ freeb(bp); break; } freeb(bp); bp = getq(q); } } /* * send the control byte if there is one */ if(ctl){ /* print("->%.2uo\n", CTL|ctl); /**/ addr->data = CTL|ctl; } /* * start the fifo emptying */ /* print("->%.2uo\n", TXEOD); /**/ addr->data = TXEOD; qunlock(&hp->xmit); } /* * return true if the input fifo is non-empty */ static int notempty(void *arg) { Device *addr; addr = (Device *)arg; return addr->csr & REF; } /* * fill a block with what is currently buffered and send it upstream */ static void upstream(Hsvme *hp, unsigned int ctl) { int n; Block *bp; n = hp->wptr - hp->buf; bp = allocb(3 + n); bp->wptr[0] = hp->chan; bp->wptr[1] = hp->chan>>8; bp->wptr[2] = ctl; if(n) memcpy(&bp->wptr[3], hp->buf, n); bp->wptr += 3 + n; bp->flags |= S_DELIM; PUTNEXT(hp->rq, bp); hp->wptr = hp->buf; } /* * Read bytes from the input fifo. Since we take an interrupt every * time the fifo goes non-empty, we need to waste time to let the * fifo fill up. */ static void hsvmekproc(void *arg) { Hsvme *hp; Device *addr; unsigned int c; hp = (Hsvme *)arg; addr = hp->addr; hp->kstarted = 1; hp->wptr = hp->buf; for(;;){ /* * die if the device is closed */ qlock(hp); if(hp->rq == 0){ qunlock(hp); hp->kstarted = 0; wakeup(&hp->r); return; } /* * let the fifo fill a bit */ delay(1); /* * 0xFFFF means an empty fifo */ while ((c = addr->data) != 0xFFFF) { /* print(" %.2uo<-\n", c); /**/ if(c & CHNO){ c &= 0x1FF; if(hp->chan == c) continue; /* * new channel, put anything saved upstream */ if(hp->wptr - hp->buf != 0) upstream(hp, 0); hp->chan = c; } else if(c & NND){ /* * ctl byte, this ends a message */ upstream(hp, c); } else { /* * data byte, put in local buffer */ *hp->wptr++ = c; if(hp->wptr == &hp->buf[sizeof hp->buf]) upstream(hp, 0); } } qunlock(hp); /* * sleep if input fifo empty */ if(!notempty(addr)) sleep(&hp->kr, notempty, addr); } } /* * only one flavor interrupt. we have to use the less than half full * and not empty bits to figure out whom to wake. */ static void hsvmeintr(int vec) { ushort csr; Device *addr; Hsvme *hp; hp = &hsvme[vec - Vmevec]; if(hp < hsvme || hp > &hsvme[Nhsvme]){ print("bad hsvme vec\n"); return; } csr = hp->addr->csr; if (csr & REF) { hp->rintr++; wakeup(&hp->kr); } if (csr & XHF) { hp->tintr++; wakeup(&hp->r); } if ((csr^XFF) & (XFF|EROFLOW|EFRAME|EPARITY|EXOFLOW)) { hp->parity++; hsvmerestart(hp); print("hsvme %d: reset, csr = 0x%ux\n", HSVME, csr); } }
M power/errno.h => power/errno.h +6 -1
@@ 36,10 36,15 @@ enum{ Etoosmall, /* read or write too small */ Ehungup, /* write to hungup stream */ Ebadnet, /* illegal network address */ Enoifc, /* no free nonet interface slots */ Enoifc, /* no free interface slots */ Enodev, /* no free devices */ Ebadctl, /* bad process control request */ Enonote, /* note overflow */ Eintr, /* interrupted */ Edestbusy, /* datakit destination busy */ Enetbusy, /* datakit controller busy */ Edestotl, /* datakit destination out to lunch */ Enetotl, /* datakit controller out to lunch */ Erejected, /* datakit destination rejected call */ Egreg, /* it's all greg's fault */ };
M power/fns.h => power/fns.h +4 -1
@@ 59,6 59,7 @@ void freepte(Orig*); void freesegs(int); void freealarm(Alarm*); Block *getb(Blist*); int getfields(char*, char**, int, char); Block *getq(Queue*); void gettlb(int, ulong*); ulong gettlbvirt(int); @@ 110,6 111,7 @@ void pgrpcpy(Pgrp*, Pgrp*); void pgrpinit(void); int postnote(Proc*, int, char*, int); int pprint(char*, ...); Block *prepend(Block*, int); void prflush(void); void printinit(void); void printslave(void); @@ 121,6 123,7 @@ void putmmu(ulong, ulong); void puttlb(ulong, ulong); void puttlbx(int, ulong, ulong); int putb(Blist*, Block*); void putbq(Blist*, Block*); int putq(Queue*, Block*); void putstrn(char*, long); ulong pwait(Waitmsg*); @@ 149,7 152,7 @@ Devgen streamgen; void streamclose(Chan*); void streaminit(void); long streamread(Chan*, void*, long); long streamwrite(Chan*, void*, long); long streamwrite(Chan*, void*, long, int); Stream* streamnew(Chan*, Qinfo*); void streamopen(Chan*, Qinfo*); int streamparse(char*, Block*);
M power/main.c => power/main.c +1 -1