From 2024b222b51463500b3f1e7c046cc36e28a4aadf Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sat, 10 Mar 1990 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1990-03-10 --- gnot/boot.c | 47 +++ gnot/boot.h | 994 +++++++++++++++++++++++++++++++++++++++++++++++++ gnot/chan.c | 601 ++++++++++++++++++++++++++++++ gnot/clock.c | 123 ++++++ gnot/dat.h | 527 ++++++++++++++++++++++++++ gnot/dev.c | 198 ++++++++++ gnot/devcons.c | 520 ++++++++++++++++++++++++++ gnot/devdup.c | 130 +++++++ gnot/devenv.c | 558 +++++++++++++++++++++++++++ gnot/devmnt.c | 645 ++++++++++++++++++++++++++++++++ gnot/devpipe.c | 218 +++++++++++ gnot/devproc.c | 387 +++++++++++++++++++ gnot/devroot.c | 140 +++++++ gnot/devsrv.c | 203 ++++++++++ gnot/errno.h | 45 +++ gnot/fault.c | 320 ++++++++++++++++ gnot/fcall.c | 379 +++++++++++++++++++ gnot/fcall.h | 89 +++++ gnot/fns.h | 141 +++++++ gnot/io.h | 5 + gnot/l.s | 265 +++++++++++++ gnot/lib.h | 109 ++++++ gnot/lock.c | 86 +++++ gnot/main.c | 235 ++++++++++++ gnot/mem.h | 91 +++++ gnot/mmu.c | 48 +++ gnot/page.c | 638 +++++++++++++++++++++++++++++++ gnot/pgrp.c | 191 ++++++++++ gnot/print.c | 287 ++++++++++++++ gnot/proc.c | 525 ++++++++++++++++++++++++++ gnot/screen.c | 176 +++++++++ gnot/stream.c | 889 +++++++++++++++++++++++++++++++++++++++++++ gnot/sysfile.c | 508 +++++++++++++++++++++++++ gnot/sysproc.c | 516 +++++++++++++++++++++++++ gnot/trap.c | 303 +++++++++++++++ gnot/u.h | 15 + gnot/ureg.h | 23 ++ gnot/vec.s | 268 +++++++++++++ port/devcons.c | 6 +- port/devmnt.c | 1 + port/proc.c | 28 +- power/dat.h | 2 +- power/trap.c | 4 +- 43 files changed, 11463 insertions(+), 21 deletions(-) create mode 100644 gnot/boot.c create mode 100644 gnot/boot.h create mode 100644 gnot/chan.c create mode 100644 gnot/clock.c create mode 100644 gnot/dat.h create mode 100644 gnot/dev.c create mode 100644 gnot/devcons.c create mode 100644 gnot/devdup.c create mode 100644 gnot/devenv.c create mode 100644 gnot/devmnt.c create mode 100644 gnot/devpipe.c create mode 100644 gnot/devproc.c create mode 100644 gnot/devroot.c create mode 100644 gnot/devsrv.c create mode 100644 gnot/errno.h create mode 100644 gnot/fault.c create mode 100644 gnot/fcall.c create mode 100644 gnot/fcall.h create mode 100644 gnot/fns.h create mode 100644 gnot/io.h create mode 100644 gnot/l.s create mode 100644 gnot/lib.h create mode 100644 gnot/lock.c create mode 100644 gnot/main.c create mode 100644 gnot/mem.h create mode 100644 gnot/mmu.c create mode 100644 gnot/page.c create mode 100644 gnot/pgrp.c create mode 100644 gnot/print.c create mode 100644 gnot/proc.c create mode 100644 gnot/screen.c create mode 100644 gnot/stream.c create mode 100644 gnot/sysfile.c create mode 100644 gnot/sysproc.c create mode 100644 gnot/trap.c create mode 100644 gnot/u.h create mode 100644 gnot/ureg.h create mode 100644 gnot/vec.s diff --git a/gnot/boot.c b/gnot/boot.c new file mode 100644 index 0000000000000000000000000000000000000000..2fda2656e0ef20877e0b2eb57121cfdef497f4f5 --- /dev/null +++ b/gnot/boot.c @@ -0,0 +1,47 @@ +#include +#include + +#include "fcall.h" + +Fcall hdr; +char buf[100]; + +void error(char *); + +main(int argc, char *argv[]) +{ + int cfd, fd, n, fu, f; + char buf[NAMELEN]; + int p[2]; + + open("#c/cons", OREAD); + open("#c/cons", OWRITE); + open("#c/cons", OWRITE); + + do{ + print("user: "); + n = read(0, buf, sizeof buf); + }while(n==0 || n==1); + if(n < 0) + error("can't read #c/cons; please reboot"); + buf[n-1] = 0; + print("hello %s!\n", buf); + if(pipe(p) == -1) + error("pipe"); + if(write(p[1], "hohoHO!", 8) != 8) + error("write"); + if(read(p[0], buf, 8) != 8) + error("read"); + print("%s\n", buf); + for(;;); +} + +void +error(char *s) +{ + char buf[64]; + + errstr(0, buf); + fprint(2, "boot: %s: %s\n", s, buf); + exits(0); +} diff --git a/gnot/boot.h b/gnot/boot.h new file mode 100644 index 0000000000000000000000000000000000000000..1326e57631e31850a05715f567f5c38a1bfc5122 --- /dev/null +++ b/gnot/boot.h @@ -0,0 +1,994 @@ +ulong bootcode[]={ + 0x00000107, + 0x00000d9c, + 0x000001bc, + 0x00000130, + 0x00000000, + 0x00002020, + 0x00000000, + 0x00000000, + 0x2f012f00, + 0x2c7c0000, + 0xbffe610c, + 0x2f006100, + 0x01604fef, + 0x000c4e75, + 0x4fefffc8, + 0x42a7486e, + 0x81126100, + 0x0d664878, + 0x0001486e, + 0x811a6100, + 0x0d5a4878, + 0x0001486e, + 0x81226100, + 0x0d4e486e, + 0x812a6100, + 0x017a4878, + 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, + 0x588f4878, + 0x0008486f, + 0x003c2f2f, + 0x00386100, + 0x0cc07208, + 0xb2806708, + 0x486e8171, + 0x6110588f, + 0x486f0044, + 0x486e8176, + 0x610000d4, + 0x60fe4fef, + 0xffc04857, + 0x42a76100, + 0x0c8c486f, + 0x00082f2f, + 0x0050486e, + 0x817a4878, + 0x00026100, + 0x011a42a7, + 0x61744fef, + 0x005c4e75, + 0x598f4281, + 0x7021b081, + 0x6f1e4ab6, + 0x1d2081be, + 0x660e2daf, + 0x00081d20, + 0x81be7001, + 0x588f4e75, + 0x52817021, + 0xb0816ee2, + 0x4280588f, + 0x4e75598f, + 0x206f0008, + 0x42827021, + 0xb0826f18, + 0x20362d20, + 0x81beb088, + 0x660642b6, + 0x2d2081be, + 0x52827021, + 0xb0826ee8, + 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, + 0x41ef0010, + 0x58882f08, + 0x2f2f0014, + 0x48691000, + 0x2f096174, + 0x2d6f0010, + 0x801290af, + 0x001c4fef, + 0x00184e75, + 0x142f0007, + 0xc43c007f, + 0x100249c0, + 0x4a360920, + 0x8092661e, + 0x701eb0ae, + 0x80166e04, + 0x70014e75, + 0x202e8016, + 0x120249c1, + 0x1d801920, + 0x809252ae, + 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, + 0x19208092, + 0x49c02076, + 0x0d20801a, + 0x4e90226f, + 0x00382a2f, + 0x0024282f, + 0x00282400, + 0x6c164482, + 0x85af0020, + 0x141949c2, + 0x20022f49, + 0x00384fef, + 0x001060a8, + 0x202f003c, + 0xd0822f40, + 0x003c4fef, + 0x00106000, + 0xfef21019, + 0x49c02400, + 0x2f490028, + 0x7030b082, + 0x6e867039, + 0xb0826d80, + 0x4a856c02, + 0x42852005, + 0x2205d281, + 0xd281d081, + 0xd080d082, + 0x90bc0000, + 0x00302a00, + 0x101949c0, + 0x24002f49, + 0x002860cc, + 0x20042204, + 0xd281d281, + 0xd081d080, + 0xd08290bc, + 0x00000030, + 0x28001019, + 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, + 0x4c450001, + 0x2600b0fc, + 0x00006d08, + 0x701e9088, + 0xb0826f04, + 0x4a836fbc, + 0x53826094, + 0x44837c01, + 0x60882611, + 0x70042f40, + 0x000c4a83, + 0x6c044483, + 0x7c01422f, + 0x0039741c, + 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, + 0x26117004, + 0x2f40000c, + 0x6000fefa, + 0x26117004, + 0x2f40000c, + 0x6000feee, + 0x26113403, + 0x360248c3, + 0x70042f40, + 0x000c6000, + 0xfedc2611, + 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, + 0x49c02400, + 0x66da4a84, + 0x6c1e2404, + 0x4482b282, + 0x6c16b1c9, + 0x640810fc, + 0x00202d48, + 0x800652ae, + 0x80125281, + 0xb2826dea, + 0x4fef000c, + 0x4e757009, + 0xb08266c8, + 0x7007d0ae, + 0x8012c0bc, + 0xfffffff8, + 0x2d408012, + 0x60b64878, + 0xffff42a7, + 0x486e818a, + 0x6100ff3c, + 0x42804fef, + 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, + 0x70044fef, + 0x000c4e75, + 0x70fc4e75, + 0x48780010, + 0x2f2f0014, + 0x2f2f0014, + 0x2f2f0014, + 0x2f2f0014, + 0x6100fd1e, + 0x4fef0014, + 0x4e75202e, + 0x8006b0ae, + 0x8002640c, + 0x1dbc0025, + 0x01618006, + 0x52ae8006, + 0x42804e75, + 0x4fefff80, + 0x2e2f0090, + 0x42af000c, + 0xf22f543a, + 0x0084f293, + 0x0016f22f, + 0x54000084, + 0xf200001a, + 0xf22f7400, + 0x008452af, + 0x000c42af, + 0x001cf23c, + 0x40000000, + 0x0000f200, + 0x0100f22f, + 0x543a0084, + 0xf28100ee, + 0x486f001c, + 0xf22f5400, + 0x0088f227, + 0x74006100, + 0x0412f22f, + 0x40000028, + 0xf23c5423, + 0x3fd34413, + 0x55475a32, + 0xf22f6000, + 0x0028202f, + 0x0028e280, + 0x2f400024, + 0x44802f00, + 0x6100053a, + 0xf22f5423, + 0x0094f22f, + 0x74000030, + 0x202f0028, + 0x90af002c, + 0x2f006100, + 0x05202e2f, + 0x00a4f22f, + 0x54230034, + 0xf2000100, + 0xf23c4000, + 0x00000001, + 0xf2000838, + 0xf2950034, + 0x53af0030, + 0x202f002c, + 0x90af0030, + 0x2f006100, + 0x04f02e2f, + 0x00a8f22f, + 0x54230038, + 0xf2000100, + 0xf23c4000, + 0x00000001, + 0xf2000838, + 0x588ff292, + 0xffd0f23c, + 0x40000000, + 0x000af200, + 0x08384fef, + 0x0014f292, + 0x003452af, + 0x001c202f, + 0x001890af, + 0x001c2f00, + 0x610004aa, + 0x2e2f0094, + 0xf22f5423, + 0x0024f200, + 0x0100f23c, + 0x40000000, + 0x000af200, + 0x0838588f, + 0xf295ffd0, + 0x4a876c02, + 0x7e087067, + 0xb0af0098, + 0x66064a87, + 0x6e0002ac, + 0x701eb087, + 0x6c027e1e, + 0x7402d487, + 0x2f470090, + 0x7066b0af, + 0x00986616, + 0x202f001c, + 0xd4806e0e, + 0x7401f23c, + 0x40000000, + 0x0000f200, + 0x01007020, + 0xb0826e18, + 0x7065b0af, + 0x00986606, + 0x7eff2f47, + 0x00907065, + 0x2f400098, + 0x6000fe9c, + 0x4284b882, + 0x6c3cf203, + 0x6100f203, + 0x4000f200, + 0x0838f295, + 0x00045383, + 0xf2034000, + 0xf2000128, + 0x7030d083, + 0x22041f80, + 0x49200059, + 0xf2000880, + 0xf23c4123, + 0x0000000a, + 0xf2000800, + 0x5284b882, + 0x6dc47605, + 0x70ffd082, + 0x24004a82, + 0x6d382002, + 0x41f72920, + 0x00591010, + 0x49c0d083, + 0x10804283, + 0x0c370039, + 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, + 0x00305282, + 0x1fbc0030, + 0x29200030, + 0x52825383, + 0x4a836ede, + 0x4a846f28, + 0x2003d084, + 0xb086660a, + 0x1fbc002e, + 0x29200030, + 0x52822202, + 0x1fb75920, + 0x00582920, + 0x00305282, + 0x52855384, + 0x4a846ed8, + 0x7067b0af, + 0x00986700, + 0x00c27068, + 0xb0af0098, + 0x670000b8, + 0x7065b0af, + 0x00986726, + 0x7067b0af, + 0x0098671e, + 0x42372920, + 0x00304878, + 0xffff2f2f, + 0x0090486f, + 0x00386100, + 0xfb5e7008, + 0x4fef008c, + 0x4e751fbc, + 0x00652920, + 0x00305282, + 0x1fbc002b, + 0x29200030, + 0x5282262f, + 0x001c6c0a, + 0x1fbc002d, + 0x2920002f, + 0x44837064, + 0xb0836e26, + 0x20034c7c, + 0x08010000, + 0x0064d0bc, + 0x00000030, + 0x22021f80, + 0x29200030, + 0x52822003, + 0x4c7c0801, + 0x00000064, + 0x26012003, + 0x4c7c0801, + 0x0000000a, + 0xd0bc0000, + 0x00302202, + 0x1f802920, + 0x00305282, + 0x20034c7c, + 0x08010000, + 0x000a2001, + 0xd0bc0000, + 0x00301f80, + 0x29200030, + 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, + 0x2f2f0014, + 0x2f2f0014, + 0x2f2f0014, + 0xf2375400, + 0x01610014, + 0xf2277400, + 0x6100fbee, + 0x4fef0018, + 0x4e754878, + 0x00662f2f, + 0x00142f2f, + 0x00142f2f, + 0x0014f237, + 0x54000161, + 0x0014f227, + 0x74006100, + 0xfbc84fef, + 0x00184e75, + 0x48780067, + 0x2f2f0014, + 0x2f2f0014, + 0x2f2f0014, + 0xf2375400, + 0x01610014, + 0xf2277400, + 0x6100fba2, + 0x4fef0018, + 0x4e75518f, + 0xf22f5500, + 0x000c206f, + 0x0014f200, + 0x083af28e, + 0x00104290, + 0xf23c4000, + 0x00000000, + 0x508f4e75, + 0xf2177500, + 0x20177214, + 0xe2a0c0bc, + 0x000007ff, + 0x90bc0000, + 0x03fe2080, + 0x0297800f, + 0xffff0097, + 0x3fe00000, + 0xf2175400, + 0x508f4e75, + 0x518ff22f, + 0x5500000c, + 0x242f0014, + 0xf200083a, + 0xf28e000e, + 0xf23c4000, + 0x00000000, + 0x508f4e75, + 0xf2177500, + 0x20177214, + 0xe2a0c0bc, + 0x000007ff, + 0xd4806e0c, + 0xf23c4000, + 0x00000000, + 0x508f4e75, + 0x0c820000, + 0x07ff6d0c, + 0x70222d40, + 0x800a243c, + 0x000007ff, + 0x0297800f, + 0xffff2002, + 0x7214e3a0, + 0x8197f217, + 0x5400508f, + 0x4e754fef, + 0xfff4206f, + 0x0018f22f, + 0x55000010, + 0xf23c4000, + 0x00000001, + 0xf2000838, + 0xf2950018, + 0xf23c4000, + 0x00000000, + 0xf2107400, + 0xf2000800, + 0x4fef000c, + 0x4e75f22f, + 0x75000004, + 0x242f0004, + 0x7214e2a2, + 0xc4bc0000, + 0x07ff94bc, + 0x000003fe, + 0x7015b082, + 0x6d2c203c, + 0x001fffff, + 0xe4a04680, + 0xc1af0004, + 0x42af0008, + 0xf22f5400, + 0x0004f210, + 0x7400f200, + 0x0800f22f, + 0x54280004, + 0x4fef000c, + 0x4e757035, + 0xb0826de0, + 0x72ead282, + 0x203c7fff, + 0xffffe2a0, + 0x4680c1af, + 0x000860cc, + 0xf22f4012, + 0x00044e75, + 0x70154e40, + 0x4e757008, + 0x4e404e75, + 0x70064e40, + 0x4e75700e, + 0x4e404e75, + 0x700f4e40, + 0x4e757014, + 0x4e404e75, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000000d, + 0x000026f6, + 0x0000270c, + 0x00002732, + 0x00002750, + 0x00002754, + 0x00002764, + 0x00002782, + 0x0000279c, + 0x000027a0, + 0x000027be, + 0x00002bcc, + 0x00002bf2, + 0x00002c18, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00090000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000001, + 0x020a0b0c, + 0x03000000, + 0x04000005, + 0x00000006, + 0x00070000, + 0x08000000, + 0x00000000, + 0x23632f63, + 0x6f6e7300, + 0x23632f63, + 0x6f6e7300, + 0x23632f63, + 0x6f6e7300, + 0x75736572, + 0x3a200063, + 0x616e2774, + 0x20726561, + 0x64202363, + 0x2f636f6e, + 0x733b2070, + 0x6c656173, + 0x65207265, + 0x626f6f74, + 0x0068656c, + 0x6c6f2025, + 0x73210a00, + 0x70697065, + 0x00686f68, + 0x6f484f21, + 0x00777269, + 0x74650072, + 0x65616400, + 0x25730a00, + 0x626f6f74, + 0x3a202573, + 0x3a202573, + 0x0a000000, + 0x2a2a2a00, + 0x00000000, + 0x01280116, + 0x00e0010a, + 0x00fe00ec, + 0x00e000e0, + 0x00840000, + 0x6e6f6e2d, + 0x7a65726f, + 0x20657869, + 0x74207374, + 0x61747573, + 0x00000000, + 0x0000f78, + 0x, +}; diff --git a/gnot/chan.c b/gnot/chan.c new file mode 100644 index 0000000000000000000000000000000000000000..1eacc10f0daa22f76b90e395e3ac3696864ffaf9 --- /dev/null +++ b/gnot/chan.c @@ -0,0 +1,601 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + + +struct{ + Lock; + Chan *free; +}chanalloc; + +int +incref(Ref *r) +{ + lock(r); + r->ref++; + unlock(r); + return r->ref; +} + +int +decref(Ref *r) +{ + lock(r); + r->ref--; + unlock(r); + return r->ref; +} + +void +chaninit(void) +{ + int i; + Chan *c; + + chanalloc.free = ialloc(conf.nchan*sizeof(Chan), 0); + + c = chanalloc.free; + for(i=0; ifid = i; + c->next = c+1; + } + c->next = 0; +} + +void +chandevreset(void) +{ + int i; + + for(i=0; inext; + c->flag = 0; + c->ref = 1; + unlock(&chanalloc); + c->offset = 0; + c->mnt = 0; + c->stream = 0; + c->mchan = 0; + c->mqid = 0; + return c; + } + unlock(&chanalloc); + print("no chans\n"); + if(u == 0) + panic("newchan"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +void +close(Chan *c) +{ + if(decref(c) == 0){ + if(!waserror()){ + (*devtab[c->type].close)(c); + poperror(); + } + lock(&chanalloc); + c->next = chanalloc.free; + chanalloc.free = c; + unlock(&chanalloc); + } +} + +int +eqchan(Chan *a, Chan *b, long qmask) +{ + if((a->qid^b->qid) & qmask) + return 0; + if(a->type != b->type) + return 0; + if(a->dev != b->dev) + return 0; + return 1; +} + +/* + * omnt is locked. return with nmnt locked. + */ +Mount* +mountsplit(Mount *omnt) +{ + Mount *nmnt; + + print("mount copy on write\n"); + nmnt = newmount(); + lock(nmnt); + nmnt->term = omnt->term; + nmnt->mountid = omnt->mountid; + nmnt->next = omnt->next; + if(nmnt->next) + incref(nmnt); + nmnt->c = omnt->c; + incref(nmnt->c); + omnt->ref--; + unlock(omnt); + return nmnt; +} + +int +mount(Chan *new, Chan *old, int flag) +{ + int i; + Mtab *mt, *mz; + Mount *mnt, *omnt, *nmnt, *pmnt; + Pgrp *pg; + int isnew; + + if(CHDIR & (old->qid^new->qid)) + error(0, Emount); + if((old->qid&CHDIR)==0 && (flag&MORDER)!=MREPL) + error(0, Emount); + + mz = 0; + isnew = 0; + pg = u->p->pgrp; + lock(pg); + if(waserror()){ + unlock(pg); + nexterror(); + } + /* + * Is old already in mount table? + */ + mt = pg->mtab; + for(i=0; inmtab; i++,mt++){ + if(mt->c==0 && mz==0) + mz = mt; + else if(eqchan(mt->c, old, CHDIR|QPATH)) + goto Found; + } + isnew = 1; + if(mz == 0){ + if(i == conf.nmtab) + error(0, Enomount); + mz = &pg->mtab[i]; + pg->nmtab++; + } + mz->mnt = 0; + mz->c = old; + mt = mz; + + Found: + new->flag = CMOUNT; + if(flag & MCREATE) + new->flag |= CCREATE; + mnt = newmount(); + mnt->c = new; + + switch(flag & MORDER){ + /* + * These two always go at head of list + */ + case MBEFORE: + if(mt->mnt == 0) + error(0, Enotunion); + /* fall through */ + + case MREPL: + omnt = mt->mnt; + if(omnt) + incref(omnt); + mnt->next = omnt; + mt->mnt = mnt; + mnt->term = 1; + if((flag&MORDER) == MBEFORE) + mnt->term = 0; + break; + + /* + * This one never goes at head of list + */ + case MAFTER: + if(mt->mnt == 0) + error(0, Enotunion); + omnt = mt->mnt; + pmnt = 0; + while(!omnt->term){ + lock(omnt); + if(omnt->ref > 1){ + omnt = mountsplit(omnt); + if(pmnt) + pmnt->next = omnt; + else + mt->mnt = omnt; + } + unlock(omnt); + nmnt = omnt->next; + if(nmnt == 0) + panic("MAFTER term"); + pmnt = omnt; + omnt = nmnt; + } + mnt->next = omnt->next; + omnt->next = mnt; + mnt->term = 1; + omnt->term = 0; + break; + } + + incref(new); + if(isnew) + incref(old); + unlock(pg); + poperror(); + return mnt->mountid; +} + +Chan* +clone(Chan *c, Chan *nc) +{ + return (*devtab[c->type].clone)(c, nc); +} + +Chan* +domount(Chan *c) +{ + int i; + ulong mntid; + Mtab *mt; + Mount *mnt; + Pgrp *pg; + Chan *nc, *mc; + + pg = u->p->pgrp; + /* + * Is c in in mount table? + */ + mt = pg->mtab; + for(i=0; inmtab; i++,mt++) + if(mt->c && eqchan(mt->c, c, CHDIR|QPATH)) + goto Found; + /* + * No; c is unaffected + */ + return c; + + /* + * Yes; move c through table + */ + Found: + lock(pg); + if(!eqchan(mt->c, c, CHDIR|QPATH)){ /* table changed underfoot */ + print("domount: changed underfoot?\n"); + unlock(pg); + return c; + } + mnt = mt->mnt; + mntid = mnt->mountid; + mc = mnt->c; + incref(mc); + unlock(pg); + if(waserror()){ + close(mc); + nexterror(); + } + nc = clone(mc, 0); + close(mc); + poperror(); + close(c); + nc->mnt = mnt; + nc->mountid = mntid; + return nc; +} + +Chan* +walk(Chan *ac, char *name, int domnt) +{ + Mount *mnt; + int first = 1; + Chan *c = ac; + Chan *nc, *mc; + Pgrp *pg = u->p->pgrp; + + /* + * name may be empty if the file name is "/", "#c" etc. + */ + Again: + if(name[0] && (*devtab[c->type].walk)(c, name)==0){ + if(!(c->flag&CMOUNT)) + goto Notfound; + mnt = c->mnt; + if(mnt == 0) + panic("walk"); + lock(pg); + if(mnt->term){ + unlock(pg); + goto Notfound; + } + if(c->mountid != mnt->mountid){ + print("walk: changed underfoot?\n"); + unlock(pg); + goto Notfound; + } + mnt = mnt->next; + mc = mnt->c; + incref(mc); + unlock(pg); + if(waserror()){ + close(mc); + nexterror(); + } + if(mnt == 0) + panic("walk 1"); + nc = clone(mc, 0); + close(mc); + poperror(); + if(!first) + close(c); + nc->mnt = mnt; + c = nc; + first = 0; + goto Again; + } + + if(name[0]) /* walk succeeded */ + c->flag &= ~CMOUNT; + + if(!first) + close(ac); + + if(domnt) + return domount(c); + return c; + + Notfound: + if(!first) + close(c); + return 0; +} + +/* + * c is a mounted non-creatable directory. find a creatable one. + */ +Chan* +createdir(Chan *c) +{ + Mount *mnt; + Pgrp *pg = u->p->pgrp; + Chan *mc, *nc; + + lock(pg); + if(waserror()){ + unlock(pg); + nexterror(); + } + mnt = c->mnt; + if(c->mountid != mnt->mountid){ + print("createdir: changed underfoot?\n"); + error(0, Enocreate); + } + do{ + if(mnt->term) + error(0, Enocreate); + mnt = mnt->next; + }while(!(mnt->c->flag&CCREATE)); + mc = mnt->c; + incref(mc); + unlock(pg); + if(waserror()){ + close(mc); + nexterror(); + } + nc = clone(mc, 0); + poperror(); + close(c); + close(mc); + nc->mnt = mnt; + return nc; +} + +/* + * Turn a name into a channel. + * &name[0] is known to be a valid address. It may be a kernel address. + */ +Chan* +namec(char *name, int amode, int omode, ulong perm) +{ + Chan *c, *nc; + int t; + int mntok; + char *elem = u->elem; + + if(name[0] == 0) + error(0, Enonexist); + mntok = 1; + if(name[0] == '/'){ + c = clone(u->slash, 0); + /* + * Skip leading slashes. + */ + name = skipslash(name); + }else if(name[0] == '#'){ + mntok = 0; + if(!((ulong)name & KZERO)) + validaddr((ulong)(name+1), 2, 0); + if(name[1]=='|' || ('A'<=name[1] && name[1]<='Z')) + error(0, Enonexist); + t = devno(name[1], 1); + if(t == -1) + error(0, Ebadsharp); + name += 2; + if(*name == '/'){ + name = skipslash(name); + elem[0]=0; + }else + name = nextelem(name, elem); + c = (*devtab[t].attach)(elem); + }else + c = clone(u->dot, 0); + + if(waserror()){ + close(c); + nexterror(); + } + + name = nextelem(name, elem); + if(mntok) + if(!(amode==Amount && elem[0]==0)) /* don't domount on dot or slash */ + c = domount(c); /* see case Atodir below */ + + /* + * How to treat the last element of the name depends on the operation. + * Therefore do all but the last element by the easy algorithm. + */ + while(*name){ + if((nc=walk(c, elem, mntok)) == 0) + error(0, Enonexist); + c = nc; + name = nextelem(name, elem); + } + /* + * Last element; act according to type of access. + */ + + switch(amode){ + case Aaccess: + if((nc=walk(c, elem, mntok)) == 0) + error(0, Enonexist); + c = nc; + break; + + case Atodir: + /* + * Directories (e.g. for cd) are left before the mount point, + * so one may mount on / or . and see the effect. + */ + if((nc=walk(c, elem, 0)) == 0) + error(0, Enonexist); + c = nc; + if(!(c->qid & CHDIR)) + error(0, Enotdir); + break; + + case Aopen: + if((nc=walk(c, elem, mntok)) == 0) + error(0, Enonexist); + c = nc; + Open: + c = (*devtab[c->type].open)(c, omode); + break; + + case Amount: + /* + * When mounting on an already mounted upon directory, one wants + * the second mount to be attached to the original directory, not + * the replacement. + */ + if((nc=walk(c, elem, 0)) == 0) + error(0, Enonexist); + c = nc; + break; + + case Acreate: + if((nc=walk(c, elem, 1)) != 0){ + c = nc; + omode |= OTRUNC; + goto Open; + } + if((c->flag&(CMOUNT|CCREATE)) == CMOUNT) + c = createdir(c); + (*devtab[c->type].create)(c, elem, omode, perm); + break; + + default: + panic("unknown namec access %d\n", amode); + } + poperror(); + return c; +} + +/* + * name[0] is addressable. + */ +char* +skipslash(char *name) +{ + while(*name == '/'){ + if(((ulong)name&KZERO)==0 && (((ulong)name+1)&(BY2PG-1))==0) + validaddr((ulong)name+1, 1, 0); + name++; + } + return name; +} + +char isfrog[]={ + /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1, + /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1, + /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1, + /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1, + [' '] 1, + ['/'] 1, + [0x7f] 1, +}; + +/* + * name[0] should not be a slash. + * Advance name to next element in path, copying current element into elem. + * Return pointer to next element, skipping slashes. + * &name[0] is known to be a valid address. + */ +char* +nextelem(char *name, char *elem) +{ + int i, user, c; + char *end, *e; + + if(*name == '/') + error(0, Efilename); + end = vmemchr(name, 0, NAMELEN); + if(end == 0){ + end = vmemchr(name, '/', NAMELEN); + if(end == 0) + error(0, Efilename); + }else{ + e = memchr(name, '/', end-name); + if(e) + end = e; + } + while(name < end){ + c = *name++; + if((c&0x80) || isfrog[c]) + error(0, Ebadchar); + *elem++ = c; + } + *elem = 0; + return skipslash(name); +} + +void +isdir(Chan *c) +{ + if(c->qid & CHDIR) + return; + error(0, Enotdir); +} diff --git a/gnot/clock.c b/gnot/clock.c new file mode 100644 index 0000000000000000000000000000000000000000..2bfd3e4e32b68b8efe86e6a2785a2aeb972ba271 --- /dev/null +++ b/gnot/clock.c @@ -0,0 +1,123 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "ureg.h" + +Alarm *alarmtab; + +Alarm* +alarm(int ms, void (*f)(Alarm*), void *arg) +{ + Alarm *a, *w, *pw; + ulong s; + if(ms < 0) + ms = 0; + a = newalarm(); + a->dt = ms/MS2HZ; + a->f = f; + a->arg = arg; + s = splhi(); + lock(&m->alarmlock); + pw = 0; + for(w=m->alarm; w; pw=w, w=w->next){ + if(w->dt <= a->dt){ + a->dt -= w->dt; + continue; + } + w->dt -= a->dt; + break; + } + insert(&m->alarm, pw, a); + unlock(&m->alarmlock); + splx(s); + return a; +} + +void +cancel(Alarm *a) +{ + a->f = 0; +} + +Alarm* +newalarm(void) +{ + int i; + Alarm *a; + + for(i=0,a=alarmtab; ibusy==0 && a->f==0 && canlock(a)){ + if(a->busy){ + unlock(a); + continue; + } + a->f = 0; + a->arg = 0; + a->busy = 1; + unlock(a); + return a; + } + panic("newalarm"); +} + +void +alarminit(void) +{ + int i; + + alarmtab = ialloc(conf.nalarm*sizeof(Alarm), 0); + for(i=0; iticks++; + p = m->proc; + if(p) + p->time[p->insyscall]++; + if(canlock(&m->alarmlock)){ + if(m->alarm){ + a = m->alarm; + a->dt--; + while(a && a->dt<=0){ + f = a->f; /* avoid race with cancel */ + if(f) + (*f)(a); + delete(&m->alarm, 0, a); + a->busy = 0; + a = m->alarm; + } + } + unlock(&m->alarmlock); + } + if((ur->sr&SPL(7)) == 0){ + spllo(); + if(p && p->state==Running) + sched(); + } +} diff --git a/gnot/dat.h b/gnot/dat.h new file mode 100644 index 0000000000000000000000000000000000000000..6fde871cd26dfbd3d2fc3d165344f1fa48eb36b4 --- /dev/null +++ b/gnot/dat.h @@ -0,0 +1,527 @@ +typedef struct Alarm Alarm; +typedef struct Block Block; +typedef struct Blist Blist; +typedef struct Chan Chan; +typedef struct Conf Conf; +typedef struct Dev Dev; +typedef struct Dir Dir; +typedef struct Dirtab Dirtab; +typedef struct Env Env; +typedef struct Envp Envp; +typedef struct Envval Envval; +typedef struct Error Error; +typedef struct FFrame FFrame; +typedef struct FPsave FPsave; +typedef struct Label Label; +typedef struct List List; +typedef struct Lock Lock; +typedef struct Mach Mach; +typedef struct Mount Mount; +typedef struct Mtab Mtab; +typedef struct Note Note; +typedef struct Orig Orig; +typedef struct PTE PTE; +typedef struct Page Page; +typedef struct Pgrp Pgrp; +typedef struct Proc Proc; +typedef struct Qinfo Qinfo; +typedef struct QLock QLock; +typedef struct Queue Queue; +typedef struct Ref Ref; +typedef struct Rendez Rendez; +typedef struct Seg Seg; +typedef struct Stream Stream; +typedef struct Ureg Ureg; +typedef struct User User; + +typedef int Devgen(Chan*, Dirtab*, int, int, Dir*); + +struct List +{ + void *next; +}; + +struct Lock +{ + char key[1]; /* addr of sync bus semaphore */ + ulong pc; +}; + +struct Ref +{ + Lock; + int ref; +}; + +struct QLock +{ + Proc *head; /* next process waiting for object */ + Proc *tail; /* last process waiting for object */ + Lock use; /* to use object */ + Lock queue; /* to access list */ +}; + +struct Label +{ + ulong sp; + ulong pc; + ushort sr; +}; + +struct Alarm +{ + List; + Lock; + int busy; + long dt; /* may underflow in clock(); must be signed */ + void (*f)(void*); + void *arg; +}; + +#define CHDIR 0x80000000L +#define QPATH 0x0000FFFFL +struct Chan +{ + QLock; /* general access */ + Ref; + union{ + Chan *next; /* allocation */ + ulong offset; /* in file */ + }; + ushort type; + ushort dev; + ushort mode; /* read/write */ + ushort flag; + ulong qid; + Mount *mnt; /* mount point that derived Chan */ + ulong mountid; + int fid; /* for devmnt */ + Stream *stream; /* for stream channels */ + Chan *mchan; /* channel to mounted server */ + ulong mqid; /* qid of root of mount point */ +}; + +struct FPsave +{ + long fpreg[32]; + long fpstatus; +}; + +struct Conf +{ + int nmach; /* processors */ + int nproc; /* processes */ + int npgrp; /* process groups */ + ulong npage; /* total physical pages of memory */ + ulong norig; /* origins */ + ulong npte; /* contiguous page table entries */ + ulong nmod; /* single (modifying) page table entries */ + int nalarm; /* alarms */ + int nchan; /* channels */ + int nenv; /* distinct environment values */ + int nenvchar; /* environment text storage */ + int npgenv; /* environment files per process group */ + int nmtab; /* mounted-upon channels per process group */ + int nmount; /* mounts */ + int nmntdev; /* mounted devices (devmnt.c) */ + int nmntbuf; /* buffers for devmnt.c messages */ + int nmnthdr; /* headers for devmnt.c messages */ + int nstream; /* streams */ + int nqueue; /* stream queues */ + int nblock; /* stream blocks */ + int nsrv; /* public servers (devsrv.c) */ +}; + +struct Dev +{ + void (*reset)(void); + void (*init)(void); + Chan *(*attach)(char*); + Chan *(*clone)(Chan*, Chan*); + int (*walk)(Chan*, char*); + void (*stat)(Chan*, char*); + Chan *(*open)(Chan*, int); + void (*create)(Chan*, char*, int, ulong); + void (*close)(Chan*); + long (*read)(Chan*, void*, long); + long (*write)(Chan*, void*, long); + void (*remove)(Chan*); + void (*wstat)(Chan*, char*); + void (*errstr)(Error*, char*); + void (*userstr)(Error*, char*); +}; + +struct Dirtab +{ + char name[NAMELEN]; + long qid; + long length; + long perm; +}; + +struct Env +{ + Lock; + Envval *val; + char name[NAMELEN]; + Env *next; /* in chain of Envs for a pgrp */ + int pgref; /* # pgrps pointing here */ +}; + +struct Envp +{ + Env *env; + int chref; /* # chans from pgrp pointing here */ +}; + +struct Mach +{ + int machno; /* physical id of processor */ + int mmask; /* 1<machno */ + ulong ticks; /* of the clock since boot time */ + Proc *proc; /* current process on this processor */ + Label sched; /* scheduler wakeup */ + Lock alarmlock; /* access to alarm list */ + void *alarm; /* alarms bound to this clock */ + int stack[1]; +}; + +struct Mount +{ + Ref; /* also used as a lock when playing lists */ + short term; /* terminates list */ + ulong mountid; + Mount *next; + Chan *c; /* channel replacing underlying channel */ +}; + +struct Mtab +{ + Chan *c; /* channel mounted upon */ + Mount *mnt; /* what's mounted upon it */ +}; + +enum{ + NUser, /* note provided externally */ + NExit, /* process should exit */ + NDebug, /* process should hang */ +}; + +struct Note +{ + char msg[ERRLEN]; + int flag; /* whether system posted it */ +}; + +struct Orig +{ + Lock; + Orig *next; /* for allocation */ + ushort nproc; /* processes using it */ + ushort npage; /* sum of refs of pages in it */ + ushort flag; + ulong va; /* va of 0th pte */ + ulong npte; /* #pte's in list */ + PTE *pte; + Chan *chan; /* channel deriving segment (if open) */ + ushort type; /* of channel (which could be non-open) */ + ulong qid; + Chan *mchan; + ulong mqid; + ulong minca; /* base of region in chan */ + ulong maxca; /* end of region in chan */ +}; + +struct Page +{ + Orig *o; /* origin of segment owning page */ + ulong va; /* virtual address */ + ulong pa; /* physical address */ + ushort ref; + Page *next; + Page *prev; +}; + +struct Pgrp +{ + Ref; /* also used as a lock when mounting */ + Pgrp *next; + ulong pgrpid; + char user[NAMELEN]; + int nmtab; /* highest active mount table entry, +1 */ + int nenv; /* highest active env table entry, +1 */ + Mtab *mtab; + Envp *etab; +}; + +struct PTE +{ + Proc *proc; /* process owning this PTE (0 in Orig) */ + PTE *nextmod; /* next at this va */ + PTE *nextva; /* next in this proc at higher va */ + Page *page; +}; + +struct Rendez +{ + Lock; + Proc *p; +}; + +struct Seg +{ + Proc *proc; /* process owning this segment */ + Orig *o; /* root list of pte's */ + ulong minva; /* va of 0th pte (not necessarily Seg->o->va) */ + ulong maxva; /* va of last pte */ + PTE *mod; /* list of modified pte's */ + ulong pad[3]; /**/ +}; + +struct Proc +{ + Label sched; + Lock; + Mach *mach; /* machine running this proc */ + char text[NAMELEN]; + Proc *rnext; /* next process in run queue */ + Proc *qnext; /* next process on queue for a QLock */ + int state; + short pidonmach[MAXMACH]; /* TLB pid on each mmu */ + Page *upage; /* BUG: should be unlinked from page list */ + Seg seg[NSEG]; + ulong pid; + Lock kidlock; /* access to kid and sib */ + Proc *pop; /* some ascendant */ + Proc *kid; /* some descendant */ + Proc *sib; /* non-ascendant relatives (circular list) */ + int nchild; + QLock wait; /* exiting children to be waited for */ + Waitmsg *waitmsg; + Proc *child; + Proc *parent; + Pgrp *pgrp; + ulong parentpid; + ulong time[6]; /* User, Sys, Real; child U, S, R */ + short exiting; + short insyscall; + int fpstate; + Lock debug; /* to access debugging elements of User */ + Rendez *r; /* rendezvous point slept on */ + Rendez sleep; /* place for tsleep and syssleep */ + int wokeup; /* whether sleep was interrupted */ + ulong pc; /* DEBUG only */ +}; + +#define NERR 10 +#define NNOTE 5 +#define NFD 100 +struct User +{ + Proc *p; + Label errlab[NERR]; + int nerrlab; + Error error; + FPsave fpsave; /* address of this is known by vdb */ + char elem[NAMELEN]; /* last name element from namec */ + Chan *slash; + Chan *dot; + Chan *fd[NFD]; + int maxfd; /* highest fd in use */ + /* + * Rest of structure controlled by devproc.c and friends. + * lock(&p->debug) to modify. + */ + Note note[NNOTE]; + short nnote; + short notified; /* sysnoted is due */ + int (*notify)(void*, char*); + void *ureg; +}; + +/* + * operations available to a queue + */ +struct Qinfo +{ + void (*iput)(Queue*, Block*); /* input routine */ + void (*oput)(Queue*, Block*); /* output routine */ + void (*open)(Queue*, Stream*); + void (*close)(Queue*); + char *name; +}; + +/* + * We reference lance buffers via descriptors kept in host memory + */ +struct Block +{ + Block *next; + uchar *rptr; /* first unconsumed byte */ + uchar *wptr; /* first empty byte */ + uchar *lim; /* 1 past the end of the buffer */ + uchar *base; /* start of the buffer */ + uchar flags; + uchar type; +}; + +/* flag bits */ +#define S_DELIM 0x80 +#define S_CLASS 0x07 + +/* type values */ +#define M_DATA 0 +#define M_CTL 1 +#define M_HANGUP 2 + +/* + * a list of blocks + */ +struct Blist { + Lock; + Block *first; /* first data block */ + Block *last; /* last data block */ + long len; /* length of list in bytes */ +}; + +/* + * a queue of blocks + */ +struct Queue { + Blist; + int flag; + Qinfo *info; /* line discipline definition */ + Queue *other; /* opposite direction, same line discipline */ + Queue *next; /* next queue in the stream */ + void (*put)(Queue*, Block*); + Rendez r; + void *ptr; /* private info for the queue */ +}; +#define QHUNGUP 0x1 /* flag bit meaning the stream has been hung up */ +#define QINUSE 0x2 +#define QHIWAT 0x4 /* queue has gone past the high water mark */ + +/* + * a stream head + */ +struct Stream { + Lock; /* structure lock */ + int inuse; /* use count */ + int type; /* correclation with Chan */ + int dev; /* ... */ + int id; /* ... */ + QLock rdlock; /* read lock */ + QLock wrlock; /* write lock */ + Queue *procq; /* write queue at process end */ + Queue *devq; /* read queue at device end */ + char tag[32]; /* when reading the tag qid */ +}; +#define RD(q) ((q)->other < (q) ? (q->other) : q) +#define WR(q) ((q)->other > (q) ? (q->other) : q) +#define GLOBAL(a) (((ulong)(a)) & 0x80000000) +#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) + +/* + * stream file qid's & high water mark + */ +enum { + Shighqid = STREAMQID(1,0) - 1, + Sdataqid = Shighqid, + Sctlqid = Sdataqid-1, + Slowqid = Sctlqid, + Streamhi= (32*1024), /* stream high water mark */ +}; + +#define PRINTSIZE 256 + +extern Mach *m; +extern User *u; + +/* + * Process states + */ +enum +{ + Dead = 0, + Moribund, + Zombie, + Ready, + Scheding, + Running, + Queueing, + MMUing, + Exiting, + Inwait, + Wakeme, + Broken, +}; +extern char *statename[]; + +/* + * Chan flags + */ +#define COPEN 1 /* for i/o */ +#define CMOUNT 2 /* is result of a mount/bind */ +#define CCREATE 4 /* permits creation if CMOUNT */ + +/* + * Proc.time + */ +enum +{ + TUser, + TSys, + TReal, + TCUser, + TCSys, + TCReal, +}; + +/* + * floating point registers + */ +enum +{ + FPinit, + FPactive, + FPinactive, +}; + +/* + * Memory management + */ +#define SSEG 0 +#define TSEG 1 +#define DSEG 2 +#define BSEG 3 +#define ESEG 4 /* used by exec to build new stack */ + +#define OWRPERM 0x01 /* write permission */ +#define OPURE 0x02 /* original data mustn't be written */ +#define OCACHED 0x04 /* cached; don't discard on exit */ + +/* + * Access types in namec + */ +enum +{ + Aaccess, /* as in access, stat */ + Atodir, /* as in chdir */ + Aopen, /* for i/o */ + Amount, /* to be mounted upon */ + Acreate, /* file is to be created */ +}; + +#define NUMSIZE 12 /* size of formatted number */ + +#define MACHP(n) (n==0? &mach0 : *(Mach**)0) + +extern Conf conf; +extern ulong initcode[]; +extern Dev devtab[]; +extern char devchar[]; +extern FPsave initfp; +extern Mach mach0; diff --git a/gnot/dev.c b/gnot/dev.c new file mode 100644 index 0000000000000000000000000000000000000000..03e8b481bdb54ac2dfc300eb20595dac6415e3d3 --- /dev/null +++ b/gnot/dev.c @@ -0,0 +1,198 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#define DEVTAB +#include "devtab.h" + +#include "fcall.h" + +int +devno(int c, int user) +{ + char *s; + + s = strchr(devchar, c); + if(s==0 || c==0){ + if(user) + return -1; + panic("devno %c 0x%ux", c, c); + } + return s - devchar; +} + +void +devdir(Chan *c, long qid, char *n, long length, long perm, Dir *db) +{ + strcpy(db->name, n); + db->qid = qid; + db->type = devchar[c->type]; + db->dev = c->dev; + if(qid & CHDIR) + db->mode = CHDIR|perm; + else + db->mode = perm; + db->atime = seconds(); + db->mtime = db->atime; + db->hlength = 0; + db->length = length; + db->uid = 0; + db->gid = 0; +} + +int +devgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) +{ + if(tab==0 || i>=ntab) + return -1; + tab += i; + devdir(c, tab->qid, tab->name, tab->length, tab->perm, dp); + return 1; +} + +Chan * +devattach(int tc, char *spec) +{ + Chan *c; + + c = newchan(); + c->qid = CHDIR; + c->type = devno(tc, 0); + return c; +} + +Chan * +devclone(Chan *c, Chan *nc) +{ + if(nc == 0) + nc = newchan(); + nc->type = c->type; + nc->mode = c->mode; + nc->qid = c->qid; + nc->offset = c->offset; + nc->dev = c->dev; + nc->flag = c->flag; + nc->mnt = c->mnt; + nc->mchan = c->mchan; + nc->mqid = c->mqid; + return nc; +} + +int +devwalk(Chan *c, char *name, Dirtab *tab, int ntab, Devgen *gen) +{ + long i; + Dir dir; + + isdir(c); + if(name[0]=='.' && name[1]==0) + return 1; + for(i=0;; i++) + switch((*gen)(c, tab, ntab, i, &dir)){ + case -1: + u->error.type = 0; + u->error.dev = 0; + u->error.code = Enonexist; + return 0; + case 0: + continue; + case 1: + if(strcmp(name, dir.name) == 0){ + c->qid = dir.qid; + return 1; + } + continue; + } +} + +void +devstat(Chan *c, char *db, Dirtab *tab, int ntab, Devgen *gen) +{ + int i; + Dir dir; + + for(i=0;; i++) + switch((*gen)(c, tab, ntab, i, &dir)){ + case -1: + /* + * devices with interesting directories usually don't get + * here, which is good because we've lost the name by now. + */ + if(c->qid & CHDIR){ + devdir(c, c->qid, ".", 0L, CHDIR|0700, &dir); + convD2M(&dir, db); + return; + } + panic("devstat"); + case 0: + break; + case 1: + if(c->qid == dir.qid){ + convD2M(&dir, db); + return; + } + break; + } +} + +long +devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen) +{ + long k, l, m; + Dir dir; + + k = c->offset/DIRLEN; + l = (c->offset+n)/DIRLEN; + n = 0; + for(m=k; moffset += DIRLEN; + break; + + case 1: + convD2M(&dir, d); + n += DIRLEN; + d += DIRLEN; + m++; + break; + } + return n; +} + +Chan * +devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen) +{ + int i; + Dir dir; + static int access[] = { 0400, 0200, 0600, 0100 }; + + for(i=0;; i++) + switch((*gen)(c, tab, ntab, i, &dir)){ + case -1: + /* Deal with union directories? */ + goto Return; + case 0: + break; + case 1: + if(c->qid == dir.qid){ + if((access[omode&3] & dir.mode) == access[omode&3]) + goto Return; + error(0, Eperm); + } + break; + } + Return: + c->offset = 0; + if((c->qid&CHDIR) && omode!=OREAD) + error(0, Eperm); + c->mode = openmode(omode); + c->flag |= COPEN; + return c; +} diff --git a/gnot/devcons.c b/gnot/devcons.c new file mode 100644 index 0000000000000000000000000000000000000000..4c6048bc5fdbc636454255de7f9e3805c93851ac --- /dev/null +++ b/gnot/devcons.c @@ -0,0 +1,520 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "errno.h" + +#include "devtab.h" + +static struct +{ + Lock; + int printing; + int c; +}printq; + +typedef struct IOQ IOQ; + +#define NQ 4096 +struct IOQ{ + union{ + Lock; + QLock; + }; + uchar buf[NQ]; + uchar *in; + uchar *out; + int state; + Rendez r; +}; + +IOQ kbdq; /* qlock to getc; interrupt putc's */ +IOQ lineq; /* lock to getc; interrupt putc's */ + +void +printinit(void) +{ + + lock(&printq); /* allocate lock */ + unlock(&printq); + + kbdq.in = kbdq.buf; + kbdq.out = kbdq.buf; + lineq.in = lineq.buf; + lineq.out = lineq.buf; + qlock(&kbdq); /* allocate qlock */ + qunlock(&kbdq); + lock(&lineq); /* allocate lock */ + unlock(&lineq); + + screeninit(); +} + +/* + * Print a string on the console. + */ +void +putstrn(char *str, long n) +{ + int s; + + s = splhi(); + lock(&printq); + printq.printing = 1; + while(--n >= 0) + screenputc(*str++); + printq.printing = 0; + unlock(&printq); + splx(s); +} + +int +cangetc(IOQ *q) +{ + return q->in != q->out; +} + +int +isbrkc(IOQ *q) +{ + uchar *p; + + for(p=q->out; p!=q->in; ){ + if(*p==0x04 || *p=='\n') + return 1; + p++; + if(p >= q->buf+sizeof(q->buf)) + p = q->buf; + } + return 0; +} + +int +getc(IOQ *q) +{ + int c; + + if(q->in == q->out) + return -1; + c = *q->out++; + if(q->out == q->buf+sizeof(q->buf)) + q->out = q->buf; + return c; +} + +int +sprint(char *s, char *fmt, ...) +{ + return donprint(s, s+PRINTSIZE, fmt, (&fmt+1)) - s; +} + +int +print(char *fmt, ...) +{ + char buf[PRINTSIZE]; + int n; + + n = donprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf; + putstrn(buf, n); + return n; +} + +void +panic(char *fmt, ...) +{ + char buf[PRINTSIZE]; + int n; + + strcpy(buf, "panic: "); + n = donprint(buf+7, buf+sizeof(buf), fmt, (&fmt+1)) - buf; + buf[n] = '\n'; + putstrn(buf, n+1); + exit(); +} +int +pprint(char *fmt, ...) +{ + char buf[2*PRINTSIZE]; + Chan *c; + int n; + + c = u->fd[2]; + if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) + return; + n = sprint(buf, "%s %d: ", u->p->text, u->p->pid); + n = donprint(buf+n, buf+sizeof(buf), fmt, (&fmt+1)) - buf; + qlock(c); + if(waserror()){ + qunlock(c); + return; + } + (*devtab[c->type].write)(c, buf, n); + c->offset += n; + qunlock(c); + return n; +} + +void +prflush(void) +{ + while(printq.printing) + delay(100); +} + +void +echo(int c) +{ + char ch; + + /* + * ^t hack BUG + */ + if(c == 0x14) + DEBUG(); + if(c == 0x15) + putstrn("^U\n", 3); + else{ + ch = c; + putstrn(&ch, 1); + } +} + +/* + * Put character into read queue at interrupt time. + * Always called splhi from proc 0. + */ +void +kbdchar(int c) +{ + if(c == '\r') + c = '\n'; + echo(c); + *kbdq.in++ = c; + if(kbdq.in == kbdq.buf+sizeof(kbdq.buf)) + kbdq.in = kbdq.buf; + if(c=='\n' || c==0x04) + wakeup(&kbdq.r); +} + +int +consactive(void) +{ + return printq.printing; +} + +/* + * I/O interface + */ +enum{ + Qdir, + Qcons, + Qcputime, + Qnull, + Qpgrpid, + Qpid, + Qppid, + Qtime, + Quser, +}; + +Dirtab consdir[]={ + "cons", Qcons, 0, 0600, + "cputime", Qcputime, 72, 0600, + "null", Qnull, 0, 0600, + "pgrpid", Qpgrpid, 12, 0600, + "pid", Qpid, 12, 0600, + "ppid", Qppid, 12, 0600, + "time", Qtime, 12, 0600, + "user", Quser, 0, 0600, +}; + +#define NCONS (sizeof consdir/sizeof(Dirtab)) + +ulong boottime; /* seconds since epoch at boot */ + +long +seconds(void) +{ + return boottime + MACHP(0)->ticks*MS2HZ/1000; +} + +int +readnum(ulong off, char *buf, ulong n, ulong val, int size) +{ + char tmp[64]; + Op op = (Op){ tmp, tmp+sizeof(tmp), &val, size-1, 0, FUNSIGN|FLONG }; + + numbconv(&op, 10); + tmp[size-1] = ' '; + off %= size; + if(off+n > size) + n = size-off; + memcpy(buf, tmp+off, n); + return n; +} + +int +readstr(ulong off, char *buf, ulong n, char *str) +{ + int size; + + size = strlen(str); + off %= size; + if(off+n > size) + n = size-off; + memcpy(buf, str+off, n); + return n; +} + +void +consreset(void) +{ +} + +void +consinit(void) +{ +} + +Chan* +consattach(char *spec) +{ + return devattach('c', spec); +} + +Chan* +consclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +conswalk(Chan *c, char *name) +{ + return devwalk(c, name, consdir, NCONS, devgen); +} + +void +consstat(Chan *c, char *dp) +{ + devstat(c, dp, consdir, NCONS, devgen); +} + +Chan* +consopen(Chan *c, int omode) +{ + if(c->qid==Quser && omode==(OWRITE|OTRUNC)){ + /* truncate? */ + if(strcmp(u->p->pgrp->user, "bootes") == 0) /* BUG */ + u->p->pgrp->user[0] = 0; + else + error(0, Eperm); + } + return devopen(c, omode, consdir, NCONS, devgen); +} + +void +conscreate(Chan *c, char *name, int omode, ulong perm) +{ + error(0, Eperm); +} + +void +consclose(Chan *c) +{ +} + +long +consread(Chan *c, void *buf, long n) +{ + int ch, i, j, k; + ulong l; + uchar *out; + char *cbuf = buf; + char *user; + int userlen; + char tmp[6*NUMSIZE]; + + if(n <= 0) + return n; + switch(c->qid&~CHDIR){ + case Qdir: + return devdirread(c, buf, n, consdir, NCONS, devgen); + + case Qcons: + qlock(&kbdq); + while(!cangetc(&lineq)){ + sleep(&kbdq.r, (int(*)(void*))isbrkc, &kbdq); + do{ + ch = getc(&kbdq); + switch(ch){ + case '\b': + if(lineq.in != lineq.out){ + if(lineq.in == lineq.buf) + lineq.in = lineq.buf+sizeof(lineq.buf); + lineq.in--; + } + break; + case 0x15: + lineq.in = lineq.out; + break; + default: + *lineq.in++ = ch; + if(lineq.in == lineq.buf+sizeof(lineq.buf)) + lineq.in = lineq.buf; + } + }while(ch!='\n' && ch!=0x04); + } + i = 0; + while(n>0){ + ch = getc(&lineq); + if(ch == 0x04 || ch == -1) + break; + i++; + *cbuf++ = ch; + --n; + } + qunlock(&kbdq); + return i; + + case Qcputime: + k = c->offset % sizeof tmp; + if(k+n > sizeof tmp) + n = sizeof tmp - k; + /* easiest to format in a separate buffer and copy out */ + for(i=0; i<6 && NUMSIZE*ip->time[i]; + if(i == TReal) + l = MACHP(0)->ticks - l; + l *= MS2HZ; + readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE); + } + memcpy(buf, tmp+k, n); + return n; + + case Qpgrpid: + return readnum(c->offset, buf, n, u->p->pgrp->pgrpid, NUMSIZE); + + case Qpid: + return readnum(c->offset, buf, n, u->p->pid, NUMSIZE); + + case Qppid: + return readnum(c->offset, buf, n, u->p->parentpid, NUMSIZE); + + case Qtime: + return readnum(c->offset, buf, n, boottime+MACHP(0)->ticks/(1000/MS2HZ), 12); + + case Quser: + return readstr(c->offset, buf, n, u->p->pgrp->user); + + case Qnull: + return 0; + + default: + panic("consread %lux\n", c->qid); + return 0; + } +} + +long +conswrite(Chan *c, void *va, long n) +{ + char cbuf[64]; + char buf[256]; + long l, m; + char *a = va; + + switch(c->qid){ + case Qcons: + /* + * Damn. Can't page fault in putstrn, so copy the data locally. + */ + l = n; + while(l > 0){ + m = l; + if(m > sizeof buf) + m = sizeof buf; + memcpy(buf, a, m); + putstrn(a, m); + a += m; + l -= m; + } + break; + + case Qtime: + if(n<=0 || boottime!=0) /* only one write please */ + return 0; + if(n >= sizeof cbuf) + n = sizeof cbuf - 1; + memcpy(cbuf, a, n); + cbuf[n-1] = 0; + boottime = strtoul(a, 0, 0); + break; + + case Quser: + if(u->p->pgrp->user[0]) /* trying to overwrite /dev/user */ + error(0, Eperm); + if(c->offset >= NAMELEN-1) + return 0; + if(c->offset+n >= NAMELEN-1) + n = NAMELEN-1 - c->offset; + memcpy(u->p->pgrp->user+c->offset, a, n); + u->p->pgrp->user[c->offset+n] = 0; + break; + + case Qcputime: + case Qpgrpid: + case Qpid: + case Qppid: + error(0, Eperm); + + case Qnull: + break; + default: + error(0, Egreg); + } + return n; +} + +void +consremove(Chan *c) +{ + error(0, Eperm); +} + +void +conswstat(Chan *c, char *dp) +{ + error(0, Eperm); +} + +void +conserrstr(Error *e, char *buf) +{ + rooterrstr(e, buf); +} + +void +consuserstr(Error *e, char *buf) +{ + strcpy(buf, u->p->pgrp->user); +} + +typedef struct Incon{ + unsigned char cdata; unsigned char u0; + unsigned char cstatus; unsigned char u1; + unsigned char creset; unsigned char u2; + unsigned char csend; unsigned char u3; + unsigned short data_cntl; /* data is high byte, cntl is low byte */ + unsigned char status; unsigned char u5; + unsigned char reset; unsigned char u6; + unsigned char send; unsigned char u7; +}Incon; + +inconintr(Ureg *ur) +{ + int x; + x = ((Incon*)0x40700000)->status; +} diff --git a/gnot/devdup.c b/gnot/devdup.c new file mode 100644 index 0000000000000000000000000000000000000000..0646a5046b2e1a8149b5701858d8b9bdd298056d --- /dev/null +++ b/gnot/devdup.c @@ -0,0 +1,130 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#include "devtab.h" + + +int +dupgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) +{ + char buf[8]; + Chan *f; + static int perm[] = { 0400, 0200, 0600, 0 }; + + if(s >= NFD) + return -1; + if((f=u->fd[s]) == 0) + return 0; + sprint(buf, "%ld", s); + devdir(c, s, buf, 0, perm[f->mode&3], dp); + return 1; +} + +void +dupinit(void) +{ +} + +void +dupreset(void) +{ +} + +Chan * +dupattach(char *spec) +{ + return devattach('d', spec); +} + +Chan * +dupclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +dupwalk(Chan *c, char *name) +{ + return devwalk(c, name, (Dirtab *)0, 0, dupgen); +} + +void +dupstat(Chan *c, char *db) +{ + devstat(c, db, (Dirtab *)0, 0L, dupgen); +} + +Chan * +dupopen(Chan *c, int omode) +{ + Chan *f; + + if(c->qid == CHDIR){ + if(omode != 0) + error(0, Eisdir); + c->mode = 0; + c->flag |= COPEN; + c->offset = 0; + return c; + } + fdtochan(c->qid, openmode(omode)); /* error check only */ + f = u->fd[c->qid]; + close(c); + incref(f); + return f; +} + +void +dupcreate(Chan *c, char *name, int omode, ulong perm) +{ + error(0, Eperm); +} + +void +dupremove(Chan *c) +{ + error(0, Eperm); +} + +void +dupwstat(Chan *c, char *dp) +{ + error(0, Egreg); +} + +void +dupclose(Chan *c) +{ +} + +long +dupread(Chan *c, void *va, long n) +{ + char *a = va; + + if(c->qid != CHDIR) + panic("dupread"); + return devdirread(c, a, n, (Dirtab *)0, 0L, dupgen); +} + +long +dupwrite(Chan *c, void *va, long n) +{ + panic("dupwrite"); +} + +void +duperrstr(Error *e, char *buf) +{ + rooterrstr(e, buf); +} + +void +dupuserstr(Error *e, char *buf) +{ + consuserstr(e, buf); +} diff --git a/gnot/devenv.c b/gnot/devenv.c new file mode 100644 index 0000000000000000000000000000000000000000..1d6d78ba85e288b6b28d075847a734f383d5d22d --- /dev/null +++ b/gnot/devenv.c @@ -0,0 +1,558 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#include "devtab.h" + +/* + * An environment value is kept in some number of contiguous + * Envvals, with the Env's val pointing at the first. + * Envvals are allocated from the end of a fixed arena, which + * is compacted when the arena end is reached. + * A `piece' (number of contiguous Envvals) is free to be + * reclaimed if its e pointer is 0. + * + * Locking: an env's val can change by compaction, so lock + * an env before using its value. A pgrp env[] slot can go + * to 0 and the corresponding env freed (by envremove()), so + * lock the pgrp around the use of a value retrieved from a slot. + * Lock in order: pgrp, envalloc, env (but ok to skip envalloc + * lock if there is no possibility of blocking). + */ + +struct Envval +{ + ulong n; /* number of Envval's (including this) in this piece */ + ulong len; /* how much of dat[] is valid */ + Env *e; /* the Env whose val points here */ + char dat[4]; /* possibly extends into further envvals after this */ +}; + +/* number of contiguous Envvals needed to hold n characters */ +#define EVNEEDED(n) ((n)<4? 1 : 1+((n)+(sizeof(Envval))-1-4)/(sizeof(Envval))) + +struct +{ + Lock; + Envval *arena; + Envval *vfree; + Envval *end; + Env *efree; + Env *earena; +}envalloc; + +void compactenv(Env *, ulong); + +void +envreset(void) +{ + int i, n; + + n = EVNEEDED(conf.nenvchar); + envalloc.arena = ialloc(n*sizeof(Envval), 0); + envalloc.vfree = envalloc.arena; + envalloc.end = envalloc.arena+n; + + envalloc.earena = ialloc(conf.nenv*sizeof(Env), 0); + envalloc.efree = envalloc.earena; + for(i=0; ival points at a value big enough to hold nchars chars. + * The caller should fix e->val->len. + * envalloc and e should be locked + */ +void +growenval(Env *e, ulong nchars) +{ + Envval *p; + ulong n, nfree; + + n = EVNEEDED(nchars); + if(p = e->val){ /* assign = */ + if(p->n < n){ + if(p+p->n == envalloc.vfree){ + compactenv(e, n - p->n); + p = e->val; + envalloc.vfree += n - p->n; + }else{ + compactenv(e, n); + p = envalloc.vfree; + envalloc.vfree += n; + memcpy(p, e->val, e->val->n*sizeof(Envval)); + p->e = e; + e->val->e = 0; + e->val = p; + } + p->n = n; + } + }else{ + compactenv(e, n); + p = envalloc.vfree; + envalloc.vfree += n; + p->n = n; + p->e = e; + e->val = p; + } +} + +/* + * Make sure there is room for n Envval's at the end of envalloc.vfree. + * Call this with envalloc and e locked. + */ +void +compactenv(Env *e, ulong n) +{ + Envval *p1, *p2; + Env *p2e; + + if(envalloc.end-envalloc.vfree >= n) + return; + p1 = envalloc.arena; /* dest */ + p2 = envalloc.arena; /* source */ + while(p2 < envalloc.vfree){ + p2e = p2->e; + if(p2e == 0){ + Free: + p2 += p2->n; + continue; + } + if(p2e=envalloc.earena+conf.nenv){ + print("%lux not an env\n", p2e); + panic("compactenv"); + } + if(p1 != p2){ + if(p2e != e) + lock(p2e); + if(p2->e != p2e){ /* freed very recently */ + print("compactenv p2e moved\n"); + if(p2->e) + panic("compactenv p2->e %lux\n", p2->e); + unlock(p2e); + goto Free; + } + if(p2+p2->n > envalloc.end) + panic("compactpte copying too much"); + memcpy(p1, p2, p2->n*sizeof(Envval)); + p2e->val = p1; + if(p2e != e) + unlock(p2e); + } + p2 += p1->n; + p1 += p1->n; + } + envalloc.vfree = p1; + if(envalloc.end-envalloc.vfree < n){ + print("env compact failed\n"); + error(0, Enoenv); + } +} + +/* + * Return an env with a copy of e's value. + * envalloc and e should be locked, + * and the value returned will be locked too. + */ +Env * +copyenv(Env *e, int trunc) +{ + Env *ne; + int n; + + ne = envalloc.efree; + if(!ne){ + print("out of envs\n"); + error(0, Enoenv); + } + envalloc.efree = ne->next; + lock(ne); + if(waserror()){ + unlock(ne); + nexterror(); + } + ne->next = 0; + ne->pgref = 1; + strncpy(ne->name, e->name, NAMELEN); + if(e->val && !trunc){ + n = e->val->len; + /* + * growenval can't hold the lock on another env + * because compactenv assumes only one is held + */ + unlock(e); + growenval(ne, n); + lock(e); + if(n != e->val->len){ + print("e changed in copyenv\n"); + if(n > ne->val->len) + n = ne->val->len; + } + if((char*)(ne->val+ne->val->n) < ne->val->dat+n) + panic("copyenv corrupt"); + memcpy(ne->val->dat, e->val->dat, n); + ne->val->len = n; + } + poperror(); + return ne; +} + +int +envgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) +{ + Env *e; + Pgrp *pg; + int ans; + + pg = u->p->pgrp; + lock(pg); + if(s >= pg->nenv) + ans = -1; + else{ + e = pg->etab[s].env; + if(e == 0) + ans = 0; + else{ + lock(e); + devdir(c, s+1, e->name, e->val? e->val->len : 0, 0666, dp); + unlock(e); + ans = 1; + } + } + unlock(pg); + return ans; +} + +Chan* +envattach(char *spec) +{ + return devattach('e', spec); +} + +Chan* +envclone(Chan *c, Chan *nc) +{ + Pgrp *pg; + + if(!(c->qid&CHDIR)){ + pg = u->p->pgrp; + lock(pg); + pg->etab[c->qid-1].chref++; + unlock(pg); + } + return devclone(c, nc); +} + +int +envwalk(Chan *c, char *name) +{ + Pgrp *pg; + + if(devwalk(c, name, 0, 0, envgen)){ + if(!(c->qid&CHDIR)){ + pg = u->p->pgrp; + lock(pg); + pg->etab[c->qid-1].chref++; + unlock(pg); + return 1; + } + } + return 0; +} + +void +envstat(Chan *c, char *db) +{ + devstat(c, db, 0, 0, envgen); +} + +Chan * +envopen(Chan *c, int omode) +{ + Env *e, *ne; + Envp *ep; + Pgrp *pg; + + if(omode & (OWRITE|OTRUNC)){ + if(c->qid & CHDIR) + error(0, Eperm); + pg = u->p->pgrp; + lock(pg); + ep = &pg->etab[c->qid-1]; + e = ep->env; + if(!e){ + unlock(pg); + error(0, Egreg); + } + lock(&envalloc); + lock(e); + if(waserror()){ + unlock(e); + unlock(&envalloc); + unlock(pg); + nexterror(); + } + if(e->pgref == 0) + panic("envopen"); + if(e->pgref == 1){ + if((omode&OTRUNC) && e->val){ + e->val->e = 0; + e->val = 0; + } + }else{ + ne = copyenv(e, omode&OTRUNC); + e->pgref--; /* it will still be positive */ + ep->env = ne; + unlock(ne); + } + poperror(); + unlock(e); + unlock(&envalloc); + unlock(pg); + } + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +envcreate(Chan *c, char *name, int omode, ulong perm) +{ + Env *e; + Pgrp *pg; + int i; + + if(c->qid != CHDIR) + error(0, Eperm); + pg = u->p->pgrp; + lock(pg); + lock(&envalloc); + if(waserror()){ + unlock(&envalloc); + unlock(pg); + nexterror(); + } + e = envalloc.efree; + if(e == 0){ + print("out of envs\n"); + error(0,Enoenv); + } + envalloc.efree = e->next; + e->next = 0; + e->pgref = 1; + strncpy(e->name, name, NAMELEN); + if(pg->nenv == conf.npgenv){ + for(i = 0; inenv; i++) + if(pg->etab[i].chref == 0) + break; + if(i == pg->nenv){ + print("out of pgroup envs\n"); + error(0, Enoenv); + } + }else + i = pg->nenv++; + c->qid = i+1; + pg->etab[i].env = e; + pg->etab[i].chref = 1; + unlock(&envalloc); + unlock(pg); + c->offset = 0; + c->mode = openmode(omode); + poperror(); + c->flag |= COPEN; +} + +void +envremove(Chan *c) +{ + Env *e; + Envp *ep; + Pgrp *pg; + + if(c->qid & CHDIR) + error(0, Eperm); + pg = u->p->pgrp; + lock(pg); + ep = &pg->etab[c->qid-1]; + e = ep->env; + if(!e){ + unlock(pg); + error(0, Enonexist); + } + ep->env = 0; + ep->chref--; + envpgclose(e); + unlock(pg); +} + +void +envwstat(Chan *c, char *db) +{ int dumpenv(void); + dumpenv(); /*DEBUG*/ + print("envwstat\n"); + error(0, Egreg); +} + +void +envclose(Chan * c) +{ + Pgrp *pg; + + if(c->qid & CHDIR) + return; + pg = u->p->pgrp; + lock(pg); + pg->etab[c->qid-1].chref--; + unlock(pg); +} + +void +envpgclose(Env *e) +{ + lock(&envalloc); + lock(e); + if(--e->pgref <= 0){ + if(e->val){ + e->val->e = 0; + e->val = 0; + } + e->next = envalloc.efree; + envalloc.efree = e; + } + unlock(e); + unlock(&envalloc); +} + +long +envread(Chan *c, void *va, long n) +{ + Env *e; + Envval *ev; + char *p; + long vn; + Pgrp *pg; + char *a = va; + + if(c->qid & CHDIR) + return devdirread(c, a, n, 0, 0, envgen); + pg = u->p->pgrp; + lock(pg); + e = pg->etab[c->qid-1].env; + if(!e){ + unlock(pg); + error(0, Eio); + } + lock(e); + ev = e->val; + vn = ev? e->val->len : 0; + if(c->offset+n > vn) + n = vn - c->offset; + if(n <= 0) + n = 0; + else + memcpy(a, ev->dat+c->offset, n); + unlock(e); + unlock(pg); + return n; +} + +long +envwrite(Chan *c, void *va, long n) +{ + Env *e; + char *p; + Envval *ev; + long vn; + Pgrp *pg; + char *a = va; + + if(n <= 0) + return 0; + pg = u->p->pgrp; + lock(pg); + e = pg->etab[c->qid-1].env; /* caller checks for CHDIR */ + if(!e){ + unlock(pg); + error(0, Eio); + } + lock(&envalloc); + lock(e); + if(waserror()){ + unlock(e); + unlock(&envalloc); + unlock(pg); + nexterror(); + } + if(e->pgref>1) + panic("envwrite to non-duped env"); + growenval(e, c->offset+n); + ev = e->val; + vn = ev? ev->len : 0; + if(c->offset > vn) + error(0, Egreg); /* perhaps should zero fill */ + memcpy(ev->dat+c->offset, a, n); + e->val->len = c->offset+n; + poperror(); + unlock(e); + unlock(&envalloc); + unlock(pg); + return n; +} + +void +dumpenv(void) +{ + Env *e; + Envp *ep; + Envval *ev; + Pgrp *pg; + int i; + char hold; + + pg = u->p->pgrp; + for(ep=pg->etab, i=0; inenv; i++, ep++) + print("P%d(%lux %d)",i, ep->env, ep->chref); + for(e=envalloc.earena; e<&envalloc.earena[conf.nenv]; e++) + if(e->pgref){ + print("E{%lux %d '%s'}[", e, e->pgref, e->name); + if(e->val){ + hold = e->val->dat[e->val->len]; + e->val->dat[e->val->len] = 0; + print("%s", e->val->dat); + e->val->dat[e->val->len] = hold; + } + print("]"); + }else if(e->val) + print("whoops, free env %lux has val=%lux\n",e,e->val); + for(i=0, e=envalloc.efree; e; e=e->next) + i++; + print("\n%d free envs", i); + for(i=0, ev=envalloc.arena; evn) + if(!ev->e) + i += ev->n*sizeof(Envval); + print(" %d free enval chars\n", i+((char *)envalloc.end-(char*)envalloc.vfree)); +} + +void +envuserstr(Error *e, char *buf) +{ + consuserstr(e, buf); +} + +void +enverrstr(Error *e, char *buf) +{ + rooterrstr(e, buf); +} + diff --git a/gnot/devmnt.c b/gnot/devmnt.c new file mode 100644 index 0000000000000000000000000000000000000000..6fdc537c0b9bf4c8dc9860acfdc884665cc2bd84 --- /dev/null +++ b/gnot/devmnt.c @@ -0,0 +1,645 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#include "devtab.h" + +#include "fcall.h" + +/* + * Easy version: multiple sessions but no intra-session multiplexing, copy the data + */ + +typedef struct Mnt Mnt; +struct Mnt +{ + Ref; /* for number of chans, incl. mntpt but not msg */ + QLock; /* for access */ + ulong mntid; /* serial # */ + Chan *msg; /* for reading and writing messages */ + Chan *mntpt; /* channel in user's name space */ +}; + +#define BUFSIZE (MAXFDATA+500) /* BUG */ +typedef struct Mntbuf Mntbuf; +struct Mntbuf +{ + Mntbuf *next; + char buf[BUFSIZE]; +}; + +struct +{ + Lock; + Mntbuf *free; +}mntbufalloc; + +typedef struct Mnthdr Mnthdr; +struct Mnthdr /* next only meaningful when buffer isn't being used */ +{ + Mnthdr *next; + Fcall thdr; + Fcall rhdr; +}; + +struct +{ + Lock; + Mnthdr *free; +}mnthdralloc; + +struct +{ + Lock; + long id; +}mntid; + +Mnt *mnt; +void mntxmit(Mnt*, Mnthdr*); + +Mntbuf* +mballoc(void) +{ + Mntbuf *mb; + +loop: + lock(&mntbufalloc); + if(mb = mntbufalloc.free){ /* assign = */ + mntbufalloc.free = mb->next; + unlock(&mntbufalloc); + return mb; + } + unlock(&mntbufalloc); + print("no mntbufs\n"); + if(u == 0) + panic("mballoc"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +void +mbfree(Mntbuf *mb) +{ + lock(&mntbufalloc); + mb->next = mntbufalloc.free; + mntbufalloc.free = mb; + unlock(&mntbufalloc); +} + +Mnthdr* +mhalloc(void) +{ + Mnthdr *mh; + +loop: + lock(&mnthdralloc); + if(mh = mnthdralloc.free){ /* assign = */ + mnthdralloc.free = mh->next; + unlock(&mnthdralloc); + return mh; + } + unlock(&mnthdralloc); + print("no mnthdrs\n"); + if(u == 0) + panic("mballoc"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +void +mhfree(Mnthdr *mh) +{ + lock(&mnthdralloc); + mh->next = mnthdralloc.free; + mnthdralloc.free = mh; + unlock(&mnthdralloc); +} + +Mnt* +mntdev(int dev, int noerr) +{ + Mnt *m; + int i; + + for(m=mnt,i=0; imntid == dev){ + if(m->msg == 0) + break; + return m; + } + if(noerr) + return 0; + error(0, Eshutdown); +} + +void +mntreset(void) +{ + int i; + Mntbuf *mb; + Mnthdr *mh; + + mnt = ialloc(conf.nmntdev*sizeof(Mnt), 0); + + mb = ialloc(conf.nmntbuf*sizeof(Mntbuf), 0); + for(i=0; iref == 0) + goto Found; + unlock(m); + } + error(0, Enomntdev); + Found: + m->ref = 1; + unlock(m); + lock(&mntid); + m->mntid = ++mntid.id; + unlock(&mntid); + c = devattach('M', spec); + c->dev = m->mntid; + m->mntpt = c; + cm = bogus.chan; + m->msg = cm; + incref(cm); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + close(c); + nexterror(); + } + mh->thdr.type = Tattach; + mh->thdr.fid = c->fid; + memcpy(mh->thdr.uname, u->p->pgrp->user, NAMELEN); + strcpy(mh->thdr.aname, spec); + mntxmit(m, mh); + c->qid = mh->rhdr.qid; + c->mchan = m->msg; + c->mqid = c->qid; + mhfree(mh); + poperror(); + return c; +} + +Chan* +mntclone(Chan *c, Chan *nc) +{ + Mnt *m; + Mnthdr *mh; + int new; + + new = 0; + if(nc == 0){ + nc = newchan(); + new = 1; + if(waserror()){ + close(nc); + nexterror(); + } + } + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = Tclone; + mh->thdr.fid = c->fid; + mh->thdr.newfid = nc->fid; + mntxmit(m, mh); + nc->type = c->type; + nc->dev = c->dev; + nc->qid = c->qid; + nc->mode = c->mode; + nc->flag = c->flag; + nc->offset = c->offset; + nc->mnt = c->mnt; + nc->mchan = c->mchan; + nc->mqid = c->qid; + if(new) + poperror(); + mhfree(mh); + poperror(); + incref(m); + return nc; +} + +int +mntwalk(Chan *c, char *name) +{ + Mnt *m; + Mnthdr *mh; + int found; + + found = 1; + m = mntdev(c->dev, 0); + mh = mhalloc(); + mh->thdr.type = Twalk; + mh->thdr.fid = c->fid; + strcpy(mh->thdr.name, name); + if(waserror()){ /* BUG: can check type of error? */ + found = 0; + goto Out; + } + mntxmit(m, mh); + c->qid = mh->rhdr.qid; + poperror(); + Out: + mhfree(mh); + return found; +} + +void +mntstat(Chan *c, char *dp) +{ + Mnt *m; + Mnthdr *mh; + + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = Tstat; + mh->thdr.fid = c->fid; + mntxmit(m, mh); + memcpy(dp, mh->rhdr.stat, DIRLEN); + dp[DIRLEN-4] = devchar[c->type]; + dp[DIRLEN-3] = 0; + dp[DIRLEN-2] = c->dev; + dp[DIRLEN-1] = c->dev>>8; + mhfree(mh); + poperror(); +} + +Chan* +mntopen(Chan *c, int omode) +{ + Mnt *m; + Mnthdr *mh; + + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = Topen; + mh->thdr.fid = c->fid; + mh->thdr.mode = omode; + mntxmit(m, mh); + c->qid = mh->rhdr.qid; + mhfree(mh); + poperror(); + c->offset = 0; + c->mode = openmode(omode); + c->flag |= COPEN; + return c; +} + +void +mntcreate(Chan *c, char *name, int omode, ulong perm) +{ + Mnt *m; + Mnthdr *mh; + + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = Tcreate; + mh->thdr.fid = c->fid; + strcpy(mh->thdr.name, name); + mh->thdr.mode = omode; + mh->thdr.perm = perm; + mntxmit(m, mh); + c->qid = mh->rhdr.qid; + mhfree(mh); + poperror(); + c->flag |= COPEN; + c->mode = openmode(omode); + c->qid = mh->rhdr.qid; +} + +void +mntclose(Chan *c) +{ + Mnt *m; + Mnthdr *mh; + + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = Tclunk; + mh->thdr.fid = c->fid; + mntxmit(m, mh); + mhfree(mh); + if(c == m->mntpt) + m->mntpt = 0; + if(decref(m) == 0){ /* BUG: need to hang up all pending i/o */ + qlock(m); + close(m->msg); + m->msg = 0; + qunlock(m); + } + poperror(); +} + +long +mntreadwrite(Chan *c, void *vbuf, long n, int type) +{ + Mnt *m; + Mnthdr *mh; + long nt, nr, count, offset; + char *buf; + + buf = vbuf; + count = 0; + offset = c->offset; + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = type; + mh->thdr.fid = c->fid; + Loop: + nt = n; + if(nt > MAXFDATA) + nt = MAXFDATA; + mh->thdr.offset = offset; + mh->thdr.count = nt; + mh->thdr.data = buf; + mntxmit(m, mh); + nr = mh->rhdr.count; + offset += nr; + count += nr; + buf += nr; + n -= nr; + if(n && nr==nt) + goto Loop; + mhfree(mh); + poperror(); + return count; +} + +long +mntread(Chan *c, void *buf, long n) +{ + long i; + uchar *b; + + n = mntreadwrite(c, buf, n, Tread); + if(c->qid & CHDIR){ + b = (uchar*)buf; + for(i=n-DIRLEN; i>=0; i-=DIRLEN){ + b[DIRLEN-4] = devchar[c->type]; + b[DIRLEN-3] = 0; + b[DIRLEN-2] = c->dev; + b[DIRLEN-1] = c->dev>>8; + b += DIRLEN; + } + } + return n; +} + +long +mntwrite(Chan *c, void *buf, long n) +{ + return mntreadwrite(c, buf, n, Twrite); +} + +void +mntremove(Chan *c) +{ + Mnt *m; + Mnthdr *mh; + + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = Tremove; + mh->thdr.fid = c->fid; + mntxmit(m, mh); + mhfree(mh); + poperror(); +} + +void +mntwstat(Chan *c, char *dp) +{ + Mnt *m; + Mnthdr *mh; + + m = mntdev(c->dev, 0); + mh = mhalloc(); + if(waserror()){ + mhfree(mh); + nexterror(); + } + mh->thdr.type = Twstat; + mh->thdr.fid = c->fid; + memcpy(mh->thdr.stat, dp, DIRLEN); + mntxmit(m, mh); + mhfree(mh); + poperror(); +} + +void +mnterrstr(Error *e, char *buf) +{ + Mnt *m; + Mnthdr *mh; + char *def="mounted device shut down"; + + m = mntdev(e->dev, 1); + if(m == 0){ + strcpy(buf, def); + return; + } + mh = mhalloc(); + if(waserror()){ + strcpy(buf, def); + mhfree(mh); + nexterror(); + } + mh->thdr.type = Terrstr; + mh->thdr.fid = 0; + mh->thdr.err = e->code; + mntxmit(m, mh); + strcpy(buf, (char*)mh->rhdr.ename); + mhfree(mh); + poperror(); +} + +void +mntuserstr(Error *e, char *buf) +{ + Mnt *m; + Mnthdr *mh; + char *def="mounted device shut down"; + + m = mntdev(e->dev, 1); + if(m == 0){ + strcpy(buf, def); + return; + } + mh = mhalloc(); + if(waserror()){ + strcpy(buf, def); + mhfree(mh); + nexterror(); + } + mh->thdr.type = Tuserstr; + mh->thdr.fid = 0; + mh->thdr.uid = e->code; + mntxmit(m, mh); + strcpy(buf, (char*)mh->rhdr.uname); + mhfree(mh); + poperror(); +} + +void +mntxmit(Mnt *m, Mnthdr *mh) +{ + ulong n; + Mntbuf *mbr, *mbw; + Chan *mntpt, *msg; + int isbit; + + mbr = mballoc(); + mbw = mballoc(); + if(waserror()){ + mbfree(mbr); + mbfree(mbw); + nexterror(); + } + n = convS2M(&mh->thdr, mbw->buf); + isbit = 0; + if(devchar[m->msg->type] == 'b') + isbit = 1; + /* + * Avoid qlock for bit, to maximize parallelism + */ + if(isbit){ + lock(&m->use); /* spin rather than sleep */ + if((msg = m->msg) == 0){ + unlock(&m->use); + error(0, Eshutdown); + } + incref(msg); + unlock(&m->use); + }else{ + qlock(m); + if((msg = m->msg) == 0){ + qunlock(m); + error(0, Eshutdown); + } + qlock(msg); + } + if(waserror()){ + if(isbit) + close(msg); + else{ + qunlock(m); + qunlock(msg); + } + nexterror(); + } + if((*devtab[msg->type].write)(msg, mbw->buf, n) != n){ + pprint("short write in mntxmit\n"); + error(0, Egreg); + } + + /* + * Read response + */ + n = (*devtab[msg->type].read)(msg, mbr->buf, BUFSIZE); + if(isbit) + close(msg); + else{ + qunlock(m); + qunlock(msg); + } + poperror(); + + if(convM2S(mbr->buf, &mh->rhdr, n) == 0){ + pprint("format error in mntxmit\n"); + error(0, Egreg); + } + + /* + * Various checks + */ + if(mh->rhdr.type != mh->thdr.type+1){ + pprint("type mismatch %d %d\n", mh->rhdr.type, mh->thdr.type+1); + error(0, Egreg); + } + if(mh->rhdr.fid != mh->thdr.fid){ + pprint("fid mismatch %d %d type %d\n", mh->rhdr.fid, mh->thdr.fid, mh->rhdr.type); + error(0, Egreg); + } + if(mh->rhdr.err){ + mntpt = m->mntpt; /* unsafe, but Errors are unsafe anyway */ + if(mntpt) + error(mntpt, mh->rhdr.err); + error(0, Eshutdown); + } + /* + * Copy out on read + */ + if(mh->thdr.type == Tread) + memcpy(mh->thdr.data, mh->rhdr.data, mh->rhdr.count); + mbfree(mbr); + mbfree(mbw); + poperror(); +} diff --git a/gnot/devpipe.c b/gnot/devpipe.c new file mode 100644 index 0000000000000000000000000000000000000000..25982e151c47603956c0c187a7c5c3aa51c778ce --- /dev/null +++ b/gnot/devpipe.c @@ -0,0 +1,218 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#include "devtab.h" +#include "fcall.h" + +static void pipeiput(Queue*, Block*); +static void pipeoput(Queue*, Block*); +static void pipestclose(Queue *); +Qinfo pipeinfo = { pipeiput, pipeoput, 0, pipestclose, "process" }; + +void +pipeinit(void) +{ +} + +void +pipereset(void) +{ +} + +/* + * allocate both streams + * + * a subsequent clone will get them the second stream + */ +Chan* +pipeattach(char *spec) +{ + Chan *c; + /* + * make the first stream + */ + c = devattach('|', spec); + c->qid = STREAMQID(0, Sdataqid); + streamnew(c, &pipeinfo); + return c; +} + +Chan* +pipeclone(Chan *c, Chan *nc) +{ + /* + * make the second stream + */ + nc = devclone(c, nc); + if(waserror()){ + close(nc); + nexterror(); + } + nc->qid = STREAMQID(1, Sdataqid); + streamnew(nc, &pipeinfo); + poperror(); + + /* + * attach it to the first + */ + c->stream->devq->other->next = nc->stream->devq; + nc->stream->devq->other->next = c->stream->devq; + return nc; +} + +int +pipewalk(Chan *c, char *name) +{ + print("pipewalk\n"); + error(0, Egreg); +} + +void +pipestat(Chan *c, char *db) +{ + Dir dir; + + devdir(c, c->qid, "pipe", 0, 0, &dir); + convD2M(&dir, db); +} + +Chan * +pipeopen(Chan *c, int omode) +{ + c->mode = omode; + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +pipecreate(Chan *c, char *name, int omode, ulong perm) +{ + print("pipecreate\n"); + error(0, Egreg); +} + +void +piperemove(Chan *c) +{ + print("piperemove\n"); + error(0, Egreg); +} + +void +pipewstat(Chan *c, char *db) +{ + print("pipewstat\n"); + error(0, Egreg); +} + +void +pipeclose(Chan *c) +{ + streamclose(c); +} + +long +piperead(Chan *c, void *va, long n) +{ + return streamread(c, va, n); +} + +long +pipewrite(Chan *c, void *va, long n) +{ + if(waserror()){ + postnote(u->p, 1, "sys: write on closed pipe", NExit); + error(0, Egreg); + } + return streamwrite(c, va, n); +} + +void +pipeuserstr(Error *e, char *buf) +{ + consuserstr(e, buf); +} + +void +pipeerrstr(Error *e, char *buf) +{ + rooterrstr(e, buf); +} + +/* + * stream stuff + */ +/* + * send a block up stream to the process. + * sleep untill there's room upstream. + */ +static void +pipeiput(Queue *q, Block *bp) +{ + flowctl(q); + PUTNEXT(q, bp); +} + +/* + * send the block to the other side without letting the connection + * disappear in mid put. + */ +static void +pipeoput(Queue *q, Block *bp) +{ + lock(q); + if(q->next) + pipeiput(q->next, bp); + unlock(q); +} + +/* + * send a hangup and disconnect the streams + */ +static void +pipestclose(Queue *q) +{ + Block *bp; + + /* + * point to the bit-bucket and let any in-progress + * write's finish. + */ + q->put = nullput; + wakeup(&q->r); + + /* + * send a hangup + */ + q = q->other; + lock(q); + if(q->next){ + bp = allocb(0); + bp->type = M_HANGUP; + pipeiput(q->next, bp); + } + unlock(q); + + /* + * disconnect (possible livelock?) + */ + for(;;){ + lock(q); + if(q->next){ + if(!canlock(q->next->other)){ + unlock(q); + continue; + } + q->next->other->next = 0; + unlock(q->next->other); + q->next = 0; + } + unlock(q); + break; + } +} diff --git a/gnot/devproc.c b/gnot/devproc.c new file mode 100644 index 0000000000000000000000000000000000000000..5b6c56fad09f6b6e6cd3cd7671fdafd2adf33411 --- /dev/null +++ b/gnot/devproc.c @@ -0,0 +1,387 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#include "devtab.h" + +enum{ + Qdir, + Qctl, + Qmem, + Qnote, + Qproc, + Qstatus, + Qtext, +}; + +Dirtab procdir[]={ + "ctl", Qctl, 0, 0600, + "mem", Qmem, 0, 0600, + "note", Qnote, 0, 0600, + "proc", Qproc, sizeof(Proc), 0600, + "status", Qstatus, NAMELEN+12+6*12, 0600, + "text", Qtext, 0, 0600, +}; + +/* + * Qids are, from bottom to top: + * 4 bits of file type (qids above) + * 12 bits of process slot number + 1 + * 15 bits of pid, for consistency checking + */ +#define NPROC (sizeof procdir/sizeof(Dirtab)) +#define QSHIFT 4 /* location in qid of proc slot # */ +#define PIDSHIFT 16 /* location in qid of pid */ +#define PIDMASK 0x7FFF /* low bits of pid used in qid */ +#define QID(q) (((q)&0x0000000F)>>0) +#define SLOT(q) ((((q)&0x0000FFF0)>>QSHIFT)-1) +#define PID(q) (((q)&0x7FFF0000)>>PIDSHIFT) + +int +procgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) +{ + Proc *p; + char buf[NAMELEN]; + ulong pid; + + if(c->qid == CHDIR){ + if(s >= conf.nproc) + return -1; + p = proctab(s); + pid = p->pid; + if(pid == 0) + return 0; + sprint(buf, "%d", pid); + devdir(c, CHDIR|(pid<= NPROC) + return -1; + if(tab) + panic("procgen"); + tab = &procdir[s]; + devdir(c, (~CHDIR)&(c->qid|tab->qid), tab->name, tab->length, tab->perm, dp); + return 1; +} + +void +procinit(void) +{ + if(conf.nproc >= (1<<(16-QSHIFT))-1) + print("warning: too many procs for devproc\n"); +} + +void +procreset(void) +{ +} + +Chan* +procattach(char *spec) +{ + Chan *c; + return devattach('p', spec); +} + +Chan* +procclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +procwalk(Chan *c, char *name) +{ + return devwalk(c, name, 0, 0, procgen); +} + +void +procstat(Chan *c, char *db) +{ + devstat(c, db, 0, 0, procgen); +} + +Chan * +procopen(Chan *c, int omode) +{ + Proc *p; + Orig *o; + Chan *tc; + + if(c->qid == CHDIR){ + if(omode != OREAD) + error(0, Eperm); + goto done; + } + p = proctab(SLOT(c->qid)); + if((p->pid&PIDMASK) != PID(c->qid)) + Died: + error(0, Eprocdied); + omode = openmode(omode); + + switch(QID(c->qid)){ + case Qtext: + o = p->seg[TSEG].o; + if(o==0 || p->state==Dead) + goto Died; + tc = o->chan; + if(tc == 0) + goto Died; + if(incref(tc) == 0){ + Close: + close(tc); + goto Died; + } + if(!(tc->flag&COPEN) || tc->mode!=OREAD) + goto Close; + if((p->pid&PIDMASK) != PID(c->qid)) + goto Close; + qlock(tc); + tc->offset = 0; + qunlock(tc); + return tc; + case Qctl: + case Qnote: + break; + case Qdir: + case Qmem: + case Qproc: + case Qstatus: + if(omode!=OREAD) + error(0, Eperm); + break; + default: + pprint("unknown qid in devopen\n"); + error(0, Egreg); + } + /* + * Affix pid to qid + */ + if(p->state != Dead) + c->qid |= (p->pid&PIDMASK)<mode = omode; + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +proccreate(Chan *c, char *name, int omode, ulong perm) +{ + error(0, Eperm); +} + +void +procremove(Chan *c) +{ + error(0, Eperm); +} + +void +procwstat(Chan *c, char *db) +{ + error(0, Eperm); +} + +void +procclose(Chan * c) +{ +} + +long +procread(Chan *c, void *va, long n) +{ + char *a = va, *b; + char statbuf[2*NAMELEN+12+6*12]; + Proc *p; + Seg *s; + Orig *o; + Page *pg; + int i; + long l; + long pid; + User *up; + + if(c->qid & CHDIR) + return devdirread(c, a, n, 0, 0, procgen); + + /* + * BUG: should lock(&p->debug)? + */ + p = proctab(SLOT(c->qid)); + if((p->pid&PIDMASK) != PID(c->qid)) + error(0, Eprocdied); + + switch(QID(c->qid)){ + case Qmem: + /* + * One page at a time + */ + if(((c->offset+n)&~(BY2PG-1)) != (c->offset&~(BY2PG-1))) + n = BY2PG - (c->offset&(BY2PG-1)); + s = seg(p, c->offset); + if(s){ + o = s->o; + if(o == 0) + error(0, Eprocdied); + lock(o); + if(s->o!=o || (p->pid&PIDMASK)!=PID(c->qid)){ + unlock(o); + error(0, Eprocdied); + } + if(seg(p, c->offset) != s){ + unlock(o); + error(0, Egreg); + } + pg = o->pte[(c->offset-o->va)>>PGSHIFT].page; + unlock(o); + if(pg == 0){ + pprint("nonresident page (complain to rob)\n"); + memset(a, 0, n); + }else{ + b = (char*)(pg->pa|KZERO); + memcpy(a, b+(c->offset&(BY2PG-1)), n); + } + return n; + } + + /* u area */ + if(c->offset>=USERADDR && c->offset<=USERADDR+BY2PG){ + if(c->offset+n > USERADDR+BY2PG) + n = USERADDR+BY2PG - c->offset; + pg = p->upage; + if(pg==0 || (p->pid&PIDMASK)!=PID(c->qid)) + error(0, Eprocdied); + b = (char*)(pg->pa|KZERO); + memcpy(a, b+(c->offset-USERADDR), n); + return n; + } + + /* kernel memory. BUG: shouldn't be so easygoing. BUG: mem mapping? */ + if(c->offset>=KZERO && c->offsetoffset+n > KZERO+conf.npage*BY2PG) + n = KZERO+conf.npage*BY2PG - c->offset; + memcpy(a, (char*)c->offset, n); + return n; + } + return 0; + break; + + case Qnote: + lock(&p->debug); + if(waserror()){ + unlock(&p->debug); + nexterror(); + } + if((p->pid&PIDMASK) != PID(c->qid)) + error(0, Eprocdied); + up = (User*)(p->upage->pa|KZERO); + if(up->p != p){ + pprint("note read u/p mismatch"); + error(0, Egreg); + } + if(n < ERRLEN) + error(0, Etoosmall); + if(up->nnote == 0) + n = 0; + else{ + memcpy(va, up->note[0].msg, ERRLEN); + up->nnote--; + memcpy(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); + n = ERRLEN; + } + unlock(&p->debug); + return n; + + case Qproc: + if(c->offset >= sizeof(Proc)) + return 0; + if(c->offset+n > sizeof(Proc)) + n = sizeof(Proc) - c->offset; + memcpy(a, ((char*)p)+c->offset, n); + return n; + + case Qstatus: + if(c->offset >= sizeof statbuf) + return 0; + if(c->offset+n > sizeof statbuf) + n = sizeof statbuf - c->offset; + sprint(statbuf, "%-27s %-27s %-11s ", p->text, p->pgrp->user, statename[p->state]); + for(i=0; i<6; i++){ + l = p->time[i]; + if(i == TReal) + l = MACHP(0)->ticks - l; + l *= MS2HZ; + readnum(0, statbuf+2*NAMELEN+12+NUMSIZE*i, NUMSIZE, l, NUMSIZE); + } + memcpy(a, statbuf+c->offset, n); + return n; + } + error(0, Egreg); +} + + +long +procwrite(Chan *c, void *va, long n) +{ + Proc *p; + User *up; + char buf[ERRLEN]; + + if(c->qid & CHDIR) + error(0, Eisdir); + p = proctab(SLOT(c->qid)); + lock(&p->debug); + if(waserror()){ + unlock(&p->debug); + nexterror(); + } + if((p->pid&PIDMASK) != PID(c->qid)) + Died: + error(0, Eprocdied); + + switch(QID(c->qid)){ + case Qctl: + if(p->state==Broken && n>=4 && strncmp(va, "exit", 4)==0) + ready(p); + else + error(0, Ebadctl); + break; + case Qnote: + up = (User*)(p->upage->pa|KZERO); + if(up->p != p){ + pprint("note write u/p mismatch"); + error(0, Egreg); + } + if(n >= ERRLEN-1) + error(0, Etoobig); + if(n>=4 && strncmp(va, "sys:", 4)==0) + error(0, Ebadarg); + memcpy(buf, va, n); + buf[n] = 0; + if(!postnote(p, 0, buf, NUser)) + error(0, Enonote); + break; + default: + pprint("unknown qid in procwrite\n"); + error(0, Egreg); + } + unlock(&p->debug); + return n; +} + +void +procuserstr(Error *e, char *buf) +{ + consuserstr(e, buf); +} + +void +procerrstr(Error *e, char *buf) +{ + rooterrstr(e, buf); +} diff --git a/gnot/devroot.c b/gnot/devroot.c new file mode 100644 index 0000000000000000000000000000000000000000..ed9de4bbf8af8c554f09355e771da3ed228b2d92 --- /dev/null +++ b/gnot/devroot.c @@ -0,0 +1,140 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" +#include "devtab.h" + +enum{ + Qdir, + Qbin, + Qboot, + Qdev, + Qenv, + Qproc, +}; + +Dirtab rootdir[]={ + "bin", Qbin|CHDIR, 0, 0700, + "boot", Qboot, 0, 0700, + "dev", Qdev|CHDIR, 0, 0700, + "env", Qenv|CHDIR, 0, 0700, + "proc", Qproc|CHDIR, 0, 0700, +}; + +#define NROOT (sizeof rootdir/sizeof(Dirtab)) + +void +rootreset(void) +{ +} + +void +rootinit(void) +{ +} + +Chan* +rootattach(char *spec) +{ + return devattach('/', spec); +} + +Chan* +rootclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +rootwalk(Chan *c, char *name) +{ + return devwalk(c, name, rootdir, NROOT, devgen); +} + +void +rootstat(Chan *c, char *dp) +{ + devstat(c, dp, rootdir, NROOT, devgen); +} + +Chan* +rootopen(Chan *c, int omode) +{ + return devopen(c, omode, rootdir, NROOT, devgen); +} + +void +rootcreate(Chan *c, char *name, int omode, ulong perm) +{ + error(0, Eperm); +} + +/* + * sysremove() knows this is a nop + */ +void +rootclose(Chan *c) +{ +} + +#include "boot.h" + +long +rootread(Chan *c, void *buf, long n) +{ + + switch(c->qid & ~CHDIR){ + case Qdir: + return devdirread(c, buf, n, rootdir, NROOT, devgen); + + case Qboot: /* boot */ + if(c->offset >= sizeof bootcode) + return 0; + if(c->offset+n > sizeof bootcode) + n = sizeof bootcode - c->offset; + memcpy(buf, ((char*)bootcode)+c->offset, n); + return n; + + case Qdev: + return 0; + } + error(0, Egreg); + return 0; +} + +long +rootwrite(Chan *c, void *buf, long n) +{ + error(0, Egreg); +} + +void +rootremove(Chan *c) +{ + error(0, Eperm); +} + +void +rootwstat(Chan *c, char *dp) +{ + error(0, Eperm); +} + +void +rootuserstr(Error *e, char *buf) +{ + consuserstr(e, buf); +} + +#include "errstr.h" + +void +rooterrstr(Error *e, char *buf) +{ + if(e->code<0 || e->code>=sizeof errstrtab/sizeof(char*)) + strcpy(buf, "no such error"); + else + strcpy(buf, errstrtab[e->code]); +} diff --git a/gnot/devsrv.c b/gnot/devsrv.c new file mode 100644 index 0000000000000000000000000000000000000000..3a96b82499f77a20dc6b176bd45865f481e86716 --- /dev/null +++ b/gnot/devsrv.c @@ -0,0 +1,203 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +#include "devtab.h" + +typedef struct Srv Srv; +struct Srv{ + Lock; + char *name; + Chan **chan; +}srv; + +int +srvgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) +{ + + if(s >= conf.nsrv) + return -1; + if(srv.chan[s] == 0) + return 0; + devdir(c, s, &srv.name[s*NAMELEN], 0, 0666, dp); + return 1; +} + +void +srvinit(void) +{ +} + +void +srvreset(void) +{ + srv.chan = ialloc(conf.nsrv*sizeof(Chan*), 0); + srv.name = ialloc(conf.nsrv*NAMELEN, 0); +} + +Chan * +srvattach(char *spec) +{ + return devattach('s', spec); +} + +Chan * +srvclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +srvwalk(Chan *c, char *name) +{ + return devwalk(c, name, (Dirtab *)0, 0, srvgen); +} + +void +srvstat(Chan *c, char *db) +{ + devstat(c, db, (Dirtab *)0, 0L, srvgen); +} + +Chan * +srvopen(Chan *c, int omode) +{ + Chan *f; + + if(c->qid == CHDIR){ + if(omode != OREAD) + error(0, Eisdir); + c->mode = omode; + c->flag |= COPEN; + c->offset = 0; + return c; + } + lock(&srv); + if(waserror()){ + unlock(&srv); + nexterror(); + } + f = srv.chan[c->qid]; + if(f == 0) + error(0, Eshutdown); + if(omode&OTRUNC) + error(0, Eperm); + if(omode!=f->mode && f->mode!=ORDWR) + error(0, Eperm); + close(c); + incref(f); + unlock(&srv); + poperror(); + return f; +} + +void +srvcreate(Chan *c, char *name, int omode, ulong perm) +{ + int j, i; + + if(omode != OWRITE) + error(0, Eperm); + lock(&srv); + if(waserror()){ + unlock(&srv); + nexterror(); + } + j = -1; + for(i=0; iqid = j; + c->flag |= COPEN; + c->mode = OWRITE; +} + +void +srvremove(Chan *c) +{ + Chan *f; + + if(c->qid == CHDIR) + error(0, Eperm); + lock(&srv); + if(waserror()){ + unlock(&srv); + nexterror(); + } + f = srv.chan[c->qid]; + if(f == 0) + error(0, Eshutdown); + if(strcmp(&srv.name[c->qid*NAMELEN], "boot") == 0) + error(0, Eperm); + srv.chan[c->qid] = 0; + unlock(&srv); + poperror(); + close(f); +} + +void +srvwstat(Chan *c, char *dp) +{ + error(0, Egreg); +} + +void +srvclose(Chan *c) +{ +} + +long +srvread(Chan *c, void *va, long n) +{ + char *a = va; + + if(c->qid != CHDIR) + panic("srvread"); + return devdirread(c, a, n, (Dirtab *)0, 0L, srvgen); +} + +long +srvwrite(Chan *c, void *va, long n) +{ + int i, fd; + char buf[32]; + + i = c->qid; + if(srv.chan[i] != c) /* already been written to */ + error(0, Egreg); + if(n >= sizeof buf) + error(0, Egreg); + memcpy(buf, va, n); /* so we can NUL-terminate */ + buf[n] = 0; + fd = strtoul(buf, 0, 0); + fdtochan(fd, -1); /* error check only */ + srv.chan[i] = u->fd[fd]; + incref(u->fd[fd]); + return n; +} + +void +srverrstr(Error *e, char *buf) +{ + rooterrstr(e, buf); +} + +void +srvuserstr(Error *e, char *buf) +{ + consuserstr(e, buf); +} diff --git a/gnot/errno.h b/gnot/errno.h new file mode 100644 index 0000000000000000000000000000000000000000..9e8c2fb90810941ce401a6153144ce7a35f8e7aa --- /dev/null +++ b/gnot/errno.h @@ -0,0 +1,45 @@ +enum{ + Enevermind, /* never mind */ + Enofd, /* no free file descriptors */ + Ebadfd, /* fd out of range or not open */ + Ebadusefd, /* inappropriate use of fd */ + Ebadarg, /* bad arg in system call */ + Enonexist, /* file does not exist */ + Efilename, /* file name syntax */ + Ebadchar, /* bad character in file name */ + Ebadsharp, /* unknown device in # filename */ + Ebadexec, /* a.out header invalid */ + Eioload, /* i/o error in demand load */ + Eperm, /* permission denied */ + Enotdir, /* not a directory */ + Enochild, /* no living children */ + Enoseg, /* no free segments */ + Ebadmount, /* inconsistent mount */ + Enomount, /* mount table full */ + Enomntdev, /* no free mount devices */ + Eshutdown, /* mounted device shut down */ + Einuse, /* device or object already in use */ + Eio, /* i/o error */ + Eisdir, /* file is a directory */ + Ebaddirread, /* directory read not quantized */ + Esegaddr, /* illegal segment addresses or size */ + Enoenv, /* no free environment resources */ + Eprocdied, /* process exited */ + Enocreate, /* mounted directory forbids creation */ + Enotunion, /* attempt to union with non-mounted directory */ + Emount, /* inconsistent mount */ + Enosrv, /* no free server slots */ + Enoqueue, /* no free stream queues */ + Ebadld, /* illegal line discipline */ + Enostream, /* no free stream heads */ + Etoobig, /* read or write too large */ + Etoosmall, /* read or write too small */ + Ehungup, /* write to hungup stream */ + Ebadnet, /* illegal network address */ + Enoifc, /* no free nonet interface slots */ + Enodev, /* no free devices */ + Ebadctl, /* bad process control request */ + Enonote, /* note overflow */ + Eintr, /* interrupted */ + Egreg, /* it's all greg's fault */ +}; diff --git a/gnot/fault.c b/gnot/fault.c new file mode 100644 index 0000000000000000000000000000000000000000..614cc2a5745c3358ce1affd263480ea96fa3d145 --- /dev/null +++ b/gnot/fault.c @@ -0,0 +1,320 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "ureg.h" +#include "errno.h" + +#define FORMAT(ur) ((((ur)->vo)>>12)&0xF) +#define OFFSET(ur) (((ur)->vo)&0xFFF) + + +struct FFrame +{ + ushort ireg0; /* internal register */ + ushort ssw; /* special status word */ + ushort ipsc; /* instr. pipe stage c */ + ushort ipsb; /* instr. pipe stage b */ + ulong addr; /* data cycle fault address */ + ushort ireg1; /* internal register */ + ushort ireg2; /* internal register */ + ulong dob; /* data output buffer */ + ushort ireg3[4]; /* more stuff */ + ulong baddr; /* stage b address */ + ushort ireg4[26]; /* more more stuff */ +}; + +/* + * SSW bits + */ +#define RW 0x0040 /* read/write for data cycle */ +#define FC 0x8000 /* fault on stage C of instruction pipe */ +#define FB 0x4000 /* fault on stage B of instruction pipe */ +#define RC 0x2000 /* rerun flag for stage C of instruction pipe */ +#define RB 0x1000 /* rerun flag for stage B of instruction pipe */ +#define DF 0x0100 /* fault/rerun flag for data cycle */ +#define RM 0x0080 /* read-modify-write on data cycle */ +#define READ 0x0040 +#define WRITE 0x0000 +#define SIZ 0x0030 /* size code for data cycle */ +#define FC2 0x0004 /* address space for data cycle */ +#define FC1 0x0002 +#define FC0 0x0001 + +void +fault(Ureg *ur, FFrame *f) +{ + ulong addr, mmuvirt, mmuphys, n, badvaddr; + Seg *s; + PTE *opte, *pte, *npte; + Orig *o; + char *l; + Page *pg; + int zeroed = 0, head = 1; + int i, user, read, insyscall; + + if(u == 0) + panic("fault"); + insyscall = u->p->insyscall; + u->p->insyscall = 1; + if(f->ssw & DF) + addr = f->addr; + else if(FORMAT(ur) == 0xA){ + if(f->ssw & FC) + addr = ur->pc+2; + else if(f->ssw & FB) + addr = ur->pc+4; + else + panic("prefetch pagefault"); + }else if(FORMAT(ur) == 0xB){ + if(f->ssw & FC) + addr = f->baddr-2; + else if(f->ssw & FB) + addr = f->baddr; + else + panic("prefetch pagefault"); + }else + panic("prefetch format"); + badvaddr = addr; + addr &= ~(BY2PG-1); + user = !(ur->sr&SUPER); + if(f->ssw & DF) + read = (f->ssw&READ) && !(f->ssw&RM); + else + read = f->ssw&(FB|FC); + + s = seg(u->p, addr); + if(s == 0){ + if(addr>USTKTOP){ + cant: + u->p->state = MMUing; + if(user){ + pprint("user %s error addr=0x%lux\n", read? "read" : "write", badvaddr); + pprint("status=0x%lux pc=0x%lux sp=0x%lux\n", ur->sr, ur->pc, ur->sp); + pexit("Suicide", 0); + } + dumpregs(ur); + panic("fault"); + exit(); + } + s = &u->p->seg[SSEG]; + if(s->o==0 || addrmaxva-4*1024*1024 || addr>=s->maxva) + goto cant; + /* grow stack */ + o = s->o; + n = o->npte; + growpte(o, (s->maxva-addr)>>PGSHIFT); + /* stacks grown down, sigh */ + lock(o); + memcpy(o->pte+(o->npte-n), o->pte, n*sizeof(PTE)); + memset(o->pte, 0, (o->npte-n)*sizeof(PTE)); + unlock(o); + s->minva = addr; + o->va = addr; + }else + o = s->o; + if(!read && (o->flag&OWRPERM)==0) + goto cant; + lock(o); + opte = &o->pte[(addr-o->va)>>PGSHIFT]; + pte = opte; + if(s->mod){ + while(pte = pte->nextmod) /* assign = */ + if(pte->proc == u->p){ + if(pte->page==0 || pte->page->va!=addr) + panic("bad page %lux", pte->page); + head = 0; + break; + } + if(pte == 0) + pte = opte; + } + if(pte->page == 0){ + if(o->chan==0 || addr>(o->va+(o->maxca-o->minca))){ + /* + * Zero fill page. If we are really doing a copy-on-write + * (e.g. into shared bss) we'll move the page later. + */ + pte->page = newpage(0, o, addr); + o->npage++; + zeroed = 1; + }else{ + /* + * Demand load. Release o because it could take a while. + */ + unlock(o); + n = (o->va+(o->maxca-o->minca)) - addr; + if(n > BY2PG) + n = BY2PG; + pg = newpage(1, o, addr); + qlock(o->chan); + if(waserror()){ + print("demand load i/o error %d\n", u->error.code); + qunlock(o->chan); + pg->o = 0; + pg->ref--; + goto cant; + } + o->chan->offset = (addr-o->va) + o->minca; + l = (char*)(pg->pa|KZERO); + if((*devtab[o->chan->type].read)(o->chan, l, n) != n) + error(0, Eioload); + qunlock(o->chan); + poperror(); + /* BUG: if was first page of bss, move to data */ + if(npte[(addr-s->minva)>>PGSHIFT]; /* could move */ + pte = opte; + if(pte->page == 0){ + pte->page = pg; + o->npage++; + }else{ /* someone beat us to it */ + pg->o = 0; + pg->ref--; + } + } + } + /* + * Copy on reference + */ + if((o->flag & OWRPERM) + && ((head && ((o->flag&OPURE) || o->nproc>1)) + || (!head && pte->page->ref>1))){ + + /* + * Look for the easy way out: are we the last non-modified? + */ + if(head && !(o->flag&OPURE)){ + npte = opte; + for(i=0; npte; i++) + npte = npte->nextmod; + if(i == o->nproc) + goto easy; + } + if(head){ + /* + * Add to mod list + */ + pte = newmod(); + pte->proc = u->p; + pte->page = opte->page; + pte->page->ref++; + o->npage++; + /* + * Link into opte mod list (same va) + */ + pte->nextmod = opte->nextmod; + opte->nextmod = pte; + /* + * Link into proc mod list (increasing va) + */ + npte = s->mod; + if(npte == 0){ + s->mod = pte; + pte->nextva = 0; + }else{ + while(npte->nextva && npte->nextva->page->vanextva; + pte->nextva = npte->nextva; + npte->nextva = pte; + } + head = 0; + } + pg = pte->page; + if(zeroed){ /* move page */ + pg->ref--; + o->npage--; + opte->page = 0; + }else{ /* copy page */ + pte->page = newpage(1, o, addr); + memcpy((void*)(pte->page->pa|KZERO), (void*)(pg->pa|KZERO), BY2PG); + if(pg->ref <= 1) + panic("pg->ref <= 1"); + pg->ref--; + } + easy: + mmuphys = 0; + }else{ + mmuphys = PTERONLY; + if(o->flag & OWRPERM) + if(o->flag & OPURE){ + if(!head && pte->page->ref==1) + mmuphys = 0; + }else + if((head && o->nproc==1) + || (!head && pte->page->ref==1)) + mmuphys = 0; + } + mmuvirt = addr; + mmuphys |= PPN(pte->page->pa) | PTEVALID; + usepage(pte->page, 1); + if(pte->page->va != addr) + panic("wrong addr in tail %lux %lux", pte->page->va, addr); + if(pte->proc && pte->proc != u->p){ + print("wrong proc in tail %d %s\n", head, u->p->text); + print("u->p %lux pte->proc %lux\n", u->p, pte->proc); + panic("addr %lux seg %d wrong proc in tail", addr, s-u->p->seg); + } + unlock(o); + putmmu(mmuvirt, mmuphys); + u->p->insyscall = insyscall; +} + +/* + * Called only in a system call + */ +void +validaddr(ulong addr, ulong len, int write) +{ + Seg *s; + + if((long)len < 0) + panic("validaddr len %lux\n", len); + s = seg(u->p, addr); + if(s==0 || addr+len>s->maxva || (write && (s->o->flag&OWRPERM)==0)){ + 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); + } +} + +/* + * &s[0] is known to be a valid address. + */ +void* +vmemchr(void *s, int c, int n) +{ + int m; + char *t; + ulong a; + + a = (ulong)s; + m = BY2PG - (a & (BY2PG-1)); + if(m < n){ + t = vmemchr(s, c, m); + if(t) + return t; + if(!(a & KZERO)) + validaddr(a+m, 1, 0); + return vmemchr((void*)(a+m), c, n-m); + } + /* + * All in one page + */ + return memchr(s, c, n); +} + +Seg* +seg(Proc *p, ulong addr) +{ + int i; + Seg *s; + + for(i=0,s=p->seg; io && s->minva<=addr && addrmaxva) + return s; + return 0; +} diff --git a/gnot/fcall.c b/gnot/fcall.c new file mode 100644 index 0000000000000000000000000000000000000000..e51e1bf54209e17ab16d4393874cc878d988f175 --- /dev/null +++ b/gnot/fcall.c @@ -0,0 +1,379 @@ +#include +#include "lib.h" +#include "fcall.h" + +#define CHAR(x) *p++ = f->x +#define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2 +#define LONG(x) p[0] = f->x; p[1] = f->x>>8; p[2] = f->x>>16; p[3] = f->x>>24; p += 4 +#define VLONG(x) p[0] = f->x; p[1] = f->x>>8; p[2] = f->x>>16; p[3] = f->x>>24;\ + p[4] = 0; p[5] = 0; p[6] = 0; p[7] = 0; p += 8 +#define STRING(x,n) memcpy(p, f->x, n); p += n + +int +convS2M(Fcall *f, char *ap) +{ + uchar *p; + + p = (uchar*)ap; + CHAR(type); + switch(f->type) + { + default: + print("bad type: %d\n", f->type); + return 0; + + case Tnop: + case Rnop: + break; + + case Tsession: + CHAR(lang); + break; + + case Tattach: + SHORT(fid); + STRING(uname, sizeof(f->uname)); + STRING(aname, sizeof(f->aname)); + break; + + case Tclone: + SHORT(fid); + SHORT(newfid); + break; + + case Twalk: + case Tremove: + SHORT(fid); + STRING(name, sizeof(f->name)); + break; + + case Topen: + SHORT(fid); + CHAR(mode); + break; + + case Tcreate: + SHORT(fid); + STRING(name, sizeof(f->name)); + LONG(perm); + CHAR(mode); + break; + + case Toread: + case Tread: + SHORT(fid); + VLONG(offset); + SHORT(count); + break; + + case Towrite: + SHORT(fid); + VLONG(offset); + SHORT(count); + STRING(data, f->count); + break; + + case Twrite: + SHORT(fid); + VLONG(offset); + SHORT(count); + p++; + STRING(data, f->count); + break; + + case Tclunk: + case Tstat: + SHORT(fid); + break; + + case Twstat: + SHORT(fid); + STRING(stat, sizeof(f->stat)); + break; + + case Terrstr: + SHORT(fid); + SHORT(err); + break; + + case Tuserstr: + SHORT(fid); + SHORT(uid); + break; +/* + */ + case Rsession: + SHORT(err); + break; + + case Rclone: + case Rclunk: + case Rremove: + case Rwstat: + SHORT(fid); + SHORT(err); + break; + + case Rwalk: + case Rattach: + case Ropen: + case Rcreate: + SHORT(fid); + SHORT(err); + LONG(qid); + break; + + case Roread: + SHORT(fid); + SHORT(err); + SHORT(count); + STRING(data, f->count); + break; + + case Rread: + SHORT(fid); + SHORT(err); + SHORT(count); + p++; + STRING(data, f->count); + break; + + case Rowrite: + case Rwrite: + SHORT(fid); + SHORT(err); + SHORT(count); + break; + + case Rstat: + SHORT(fid); + SHORT(err); + STRING(stat, sizeof(f->stat)); + break; + + case Rerrstr: + SHORT(fid); + SHORT(err); + STRING(ename, sizeof(f->ename)); + break; + + case Ruserstr: + SHORT(fid); + SHORT(err); + STRING(uname, sizeof(f->uname)); + break; + } + return p - (uchar*)ap; +} + +int +convD2M(Dir *f, char *ap) +{ + uchar *p; + + p = (uchar*)ap; + STRING(name, sizeof(f->name)); + LONG(qid); + p += 4; + LONG(mode); + LONG(atime); + LONG(mtime); + VLONG(length); + SHORT(uid); + SHORT(gid); + SHORT(type); + SHORT(dev); + return p - (uchar*)ap; +} + +#undef CHAR +#undef SHORT +#undef LONG +#undef VLONG +#undef STRING + +#define CHAR(x) f->x = *p++ +#define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2 +#define LONG(x) f->x = (p[0] | (p[1]<<8) |\ + (p[2]<<16) | (p[3]<<24)); p += 4 +#define VLONG(x) f->x = (p[0] | (p[1]<<8) |\ + (p[2]<<16) | (p[3]<<24)); p += 8 +#define STRING(x,n) memcpy(f->x, p, n); p += n + +int +convM2S(char *ap, Fcall *f, int n) +{ + uchar *p; + + p = (uchar*)ap; + CHAR(type); + switch(f->type) + { + default: + print("bad type: %d\n", f->type); + return 0; + + case Tnop: + case Rnop: + break; + + case Tsession: + CHAR(lang); + break; + + case Tattach: + SHORT(fid); + STRING(uname, sizeof(f->uname)); + STRING(aname, sizeof(f->aname)); + break; + + case Tclone: + SHORT(fid); + SHORT(newfid); + break; + + case Twalk: + case Tremove: + SHORT(fid); + STRING(name, sizeof(f->name)); + break; + + case Topen: + SHORT(fid); + CHAR(mode); + break; + + case Tcreate: + SHORT(fid); + STRING(name, sizeof(f->name)); + LONG(perm); + CHAR(mode); + break; + + case Toread: + case Tread: + SHORT(fid); + VLONG(offset); + SHORT(count); + break; + + case Towrite: + SHORT(fid); + VLONG(offset); + SHORT(count); + f->data = (char*)p; p += f->count; + break; + + case Twrite: + SHORT(fid); + VLONG(offset); + SHORT(count); + p++; + f->data = (char*)p; p += f->count; + break; + + case Tclunk: + case Tstat: + SHORT(fid); + break; + + case Twstat: + SHORT(fid); + STRING(stat, sizeof(f->stat)); + break; + + case Terrstr: + SHORT(fid); + SHORT(err); + break; + + case Tuserstr: + SHORT(fid); + SHORT(uid); + break; + + case Rsession: + SHORT(err); + break; + + case Rclone: + case Rclunk: + case Rremove: + case Rwstat: + SHORT(fid); + SHORT(err); + break; + + case Rwalk: + case Rattach: + case Ropen: + case Rcreate: + SHORT(fid); + SHORT(err); + LONG(qid); + break; + + case Roread: + SHORT(fid); + SHORT(err); + SHORT(count); + f->data = (char*)p; p += f->count; + break; + + case Rread: + SHORT(fid); + SHORT(err); + SHORT(count); + p++; + f->data = (char*)p; p += f->count; + break; + + case Rowrite: + case Rwrite: + SHORT(fid); + SHORT(err); + SHORT(count); + break; + + case Rstat: + SHORT(fid); + SHORT(err); + STRING(stat, sizeof(f->stat)); + break; + + case Rerrstr: + SHORT(fid); + SHORT(err); + STRING(ename, sizeof(f->ename)); + break; + + case Ruserstr: + SHORT(fid); + SHORT(err); + STRING(uname, sizeof(f->uname)); + break; + } + if((uchar*)ap+n == p) + return n; + return 0; +} + +int +convM2D(char *ap, Dir *f) +{ + uchar *p; + + p = (uchar*)ap; + STRING(name, sizeof(f->name)); + LONG(qid); + p += 4; + LONG(mode); + LONG(atime); + LONG(mtime); + VLONG(length); + SHORT(uid); + SHORT(gid); + SHORT(type); + SHORT(dev); + return p - (uchar*)ap; +} diff --git a/gnot/fcall.h b/gnot/fcall.h new file mode 100644 index 0000000000000000000000000000000000000000..a61e67b833ffd0ff566cfd35cde4c1012acd0583 --- /dev/null +++ b/gnot/fcall.h @@ -0,0 +1,89 @@ +typedef struct Fcall Fcall; + +struct Fcall +{ + char type; + short fid; + short err; + union + { + struct + { + short uid; /* T-Userstr */ + short newfid; /* T-Clone */ + char lang; /* T-Session */ + ulong qid; /* R-Attach, R-Walk, R-Open, R-Create */ + }; + struct + { + char uname[28]; /* T-Attach, R-Userstr */ + char aname[28]; /* T-Attach */ + }; + struct + { + char ename[64]; /* R-Errstr */ + }; + struct + { + long perm; /* T-Create */ + char name[28]; /* T-Walk, T-Create, T-Remove */ + char mode; /* T-Create, T-Open */ + }; + struct + { + long offset; /* T-Read, T-Write */ + long count; /* T-Read, T-Write, R-Read */ + char *data; /* T-Write, R-Read */ + }; + struct + { + char stat[DIRLEN]; /* T-Wstat, R-Stat */ + }; + }; +}; + +#define MAXFDATA 8192 + +enum +{ + Tnop = 0, + Rnop, + Tsession = 2, + Rsession, + Tattach = 10, + Rattach, + Tclone = 12, + Rclone, + Twalk = 14, + Rwalk, + Topen = 16, + Ropen, + Tcreate = 18, + Rcreate, + Toread = 20, + Roread, + Towrite = 22, + Rowrite, + Tclunk = 24, + Rclunk, + Tremove = 26, + Rremove, + Tstat = 28, + Rstat, + Twstat = 30, + Rwstat, + Terrstr = 32, + Rerrstr, + Tuserstr = 34, + Ruserstr, + Tread = 36, + Rread, + Twrite = 38, + Rwrite, +}; + +int convM2S(char*, Fcall*, int); +int convS2M(Fcall*, char*); + +int convM2D(char*, Dir*); +int convD2M(Dir*, char*); diff --git a/gnot/fns.h b/gnot/fns.h new file mode 100644 index 0000000000000000000000000000000000000000..09fe8a007972594635665408aabaf4ca2dfeaaf1 --- /dev/null +++ b/gnot/fns.h @@ -0,0 +1,141 @@ +Alarm *alarm(int, void (*)(Alarm*), void*); +void alarminit(void); +Block *allocb(ulong); +void append(List**, List*); +void cancel(Alarm*); +int canlock(Lock*); +void chaninit(void); +void chandevreset(void); +void chandevinit(void); +void clock(Ureg*); +Chan *clone(Chan*, Chan*); +void close(Chan*); +void closemount(Mount*); +void closepgrp(Pgrp*); +long clrfpintr(void); +void compactpte(Orig*, ulong); +void confinit(void); +Env *copyenv(Env*, int); +int decref(Ref*); +void delay(int); +void delete(List**, List*, List*); +void delete0(List**, List*); +Chan *devattach(int, char*); +Chan *devclone(Chan*, Chan*); +void devdir(Chan*, long, char*, long, long, Dir*); +long devdirread(Chan*, char*, long, Dirtab*, int, Devgen*); +Devgen devgen; +int devno(int, int); +Chan* devopen(Chan*, int, Dirtab*, int, Devgen*); +void devstat(Chan*, char*, Dirtab*, int, Devgen*); +int devwalk(Chan*, char*, Dirtab*, int, Devgen*); +void dumpregs(Ureg*); +void dumpstack(void); +int eqchan(Chan*, Chan*, long); +void envpgclose(Env *); +void error(Chan*, int); +void exit(void); +void fault(Ureg*, FFrame*); +Chan* fdtochan(int, int); +void firmware(void); +void flowctl(Queue*); +void flushcpucache(void); +void flushmmu(void); +void forkmod(Seg*, Seg*, Proc*); +void freeb(Block*); +void freepage(Orig*); +void freepte(Orig*); +void freesegs(int); +void freealarm(Alarm*); +Block *getq(Queue *); +void gotolabel(Label*); +void growpte(Orig*, ulong); +void *ialloc(ulong, int); +int incref(Ref*); +void insert(List**, List*, List*); +void isdir(Chan*); +void kbdchar(int); +void lock(Lock*); +void lockinit(void); +Orig *lookorig(ulong, ulong, int, Chan*); +void machinit(void); +void mapstack(Proc*); +void mmuinit(void); +int mount(Chan*, Chan*, int); +Chan *namec(char*, int, int, ulong); +void nexterror(void); +Alarm *newalarm(void); +Chan *newchan(void); +PTE *newmod(void); +Mount *newmount(void); +Orig *neworig(ulong, ulong, int, Chan*); +Page *newpage(int, Orig*, ulong); +Pgrp *newpgrp(void); +Proc *newproc(void); +char *nextelem(char*, char*); +void nullput(Queue*, Block*); +int openmode(ulong); +void pageinit(void); +void panic(char*, ...); +void pexit(char*, int); +void pgrpcpy(Pgrp*, Pgrp*); +void pgrpinit(void); +int postnote(Proc*, int, char*, int); +int pprint(char*, ...); +void printinit(void); +void printslave(void); +void procinit0(void); +Proc *proctab(int); +void putkmmu(ulong, ulong); +void putmmu(ulong, ulong); +int putq(Queue*, Block*); +void putstr(char*); +void putstrn(char*, long); +ulong pwait(Waitmsg*); +int readnum(ulong, char*, ulong, ulong, int); +void ready(Proc*); +void rooterrstr(Error*, char*); +void qlock(QLock*); +void qunlock(QLock*); +void restartprint(Alarm*); +void restfpregs(FPsave*); +Proc *runproc(void); +void savefpregs(FPsave*); +void sched(void); +void schedinit(void); +void screeninit(void); +void screenputc(int); +long seconds(void); +Seg *seg(Proc*, ulong); +int segaddr(Seg*, ulong, ulong); +int setlabel(Label*); +char* skipslash(char*); +void sleep(Rendez*, int(*)(void*), void*); +int splhi(void); +int spllo(void); +void splx(int); +Devgen streamgen; +void streamclose(Chan*); +void streaminit(void); +long streamread(Chan*, void*, long); +long streamwrite(Chan*, void*, long); +Stream* streamnew(Chan*, Qinfo*); +void streamopen(Chan*, Qinfo*); +int streamparse(char*, Block*); +long syscall(Ureg*); +int tas(char*); +void touser(void); +void tsleep(Rendez*, int (*)(void*), void*, int); +void twakeme(Alarm*); +void unlock(Lock*); +void usepage(Page*, int); +void userinit(void); +void validaddr(ulong, ulong, int); +void* vmemchr(void*, int, int); +void wakeme(Alarm*); +void wakeup(Rendez*); + +#define waserror() (u->nerrlab++, setlabel(&u->errlab[u->nerrlab-1])) +#define poperror() u->nerrlab-- + +#define evenaddr(x) /* 68020 doesn't care */ diff --git a/gnot/io.h b/gnot/io.h new file mode 100644 index 0000000000000000000000000000000000000000..f04df77d907dafe1e1fc58536f7f9105a3092ed0 --- /dev/null +++ b/gnot/io.h @@ -0,0 +1,5 @@ +typedef struct Duart Duart; + +#define SYNCREG ((char*)0x40400000) +#define DISPLAYRAM 0x02000000 +#define DUARTREG ((Duart*)0x40100000) diff --git a/gnot/l.s b/gnot/l.s new file mode 100644 index 0000000000000000000000000000000000000000..bbed84bb26c26a36eb280d8b62980310c15cad63 --- /dev/null +++ b/gnot/l.s @@ -0,0 +1,265 @@ +#include "mem.h" + +/* + * Boot first processor + */ +TEXT start(SB), $-4 + + MOVW $(SUPER|SPL(7)), SR + MOVL $0, R0 + MOVL R0, CACR + MOVL R0, TACADDR + MOVL $a6base(SB), A6 + + MOVL $mach0(SB), A0 + MOVL A0, m(SB) + MOVL $0, 0(A0) + MOVL A0, A7 + ADDL $(MACHSIZE-4), A7 + MOVL $0, u(SB) + + MOVL $vectors(SB), A0 + MOVL A0, VBR + + BSR main(SB) + /* never returns */ +dead: + BRA dead + +/* + * Take first processor into user mode + */ + +TEXT touser(SB), $-4 + + MOVL $(USERADDR+BY2PG), A7 + MOVW $0, -(A7) + MOVL $(UTZERO+32), -(A7) /* header is in text */ + MOVW $0, -(A7) + MOVL $(USTKTOP-4*BY2WD), A0 + MOVL A0, USP + MOVW $(SUPER|SPL(0)), SR + MOVL $8, R0 + MOVL R0, CACR + RTE + +TEXT splhi(SB), $0 + + MOVL $0, R0 + MOVW SR, R0 + MOVW $(SUPER|SPL(7)), SR + RTS + +TEXT spllo(SB), $0 + + MOVL $0, R0 + MOVW SR, R0 + MOVW $(SUPER|SPL(0)), SR + RTS + +TEXT splx(SB), $0 + + MOVL sr+0(FP), R0 + MOVW R0, SR + RTS + + +TEXT flushcpucache(SB), $0 + + MOVL $(CCLEAR|CENABLE), R0 + MOVL R0, CACR + RTS + +TEXT setlabel(SB), $0 + + MOVL sr+0(FP), A0 + MOVL A7, (A0)+ /* stack pointer */ + MOVL (A7), (A0)+ /* pc of caller */ + MOVW SR, (A0)+ /* status register */ + CLRL R0 /* ret 0 => not returning */ + RTS + +TEXT gotolabel(SB), $0 + + MOVL p+0(FP), A0 + MOVW $(SUPER|SPL(7)), SR + MOVL (A0)+, A7 /* stack pointer */ + MOVL (A0)+, (A7) /* pc; stuff into stack frame */ + MOVW (A0)+, R0 /* status register */ + MOVW R0, SR + MOVL $1, R0 /* ret 1 => returning */ + RTS + +/* + * Test and set, as a subroutine + */ + +TEXT tas(SB), $0 + + MOVL $0, R0 + MOVL a+0(FP), A0 + TAS (A0) + BEQ tas_1 + MOVL $1, R0 +tas_1: + RTS + +TEXT illegal(SB), $0 + + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0xFFFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR trap(SB) + ADDL $4, A7 + MOVL ((8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVEM (A7), $0xFFFF + ADDL $((8+8+1)*4), A7 + RTE + +TEXT systrap(SB), $0 + + SUBL $((8+8+1)*BY2WD), A7 + MOVL A6, ((8+6)*BY2WD)(A7) + MOVL R0, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR syscall(SB) + MOVL ((1+8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVL ((1+8+6)*BY2WD)(A7), A6 + ADDL $((1+8+8+1)*4), A7 + RTE + +TEXT buserror(SB), $0 + + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0xFFFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + PEA ((8+8+1+2)*BY2WD)(A7) + PEA 4(A7) + BSR fault(SB) + ADDL $8, A7 + MOVL ((8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVEM (A7), $0xFFFF + ADDL $((8+8+1)*4), A7 + RTE + +TEXT tacintr(SB), $0 /* level 1 */ + + MOVL R0, -(A7) + MOVL TACADDR, R0 + ADDL $4, A7 + RTE + +TEXT dkintr(SB), $0 /* level 2 */ + + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0xFFFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR inconintr(SB) + ADDL $4, A7 + MOVL ((8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVEM (A7), $0xFFFF + ADDL $((8+8+1)*4), A7 + RTE + +TEXT mouseintr(SB), $0 /* level 4 */ + + MOVEM $0x8082, -(A7) /* D0, A0, A6 */ + MOVL $a6base(SB), A6 + MOVL $15, R0 /* mask off hex switch */ + ANDB MOUSE,R0 /* clears quadrature interrupt */ + LEA mousetab(SB)(R0.W*8), A0 +#ifdef asdf + MOVL (A0)+, R0 + ADDL R0, mousedx(SB) + MOVL (A0), R0 + ADDL R0, mousedy(SB) + ADDL $1, mousechanged(SB) + ADDL $1, dotrack(SB) +#endif + MOVEM (A7)+, $0x4101 + RTE + +TEXT uartintr(SB), $0 /* level 5 */ + + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0xFFFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR duartintr(SB) + ADDL $4, A7 + MOVL ((8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVEM (A7), $0xFFFF + ADDL $((8+8+1)*4), A7 + RTE + +TEXT syncintr(SB), $0 /* level 6 */ + + SUBL $((8+8+1)*BY2WD), A7 + MOVEM $0xFFFF, (A7) + MOVL $a6base(SB), A6 + MOVL USP, A0 + MOVL A0, ((8+8)*BY2WD)(A7) + MOVL A7, -(A7) + BSR clock(SB) + ADDL $4, A7 + MOVL ((8+8)*BY2WD)(A7), A0 + MOVL A0, USP + MOVEM (A7), $0xFFFF + ADDL $((8+8+1)*4), A7 + RTE + +GLOBL mousetab(SB), $128 +DATA mousetab+ 0(SB)/4, -1 /* x down, */ +DATA mousetab+ 4(SB)/4, 1 /* y up */ +DATA mousetab+ 8(SB)/4, 0 /* x - */ +DATA mousetab+ 12(SB)/4, 1 /* y up */ +DATA mousetab+ 16(SB)/4, 1 /* x up */ +DATA mousetab+ 20(SB)/4, 1 /* y up */ +DATA mousetab+ 24(SB)/4, 0 /* x - */ +DATA mousetab+ 28(SB)/4, 1 /* y up */ +DATA mousetab+ 32(SB)/4, -1 /* x down */ +DATA mousetab+ 36(SB)/4, 0 /* y - */ +DATA mousetab+ 40(SB)/4, 0 /* x - */ +DATA mousetab+ 44(SB)/4, 0 /* y - */ +DATA mousetab+ 48(SB)/4, 1 /* x up, */ +DATA mousetab+ 52(SB)/4, 0 /* y - */ +DATA mousetab+ 56(SB)/4, 0 /* x - */ +DATA mousetab+ 60(SB)/4, 0 /* y - */ +DATA mousetab+ 64(SB)/4, -1 /* x down */ +DATA mousetab+ 68(SB)/4, -1 /* y down */ +DATA mousetab+ 72(SB)/4, 0 /* x - */ +DATA mousetab+ 76(SB)/4, -1 /* y down */ +DATA mousetab+ 80(SB)/4, 1 /* x up */ +DATA mousetab+ 84(SB)/4, -1 /* y down */ +DATA mousetab+ 88(SB)/4, 0 /* x - */ +DATA mousetab+ 92(SB)/4, -1 /* y down */ +DATA mousetab+ 96(SB)/4, -1 /* x down */ +DATA mousetab+100(SB)/4, 0 /* y - */ +DATA mousetab+104(SB)/4, 0 /* x - */ +DATA mousetab+108(SB)/4, 0 /* y - */ +DATA mousetab+112(SB)/4, 1 /* x up */ +DATA mousetab+116(SB)/4, 0 /* y - */ +DATA mousetab+120(SB)/4, 0 /* x - */ +DATA mousetab+124(SB)/4, 0 /* y - */ + +GLOBL mach0+0(SB), $MACHSIZE +GLOBL u(SB), $4 +GLOBL m(SB), $4 diff --git a/gnot/lib.h b/gnot/lib.h new file mode 100644 index 0000000000000000000000000000000000000000..441389b966e862cee396bb6a6b37436f05762c3e --- /dev/null +++ b/gnot/lib.h @@ -0,0 +1,109 @@ +/* + * functions (possibly) linked in, complete, from libc. + */ + +/* + * mem routines + */ +extern void *memccpy(void*, void*, int, long); +extern void *memset(void*, int, long); +extern int memcmp(void*, void*, long); +extern void *memcpy(void*, void*, long); +extern void *memchr(void*, int, long); + +/* + * string routines + */ +extern char *strcat(char*, char*); +extern char *strchr(char*, char); +extern int strcmp(char*, char*); +extern char *strcpy(char*, char*); +extern char *strncat(char*, char*, long); +extern char *strncpy(char*, char*, long); +extern int strncmp(char*, char*, long); +extern long strlen(char*); + +/* + * print routines + */ + +#define FUNSIGN 4 +#define FSHORT 2 +#define FLONG 1 + +typedef struct Op Op; +struct Op +{ + char *p; + char *ep; + void *argp; + int f1; + int f2; + int f3; +}; +extern void strconv(char*, Op*, int, int); +extern int numbconv(Op*, int); +extern char *donprint(char*, char*, char*, void*); +extern int fmtinstall(char, int (*)(Op*)); +extern int sprint(char*, char*, ...); +extern int print(char*, ...); + +/* + * one-of-a-kind + */ +extern long strtol(char*, char**, int); +extern ulong strtoul(char*, char**, int); +extern long end; + +/* + * Syscall data structures + */ + +#define MORDER 0x0003 /* mask for bits defining order of mounting */ +#define MREPL 0x0000 /* mount replaces object */ +#define MBEFORE 0x0001 /* mount goes before others in union directory */ +#define MAFTER 0x0002 /* mount goes after others in union directory */ +#define MCREATE 0x0004 /* permit creation in mounted directory */ +#define MMASK 0x0007 /* all bits on */ + +#define OREAD 0 /* open for read */ +#define OWRITE 1 /* write */ +#define ORDWR 2 /* read and write */ +#define OEXEC 3 /* execute, == read but check execute permission */ +#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */ + +typedef struct Error Error; +typedef struct Dir Dir; +typedef struct Waitmsg Waitmsg; + +struct Error +{ + int type; + int dev; + int code; +}; + +#define ERRLEN 64 +#define DIRLEN 64 +#define NAMELEN 28 +struct Dir +{ + char name[NAMELEN]; + long qid; + long mode; + long atime; + long mtime; + Length; + short uid; + short gid; + short type; + short dev; +}; + +struct Waitmsg +{ + int pid; /* of loved one */ + int status; /* unused; a placeholder */ + ulong time[3]; /* of loved one */ + char msg[ERRLEN]; +}; diff --git a/gnot/lock.c b/gnot/lock.c new file mode 100644 index 0000000000000000000000000000000000000000..2a53ee561c45ed1adda7ab19a1bbdbf1e5804578 --- /dev/null +++ b/gnot/lock.c @@ -0,0 +1,86 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +void +lock(Lock *l) +{ + int i; + + /* + * Try the fast grab first + */ + if(tas(l->key) == 0){ + l->pc = ((ulong*)&l)[-1]; + return; + } + for(i=0; i<10000000; i++) + if(tas(l->key) == 0){ + l->pc = ((ulong*)&l)[-1]; + return; + } + l->key[0] = 0; + panic("lock loop %lux pc %lux held by pc %lux\n", l, ((ulong*)&l)[-1], l->pc); +} + +int +canlock(Lock *l) +{ + if(tas(l->key) == 0){ + l->pc = ((ulong*)&l)[-1]; + return 1; + } + return 0; +} + +void +unlock(Lock *l) +{ + l->pc = 0; + l->key[0] = 0; +} + +void +qlock(QLock *q) +{ + Proc *p; + + if(canlock(&q->use)) + return; + lock(&q->queue); + if(canlock(&q->use)){ + unlock(&q->queue); + return; + } + p = q->tail; + if(p == 0) + q->head = u->p; + else + p->qnext = u->p; + q->tail = u->p; + u->p->qnext = 0; + u->p->state = Queueing; + unlock(&q->queue); + sched(); +} + +void +qunlock(QLock *q) +{ + Proc *p; + + lock(&q->queue); + if(q->head){ + p = q->head; + q->head = p->qnext; + if(q->head == 0) + q->tail = 0; + unlock(&q->queue); + ready(p); + }else{ + unlock(&q->use); + unlock(&q->queue); + } +} diff --git a/gnot/main.c b/gnot/main.c new file mode 100644 index 0000000000000000000000000000000000000000..caf53f1d31d5ba46300570763987c8671a9652a5 --- /dev/null +++ b/gnot/main.c @@ -0,0 +1,235 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" +#include "init.h" + +void +main(void) +{ + Lock l; + machinit(); + mmuinit(); + confinit(); + printinit(); + flushmmu(); + procinit0(); + pgrpinit(); + chaninit(); + alarminit(); + chandevreset(); + streaminit(); + pageinit(); + userinit(); + schedinit(); +} + +void +machinit(void) +{ + int n; + + n = m->machno; + memset(m, 0, sizeof(Mach)); + m->machno = n; + m->mmask = 1<machno; +} + +void +mmuinit(void) +{ + ulong l, d, i; + + /* + * Invalidate user addresses + */ + for(l=0; l<4*1024*1024; l+=BY2PG) + putmmu(l, INVALIDPTE); + /* + * Two meg of usable memory + */ + for(i=1,l=KTZERO; i<2*1024*1024/BY2PG; l+=BY2PG,i++) + putkmmu(l, PPN(l)|PTEVALID|PTEKERNEL); + /* + * Screen at two meg + */ + for(i=0,d=DISPLAYRAM; i<256*1024/BY2PG; d+=BY2PG,l+=BY2PG,i++) + putkmmu(l, PPN(d)|PTEVALID|PTEKERNEL); +} + +void +init0(void) +{ + m->proc = u->p; + u->p->state = Running; + u->p->mach = m; + spllo(); + chandevinit(); + + u->slash = (*devtab[0].attach)(0); + u->dot = clone(u->slash, 0); + + touser(); +} + +FPsave initfp; + +void +userinit(void) +{ + Proc *p; + Seg *s; + User *up; + + p = newproc(); + p->pgrp = newpgrp(); + strcpy(p->text, "*init*"); + strcpy(p->pgrp->user, "bootes"); +/* savefpregs(&initfp); /**/ +/* p->fpstate = FPinit; /**/ + + /* + * Kernel Stack + */ + p->sched.pc = (ulong)init0; + p->sched.sp = USERADDR+BY2PG-20; /* BUG */ + p->sched.sr = SUPER|SPL(7); + p->upage = newpage(0, 0, USERADDR|(p->pid&0xFFFF)); + + /* + * User + */ + up = (User*)(p->upage->pa|KZERO); + up->p = p; + + /* + * User Stack + */ + s = &p->seg[SSEG]; + s->proc = p; + s->o = neworig(USTKTOP-BY2PG, 1, OWRPERM, 0); + s->minva = USTKTOP-BY2PG; + s->maxva = USTKTOP; + + /* + * Text + */ + s = &p->seg[TSEG]; + s->proc = p; + s->o = neworig(UTZERO, 1, 0, 0); + s->o->pte[0].page = newpage(0, 0, UTZERO); + memcpy((ulong*)(s->o->pte[0].page->pa|KZERO), initcode, sizeof initcode); + s->minva = UTZERO; + s->maxva = UTZERO+BY2PG; + + ready(p); +} + +void +exit(void) +{ + int i; + + u = 0; + splhi(); + print("exiting\n"); + for(;;) + ; +} + +/* + * Insert new into list after where + */ +void +insert(List **head, List *where, List *new) +{ + if(where == 0){ + new->next = *head; + *head = new; + }else{ + new->next = where->next; + where->next = new; + } + +} + +/* + * Insert new into list at end + */ +void +append(List **head, List *new) +{ + List *where; + + where = *head; + if(where == 0) + *head = new; + else{ + while(where->next) + where = where->next; + where->next = new; + } + new->next = 0; +} + +/* + * Delete old from list + */ +void +delete0(List **head, List *old) +{ + List *l; + + l = *head; + if(l == old){ + *head = old->next; + return; + } + while(l->next != old) + l = l->next; + l->next = old->next; +} + +/* + * Delete old from list. where->next is known to be old. + */ +void +delete(List **head, List *where, List *old) +{ + if(where == 0){ + *head = old->next; + return; + } + where->next = old->next; +} + +Conf conf; + +void +confinit(void) +{ + conf.nmach = 1; + if(conf.nmach > MAXMACH) + panic("confinit"); + conf.nproc = 15; + conf.npgrp = 15; + conf.npage = (2*1024*1024)/BY2PG; + conf.npte = 500; + conf.nmod = 50; + conf.nalarm = 50; + conf.norig = 50; + conf.nchan = 100; + conf.nenv = 50; + conf.nenvchar = 4000; + conf.npgenv = 100; + conf.nmtab = 50; + conf.nmount = 100; + conf.nmntdev = 5; + conf.nstream = 64; + conf.nqueue = 5 * conf.nstream; + conf.nblock = 16 * conf.nstream; + conf.nsrv = 32; +} diff --git a/gnot/mem.h b/gnot/mem.h new file mode 100644 index 0000000000000000000000000000000000000000..b73829f20e289b3bb0e7b13edc2a07dfcffdb2f7 --- /dev/null +++ b/gnot/mem.h @@ -0,0 +1,91 @@ +/* + * Memory and machine-specific definitions. Used in C and assembler. + */ + +/* + * Sizes + */ + +#define BI2BY 8 /* bits per byte */ +#define BI2WD 32 /* bits per word */ +#define BY2WD 4 /* bytes per word */ +#define BY2PG 8192 /* bytes per page */ +#define WD2PG (BY2PG/BY2WD) /* words per page */ +#define PGSHIFT 13 /* log(BY2PG) */ +#define MS2HZ 16 /* BUG */ /* millisec per clock tick */ + +#define MAXMACH 1 /* max # cpus system can run */ + +/* + * SR bits + */ +#define SUPER 0x2000 +#define SPL(n) (n<<8) + +/* + * CACR + */ +#define CCLEAR 0x08 +#define CENABLE 0x01 + +/* + * Magic registers + */ + +#define MACH A5 /* A5 is m-> */ +#define USER A4 /* A4 is u-> */ + +/* + * Fundamental addresses + */ + +#define USERADDR 0x80000000 +#define UREGADDR (USERADDR+BY2PG-(2+4+2+(8+8+1)*BY2WD)) + +/* + * Devices poked during bootstrap + */ +#define TACADDR 0x40600000 +#define MOUSE 0x40200000 + +/* + * MMU + */ + +#define KUSEG 0x00000000 +#define KSEG 0x80000000 + +/* + * MMU entries + */ +#define PTEVALID (1<<13) +#define PTERONLY (1<<14) +#define PTEKERNEL (1<<15) +#define INVALIDPTE 0 +#define PPN(pa) ((pa>>13)&0x1FFF) + +#define KMAP ((unsigned long *)0xD0000000) +#define UMAP ((unsigned long *)0x50000000) + +/* + * Virtual addresses + */ +#define VTAG(va) ((va>>22)&0x03F) +#define VPN(va) ((va>>13)&0x1FF) + +#define PARAM ((char*)0x40500000) +#define TLBFLUSH_ 0x01 + +/* + * Address spaces + */ + +#define UZERO KUSEG /* base of user address space */ +#define UTZERO (UZERO+BY2PG) /* first address in user text */ +#define TSTKTOP 0x10000000 /* end of new stack in sysexec */ +#define USTKTOP (TSTKTOP-100*BY2PG) /* byte just beyond user stack */ +#define KZERO KSEG /* base of kernel address space */ +#define KTZERO (KZERO+BY2PG) /* first address in kernel text */ + +#define NSEG 5 +#define MACHSIZE 4096 diff --git a/gnot/mmu.c b/gnot/mmu.c new file mode 100644 index 0000000000000000000000000000000000000000..7a29b69855391ed0df800abfd294885502786e6f --- /dev/null +++ b/gnot/mmu.c @@ -0,0 +1,48 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +/* + * Called splhi, not in Running state + */ +void +mapstack(Proc *p) +{ + ulong tlbvirt, tlbphys; + + if(p->upage->va != (USERADDR|(p->pid&0xFFFF))) + panic("mapstack %d 0x%lux 0x%lux", p->pid, p->upage->pa, p->upage->va); + tlbvirt = USERADDR; + tlbphys = PPN(p->upage->pa) | PTEVALID | PTEKERNEL; + putkmmu(tlbvirt, tlbphys); + flushmmu(); + u = (User*)USERADDR; +} + +void +putkmmu(ulong tlbvirt, ulong tlbphys) +{ + if(!(tlbvirt&KZERO)) + panic("putkmmu"); + tlbvirt &= ~KZERO; + KMAP[(tlbvirt&0x003FE000L)>>2] = tlbphys; +} + +void +putmmu(ulong tlbvirt, ulong tlbphys) +{ + if(tlbvirt&KZERO) + panic("putmmu"); + tlbphys |= VTAG(tlbvirt)<<24; + UMAP[(tlbvirt&0x003FE000L)>>2] = tlbphys; +} + +void +flushmmu(void) +{ + flushcpucache(); + *PARAM &= ~TLBFLUSH_; + *PARAM |= TLBFLUSH_; +} diff --git a/gnot/page.c b/gnot/page.c new file mode 100644 index 0000000000000000000000000000000000000000..2889dcbeda970773d0016f2228fceb4cc93dd18c --- /dev/null +++ b/gnot/page.c @@ -0,0 +1,638 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "ureg.h" + +struct +{ + Lock; + ulong addr; + int active; + Page *page; /* base of Page structures, indexed by phys addr */ + ulong minppn; /* index of first usable page */ + Page *head; /* most recently used */ + Page *tail; /* least recently used */ +}palloc; + +struct +{ + Lock; + Orig *arena; + Orig *free; +}origalloc; + +typedef union PTEA PTEA; +union PTEA{ + PTE; + struct{ + ulong n; /* for growpte */ + Orig *o; /* for growpte */ + PTEA *next; /* for newmod */ + }; +}; + +struct +{ + Lock; + PTEA *arena; + PTEA *free; + PTEA *end; +}ptealloc; + +struct{ + Lock; + PTEA *free; +}modalloc; + +/* + * Called to allocate permanent data structures, before calling pageinit(). + */ +void* +ialloc(ulong n, int align) +{ + ulong p; + + if(palloc.active) + print("ialloc bad\n"); + if(palloc.addr == 0) + palloc.addr = ((ulong)&end)&~KZERO; + if(align){ + palloc.addr += BY2PG-1; + palloc.addr &= ~(BY2PG-1); + } + memset((void*)(palloc.addr|KZERO), 0, n); + p = palloc.addr; + palloc.addr += n; + if(align){ + palloc.addr += BY2PG-1; + palloc.addr &= ~(BY2PG-1); + } + return (void*)(p|KZERO); +} + +void +audit(char *s) +{ + int nf, nb; + Page *p; + static int here; + + do;while(here); + here=1; + p = palloc.head; + nf=nb=0; + while(p){ + print("%lux %lux %d\n", p->pa, p->va, p->ref); + if(p->o){ + print("\t%d %lux %c\n", p->o->nproc, p->o->qid, devchar[p->o->type]); + delay(100); /* let it drain; there's a lot here */ + } + nf++; + p = p->next; + } + p = palloc.tail; + while(p){ + nb++; + p = p->prev; + } + print("%s: nf: %d nb: %d\n", s, nf, nb); + delay(1000); + here=0; +} + +void +pageinit(void) +{ + ulong pa, nb, ppn; + ulong i; + Page *p; + PTEA *pte; + Orig *o; + + ptealloc.arena = ialloc(conf.npte*sizeof(PTEA), 0); + ptealloc.free = ptealloc.arena; + ptealloc.end = ptealloc.arena+conf.npte; + + modalloc.free = ialloc(conf.nmod*sizeof(PTEA), 0); + + pte = modalloc.free; + for(i=0; inext = pte+1; + pte->next = 0; + + origalloc.free = ialloc(conf.norig*sizeof(Orig), 0); + origalloc.arena = origalloc.free; + + o = origalloc.free; + for(i=0; inext = o+1; + o->next = 0; + palloc.active = 1; + + nb = (conf.npage<>PGSHIFT)*sizeof(Page); /* safe overestimate */ + nb &= ~(BY2PG-1); + pa = (conf.npage<> PGSHIFT; /* physical page number of first free page */ + palloc.page = (Page *)((palloc.addr - ppn*sizeof(Page))|KZERO); + /* + * Now palloc.page[ppn] describes first free page + */ + palloc.minppn = ppn; + palloc.addr = ppn<next = p+1; + p->prev = p-1; + p->pa = ppn<prev = 0; + palloc.tail->next = 0; +} + +Page* +newpage(int noclear, Orig *o, ulong va) +{ + Page *p; + Orig *o1; + + if(palloc.active == 0) + print("newpage inactive\n"); +loop: + lock(&palloc); + for(p=palloc.tail; p; p=p->prev){ + if(p->ref == 0) + goto out; +#ifdef asdf + if(p->ref == 1){ /* a pageout daemon should do this */ + o1 = p->o; + if(o1 && o1->nproc==0 && canlock(o1)){ + if(o1->nproc){ + unlock(o1); + continue; + } + print("free %d pages va %lux %lux %c\n", o1->npage, o->va, o1->qid, devchar[o1->type]); + freepage(o1); + /* neworig will free the orig and pte's later */ + unlock(o1); + if(p->ref == 0) + goto out; + print("newpage ref != 0"); + } + } +#endif + } + print("no physical memory\n"); + unlock(&palloc); + if(u == 0) + panic("newpage"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; + out: + if(p->o){ + print("page in use %lux %lux %lux\n", p->va, p->o, origalloc.arena); + print("%c %lux %lux, %d %d %d\n", devchar[p->o->type], p->o->va, p->o->qid, p->o->flag, p->o->nproc, p->o->npte); + panic("shit"); + } + p->ref = 1; + usepage(p, 0); + unlock(&palloc); + if(!noclear) + memset((void*)(p->pa|KZERO), 0, BY2PG); + p->o = o; + p->va = va; + + return p; +} + +/* + * Move page to head of list + */ +void +usepage(Page *p, int dolock) +{ + if(dolock) + lock(&palloc); + /* + * Unlink + */ + if(p->prev) + p->prev->next = p->next; + else + palloc.head = p->next; + if(p->next) + p->next->prev = p->prev; + else + palloc.tail = p->prev; + /* + * Link + */ + p->next = palloc.head; + p->prev = 0; + if(p->next) + p->next->prev = p; + else + palloc.tail = p; + palloc.head = p; + if(dolock) + unlock(&palloc); +} + +Orig* +lookorig(ulong va, ulong npte, int flag, Chan *c) +{ + Orig *o; + ulong i; + + for(o=origalloc.arena,i=0; inpage && o->qid==c->qid && o->va==va){ + lock(o); + if(o->npage && o->qid==c->qid) + if(o->va==va && o->npte==npte && o->flag==flag) + if(o->mchan==c->mchan && o->mqid==c->mqid && o->type==c->type){ + if(o->chan == 0){ + o->chan = c; + incref(c); + } + o->nproc++; + unlock(o); + return o; + } + unlock(o); + } + return 0; +} + +Orig* +neworig(ulong va, ulong npte, int flag, Chan *c) +{ + Orig *o; + int i, freed; + + lock(&origalloc); +loop: + if(o = origalloc.free){ /* assign = */ + origalloc.free = o->next; + o->va = va; + o->pte = 0; + o->flag = flag; + o->nproc = 1; + o->npage = 0; + o->chan = c; + if(c){ + o->type = c->type; + o->qid = c->qid; + o->mchan = c->mchan; + o->mqid = c->mqid; + incref(c); + }else{ + o->type = -1; + o->qid = -1; + o->mqid = -1; + o->mchan = 0; + } + growpte(o, npte); + unlock(&origalloc); + return o; + } + /* + * This is feeble. Orig's should perhaps be held in + * an LRU list. This algorithm is too aggressive. + */ + freed = 0; + for(o=origalloc.arena,i=0; inproc==0 && canlock(o)){ + if(o->nproc){ + unlock(o); + continue; + } + freepage(o); + freepte(o); + unlock(o); + o->next = origalloc.free; + origalloc.free = o; + freed++; + } + } + if(freed) + goto loop; + print("no origs freed\n"); + unlock(&origalloc); + if(u == 0) + panic("neworig"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + lock(&origalloc); + goto loop; +} + +PTE* +newmod(void) +{ + PTEA *pte; + +loop: + lock(&modalloc); + if(pte = modalloc.free){ /* assign = */ + modalloc.free = pte->next; + unlock(&modalloc); + memset(pte, 0, sizeof(PTE)); + return pte; + } + unlock(&modalloc); + print("no mods\n"); + if(u == 0) + panic("newmod"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +/* + * Duplicate mod structure for this segment (old) in new process p. + * old->o must be locked. + */ +void +forkmod(Seg *old, Seg *new, Proc *p) +{ + Orig *o; + PTE *pte, *ppte, *opte, *npte; + ulong va; + + o = old->o; + ppte = 0; + pte = old->mod; + while(pte){ +if(pte->page==0) panic("forkmod zero page"); +if(pte->proc != u->p) panic("forkmod wrong page"); + npte = newmod(); + npte->proc = p; + npte->page = pte->page; + pte->page->ref++; + o->npage++; + /* + * Link into mod list for this va + */ + npte->nextmod = pte->nextmod; + pte->nextmod = npte; + /* + * Link into mod list for new segment + */ + if(ppte == 0) + new->mod = npte; + else + ppte->nextva = npte; + npte->nextva = 0; + ppte = npte; + pte = pte->nextva; + } +} + +void +freesegs(int save) +{ + int i, j; + Seg *s; + Orig *o; + PTE *pte, *opte; + PTEA *old; + Page *pg; + Chan *c; + + s = u->p->seg; + for(i=0; io; + if(o == 0) + continue; + lock(o); + if(pte = s->mod){ /* assign = */ + while(pte){ + opte = &o->pte[(pte->page->va-o->va)>>PGSHIFT]; + while(opte->nextmod != pte){ + if(opte->page && opte->page->va != pte->page->va) + panic("pte %lux %lux\n", opte->page->va, pte->page->va); + opte = opte->nextmod; + if(opte == 0) + panic("freeseg opte==0"); + } + opte->nextmod = pte->nextmod; + pg = pte->page; + if(pg->ref == 1){ + pte->page = 0; + pg->o = 0; + } + pg->ref--; + o->npage--; + old = (PTEA*)pte; + pte = pte->nextva; + lock(&modalloc); + old->next = modalloc.free; + modalloc.free = old; + unlock(&modalloc); + } + } + o->nproc--; + if(o->nproc == 0){ + if(c = o->chan){ /* assign = */ + o->chan = 0; + close(c); + } + if(!(o->flag&OCACHED) || o->npage==0){ + freepage(o); + freepte(o); + unlock(o); + lock(&origalloc); + o->next = origalloc.free; + origalloc.free = o; + unlock(&origalloc); + }else + unlock(o); + }else{ + /* + * BUG: there is a leak here. if the origin pte is being used only + * by the exiting process, the associated page will linger. the fix + * is to remember either the length of the mod list at each va or + * the number of processes sharing the origin pte, and to promote one + * of the mods to the origin pte when no process is left using the + * origin pte. + */ + unlock(o); + } + } +} + +/* + * Adjust segment to desired size. This implementation is rudimentary. + */ +int +segaddr(Seg *s, ulong min, ulong max) +{ + Orig *o; + + if(max < min) + return 0; + if(min != s->minva) /* can't grow down yet (stacks: fault.c) */ + return 0; + max = (max+(BY2PG-1)) & ~(BY2PG-1); + o = s->o; + if(max == s->maxva) + return 1; + if(max > s->maxva){ + /* + * Grow + */ + /* BUG: check spill onto other segments */ + if(o->va+BY2PG*o->npte < max) + growpte(o, (max-o->va)>>PGSHIFT); + s->maxva = max; + return 1; + } + /* + * Shrink + */ + print("segaddr shrink"); + for(;;); +} + +/* + * o is locked + */ +void +freepage(Orig *o) +{ + PTE *pte; + Page *pg; + int i; + + pte = o->pte; + for(i=0; inpte; i++,pte++) + if(pg = pte->page){ /* assign = */ + if(pg->ref == 1){ + pte->page = 0; + pg->o = 0; + } + pg->ref--; + } + o->npage = 0; +} + +/* + * Compacting allocator + */ + +void +freepte(Orig *o) /* o is locked */ +{ + PTEA *p; + p = (PTEA*)(o->pte - 1); + p->o = 0; +} + +void +growpte(Orig *o, ulong n) +{ + PTEA *p; + ulong nfree; + + lock(&ptealloc); + lock(o); + if(o->pte){ + if(o->npte == n) + panic("growpte pointless"); + p = (PTEA*)(o->pte - 1); + if(o->npte > n){ + nfree = o->npte - n; + p->n -= nfree; + o->npte -= nfree; + p += p->n; + p->o = 0; + p->n = nfree; + }else{ + n++; + if(p+p->n == ptealloc.free){ + compactpte(o, n - p->n); + p = (PTEA*)(o->pte - 1); + ptealloc.free += n - p->n; + }else{ + compactpte(o, n); + p = ptealloc.free; + ptealloc.free += n; + memcpy(p+1, o->pte, o->npte*sizeof(PTE)); + p->o = o; + ((PTEA*)(o->pte-1))->o = 0; + o->pte = p+1; + } + memset(p+1+o->npte, 0, (n-(1+o->npte))*sizeof(PTE)); + p->n = n; + o->npte = n-1; + } + unlock(o); + unlock(&ptealloc); + return; + } + n++; + compactpte(o, n); + p = ptealloc.free; + ptealloc.free += n; + memset(p, 0, n*sizeof(PTE)); + p->n = n; + p->o = o; + o->pte = p+1; + o->npte = n-1; + unlock(o); + unlock(&ptealloc); +} + +void +compactpte(Orig *o, ulong n) +{ + PTEA *p1, *p2; + Orig *p2o; + + if(ptealloc.end-ptealloc.free >= n) + return; + p1 = ptealloc.arena; /* dest */ + p2 = ptealloc.arena; /* source */ + while(p2 < ptealloc.free){ + p2o = p2->o; + if(p2o == 0){ + Free: + p2 += p2->n; + continue; + } + if(p1 != p2){ + if(p2o != o) + lock(p2o); + if(p2->o != p2o){ /* freepte()d very recently */ + if(p2->o) + panic("compactpte p2->o %lux\n", p2->o); + unlock(p2o); + goto Free; + } + memcpy(p1, p2, p2->n*sizeof(PTE)); + p2o->pte = p1+1; + if(p2o != o) + unlock(p2o); + } + p2 += p1->n; + p1 += p1->n; + } + ptealloc.free = p1; + if(ptealloc.end-ptealloc.free >= n) + return; + unlock(o); + unlock(&ptealloc); + panic("compactpte %d %lux %d", n, o->va, o->npte); +} diff --git a/gnot/pgrp.c b/gnot/pgrp.c new file mode 100644 index 0000000000000000000000000000000000000000..6da4efc58b0a99b7a891c7b1508130ca4ef81a21 --- /dev/null +++ b/gnot/pgrp.c @@ -0,0 +1,191 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +struct{ + Lock; + Pgrp *free; + ulong pgrpid; +}pgrpalloc; + +struct{ + Lock; + Mount *free; + ulong mountid; +}mountalloc; + +void +pgrpinit(void) +{ + int i; + Pgrp *p; + Mount *m; + + pgrpalloc.free = ialloc(conf.npgrp*sizeof(Pgrp), 0); + + p = pgrpalloc.free; + for(i=0; inext = p+1; + p->mtab = ialloc(conf.nmtab*sizeof(Mtab), 0); + p->etab = ialloc(conf.npgenv*sizeof(Envp*), 0); + } + p->next = 0; + + mountalloc.free = ialloc(conf.nmount*sizeof(Mount), 0); + + m = mountalloc.free; + for(i=0; inext = m+1; + m->next = 0; +} + +Pgrp* +newpgrp(void) +{ + Pgrp *p; + +loop: + lock(&pgrpalloc); + if(p = pgrpalloc.free){ /* assign = */ + pgrpalloc.free = p->next; + p->ref = 1; + p->pgrpid = ++pgrpalloc.pgrpid; + p->nmtab = 0; + p->nenv = 0; + unlock(&pgrpalloc); + return p; + } + unlock(&pgrpalloc); + print("no pgrps\n"); + if(u == 0) + panic("newpgrp"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +void +closepgrp(Pgrp *p) +{ + int i; + Mtab *m; + Envp *ep; + + if(decref(p) == 0){ + m = p->mtab; + for(i=0; inmtab; i++,m++) + if(m->c){ + close(m->c); + closemount(m->mnt); + } + ep = p->etab; + for(i=0; inenv; i++,ep++) + if(ep->env) + envpgclose(ep->env); + lock(&pgrpalloc); + p->next = pgrpalloc.free; + pgrpalloc.free = p; + unlock(&pgrpalloc); + } +} + +Mount* +newmount(void) +{ + Mount *m; + +loop: + lock(&mountalloc); + if(m = mountalloc.free){ /* assign = */ + mountalloc.free = m->next; + m->ref = 1; + m->mountid = ++mountalloc.mountid; + unlock(&mountalloc); + return m; + } + unlock(&mountalloc); + print("no mounts\n"); + if(u == 0) + panic("newmount"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +void +closemount(Mount *m) +{ + lock(m); + if(m->ref == 1){ + close(m->c); + if(m->next) + closemount(m->next); + unlock(m); + lock(&mountalloc); + m->mountid = 0; + m->next = mountalloc.free; + mountalloc.free = m; + unlock(&mountalloc); + return; + } + m->ref--; + unlock(m); +} + +void +pgrpcpy(Pgrp *to, Pgrp *from) +{ + int i; + Mtab *m; + Envp *ep; + Env *e; + + lock(from); + memcpy(to->user, from->user, NAMELEN); + memcpy(to->mtab, from->mtab, from->nmtab*sizeof(Mtab)); + to->nmtab = from->nmtab; + m = to->mtab; + for(i=0; inmtab; i++,m++) + if(m->c){ + incref(m->c); + lock(m->mnt); + m->mnt->ref++; + unlock(m->mnt); + } + + to->nenv = from->nenv; + ep = to->etab; + for(i=0; inenv; i++,ep++){ + ep->chref = 0; + e = ep->env = from->etab[i].env; + if(e){ + lock(e); + if(waserror()){ + unlock(e); + unlock(from); + ep->env = 0; + nexterror(); + } + /* + * If pgrp being forked has an open channel + * on this env, it may write it after the fork + * so make a copy now. + * Don't worry about other pgrps, because they + * will copy if they are about to write. + */ + if(from->etab[i].chref){ + ep->env = copyenv(e, 0); + unlock(ep->env); + }else + e->pgref++; + poperror(); + unlock(e); + } + } + unlock(from); +} diff --git a/gnot/print.c b/gnot/print.c new file mode 100644 index 0000000000000000000000000000000000000000..5f59dda8872ef0216f2e41e504ec77541fdfeac9 --- /dev/null +++ b/gnot/print.c @@ -0,0 +1,287 @@ +#include "u.h" +#include "lib.h" + +#define PTR sizeof(char*) +#define SHORT sizeof(int) +#define INT sizeof(int) +#define LONG sizeof(long) +#define IDIGIT 30 +#define MAXCON 30 + +static int convcount = { 10 }; + +#define PUT(o, c) if((o)->p < (o)->ep) *(o)->p++ = c + +static int noconv(Op*); +static int cconv(Op*); +static int dconv(Op*); +static int hconv(Op*); +static int lconv(Op*); +static int oconv(Op*); +static int sconv(Op*); +static int uconv(Op*); +static int xconv(Op*); +static int percent(Op*); + +static +int (*fmtconv[MAXCON])(Op*) = +{ + noconv, + cconv, dconv, hconv, lconv, + oconv, sconv, uconv, xconv, + percent, +}; +static +char fmtindex[128] = +{ + ['c'] 1, + ['d'] 2, + ['h'] 3, + ['l'] 4, + ['o'] 5, + ['s'] 6, + ['u'] 7, + ['x'] 8, + ['%'] 9, +}; + +int +fmtinstall(char c, int (*f)(Op*)) +{ + + c &= 0177; + if(fmtindex[c] == 0) { + if(convcount >= MAXCON) + return 1; + fmtindex[c] = convcount++; + } + fmtconv[fmtindex[c]] = f; + return 0; +} + +char* +donprint(char *p, char *ep, char *fmt, void *argp) +{ + int sf1, c; + Op o; + + o.p = p; + o.ep = ep; + o.argp = argp; + +loop: + c = *fmt++; + if(c != '%') { + if(c == 0) { + if(o.p < o.ep) + *o.p = 0; + return o.p; + } + PUT(&o, c); + goto loop; + } + o.f1 = 0; + o.f2 = -1; + o.f3 = 0; + c = *fmt++; + sf1 = 0; + if(c == '-') { + sf1 = 1; + c = *fmt++; + } + while(c >= '0' && c <= '9') { + o.f1 = o.f1*10 + c-'0'; + c = *fmt++; + } + if(sf1) + o.f1 = -o.f1; + if(c != '.') + goto l1; + c = *fmt++; + while(c >= '0' && c <= '9') { + if(o.f2 < 0) + o.f2 = 0; + o.f2 = o.f2*10 + c-'0'; + c = *fmt++; + } +l1: + if(c == 0) + fmt--; + c = (*fmtconv[fmtindex[c&0177]])(&o); + if(c < 0) { + o.f3 |= -c; + c = *fmt++; + goto l1; + } + o.argp = (char*)o.argp + c; + goto loop; +} + +int +numbconv(Op *op, int base) +{ + char b[IDIGIT]; + int i, f, n, r; + long v; + short h; + + f = 0; + switch(op->f3 & (FLONG|FSHORT|FUNSIGN)) { + case FLONG: + v = *(long*)op->argp; + r = LONG; + break; + + case FUNSIGN|FLONG: + v = *(unsigned long*)op->argp; + r = LONG; + break; + + case FSHORT: + h = *(int*)op->argp; + v = h; + r = SHORT; + break; + + case FUNSIGN|FSHORT: + h = *(int*)op->argp; + v = (unsigned short)h; + r = SHORT; + break; + + default: + v = *(int*)op->argp; + r = INT; + break; + + case FUNSIGN: + v = *(unsigned*)op->argp; + r = INT; + break; + } + if(!(op->f3 & FUNSIGN) && v < 0) { + v = -v; + f = 1; + } + b[IDIGIT-1] = 0; + for(i = IDIGIT-2;; i--) { + n = (unsigned long)v % base; + n += '0'; + if(n > '9') + n += 'a' - ('9'+1); + b[i] = n; + if(i < 2) + break; + v = (unsigned long)v / base; + if(op->f2 >= 0 && i >= IDIGIT-op->f2) + continue; + if(v <= 0) + break; + } +sout: + if(f) + b[--i] = '-'; + strconv(b+i, op, op->f1, -1); + return r; +} + +void +strconv(char *o, Op *op, int f1, int f2) +{ + int n, c; + char *p; + + n = strlen(o); + if(f1 >= 0) + while(n < f1) { + PUT(op, ' '); + n++; + } + for(p=o; c = *p++;) + if(f2 != 0) { + PUT(op, c); + f2--; + } + if(f1 < 0) { + f1 = -f1; + while(n < f1) { + PUT(op, ' '); + n++; + } + } +} + +static int +noconv(Op *op) +{ + + strconv("***", op, 0, -1); + return 0; +} + +static int +cconv(Op *op) +{ + char b[2]; + + b[0] = *(int*)op->argp; + b[1] = 0; + strconv(b, op, op->f1, -1); + return INT; +} + +static int +dconv(Op *op) +{ + + return numbconv(op, 10); +} + +static int +hconv(Op *op) +{ + return -FSHORT; +} + +static int +lconv(Op *op) +{ + + return -FLONG; +} + +static int +oconv(Op *op) +{ + + return numbconv(op, 8); +} + +static int +sconv(Op *op) +{ + + strconv(*(char**)op->argp, op, op->f1, op->f2); + return PTR; +} + +static int +uconv(Op *op) +{ + return -FUNSIGN; +} + +static int +xconv(Op *op) +{ + + return numbconv(op, 16); +} + +static int +percent(Op *op) +{ + + PUT(op, '%'); + return 0; +} diff --git a/gnot/proc.c b/gnot/proc.c new file mode 100644 index 0000000000000000000000000000000000000000..053c6a236b27f0228c9409598aa46f55ab2b093f --- /dev/null +++ b/gnot/proc.c @@ -0,0 +1,525 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" + +struct +{ + Lock; + ulong pid; +}pidalloc; + +struct +{ + Lock; + Proc *arena; + Proc *free; +}procalloc; + +struct +{ + Lock; + Proc *head; + Proc *tail; +}runq; + +char *statename[]={ /* BUG: generate automatically */ + "Dead", + "Moribund", + "Zombie", + "Ready", + "Scheding", + "Running", + "Queueing", + "MMUing", + "Exiting", + "Inwait", + "Wakeme", + "Broken", +}; + +/* + * Always splhi()'ed. + */ +void +schedinit(void) /* never returns */ +{ + Proc *p; + + setlabel(&m->sched); + if(u){ + m->proc = 0; + p = u->p; + putkmmu(USERADDR, INVALIDPTE); /* safety first */ + u = 0; + if(p->state == Running) + ready(p); + else if(p->state == Moribund){ + p->pid = 0; + unlock(&p->debug); + p->upage->ref--; + /* procalloc already locked */ + p->qnext = procalloc.free; + procalloc.free = p; + p->upage = 0; + unlock(&procalloc); + p->state = Dead; + } + p->mach = 0; + } + sched(); +} + +void +sched(void) +{ + Proc *p; + ulong tlbvirt, tlbphys; + void (*f)(ulong); + + if(u){ + splhi(); + if(setlabel(&u->p->sched)){ /* woke up */ +if(u->p->mach)panic("mach non zero"); + p = u->p; + p->state = Running; + p->mach = m; + m->proc = p; + spllo(); + return; + } + gotolabel(&m->sched); + } + spllo(); + p = runproc(); + splhi(); + mapstack(p); + gotolabel(&p->sched); +} + +void +ready(Proc *p) +{ + int s; + + s = splhi(); + lock(&runq); + p->rnext = 0; + if(runq.tail) + runq.tail->rnext = p; + else + runq.head = p; + runq.tail = p; + p->state = Ready; + unlock(&runq); + splx(s); +} + +/* + * Always called spllo + */ +Proc* +runproc(void) +{ + Proc *p; + +loop: + do; while(runq.head == 0); + splhi(); + lock(&runq); + p = runq.head; + if(p==0 || p->mach){ /* p->mach==0 only when process state is saved */ + unlock(&runq); + spllo(); + goto loop; + } + if(p->rnext == 0) + runq.tail = 0; + runq.head = p->rnext; + if(p->state != Ready) + print("runproc %s %d %s\n", p->text, p->pid, statename[p->state]); + unlock(&runq); + p->state = Scheding; + spllo(); + return p; +} + +Proc* +newproc(void) +{ + Proc *p; + +loop: + lock(&procalloc); + if(p = procalloc.free){ /* assign = */ + procalloc.free = p->qnext; + p->state = Zombie; + unlock(&procalloc); + p->mach = 0; + p->qnext = 0; + p->kid = 0; + p->sib = 0; + p->pop = 0; + p->nchild = 0; + p->child = 0; + p->exiting = 0; + memset(p->pidonmach, 0, sizeof p->pidonmach); + memset(p->seg, 0, sizeof p->seg); + lock(&pidalloc); + p->pid = ++pidalloc.pid; + unlock(&pidalloc); + if(p->pid == 0) + panic("pidalloc"); + return p; + } + unlock(&procalloc); + print("no procs\n"); + if(u == 0) + panic("newproc"); + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +void +procinit0(void) /* bad planning - clashes with devproc.c */ +{ + Proc *p; + int i; + + procalloc.free = ialloc(conf.nproc*sizeof(Proc), 0); + procalloc.arena = procalloc.free; + + p = procalloc.free; + for(i=0; iqnext = p+1; + p->qnext = 0; +} + +void +sleep1(Rendez *r, int (*f)(void*), void *arg) +{ + Proc *p; + int s; + + /* + * spl is to allow lock to be called + * at interrupt time. lock is mutual exclusion + */ + s = splhi(); + lock(r); + + /* + * if condition happened, never mind + */ + if((*f)(arg)){ + unlock(r); + splx(s); + return; + } + + /* + * now we are committed to + * change state and call scheduler + */ + p = u->p; + if(r->p) + print("double sleep %d %d\n", r->p->pid, p->pid); + p->r = r; + p->wokeup = 0; + p->state = Wakeme; + r->p = p; + unlock(r); +} + +void +sleep(Rendez *r, int (*f)(void*), void *arg) +{ + sleep1(r, f, arg); + sched(); + if(u->p->wokeup){ + u->p->wokeup = 0; + error(0, Eintr); + } +} + +void +tsleep(Rendez *r, int (*f)(void*), void *arg, int ms) +{ + Alarm *a; + + sleep1(r, f, arg); + a = alarm(ms, twakeme, r); + sched(); + cancel(a); + if(u->p->wokeup){ + u->p->wokeup = 0; + error(0, Eintr); + } +} + +void +wakeup(Rendez *r) +{ + Proc *p; + int s; + + s = splhi(); + lock(r); + p = r->p; + if(p){ + r->p = 0; + if(p->state != Wakeme) + panic("wakeup: not Wakeme"); + p->r = 0; + ready(p); + } + unlock(r); + splx(s); +} + +void +wakeme(Alarm *a) +{ + ready((Proc*)(a->arg)); + cancel(a); +} + +void +twakeme(Alarm *a) +{ + wakeup((Rendez*)(a->arg)); +} + +int +postnote(Proc *p, int dolock, char *n, int flag) +{ + User *up; + int s; + Rendez *r; + + if(dolock) + lock(&p->debug); + up = (User*)(p->upage->pa|KZERO); + if(flag!=NUser && (up->notify==0 || up->notified)) + up->nnote = 0; /* force user's hand */ + else if(up->nnote == NNOTE-1) + return 0; + strcpy(up->note[up->nnote].msg, n); + up->note[up->nnote++].flag = flag; + if(dolock) + unlock(&p->debug); + if(r = p->r){ /* assign = */ + /* wake up */ + s = splhi(); + lock(r); + if(p->r==r && r->p==p){ + r->p = 0; + if(p->state != Wakeme) + panic("postnote wakeup: not Wakeme"); + p->wokeup = 1; + p->r = 0; + ready(p); + } + unlock(r); + splx(s); + } + return 1; +} + +void +pexit(char *s, int freemem) +{ + char status[64]; + ulong mypid; + Proc *p, *c, *k, *l; + Waitmsg w; + int n; + Chan *ch; + ulong *up, *ucp, *wp; + + c = u->p; + mypid = c->pid; + if(s) + strcpy(status, s); + else + status[0] = 0; + if(freemem){ + freesegs(-1); + closepgrp(c->pgrp); + close(u->dot); + } + for(n=0; n<=u->maxfd; n++) + if(ch = u->fd[n]) /* assign = */ + close(ch); + /* + * Any of my children exiting? + */ + while(c->nchild){ + lock(&c->wait.queue); + if(canlock(&c->wait.use)){ /* no child is exiting */ + c->exiting = 1; + unlock(&c->wait.use); + unlock(&c->wait.queue); + break; + }else{ /* must wait for child */ + unlock(&c->wait.queue); + pwait(0); + } + } + + c->time[TReal] = MACHP(0)->ticks - c->time[TReal]; + /* + * Tell my parent + */ + p = c->parent; + if(p == 0) + goto out; + qlock(&p->wait); + lock(&p->wait.queue); + if(p->pid==c->parentpid && !p->exiting){ + w.pid = mypid; + strcpy(w.msg, status); + wp = &w.time[TUser]; + up = &c->time[TUser]; + ucp = &c->time[TCUser]; + *wp++ = (*up++ + *ucp++)*MS2HZ; + *wp++ = (*up++ + *ucp )*MS2HZ; + *wp = (*up )*MS2HZ; + p->child = c; + /* + * Pass info through back door, to avoid huge Proc's + */ + p->waitmsg = (Waitmsg*)(c->upage->pa|(((ulong)&w)&(BY2PG-1))|KZERO); + c->state = Exiting; + if(p->state == Inwait) + ready(p); + unlock(&p->wait.queue); + sched(); + }else{ + unlock(&p->wait.queue); + qunlock(&p->wait); + } + out: + if(!freemem){ + c->state = Broken; + sched(); /* until someone lets us go */ + freesegs(-1); + closepgrp(c->pgrp); + close(u->dot); + } + + /* + * Rearrange inheritance hierarchy + * 1. my children's pop is now my pop + */ + lock(&c->kidlock); + p = c->pop; + if(k = c->kid) /* assign = */ + do{ + k->pop = p; + k = k->sib; + }while(k != c->kid); + + /* + * 2. cut me from pop's tree + */ + if(p == 0) /* init process only; fix pops */ + goto done; + lock(&p->kidlock); + k = p->kid; + while(k->sib != c) + k = k->sib; + if(k == c) + p->kid = 0; + else{ + if(p->kid == c) + p->kid = c->sib; + k->sib = c->sib; + } + + /* + * 3. pass my children (pop's grandchildren) to pop + */ + if(k = c->kid){ /* assign = */ + if(p->kid == 0) + p->kid = k; + else{ + l = k->sib; + k->sib = p->kid->sib; + p->kid->sib = l; + } + } + unlock(&p->kidlock); + done: + unlock(&c->kidlock); + + lock(&procalloc); /* sched() can't do this */ + lock(&c->debug); /* sched() can't do this */ + c->state = Moribund; + sched(); /* never returns */ +} + +ulong +pwait(Waitmsg *w) +{ + Proc *c, *p; + ulong cpid; + + p = u->p; +again: + while(canlock(&p->wait.use)){ + if(p->nchild == 0){ + qunlock(&p->wait); + error(0, Enochild); + } + p->state = Inwait; + qunlock(&p->wait); + sched(); + } + lock(&p->wait.queue); /* wait until child is finished */ + c = p->child; + if(c == 0){ + print("pwait %d\n", p->pid); + p->state = Inwait; + unlock(&p->wait.queue); + sched(); + goto again; + } + p->child = 0; + if(w) + *w = *p->waitmsg; + cpid = p->waitmsg->pid; + p->time[TCUser] += c->time[TUser] + c->time[TCUser]; + p->time[TCSys] += c->time[TSys] + c->time[TCSys]; + p->time[TCReal] += c->time[TReal]; + p->nchild--; + unlock(&p->wait.queue); + qunlock(&p->wait); + ready(c); + return cpid; +} + +Proc* +proctab(int i) +{ + return &procalloc.arena[i]; +} + +#include +DEBUG() +{ + int i; + Proc *p; + + print("DEBUG\n"); + for(i=0; istate != 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]); + } +} diff --git a/gnot/screen.c b/gnot/screen.c new file mode 100644 index 0000000000000000000000000000000000000000..1a078314d9893873cb2c6ebee35098c456fa65b2 --- /dev/null +++ b/gnot/screen.c @@ -0,0 +1,176 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "gnot.h" + +#define MINX 8 + +extern Font defont0; + +struct{ + Point pos; + int bwid; +}out; + +Bitmap screen = +{ + (ulong*)(2*1024*1024|KZERO), /* BUG */ + 0, + 64, + 0, + 0, 0, 1024, 1024, + 0 +}; + +void +screeninit(void) +{ + bitblt(&screen, Pt(0, 0), &screen, screen.rect, 0); + out.pos.x = MINX; + out.pos.y = 0; + out.bwid = defont0.info[' '].width; +} + +void +screenputc(int c) +{ + char buf[2]; + int nx; + + if(c == '\n'){ + out.pos.x = MINX; + out.pos.y += defont0.height; + if(out.pos.y > screen.rect.max.y-defont0.height) + out.pos.y = screen.rect.min.y; + bitblt(&screen, Pt(0, out.pos.y), &screen, + Rect(0, out.pos.y, screen.rect.max.x, out.pos.y+2*defont0.height), 0); + }else if(c == '\t'){ + nx = out.pos.x + (8-(out.pos.x/out.bwid&7))*out.bwid; + out.pos.x = nx; + if(out.pos.x >= screen.rect.max.x) + screenputc('\n'); + }else if(c == '\b'){ + if(out.pos.x >= out.bwid+MINX){ + out.pos.x -= out.bwid; + screenputc(' '); + out.pos.x -= out.bwid; + } + }else{ + if(out.pos.x >= screen.rect.max.x-out.bwid) + screenputc('\n'); + buf[0] = c&0x7F; + buf[1] = 0; + out.pos = string(&screen, out.pos, &defont0, buf, S); + } +} + +/* + * Register set for half the duart. There are really two sets. + */ +struct Duart{ + uchar mr1_2; /* Mode Register Channels 1 & 2 */ + uchar sr_csr; /* Status Register/Clock Select Register */ + uchar cmnd; /* Command Register */ + uchar data; /* RX Holding / TX Holding Register */ + uchar ipc_acr; /* Input Port Change/Aux. Control Register */ + uchar is_imr; /* Interrupt Status/Interrupt Mask Register */ + uchar ctur; /* Counter/Timer Upper Register */ + uchar ctlr; /* Counter/Timer Lower Register */ +}; + +enum{ + CHAR_ERR =0x00, /* MR1x - Mode Register 1 */ + EVEN_PAR =0x00, + ODD_PAR =0x04, + NO_PAR =0x10, + CBITS8 =0x03, + CBITS7 =0x02, + CBITS6 =0x01, + CBITS5 =0x00, + NORM_OP =0x00, /* MR2x - Mode Register 2 */ + TWOSTOPB =0x0F, + ONESTOPB =0x07, + ENB_RX =0x01, /* CRx - Command Register */ + DIS_RX =0x02, + ENB_TX =0x04, + DIS_TX =0x08, + RESET_MR =0x10, + RESET_RCV =0x20, + RESET_TRANS =0x30, + RESET_ERR =0x40, + RESET_BCH =0x50, + STRT_BRK =0x60, + STOP_BRK =0x70, + RCV_RDY =0x01, /* SRx - Channel Status Register */ + FIFOFULL =0x02, + XMT_RDY =0x04, + XMT_EMT =0x08, + OVR_ERR =0x10, + PAR_ERR =0x20, + FRM_ERR =0x40, + RCVD_BRK =0x80, + IM_IPC =0x80, /* IMRx/ISRx - Interrupt Mask/Interrupt Status */ + IM_DBB =0x40, + IM_RRDYB =0x20, + IM_XRDYB =0x10, + IM_CRDY =0x08, + IM_DBA =0x04, + IM_RRDYA =0x02, + IM_XRDYA =0x01, +}; + +uchar keymap[]={ +/*80*/ 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x8e, 0x58, +/*90*/ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x58, 0x58, 0x58, 0x58, +/*A0*/ 0x58, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xae, 0xaf, +/*B0*/ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0x80, 0xb7, + 0xb8, 0xb9, 0x00, 0xbb, 0x1e, 0xbd, 0x60, 0x1f, +/*C0*/ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0x58, 0xc6, 0x0d, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, +/*D0*/ 0x09, 0x08, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x7f, 0x58, +/*E0*/ 0x58, 0x58, 0xe2, 0x1b, 0x0a, 0xe5, 0x58, 0x0d, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, +/*F0*/ 0x09, 0x08, 0xb2, 0x1b, 0x0a, 0xf5, 0x81, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x7f, 0xb2, +}; + +void +duartintr(void) +{ + int cause, status, c; + Duart *duart; + + duart = DUARTREG; + cause = duart->is_imr; + /* + * I can guess your interrupt. + */ + /* + * Is it 1? + */ + if(cause & IM_RRDYA){ /* keyboard input */ + status = duart->sr_csr; + c = duart->data; + if(status & (FRM_ERR|OVR_ERR|PAR_ERR)) + duart->cmnd = RESET_ERR; + if(c == 0x7F) + c = 0xFF; /* VIEW key (bizarre) */ + if(c & 0x80) + c = keymap[c&0x7F]; + kbdchar(c); + } + /* + * Is it 2? + */ + if(cause & IM_RRDYB) /* pen input */ + c = duart[1].data; +} + diff --git a/gnot/stream.c b/gnot/stream.c new file mode 100644 index 0000000000000000000000000000000000000000..360b6db85bac109118ae0cff172eb64bc85d6615 --- /dev/null +++ b/gnot/stream.c @@ -0,0 +1,889 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "errno.h" +#include "devtab.h" + +static void stputq(Queue*, Block*); +Qinfo procinfo = { stputq, nullput, 0, 0, "process" } ; +/*extern Qinfo noetherinfo; */ + +static Qinfo *lds[] = { +/* &noetherinfo, */ + 0 +}; + +enum { + Nclass=4, +}; + +/* + * All stream structures are ialloc'd at boot time + */ +Stream *slist; +Queue *qlist; +Block *blist; +static Lock garbagelock; + +/* + * The block classes. There are Nclass block sizes, each with its own free list. + * All are ialloced at qinit() time. + */ +typedef struct { + int size; + Queue; +} Bclass; +Bclass bclass[Nclass]={ + { 0 }, + { 64 }, + { 512 }, + { 4096 }, +}; + +/* + * Allocate streams, queues, and blocks. Allocate n block classes with + * 1/2(m+1) to class m < n-1 + * 1/2(n-1) to class n-1 + */ +void +streaminit(void) +{ + int class, i, n; + Block *bp; + Bclass *bcp; + + slist = (Stream *)ialloc(conf.nstream * sizeof(Stream), 0); + qlist = (Queue *)ialloc(conf.nqueue * sizeof(Queue), 0); + blist = (Block *)ialloc(conf.nblock * sizeof(Block), 0); + bp = blist; + n = conf.nblock; + for(class = 0; class < Nclass; class++){ + if(class < Nclass-1) + n = n/2; + bcp = &bclass[class]; + for(i = 0; i < n; i++) { + if(bcp->size) + bp->base = (uchar *)ialloc(bcp->size, 0); + bp->lim = bp->base + bcp->size; + bp->flags = class; + freeb(bp); + bp++; + } + } +} + + +/* + * allocate a block + */ +static int +isblock(void *arg) +{ + Bclass *bcp; + + bcp = (Bclass *)arg; + return bcp->first!=0; +} +Block * +allocb(ulong size) +{ + Block *bp; + Bclass *bcp; + int i; + + + /* + * map size to class + */ + for(bcp=bclass; bcp->sizefirst == 0){ + unlock(bcp); + print("waiting for blocks\n"); + sleep(&bcp->r, isblock, (void *)bcp); + lock(bcp); + } + bp = bcp->first; + bcp->first = bp->next; + if(bcp->first == 0) + bcp->last = 0; + unlock(bcp); + + /* + * return an empty block + */ + bp->rptr = bp->wptr = bp->base; + bp->next = 0; + bp->type = M_DATA; + bp->flags &= S_CLASS; + return bp; +} + +/* + * Free a block. Poison its pointers so that someone trying to access + * it after freeing will cause a dump. + */ +void +freeb(Block *bp) +{ + Bclass *bcp; + + bcp = &bclass[bp->flags & S_CLASS]; + bp->rptr = bp->wptr = 0; + lock(bcp); + if(bcp->first) + bcp->last->next = bp; + else + bcp->first = bp; + bcp->last = bp; + bp->next = 0; + wakeup(&bcp->r); + unlock(bcp); +} + +/* + * allocate a pair of queues. flavor them with the requested put routines. + * the `QINUSE' flag on the read side is the only one used. + */ +static Queue * +allocq(Qinfo *qi) +{ + Queue *q, *wq; + + for(q=qlist; q<&qlist[conf.nqueue]; q++, q++) { + if(q->flag == 0){ + if(canlock(q)){ + if(q->flag == 0) + break; + unlock(q); + } + } + } + + if(q == &qlist[conf.nqueue]){ + print("no more queues\n"); + error(0, Enoqueue); + } + + q->flag = QINUSE; + q->r.p = 0; + q->info = qi; + q->put = qi->iput; + wq = q->other = q + 1; + + wq->r.p = 0; + wq->info = qi; + wq->put = qi->oput; + wq->other = q; + + unlock(q); + + return q; +} + +/* + * free a queue + */ +static void +freeq(Queue *q) +{ + Block *bp; + + q = RD(q); + while(bp = getq(q)) + freeb(bp); + q = WR(q); + while(bp = getq(q)) + freeb(bp); + RD(q)->flag = 0; +} + +/* + * push a queue onto a stream referenced by the proc side write q + */ +Queue * +pushq(Stream* s, Qinfo *qi) +{ + Queue *q; + Queue *nq; + + q = RD(s->procq); + + /* + * make the new queue + */ + nq = allocq(qi); + + /* + * push + */ + RD(nq)->next = q; + RD(WR(q)->next)->next = RD(nq); + WR(nq)->next = WR(q)->next; + WR(q)->next = WR(nq); + + if(qi->open) + (*qi->open)(RD(nq), s); + + return WR(nq)->next; +} + +/* + * pop off the top line discipline + */ +static void +popq(Stream *s) +{ + Queue *q; + + if(s->procq->next == WR(s->devq)) + error(0, Ebadld); + q = s->procq->next; + if(q->info->close) + (*q->info->close)(RD(q)); + s->procq->next = q->next; + RD(q->next)->next = RD(s->procq); + freeq(q); +} + +/* + * add a block (or list of blocks) to the end of a queue. return true + * if one of the blocks contained a delimiter. + */ +int +putq(Queue *q, Block *bp) +{ + int delim; + + delim = 0; + lock(q); + if(q->first) + q->last->next = bp; + else + q->first = bp; + q->len += bp->wptr - bp->rptr; + delim = bp->flags & S_DELIM; + while(bp->next) { + bp = bp->next; + q->len += bp->wptr - bp->rptr; + delim |= bp->flags & S_DELIM; + } + q->last = bp; + if(q->len >= Streamhi) + q->flag |= QHIWAT; + unlock(q); + return delim; +} +int +putb(Blist *q, Block *bp) +{ + int delim; + + delim = 0; + if(q->first) + q->last->next = bp; + else + q->first = bp; + q->len += bp->wptr - bp->rptr; + delim = bp->flags & S_DELIM; + while(bp->next) { + bp = bp->next; + q->len += bp->wptr - bp->rptr; + delim |= bp->flags & S_DELIM; + } + q->last = bp; + bp->next = 0; + return delim; +} + +/* + * add a block to the start of a queue + */ +static void +putbq(Blist *q, Block *bp) +{ + lock(q); + if(q->first) + bp->next = q->first; + else + q->last = bp; + q->first = bp; + q->len += bp->wptr - bp->rptr; + unlock(q); +} + +/* + * remove the first block from a queue + */ +Block * +getq(Queue *q) +{ + Block *bp; + + lock(q); + bp = q->first; + if(bp) { + q->first = bp->next; + if(q->first == 0) + q->last = 0; + q->len -= bp->wptr - bp->rptr; + if((q->flag&QHIWAT) && q->len < Streamhi/2){ + wakeup(&q->other->next->other->r); + q->flag &= ~QHIWAT; + } + bp->next = 0; + } + unlock(q); + return bp; +} +Block * +getb(Blist *q) +{ + Block *bp; + + bp = q->first; + if(bp) { + q->first = bp->next; + if(q->first == 0) + q->last = 0; + q->len -= bp->wptr - bp->rptr; + bp->next = 0; + } + return bp; +} + +/* + * put a block into the bit bucket + */ +void +nullput(Queue *q, Block *bp) +{ + freeb(bp); + error(0, Ehungup); +} + +/* + * find the info structure for line discipline 'name' + */ +static Qinfo * +qinfofind(char *name) +{ + Qinfo **qip; + + if(name == 0) + error(0, Ebadld); + for(qip = lds; *qip; qip++) + if(strcmp((*qip)->name, name)==0) + return *qip; + error(0, Ebadld); +} + +/* + * send a hangup up a stream + */ +static void +hangup(Stream *s) +{ + Block *bp; + + bp = allocb(0); + bp->type = M_HANGUP; + (*s->devq->put)(s->devq, bp); +} + +/* + * parse a string and return a pointer to the second element if the + * first matches name. bp->rptr will be updated to point to the + * second element. + * + * return 0 if no match. + * + * it is assumed that the block data is null terminated. streamwrite + * guarantees this. + */ +int +streamparse(char *name, Block *bp) +{ + int len; + + len = strlen(name); + if(bp->wptr - bp->rptr < len) + return 0; + if(strncmp(name, (char *)bp->rptr, len)==0){ + if(bp->rptr[len] == ' ') + bp->rptr += len+1; + else if(bp->rptr[len]) + return 0; + else + bp->rptr += len; + return 1; + } + return 0; +} + +/* + * the per stream directory structure + */ +Dirtab streamdir[]={ + "data", Sdataqid, 0, 0600, + "ctl", Sctlqid, 0, 0600, +}; + +/* + * A stream device consists of the contents of streamdir plus + * any directory supplied by the actual device. + * + * values of s: + * 0 to ntab-1 apply to the auxiliary directory. + * ntab to ntab+Shighqid-Slowqid+1 apply to streamdir. + */ +int +streamgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) +{ + Proc *p; + char buf[NAMELEN]; + + if(s < ntab) + tab = &tab[s]; + else if(s < ntab + Shighqid - Slowqid + 1) + tab = &streamdir[s - ntab]; + else + return -1; + + devdir(c, STREAMQID(STREAMID(c->qid),tab->qid), tab->name, tab->length, + tab->perm, dp); + return 1; +} + +/* + * create a new stream + */ +Stream * +streamnew(Chan *c, Qinfo *qi) +{ + Stream *s; + Queue *q; + + /* + * find a free stream struct + */ + for(s = slist; s < &slist[conf.nstream]; s++) { + if(s->inuse == 0){ + if(canlock(s)){ + if(s->inuse == 0) + break; + unlock(s); + } + } + } + if(s == &slist[conf.nstream]){ + print("no more streams\n"); + error(0, Enostream); + } + if(waserror()){ + unlock(s); + streamclose(c); + nexterror(); + } + + /* + * marry a stream and a channel + */ + if(c){ + c->stream = s; + s->type = c->type; + s->dev = c->dev; + s->id = STREAMID(c->qid); + } else + s->type = -1; + + /* + * hang a device and process q off the stream + */ + s->inuse = 1; + s->tag[0] = 0; + q = allocq(&procinfo); + s->procq = WR(q); + q = allocq(qi); + s->devq = RD(q); + WR(s->procq)->next = WR(s->devq); + RD(s->procq)->next = 0; + RD(s->devq)->next = RD(s->procq); + WR(s->devq)->next = 0; + + if(qi->open) + (*qi->open)(RD(s->devq), s); + + c->flag |= COPEN; + unlock(s); + poperror(); + return s; +} + +/* + * (Re)open a stream. If this is the first open, create a stream. + */ +void +streamopen(Chan *c, Qinfo *qi) +{ + Stream *s; + Queue *q; + + /* + * if the stream already exists, just up the reference count. + */ + for(s = slist; s < &slist[conf.nstream]; s++) { + if(s->inuse && s->type == c->type && s->dev == c->dev + && s->id == STREAMID(c->qid)){ + lock(s); + if(s->inuse && s->type == c->type + && s->dev == c->dev + && s->id == STREAMID(c->qid)){ + s->inuse++; + c->stream = s; + unlock(s); + return; + } + unlock(s); + } + } + + /* + * create a new stream + */ + streamnew(c, qi); +} + +/* + * On the last close of a stream, for each queue on the + * stream release its blocks and call its close routine. + */ +void +streamclose(Chan *c) +{ + Queue *q, *nq; + Block *bp; + Stream *s = c->stream; + + /* + * if not open, ignore it + */ + if(!(c->flag & COPEN)) + return; + + /* + * decrement the reference cound + */ + lock(s); + if(s->inuse != 1){ + s->inuse--; + unlock(c->stream); + return; + } + + /* + * descend the stream closing the queues + */ + for(q = s->procq; q; q = q->next){ + if(q->info->close) + (*q->info->close)(q->other); + if(q == s->devq->other) + break; + } + /* + * ascend the stream freeing the queues + */ + for(q = s->devq; q; q = nq){ + nq = q->next; + freeq(q); + } + s->id = s->dev = s->type = 0; + s->inuse--; + unlock(s); +} + +/* + * put a block to be read into the queue. wakeup any waiting reader + */ +void +stputq(Queue *q, Block *bp) +{ + int i; + + if(bp->type == M_HANGUP){ + freeb(bp); + q->flag |= QHUNGUP; + q->other->flag |= QHUNGUP; + } else { + lock(q); + if(q->first) + q->last->next = bp; + else + q->first = bp; + q->last = bp; + q->len += bp->wptr - bp->rptr; + if(q->len >= Streamhi) + q->flag |= QHIWAT; + unlock(q); + } + wakeup(&q->r); +} + +/* + * read a string. update the offset accordingly. + */ +long +stringread(Chan *c, uchar *buf, long n, char *str) +{ + long i; + + i = strlen(str); + i -= c->offset; + if(ioffset, str, n); + c->offset += n; + return n; +} + +/* + * return true if there is an output buffer available + */ +static int +isinput(void *x) +{ + return ((Queue *)x)->first != 0; +} + +/* + * read until we fill the buffer or until a DELIM is encountered + */ +long +streamread(Chan *c, void *vbuf, long n) +{ + Block *bp; + Stream *s; + Queue *q; + long rv = 0; + int left, i, x; + uchar *buf = vbuf; + char num[32]; + + s = c->stream; + switch(STREAMTYPE(c->qid)){ + case Sdataqid: + break; + case Sctlqid: + sprint(num, "%d", s->id); + return stringread(c, buf, n, num); + default: + if(CHDIR & c->qid) + return devdirread(c, vbuf, n, 0, 0, streamgen); + else + panic("streamread"); + } + + /* + * one reader at a time + */ + qlock(&s->rdlock); + if(waserror()){ + qunlock(&s->rdlock); + nexterror(); + } + + /* + * sleep till data is available + */ + q = RD(s->procq); + left = n; + while(left){ + bp = getq(q); + if(bp == 0){ + if(q->flag & QHUNGUP) + break; + sleep(&q->r, &isinput, (void *)q); + continue; + } + + i = bp->wptr - bp->rptr; + if(i <= left){ + memcpy(buf, bp->rptr, i); + left -= i; + buf += i; + if(bp->flags & S_DELIM){ + freeb(bp); + break; + } else + freeb(bp); + } else { + memcpy(buf, bp->rptr, left); + bp->rptr += left; + putbq(q, bp); + left = 0; + } + }; + + qunlock(&s->rdlock); + poperror(); + return n - left; +} + +/* + * Handle a ctl request. Streamwide requests are: + * + * hangup -- send an M_HANGUP up the stream + * push ldname -- push the line discipline named ldname + * pop -- pop a line discipline + * + * This routing is entrered with s->wrlock'ed and must unlock. + */ +static long +streamctlwrite(Stream *s, void *a, long n) +{ + Qinfo *qi; + Block *bp; + + /* + * package + */ + bp = allocb(n+1); + memcpy(bp->wptr, a, n); + bp->wptr[n] = 0; + bp->wptr += n + 1; + + /* + * check for standard requests + */ + if(streamparse("hangup", bp)){ + hangup(s); + freeb(bp); + } else if(streamparse("push", bp)){ + qi = qinfofind((char *)bp->rptr); + pushq(s, qi); + freeb(bp); + } else if(streamparse("pop", bp)){ + popq(s); + freeb(bp); + } else { + bp->type = M_CTL; + bp->flags |= S_DELIM; + PUTNEXT(s->procq, bp); + } + + return n; +} + +/* + * wait till there's room in the next stream + */ +static int +notfull(void *arg) +{ + Queue *q; + + q = (Queue *)arg; + return q->len < Streamhi; +} +void +flowctl(Queue *q) +{ + if(q->next->len >= Streamhi) + sleep(&q->r, notfull, q->next); +} + +/* + * send the request as a single delimited block + */ +long +streamwrite(Chan *c, void *a, long n) +{ + Stream *s; + Block *bp; + Queue *q; + long rem; + int i; + + /* + * one writer at a time + */ + s = c->stream; + qlock(&s->wrlock); + if(waserror()){ + qunlock(&s->wrlock); + nexterror(); + } + + /* + * decode the qid + */ + switch(STREAMTYPE(c->qid)){ + case Sdataqid: + break; + case Sctlqid: + n = streamctlwrite(s, a, n); + qunlock(&s->wrlock); + poperror(); + return n; + default: + panic("bad stream qid\n"); + } + + /* + * No writes allowed on hungup channels + */ + q = s->procq; + if(q->other->flag & QHUNGUP) + error(0, Ehungup); + + if(GLOBAL(a) || n==0){ + /* + * `a' is global to the whole system, just create a + * pointer to it and pass it on. + */ + flowctl(q); + bp = allocb(0); + bp->rptr = bp->base = (uchar *)a; + bp->wptr = bp->lim = (uchar *)a+n; + bp->flags |= S_DELIM; + bp->type = M_DATA; + PUTNEXT(q, bp); + } else { + /* + * `a' is in the user's address space, copy it into + * system buffers and pass the buffers on. + */ + for(rem = n; ; rem -= i) { + flowctl(q); + bp = allocb(rem); + i = bp->lim - bp->wptr; + if(i >= rem){ + memcpy(bp->wptr, a, rem); + bp->flags |= S_DELIM; + bp->wptr += rem; + bp->type = M_DATA; + PUTNEXT(q, bp); + break; + } else { + memcpy(bp->wptr, a, i); + bp->wptr += i; + bp->type = M_DATA; + PUTNEXT(q, bp); + a = ((char*)a) + i; + } + } + } + qunlock(&s->wrlock); + poperror(); + return n; +} diff --git a/gnot/sysfile.c b/gnot/sysfile.c new file mode 100644 index 0000000000000000000000000000000000000000..f607a8852df8e24c591ad99a7e335c67adc86785 --- /dev/null +++ b/gnot/sysfile.c @@ -0,0 +1,508 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" +#include "fcall.h" + +/* + * The sys*() routines needn't poperror() as they return directly to syscall(). + */ + +int +newfd(void) +{ + int i; + + for(i=0; ifd[i] == 0){ + if(i > u->maxfd) + u->maxfd = i; + return i; + } + error(0, Enofd); +} + +Chan* +fdtochan(int fd, int mode) +{ + Chan *c; + + if(fd<0 || NFD<=fd || (c=u->fd[fd])==0) + error(0, Ebadfd); + if(mode<0 || c->mode == 2) + return c; + if((mode&16) && c->mode==0) + err: + error(0, Ebadusefd); + if((mode&~16) != c->mode) + goto err; + return c; +} + +int +openmode(ulong o) +{ + if(o >= (OTRUNC|OEXEC)) + Err: + error(0, Ebadarg); + o &= ~OTRUNC; + if(o > OEXEC) + goto Err; + if(o == OEXEC) + return OREAD; + return o; +} + +long +sysdup(ulong *arg) +{ + int fd; + Chan *c, *oc; + + /* + * Close after dup'ing, so date > #d/1 works + */ + c = fdtochan(arg[0], -1); + fd = arg[1]; + if(fd != -1) + oc = u->fd[fd]; + else{ + oc = 0; + fd = newfd(); + } + u->fd[fd] = c; + incref(c); + if(oc) + close(oc); + return fd; +} + +long +sysopen(ulong *arg) +{ + int fd; + Chan *c; + + openmode(arg[1]); /* error check only */ + fd = newfd(); + validaddr(arg[0], 1, 0); + c = namec((char*)arg[0], Aopen, arg[1], 0); + u->fd[fd] = c; + return fd; +} + +void +fdclose(int fd) +{ + int i; + + u->fd[fd] = 0; + if(fd == u->maxfd) + for(i=fd; --i>=0 && u->fd[i]==0; ) + u->maxfd = i; +} + +long +sysclose(ulong *arg) +{ + Chan *c; + + c = fdtochan(arg[0], -1); + close(c); + fdclose(arg[0]); + return 0; +} + +long +unionread(Chan *c, void *va, long n) +{ + Mount *mnt; + Chan *mc, *nc; + Pgrp *pg = u->p->pgrp; + long nr; + + mnt = c->mnt; + lock(pg); + if(c->mountid != mnt->mountid){ + print("unionread: changed underfoot?\n"); + unlock(pg); + return 0; + } + Again: + mc = mnt->c; + incref(mc); + unlock(pg); + if(waserror()){ + close(mc); + nexterror(); + } + nc = clone(mc, 0); + close(mc); + poperror(); + if(waserror()){ + close(nc); + nexterror(); + } + nc = (*devtab[nc->type].open)(nc, OREAD); + nc->offset = c->offset; + nr = (*devtab[nc->type].read)(nc, va, n); + close(nc); + poperror(); + if(nr > 0) + return nr; + /* + * Advance to next element + */ + lock(pg); + mnt = c->mnt; + if(c->mountid != mnt->mountid){ + print("unionread: changed underfoot?\n"); + unlock(pg); + return 0; + } + if(mnt->term){ + unlock(pg); + return 0; + } + mnt = mnt->next; + c->mnt = mnt; + c->mountid = mnt->mountid; + c->offset = 0; + goto Again; +} + +long +sysread(ulong *arg) +{ + Chan *c; + long n; + + c = fdtochan(arg[0], 0); + validaddr(arg[1], arg[2], 0); + qlock(c); + if(waserror()){ + qunlock(c); + nexterror(); + } + n = arg[2]; + if(c->qid&CHDIR){ + n -= n%DIRLEN; + if(c->offset%DIRLEN || n==0) + error(0, Ebaddirread); + } + if((c->qid&CHDIR) && c->flag&CMOUNT) + n = unionread(c, (void*)arg[1], n); + else + n = (*devtab[c->type].read)(c, (void*)arg[1], n); + c->offset += n; + qunlock(c); + return n; +} + +long +syswrite(ulong *arg) +{ + Chan *c; + long n; + + c = fdtochan(arg[0], 1); + validaddr(arg[1], arg[2], 0); + qlock(c); + if(waserror()){ + qunlock(c); + nexterror(); + } + if(c->qid & CHDIR) + error(0, Eisdir); + n = (*devtab[c->type].write)(c, (void*)arg[1], arg[2]); + c->offset += n; + qunlock(c); + return n; +} + +long +sysseek(ulong *arg) +{ + Chan *c; + char buf[DIRLEN]; + Dir dir; + long off; + + c = fdtochan(arg[0], -1); + if(c->qid & CHDIR) + error(0, Eisdir); + qlock(c); + if(waserror()){ + qunlock(c); + nexterror(); + } + switch(arg[2]){ + case 0: + c->offset = arg[1]; + break; + + case 1: + c->offset += (long)arg[1]; + break; + + case 2: + (*devtab[c->type].stat)(c, buf); + convM2D(buf, &dir); + c->offset = dir.length + (long)arg[1]; + break; + } + off = c->offset; + qunlock(c); + poperror(); + return off; +} + +long +sysfstat(ulong *arg) +{ + Chan *c; + long n; + + validaddr(arg[1], DIRLEN, 1); + evenaddr(arg[1]); + c = fdtochan(arg[0], -1); + (*devtab[c->type].stat)(c, (char*)arg[1]); + return 0; +} + +long +sysstat(ulong *arg) +{ + Chan *c; + long n; + + validaddr(arg[1], DIRLEN, 1); + evenaddr(arg[1]); + validaddr(arg[0], 1, 0); + c = namec((char*)arg[0], Aaccess, 0, 0); + if(waserror()){ + close(c); + nexterror(); + } + (*devtab[c->type].stat)(c, (char*)arg[1]); + poperror(); + close(c); + return 0; +} + +long +sysaccess(ulong *arg) +{ + Chan *c; + long mode; + + validaddr(arg[0], 1, 0); + c = namec((char*)arg[0], Aaccess, 0, 0); + mode = c->mode; + close(c); + /* BUG: check modes */ + return 0; +} + +long +syschdir(ulong *arg) +{ + Chan *c; + + validaddr(arg[0], 1, 0); + c = namec((char*)arg[0], Atodir, 0, 0); + close(u->dot); + u->dot = c; + return 0; +} + +long +bindmount(ulong *arg, int ismount) +{ + Chan *c0, *c1; + ulong flag; + long ret; + struct{ + Chan *chan; + char *spec; + }bogus; + + flag = arg[2]; + if(flag>MMASK || (flag&MORDER)==(MBEFORE|MAFTER)) + error(0, Ebadarg); + if(ismount){ + bogus.chan = fdtochan(arg[0], 2); +/*BUG: check validaddr for ALL of arg[3]!! */ + validaddr(arg[3], 1, 0); + bogus.spec = (char*)arg[3]; + ret = devno('M', 0); + c0 = (*devtab[ret].attach)((char*)&bogus); + }else{ + validaddr(arg[0], 1, 0); + c0 = namec((char*)arg[0], Aaccess, 0, 0); + } + if(waserror()){ + close(c0); + nexterror(); + } + validaddr(arg[1], 1, 0); + c1 = namec((char*)arg[1], Amount, 0, 0); + if(waserror()){ + close(c1); + nexterror(); + } + if((c0->qid^c1->qid) & CHDIR) + error(0, Ebadmount); + if(flag && !(c0->qid&CHDIR)) + error(0, Ebadmount); + ret = mount(c0, c1, flag); + close(c0); + close(c1); + if(ismount){ + close(bogus.chan); + fdclose(arg[0]); + } + return ret; +} + +long +sysbind(ulong *arg) +{ + return bindmount(arg, 0); +} + +long +sysmount(ulong *arg) +{ + return bindmount(arg, 1); +} + +long +syspipe(ulong *arg) +{ + int fd[2]; + Chan *c[2]; + Dev *d; + + validaddr(arg[0], 2*BY2WD, 1); + evenaddr(arg[0]); + d = &devtab[devno('|', 0)]; + c[0] = (*d->attach)(0); + c[1] = 0; + fd[0] = -1; + fd[1] = -1; + if(waserror()){ + close(c[0]); + if(c[1]) + close(c[1]); + if(fd[0] >= 0) + u->fd[fd[0]]=0; + if(fd[1] >= 0) + u->fd[fd[1]]=0; + nexterror(); + } + c[1] = (*d->clone)(c[0], 0); + c[0] = (*d->open)(c[0], ORDWR); + c[1] = (*d->open)(c[1], ORDWR); + c[0]->mode = 2; + c[1]->mode = 2; + c[0]->flag |= COPEN; + c[1]->flag |= COPEN; + fd[0] = newfd(); + u->fd[fd[0]] = c[0]; + fd[1] = newfd(); + u->fd[fd[1]] = c[1]; + ((long*)arg[0])[0] = fd[0]; + ((long*)arg[0])[1] = fd[1]; + poperror(); + return 0; +} + +long +syscreate(ulong *arg) +{ + int fd; + Chan *c; + + openmode(arg[1]); /* error check only */ + fd = newfd(); + validaddr(arg[0], 1, 0); + c = namec((char*)arg[0], Acreate, arg[1], arg[2]); + u->fd[fd] = c; + return fd; +} + +long +sysuserstr(ulong *arg) +{ + Error err; + char buf[NAMELEN]; + + validaddr(arg[0], sizeof(Error), 0); + validaddr(arg[1], NAMELEN, 1); + err = *(Error*)arg[0]; + err.type = devno(err.type, 1); + if(err.type == -1) + strcpy((char*)arg[1], "*gok*"); + else{ + (*devtab[err.type].userstr)(&err, buf); + memcpy((char*)arg[1], buf, sizeof buf); + } + return 0; +} + +long +sysremove(ulong *arg) +{ + Chan *c; + + validaddr(arg[0], 1, 0); + c = namec((char*)arg[0], Aaccess, 0, 0); + if(waserror()){ + close(c); + nexterror(); + } + (*devtab[c->type].remove)(c); + /* + * Remove clunks the fid, but we need to recover the Chan + * so fake it up. rootclose() is known to be a nop. + */ + c->type = 0; + close(c); + return 0; +} + +long +syswstat(ulong *arg) +{ + Chan *c; + long n; + + validaddr(arg[1], DIRLEN, 0); + evenaddr(arg[1]); + validaddr(arg[0], 1, 0); + c = namec((char*)arg[0], Aaccess, 0, 0); + if(waserror()){ + close(c); + nexterror(); + } + (*devtab[c->type].wstat)(c, (char*)arg[1]); + poperror(); + close(c); + return 0; +} + +long +sysfwstat(ulong *arg) +{ + Chan *c; + long n; + + validaddr(arg[1], DIRLEN, 0); + evenaddr(arg[1]); + c = fdtochan(arg[0], -1); + (*devtab[c->type].wstat)(c, (char*)arg[1]); + return 0; +} diff --git a/gnot/sysproc.c b/gnot/sysproc.c new file mode 100644 index 0000000000000000000000000000000000000000..668f19b2a0a723b8bf3c23e762b4a41e6b637858 --- /dev/null +++ b/gnot/sysproc.c @@ -0,0 +1,516 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "ureg.h" +#include "errno.h" + +#include + +int shargs(char*, int, char**); + +long +sysr1(ulong *arg) +{ + print("[%d] r1 = %d\n", u->p->pid, arg[0]); + return 0; +} + +long +sysfork(ulong *arg) +{ + Proc *p; + Seg *s; + Page *np, *op; + ulong usp, upa, pid; + Chan *c; + Orig *o; + int n, on, i; + int lastvar; /* used to compute stack address */ + + /* + * Kernel stack + */ + p = newproc(); + p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF)); + upa = p->upage->pa|KZERO; + /* + * 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; + + /* + * User stack + */ + p->seg[SSEG] = u->p->seg[SSEG]; + s = &p->seg[SSEG]; + s->proc = p; + on = (s->maxva-s->minva)>>PGSHIFT; + usp = ((Ureg*)UREGADDR)->sp; + if(usp >= USTKTOP) + panic("fork bad usp %lux", usp); + if(usp < u->p->seg[SSEG].minva) + s->minva = u->p->seg[SSEG].minva; + else + s->minva = usp & ~(BY2PG-1); + usp = s->minva & (BY2PG-1); /* just low bits */ + s->maxva = USTKTOP; + n = (s->maxva-s->minva)>>PGSHIFT; + s->o = neworig(s->minva, n, OWRPERM, 0); + lock(s->o); + /* + * Only part of last stack page + */ + for(i=0; ip->seg[SSEG].o->pte[i+(on-n)].page; + if(op){ + np = newpage(1, s->o, op->va); + p->seg[SSEG].o->pte[i].page = np; + if(i == 0){ /* only part of last stack page */ + memset((void*)(np->pa|KZERO), 0, usp); + memcpy((void*)((np->pa+usp)|KZERO), + (void*)((op->pa+usp)|KZERO), BY2PG-usp); + }else /* all of higher pages */ + memcpy((void*)(np->pa|KZERO), (void*)(op->pa|KZERO), BY2PG); + } + } + unlock(s->o); + /* + * Duplicate segments + */ + for(s=&u->p->seg[0], n=0; no == 0) + continue; + p->seg[n] = *s; + p->seg[n].proc = p; + o = s->o; + lock(o); + o->nproc++; + if(s->mod) + forkmod(s, &p->seg[n], p); + unlock(o); + } + /* + * Refs + */ + incref(u->dot); + for(n=0; n<=u->maxfd; n++) + if(c = u->fd[n]) /* assign = */ + incref(c); + /* + * Committed. Link into hierarchy + */ + lock(&p->kidlock); + lock(&u->p->kidlock); + if(u->p->kid == 0){ + p->sib = p; + u->p->kid = p; + }else{ + p->sib = u->p->kid->sib; + u->p->kid->sib = p; + } + unlock(&u->p->kidlock); + unlock(&p->kidlock); + /* + * Sched + */ + if(setlabel(&p->sched)){ + u->p = p; + p->state = Running; + p->mach = m; + m->proc = p; + spllo(); + return 0; + } + p->pop = u->p; + p->parent = u->p; + p->parentpid = u->p->pid; + p->pgrp = u->p->pgrp; + incref(p->pgrp); + u->p->nchild++; + pid = p->pid; + memset(p->time, 0, sizeof(p->time)); + p->time[TReal] = MACHP(0)->ticks; + memcpy(p->text, u->p->text, NAMELEN); + ready(p); + flushmmu(); + return pid; +} + +long +sysexec(ulong *arg) +{ + Proc *p; + Seg *s; + ulong l, t, d, b, v; + int i; + Chan *tc; + Orig *o; + char **argv, **argp; + char *a, *charp, *file; + char *progarg[sizeof(Exec)/2+1], elem[NAMELEN]; + ulong ssize, spage, nargs, nbytes, n; + ulong *sp; + int indir; + Exec exec; + char line[sizeof(Exec)]; + + p = u->p; + validaddr(arg[0], 1, 0); + file = (char*)arg[0]; + indir = 0; + Header: + tc = namec(file, Aopen, OEXEC, 0); + if(waserror()){ + close(tc); + nexterror(); + } + if(!indir) + strcpy(elem, u->elem); + n = (*devtab[tc->type].read)(tc, &exec, sizeof(Exec)); + if(n < 2) + 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) + goto Err; + goto Binary; + } + + /* + * Process #! /bin/sh args ... + */ + memcpy(line, &exec, sizeof(Exec)); + if(indir || line[0]!='#' || line[1]!='!') + goto Err; + n = shargs(line, n, progarg); + if(n == 0) + goto Err; + indir = 1; + /* + * First arg becomes complete file name + */ + progarg[n++] = file; + progarg[n] = 0; + validaddr(arg[1], BY2WD, 1); + arg[1] += BY2WD; + file = progarg[0]; + progarg[0] = elem; + close(tc); + poperror(); + goto Header; + + Binary: + t = (UTZERO+sizeof(Exec)+exec.text+(BY2PG-1)) & ~(BY2PG-1); + /* + * Last partial page of data goes into BSS. + */ + d = (t + exec.data) & ~(BY2PG-1); + b = (t + exec.data + exec.bss + (BY2PG-1)) & ~(BY2PG-1); + if((t|d|b) & KZERO) + error(0, Ebadexec); + + /* + * Args: pass 1: count + */ + nbytes = 0; + nargs = 0; + if(indir){ + argp = progarg; + while(*argp){ + a = *argp++; + nbytes += strlen(a) + 1; + nargs++; + } + } + evenaddr(arg[1]); + argp = (char**)arg[1]; + validaddr((ulong)argp, BY2WD, 0); + while(*argp){ + a = *argp++; + if(((ulong)argp&(BY2PG-1)) < BY2WD) + validaddr((ulong)argp, BY2WD, 0); + validaddr((ulong)a, 1, 0); + nbytes += (vmemchr(a, 0, 0xFFFFFFFF) - a) + 1; + nargs++; + } + ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1)); + spage = (ssize+(BY2PG-1)) >> PGSHIFT; + + /* + * Build the stack segment, putting it in kernel virtual for the moment + */ + s = &p->seg[ESEG]; + s->proc = p; + s->o = neworig(TSTKTOP-(spage<minva = s->o->va; + s->maxva = TSTKTOP; + + /* + * Args: pass 2: assemble; the pages will be faulted in + */ + argv = (char**)(TSTKTOP - ssize); + charp = (char*)(TSTKTOP - nbytes); + if(indir) + argp = progarg; + else + argp = (char**)arg[1]; + for(i=0; itext, elem, NAMELEN); + + /* + * Committed. Free old memory + */ + freesegs(ESEG); + + /* + * Text. Shared. + */ + s = &p->seg[TSEG]; + s->proc = p; + o = lookorig(UTZERO, (t-UTZERO)>>PGSHIFT, OCACHED, tc); + if(o == 0){ + o = neworig(UTZERO, (t-UTZERO)>>PGSHIFT, OCACHED, tc); + o->minca = 0; + o->maxca = sizeof(Exec)+exec.text; + } + s->o = o; + s->minva = UTZERO; + s->maxva = t; + s->mod = 0; + + /* + * Data. Shared. + */ + s = &p->seg[DSEG]; + s->proc = p; + o = lookorig(t, (d-t)>>PGSHIFT, OWRPERM|OPURE|OCACHED, tc); + if(o == 0){ + o = neworig(t, (d-t)>>PGSHIFT, OWRPERM|OPURE|OCACHED, tc); + o->minca = p->seg[TSEG].o->maxca; + o->maxca = o->minca + (exec.data & ~(BY2PG-1)); + } + s->o = o; + s->minva = t; + s->maxva = d; + s->mod = 0; + + /* + * BSS. Created afresh, starting with last page of data. + * BUG: should pick up the last page of data, which should be cached in the + * data segment. + */ + s = &p->seg[BSEG]; + s->proc = p; + o = neworig(d, (b-d)>>PGSHIFT, OWRPERM, tc); + o->minca = p->seg[DSEG].o->maxca; + o->maxca = o->minca + (exec.data & (BY2PG-1)); + s->o = o; + s->minva = d; + s->maxva = b; + s->mod = 0; + + close(tc); + + /* + * Move the stack + */ + s = &p->seg[SSEG]; + *s = p->seg[ESEG]; + p->seg[ESEG].o = 0; + o = s->o; + o->va += (USTKTOP-TSTKTOP); + s->minva = o->va; + s->maxva = USTKTOP; + lock(o); + for(i=0; inpte; i++) + o->pte[i].page->va += (USTKTOP-TSTKTOP); + unlock(o); + + flushmmu(); + ((Ureg*)UREGADDR)->pc = exec.entry - 4; + sp = (ulong*)(USTKTOP - ssize); + *--sp = nargs; + ((Ureg*)UREGADDR)->sp = (ulong)sp; + lock(&p->debug); + u->nnote = 0; + u->notify = 0; + u->notified = 0; + unlock(&p->debug); + return 0; +} + +int +shargs(char *s, int n, char **ap) +{ + int i; + + s += 2, n -= 2; /* skip #! */ + for(i=0; s[i]!='\n'; i++) + if(i == n-1) + return 0; + s[i] = 0; + *ap = 0; + i = 0; + for(;;){ + while(*s==' ' || *s=='\t') + s++; + if(*s == 0) + break; + i++; + *ap++ = s; + *ap = 0; + while(*s && *s!=' ' && *s!='\t') + s++; + if(*s == 0) + break; + else + *s++ = 0; + } + return i; +} + +int +return0(void *a) +{ + return 0; +} + +long +syssleep(ulong *arg) +{ + int ms; + + tsleep(&u->p->sleep, return0, 0, arg[0]); + return 0; +} + + +long +sysexits(ulong *arg) +{ + char *status; + + status = (char*)arg[0]; + if(status){ + if(waserror()) + status = "invalid exit string"; + else{ + validaddr((ulong)status, 1, 0); + vmemchr(status, 0, ERRLEN); + } + } + pexit(status, 1); +} + +long +syswait(ulong *arg) +{ + if(arg[0]){ + validaddr(arg[0], sizeof(Waitmsg), 1); + evenaddr(arg[0]); + } + return pwait((Waitmsg*)arg[0]); +} + +long +syslasterr(ulong *arg) +{ + Error *e; + + validaddr(arg[0], sizeof u->error, 1); + evenaddr(arg[0]); + e = (Error *)arg[0]; + memcpy(e, &u->error, sizeof u->error); + memset(&u->error, 0, sizeof u->error); + e->type = devchar[e->type]; + return 0; +} + +long +syserrstr(ulong *arg) +{ + Error *e, err; + char buf[ERRLEN]; + + validaddr(arg[1], ERRLEN, 1); + e = &err; + if(arg[0]){ + validaddr(arg[0], sizeof u->error, 0); + memcpy(e, (Error*)arg[0], sizeof(Error)); + e->type = devno(e->type, 1); + if(e->type == -1){ + e->type = 0; + e->code = Egreg+1; /* -> "no such error" */ + } + }else{ + memcpy(e, &u->error, sizeof(Error)); + memset(&u->error, 0, sizeof(Error)); + } + (*devtab[e->type].errstr)(e, buf); + memcpy((char*)arg[1], buf, sizeof buf); + return 0; +} + +long +sysforkpgrp(ulong *arg) +{ + Pgrp *pg; + + pg = newpgrp(); + if(waserror()){ + closepgrp(pg); + nexterror(); + } + if(arg[0] == 0) + pgrpcpy(pg, u->p->pgrp); + closepgrp(u->p->pgrp); + u->p->pgrp = pg; + return pg->pgrpid; +} + +long +sysnotify(ulong *arg) +{ + validaddr(arg[0], sizeof(ulong), 0); + u->notify = (int(*)(void*, char*))(arg[0]); + return 0; +} + +long +sysnoted(ulong *arg) +{ + if(u->notified == 0) + error(0, Egreg); + return 0; +} + +/* + * Temporary; should be replaced by a generalized segment control operator + */ +long +sysbrk_(ulong *arg) +{ + if(segaddr(&u->p->seg[BSEG], u->p->seg[BSEG].minva, arg[0]) == 0) + error(0, Esegaddr); + return 0; +} diff --git a/gnot/trap.c b/gnot/trap.c new file mode 100644 index 0000000000000000000000000000000000000000..3993e88ffd37aff9366dab5c0e54d3c447e42476 --- /dev/null +++ b/gnot/trap.c @@ -0,0 +1,303 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "ureg.h" +#include "io.h" + +void notify(Ureg*); +void noted(Ureg**); +void rfnote(Ureg**); + +char *regname[]={ + "R0", + "R1", + "R2", + "R3", + "R4", + "R5", + "R6", + "R7", + "A0", + "A1", + "A2", + "A3", + "A4", + "A5", + "A6", + "A7", +}; + +long ticks; + +char *trapname[]={ + "reset isp", + "reset ipc", + "bus error", + "address error", + "illegal instruction", + "zero divide", + "chk, chk2 instruction", + "cptrapcc, trapcc, trapv instruction", + "privilege violation", + "trace", + "line 1010 emulator", + "line 1111 emulator", + "reserved", + "coprocessor protocol violation", + "format error", + "uninitialized interrupt", + "unassigned 0x40", + "unassigned 0x44", + "unassigned 0x48", + "unassigned 0x4C", + "unassigned 0x50", + "unassigned 0x54", + "unassigned 0x58", + "unassigned 0x5C", + "spurious interrupt", + "level 1 autovector (tac)", + "level 2 autovector (port)", + "level 3 autovector (incon)", + "level 4 autovector (mouse)", + "level 5 autovector (uart)", + "level 6 autovector (sync)", + "level 7 autovector", +}; + +char* +excname(unsigned vo) +{ + static char buf[32]; /* BUG: not reentrant! */ + + vo &= 0x0FFF; + vo >>= 2; + if(vo < sizeof trapname/sizeof(char*)) + return trapname[vo]; + sprint(buf, "offset 0x%ux", vo<<2); + return buf; +} + +void +trap(Ureg *ur) +{ + int user; + char buf[64]; + + user = !(ur->sr&SUPER); + + if(u) + u->p->pc = ur->pc; /* BUG */ + if(user){ + sprint(buf, "pc=%lux trap: %s", ur->pc, excname(ur->vo)); + postnote(u->p, 1, buf, NDebug); + }else{ + print("kernel trap vo=%ux pc=%lux\n", ur->vo, ur->pc); + dumpregs(ur); + exit(); + } + if(user && u->nnote) + notify(ur); +} + +void +dumpstack(void) +{ + ulong l, v; + extern ulong etext; + + if(u) + for(l=(ulong)&l; lp->text, u->p->pid); + else + print("registers for kernel\n"); + print("SR=%ux PC=%lux VO=%lux, USP=%lux\n", ur->sr, ur->pc, ur->vo, ur->usp); + l = &ur->r0; + for(i=0; ip->debug); + if(u->nnote==0){ + unlock(&u->p->debug); + return; + } + if(u->note[0].flag!=NUser && (u->notified || u->notify==0)){ + if(u->note[0].flag == NDebug) + pprint("suicide: %s\n", u->note[0].msg); + Die: + unlock(&u->p->debug); + pexit(u->note[0].msg, u->note[0].flag!=NDebug); + } + if(!u->notified){ + if(!u->notify) + goto Die; + #ifdef asdfasdf + sp = ur->sp; + sp -= sizeof(Ureg); + u->ureg = (void*)sp; + memcpy((Ureg*)sp, ur, sizeof(Ureg)); + sp -= ERRLEN; + memcpy((char*)sp, u->note[0].msg, ERRLEN); + sp -= 3*BY2WD; + *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */ + *(ulong*)(sp+1*BY2WD) = (ulong)u->ureg; /* arg 1 is ureg* */ + *(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */ + ur->sp = sp; + ur->pc = (ulong)u->notify; + u->notified = 1; + u->nnote--; + memcpy(&u->note[0], &u->note[1], u->nnote*sizeof(Note)); + #endif + panic("notify"); + } + unlock(&u->p->debug); +} + +/* + * Return user to state before notify() + */ +void +noted(Ureg **urp) +{ + #ifdef asdfasdf + lock(&u->p->debug); + u->notified = 0; + memcpy(*urp, u->ureg, sizeof(Ureg)); + unlock(&u->p->debug); + splhi(); + rfnote(urp); + #endif + panic("noted"); +} + +#undef CHDIR /* BUG */ +#include "/sys/src/libc/680209sys/sys.h" + +typedef long Syscall(ulong*); +Syscall sysr1, sysfork, sysexec, sysgetpid, syssleep, sysexits, syslasterr, syswait; +Syscall sysopen, sysclose, sysread, syswrite, sysseek, syserrstr, sysaccess, sysstat, sysfstat; +Syscall sysdup, syschdir, sysforkpgrp, sysbind, sysmount, syspipe, syscreate, sysuserstr; +Syscall sysbrk_, sysremove, syswstat, sysfwstat; + +Syscall *systab[]={ + sysr1, + sysaccess, + sysbind, + syschdir, + sysclose, + sysdup, + syserrstr, + sysexec, + sysexits, + sysfork, + sysforkpgrp, + sysfstat, + syslasterr, + sysmount, + sysopen, + sysread, + sysseek, + syssleep, + sysstat, + syswait, + syswrite, + syspipe, + syscreate, + sysuserstr, + sysbrk_, + sysremove, + syswstat, + sysfwstat, +}; + +long +syscall(Ureg *aur) +{ + long ret; + ulong sp; + ulong r0; + Ureg *ur; + + u->p->insyscall = 1; + ur = aur; + if(ur->sr & SUPER) + panic("recursive system call"); +#ifdef asdf + /* + * since the system call interface does not + * guarantee anything about registers + */ + if(u->p->fpstate == FPactive) { + u->p->fpstate = FPinit; /* BUG */ + ur->status &= ~CU1; + } +#endif + r0 = ur->r0; + sp = ur->usp; + if(r0 >= sizeof systab/BY2WD) + panic("syscall %d\n", r0); + if(sp & (BY2WD-1)) + panic("syscall odd sp"); + if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-4*BY2WD)) + validaddr(sp, 4*BY2WD, 0); + + u->nerrlab = 0; + ret = -1; + if(!waserror()) + ret = (*systab[r0])((ulong*)(sp+BY2WD)); + u->nerrlab = 0; + u->p->insyscall = 0; + if(r0 == NOTED) /* ugly hack */ + noted(&aur); /* doesn't return */ + if(u->nnote){ + ur->r0 = ret; + notify(ur); + } +{ulong *arg=(ulong*)(sp+BY2WD); +if(ret==-1)print("syscall %d(%lux %lux %lux) returns error %d\n", r0, arg[0], arg[1], arg[2], u->error.code);} + return ret; +} + +void +error(Chan *c, int code) +{ + if(c){ + u->error.type = c->type; + u->error.dev = c->dev; + }else{ + u->error.type = 0; + u->error.dev = 0; + } + u->error.code = code; + nexterror(); +} + +void +nexterror(void) +{ + gotolabel(&u->errlab[--u->nerrlab]); +} diff --git a/gnot/u.h b/gnot/u.h new file mode 100644 index 0000000000000000000000000000000000000000..81dfccf482a2af1e3a96426b21223e1c14af86d6 --- /dev/null +++ b/gnot/u.h @@ -0,0 +1,15 @@ +typedef unsigned short ushort; +typedef unsigned char uchar; +typedef unsigned long ulong; +typedef long vlong; +typedef union Length Length; + +union Length +{ + char clength[8]; + vlong vlength; + struct{ + long hlength; + long length; + }; +}; diff --git a/gnot/ureg.h b/gnot/ureg.h new file mode 100644 index 0000000000000000000000000000000000000000..e6a9c2271029a74976b9515f582b047e38db5b40 --- /dev/null +++ b/gnot/ureg.h @@ -0,0 +1,23 @@ +struct Ureg +{ + ulong r0; + ulong r1; + ulong r2; + ulong r3; + ulong r4; + ulong r5; + ulong r6; + ulong r7; + ulong a0; + ulong a1; + ulong a2; + ulong a3; + ulong a4; + ulong a5; + ulong a6; + ulong sp; + ulong usp; + ushort sr; + ulong pc; + ushort vo; +}; diff --git a/gnot/vec.s b/gnot/vec.s new file mode 100644 index 0000000000000000000000000000000000000000..87215255b1dd4134c3d26cbd69bf4adaa6ca9fb4 --- /dev/null +++ b/gnot/vec.s @@ -0,0 +1,268 @@ +TEXT vectors(SB), $0 + WORD $0x4eb9 /* JSR start (never to return) */ + WORD $0x8000 + WORD $0x2420 + WORD $0x0000 +TEXT vectors0<>(SB), $0 +/* origin 0008, vector 2 */ + LONG buserror(SB) /* bus error */ + LONG illegal(SB) /* address error */ + LONG illegal(SB) /* illegal(SB) instruction */ + LONG illegal(SB) /* zero divide */ + LONG illegal(SB) /* chk, chk2 instruction */ + LONG illegal(SB) /* cptrapcc, trapcc, trapv instruction */ + LONG illegal(SB) /* privilege violation */ + LONG illegal(SB) /* trace */ + LONG illegal(SB) /* line 1010 emulator */ + LONG illegal(SB) /* line 1111 emulator */ + LONG illegal(SB) /* unassigned */ + LONG illegal(SB) /* coprocessor protocol violation */ + LONG illegal(SB) /* format error */ + LONG illegal(SB) /* uninitialized interrupt */ +/* origin 0040, vector 16 */ + LONG illegal(SB) /* 16 */ + LONG illegal(SB) /* 17 */ + LONG illegal(SB) /* 18 */ + LONG illegal(SB) /* 19 */ + LONG illegal(SB) /* 20 */ + LONG illegal(SB) /* 21 */ + LONG illegal(SB) /* 22 */ + LONG illegal(SB) /* 23 */ + LONG illegal(SB) /* 24 */ +/* origin 0064, vector 25 */ + LONG tacintr(SB) /* level 1 autovector */ + LONG illegal(SB) /* level 2 autovector (port)*/ + LONG dkintr(SB) /* level 3 autovector */ + LONG mouseintr(SB) /* level 4 autovector */ + LONG uartintr(SB) /* level 5 autovector */ + LONG syncintr(SB) /* level 6 autovector */ + LONG illegal(SB) /* level 7 autovector */ +/* origin 0080, vector 32 */ + LONG systrap(SB) /* trap #0 */ + LONG illegal(SB) /* trap #1 */ + LONG illegal(SB) /* trap #2 */ + LONG illegal(SB) /* trap #3 */ + LONG illegal(SB) /* trap #4 */ + LONG illegal(SB) /* trap #5 */ + LONG illegal(SB) /* trap #6 */ + LONG illegal(SB) /* trap #7 */ + LONG illegal(SB) /* trap #8 */ + LONG illegal(SB) /* trap #9 */ + LONG illegal(SB) /* trap #10 */ + LONG illegal(SB) /* trap #11 */ + LONG illegal(SB) /* trap #12 */ + LONG illegal(SB) /* trap #13 */ + LONG illegal(SB) /* trap #14 */ + LONG illegal(SB) /* trap #15 */ +/* origin 00C0, vector 48 */ + LONG illegal(SB) /* fpcp branch or set on unordered cond. */ + LONG illegal(SB) /* fpcp inexact result */ + LONG illegal(SB) /* fpcp divide by zero */ + LONG illegal(SB) /* fpcp underflow */ + LONG illegal(SB) /* fpcp operand error */ + LONG illegal(SB) /* fpcp overflow */ + LONG illegal(SB) /* fpcp signaling nan */ + LONG illegal(SB) /* unassigned, reserved */ + LONG illegal(SB) /* pmmu configuration */ + LONG illegal(SB) /* pmmu illegal(SB) operation */ + LONG illegal(SB) /* pmmu access level violation */ +/* origin 00EC, vector 59 */ + LONG illegal(SB) /* vector #59 */ + LONG illegal(SB) /* vector #60 */ + LONG illegal(SB) /* vector #61 */ + LONG illegal(SB) /* vector #62 */ + LONG illegal(SB) /* vector #63 */ + LONG illegal(SB) /* vector #64 */ + LONG illegal(SB) /* vector #65 */ + LONG illegal(SB) /* vector #66 */ + LONG illegal(SB) /* vector #67 */ + LONG illegal(SB) /* vector #68 */ + LONG illegal(SB) /* vector #69 */ + LONG illegal(SB) /* vector #70 */ + LONG illegal(SB) /* vector #71 */ + LONG illegal(SB) /* vector #72 */ + LONG illegal(SB) /* vector #73 */ + LONG illegal(SB) /* vector #74 */ + LONG illegal(SB) /* vector #75 */ + LONG illegal(SB) /* vector #76 */ + LONG illegal(SB) /* vector #77 */ + LONG illegal(SB) /* vector #78 */ + LONG illegal(SB) /* vector #79 */ + LONG illegal(SB) /* vector #80 */ + LONG illegal(SB) /* vector #81 */ + LONG illegal(SB) /* vector #82 */ + LONG illegal(SB) /* vector #83 */ + LONG illegal(SB) /* vector #84 */ + LONG illegal(SB) /* vector #85 */ + LONG illegal(SB) /* vector #86 */ + LONG illegal(SB) /* vector #87 */ + LONG illegal(SB) /* vector #88 */ + LONG illegal(SB) /* vector #89 */ + LONG illegal(SB) /* vector #90 */ + LONG illegal(SB) /* vector #91 */ + LONG illegal(SB) /* vector #92 */ + LONG illegal(SB) /* vector #93 */ + LONG illegal(SB) /* vector #94 */ + LONG illegal(SB) /* vector #95 */ + LONG illegal(SB) /* vector #96 */ + LONG illegal(SB) /* vector #97 */ + LONG illegal(SB) /* vector #98 */ + LONG illegal(SB) /* vector #99 */ + LONG illegal(SB) /* vector #100 */ + LONG illegal(SB) /* vector #101 */ + LONG illegal(SB) /* vector #102 */ + LONG illegal(SB) /* vector #103 */ + LONG illegal(SB) /* vector #104 */ + LONG illegal(SB) /* vector #105 */ + LONG illegal(SB) /* vector #106 */ + LONG illegal(SB) /* vector #107 */ + LONG illegal(SB) /* vector #108 */ + LONG illegal(SB) /* vector #109 */ + LONG illegal(SB) /* vector #110 */ + LONG illegal(SB) /* vector #111 */ + LONG illegal(SB) /* vector #112 */ + LONG illegal(SB) /* vector #113 */ + LONG illegal(SB) /* vector #114 */ + LONG illegal(SB) /* vector #115 */ + LONG illegal(SB) /* vector #116 */ + LONG illegal(SB) /* vector #117 */ + LONG illegal(SB) /* vector #118 */ + LONG illegal(SB) /* vector #119 */ + LONG illegal(SB) /* vector #120 */ + LONG illegal(SB) /* vector #121 */ + LONG illegal(SB) /* vector #122 */ + LONG illegal(SB) /* vector #123 */ + LONG illegal(SB) /* vector #124 */ + LONG illegal(SB) /* vector #125 */ + LONG illegal(SB) /* vector #126 */ + LONG illegal(SB) /* vector #127 */ + LONG illegal(SB) /* vector #128 */ + LONG illegal(SB) /* vector #129 */ + LONG illegal(SB) /* vector #130 */ + LONG illegal(SB) /* vector #131 */ + LONG illegal(SB) /* vector #132 */ + LONG illegal(SB) /* vector #133 */ + LONG illegal(SB) /* vector #134 */ + LONG illegal(SB) /* vector #135 */ + LONG illegal(SB) /* vector #136 */ + LONG illegal(SB) /* vector #137 */ + LONG illegal(SB) /* vector #138 */ + LONG illegal(SB) /* vector #139 */ + LONG illegal(SB) /* vector #140 */ + LONG illegal(SB) /* vector #141 */ + LONG illegal(SB) /* vector #142 */ + LONG illegal(SB) /* vector #143 */ + LONG illegal(SB) /* vector #144 */ + LONG illegal(SB) /* vector #145 */ + LONG illegal(SB) /* vector #146 */ + LONG illegal(SB) /* vector #147 */ + LONG illegal(SB) /* vector #148 */ + LONG illegal(SB) /* vector #149 */ + LONG illegal(SB) /* vector #150 */ + LONG illegal(SB) /* vector #151 */ + LONG illegal(SB) /* vector #152 */ + LONG illegal(SB) /* vector #153 */ + LONG illegal(SB) /* vector #154 */ + LONG illegal(SB) /* vector #155 */ + LONG illegal(SB) /* vector #156 */ + LONG illegal(SB) /* vector #157 */ + LONG illegal(SB) /* vector #158 */ + LONG illegal(SB) /* vector #159 */ + LONG illegal(SB) /* vector #160 */ + LONG illegal(SB) /* vector #161 */ + LONG illegal(SB) /* vector #162 */ + LONG illegal(SB) /* vector #163 */ + LONG illegal(SB) /* vector #164 */ + LONG illegal(SB) /* vector #165 */ + LONG illegal(SB) /* vector #166 */ + LONG illegal(SB) /* vector #167 */ + LONG illegal(SB) /* vector #168 */ + LONG illegal(SB) /* vector #169 */ + LONG illegal(SB) /* vector #170 */ + LONG illegal(SB) /* vector #171 */ + LONG illegal(SB) /* vector #172 */ + LONG illegal(SB) /* vector #173 */ + LONG illegal(SB) /* vector #174 */ + LONG illegal(SB) /* vector #175 */ + LONG illegal(SB) /* vector #176 */ + LONG illegal(SB) /* vector #177 */ + LONG illegal(SB) /* vector #178 */ + LONG illegal(SB) /* vector #179 */ + LONG illegal(SB) /* vector #180 */ + LONG illegal(SB) /* vector #181 */ + LONG illegal(SB) /* vector #182 */ + LONG illegal(SB) /* vector #183 */ + LONG illegal(SB) /* vector #184 */ + LONG illegal(SB) /* vector #185 */ + LONG illegal(SB) /* vector #186 */ + LONG illegal(SB) /* vector #187 */ + LONG illegal(SB) /* vector #188 */ + LONG illegal(SB) /* vector #189 */ + LONG illegal(SB) /* vector #190 */ + LONG illegal(SB) /* vector #191 */ + LONG illegal(SB) /* vector #192 */ + LONG illegal(SB) /* vector #193 */ + LONG illegal(SB) /* vector #194 */ + LONG illegal(SB) /* vector #195 */ + LONG illegal(SB) /* vector #196 */ + LONG illegal(SB) /* vector #197 */ + LONG illegal(SB) /* vector #198 */ + LONG illegal(SB) /* vector #199 */ + LONG illegal(SB) /* vector #200 */ + LONG illegal(SB) /* vector #201 */ + LONG illegal(SB) /* vector #202 */ + LONG illegal(SB) /* vector #203 */ + LONG illegal(SB) /* vector #204 */ + LONG illegal(SB) /* vector #205 */ + LONG illegal(SB) /* vector #206 */ + LONG illegal(SB) /* vector #207 */ + LONG illegal(SB) /* vector #208 */ + LONG illegal(SB) /* vector #209 */ + LONG illegal(SB) /* vector #210 */ + LONG illegal(SB) /* vector #211 */ + LONG illegal(SB) /* vector #212 */ + LONG illegal(SB) /* vector #213 */ + LONG illegal(SB) /* vector #214 */ + LONG illegal(SB) /* vector #215 */ + LONG illegal(SB) /* vector #216 */ + LONG illegal(SB) /* vector #217 */ + LONG illegal(SB) /* vector #218 */ + LONG illegal(SB) /* vector #219 */ + LONG illegal(SB) /* vector #220 */ + LONG illegal(SB) /* vector #221 */ + LONG illegal(SB) /* vector #222 */ + LONG illegal(SB) /* vector #223 */ + LONG illegal(SB) /* vector #224 */ + LONG illegal(SB) /* vector #225 */ + LONG illegal(SB) /* vector #226 */ + LONG illegal(SB) /* vector #227 */ + LONG illegal(SB) /* vector #228 */ + LONG illegal(SB) /* vector #229 */ + LONG illegal(SB) /* vector #230 */ + LONG illegal(SB) /* vector #231 */ + LONG illegal(SB) /* vector #232 */ + LONG illegal(SB) /* vector #233 */ + LONG illegal(SB) /* vector #234 */ + LONG illegal(SB) /* vector #235 */ + LONG illegal(SB) /* vector #236 */ + LONG illegal(SB) /* vector #237 */ + LONG illegal(SB) /* vector #238 */ + LONG illegal(SB) /* vector #239 */ + LONG illegal(SB) /* vector #240 */ + LONG illegal(SB) /* vector #241 */ + LONG illegal(SB) /* vector #242 */ + LONG illegal(SB) /* vector #243 */ + LONG illegal(SB) /* vector #244 */ + LONG illegal(SB) /* vector #245 */ + LONG illegal(SB) /* vector #246 */ + LONG illegal(SB) /* vector #247 */ + LONG illegal(SB) /* vector #248 */ + LONG illegal(SB) /* vector #249 */ + LONG illegal(SB) /* vector #250 */ + LONG illegal(SB) /* vector #251 */ + LONG illegal(SB) /* vector #252 */ + LONG illegal(SB) /* vector #253 */ + LONG illegal(SB) /* vector #254 */ + LONG illegal(SB) /* vector #255 */ +/* origin 400 */ +/* start(SB) follows immediately */ diff --git a/port/devcons.c b/port/devcons.c index 2e7f51d4766b3536a12cf8d9cca29b58bc152384..cd1a3c1cddca2ae31204d2c25efd36015fa6d57e 100644 --- a/port/devcons.c +++ b/port/devcons.c @@ -144,10 +144,7 @@ getc(IOQ *q) int sprint(char *s, char *fmt, ...) { - char *out; - - out = donprint(s, s+PRINTSIZE, fmt, (&fmt+1)); - return out-s; + return donprint(s, s+PRINTSIZE, fmt, (&fmt+1)) - s; } int @@ -233,6 +230,7 @@ void echo(int c) { char ch; + /* * ^t hack BUG */ diff --git a/port/devmnt.c b/port/devmnt.c index 6fdc537c0b9bf4c8dc9860acfdc884665cc2bd84..e33688ffa958f0ee9f5d616a34008c8cadad2876 100644 --- a/port/devmnt.c +++ b/port/devmnt.c @@ -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; diff --git a/port/proc.c b/port/proc.c index f0639ded6ae9cdb3a06627601af9b659864707b9..d0fad9f0ba699e260e04bba2c83478dc2f566564 100644 --- a/port/proc.c +++ b/port/proc.c @@ -195,8 +195,6 @@ procinit0(void) /* bad planning - clashes with devproc.c */ Proc *p; int i; - print("procinit\n"); - procalloc.free = ialloc(conf.nproc*sizeof(Proc), 0); procalloc.arena = procalloc.free; @@ -288,6 +286,19 @@ wakeup(Rendez *r) splx(s); } +void +wakeme(Alarm *a) +{ + ready((Proc*)(a->arg)); + cancel(a); +} + +void +twakeme(Alarm *a) +{ + wakeup((Rendez*)(a->arg)); +} + int postnote(Proc *p, int dolock, char *n, int flag) { @@ -324,19 +335,6 @@ postnote(Proc *p, int dolock, char *n, int flag) return 1; } -void -wakeme(Alarm *a) -{ - ready((Proc*)(a->arg)); - cancel(a); -} - -void -twakeme(Alarm *a) -{ - wakeup((Rendez*)(a->arg)); -} - void pexit(char *s, int freemem) { diff --git a/power/dat.h b/power/dat.h index 0b8aeef2b3472c8f984ca3075ee9111d7794e75d..4003dd8e5320b0b39a933edfebe4165819c2b451 100644 --- a/power/dat.h +++ b/power/dat.h @@ -26,10 +26,10 @@ typedef struct Proc Proc; typedef struct QLock QLock; typedef struct Qinfo Qinfo; typedef struct Queue Queue; -typedef struct Stream Stream; typedef struct Ref Ref; typedef struct Rendez Rendez; typedef struct Seg Seg; +typedef struct Stream Stream; typedef struct Ureg Ureg; typedef struct User User; diff --git a/power/trap.c b/power/trap.c index 01c9a39dc56173e128bd243ba2bdad0d8366d884..5eb654e7af8e68da59cdfc36c349f7281294d57d 100644 --- a/power/trap.c +++ b/power/trap.c @@ -279,6 +279,7 @@ fpexcname(ulong x) return str[i]; return "no floating point exception"; } + void dumpstack(void) { @@ -420,6 +421,7 @@ syscall(Ureg *aur) u->p->insyscall = 1; ur = aur; + u->p->pc = ur->pc; /* BUG */ /* * since the system call interface does not * guarantee anything about registers, @@ -445,13 +447,13 @@ syscall(Ureg *aur) ur->pc += 4; u->nerrlab = 0; splhi(); + u->p->insyscall = 0; if(r1 == NOTED) /* ugly hack */ noted(&aur); /* doesn't return */ if(u->nnote){ ur->r1 = ret; notify(ur); } - u->p->insyscall = 0; return ret; }