From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Maksim Radziwill" <7c00@wp.pl> To: <9fans@cse.psu.edu> Message-ID: <000001c2daaf$c28d7e60$f7e84dd5@makr4j0ty5i9an> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_0001_01C2DAB8.2451E660" Subject: [9fans] Apm Enhancement + some bonuses Date: Sat, 22 Feb 2003 21:19:52 +0100 Topicbox-Message-UUID: 6e43891e-eacb-11e9-9e20-41e7f4b1d025 This is a multi-part message in MIME format. ------=_NextPart_000_0001_01C2DAB8.2451E660 Content-Type: multipart/alternative; boundary="----=_NextPart_001_0002_01C2DAB8.2451E660" ------=_NextPart_001_0002_01C2DAB8.2451E660 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Hi all, I wrote a (ugly) enhancement to the plan9 kernel that allows users using workstations To press ^P and power off the machine, this is especially useful on (old) notebooks That has a broken power switch. I have added too some extra feature ^T^T 5 will turn off the screen ^T^T 6 will put it into a ready state ^T^T f confirms apm is present in the kernel ^T^T g is equivalent to ^P on workstations There was too an options to poweroff disks, but it may hang the whole system. Normally aux/apm disallows you to power off because you won't be able to sync the fs And if you halt the fs you won't be able to power off using aux/apm . ;) (Of course if you uncomment those two lines that allows suspending the sys in the aux/apm code) What is the solutions to this ? Place the power off sequence in the kernel as a key shortcut We will use ^P because using it will power off workstations and reboot cpu's , a nice behavior (since we won't need to power off cpu server) VERY IMPORTANT !!! This thing won't work if aux/apm isn't working in the background. And if boot.ini don't have the apm0= line added. So how to install the code? Copy the attached lib.h to /sys/src/9/port/lib.h The devcons.c to /sys/src/9/port/devcons.c The apm.c to /sys/src/9/pc/apm.c And recompile the kernel and then install it. This is a *extremely* dirty (and ugly) hack, don't blame me for it please. If you ever want to add some shorcuts for other devices (like net cards) Then you'll have to know that the poweroff_call functions Takes too argument - Which device - What to do with it So as an example poweroff_call(ALL_DEVICES,POWEROFF); Will effectively power off all devices The defines for the Devices are self explanatory: #define BIOS 0x00 #define ALL_DEVICES 0x01 #define DISPLAY 0x1ff #define SEC_STORAGE 0x2ff #define PARALE_PORT 0x3ff #define SERIAL_PORT 0x4ff #define NET_ADAPTER 0x5ff #define PCMCIA 0x6ff #define BATTERY 0x80ff Consider BIOS equivalent to ALL_DEVICES The same for the action taken: #define POWEROFF 0x03 #define SLEEP_DEEP 0x02 #define SLEEP_LIGHT 0x01 #define READY 0x00 Anyway HAVE FUN, Maks P.S: If you got some troubles just mail me I'm planning too to clean that stuff one of those days. ------=_NextPart_001_0002_01C2DAB8.2451E660 Content-Type: text/html; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Hi all,

Hi all,

I wrote a (ugly) enhancement to the plan9 kernel that = allows users using workstations

To press ^P and power off the machine, this is = especially useful on (old) notebooks

That has a broken power = switch…

 

I have added too some extra feature ^T^T 5 will turn = off the screen

^T^T 6 will put it into a ready = state

^T^T f confirms apm is = present in the kernel

^T^T g is equivalent to ^P on = workstations

There was too an options = to poweroff disks, but it may hang the whole = system…

 

Normally aux/apm = disallows you to power off because you won’t be able to sync the fs

And if you halt the fs = you won’t be able to power off using aux/apm … ;)

(Of course if you uncomment those two lines that = allows suspending  = the sys in the aux/apm = code)

What is the solutions to this = ? Place the power off sequence in the kernel as a key = shortcut

We will use ^P because using it will power off = workstations and reboot cpu’s , a nice behavior

(since we won’t need = to power off cpu server)

 

VERY IMPORTANT !!! This = thing won’t work if aux/apm isn’t = working in the background…

        = ;            =            &nbs= p;  And if boot.ini don’t have the = apm0=3D line added…

 

 

So how to install the = code?

Copy the attached lib.h = to /sys/src/9/port/lib.h

The devcons.c to /sys/src/9/port/devcons.c

The apm.c to = /sys/src/9/pc/apm.c

And recompile the kernel and then install = it…

 

This is a *extremely* dirty (and ugly) hack, = don’t blame me for it please.

 

If you ever want to add some shorcuts for other devices (like net cards)

Then you’ll have to know that the poweroff_call functions

Takes too argument

-          Which = device

-          What to do with = it

 

So as an example poweroff_call(ALL_DEVICES,POWEROFF);

=

Will effectively power off all = devices

The = defines for the Devices are self explanatory:

#define BIOS       &nbs= p;  0x00

#define ALL_DEVICES   = 0x01

#define DISPLAY       0x1ff

#define SEC_STORAGE   = 0x2ff

#define PARALE_PORT   = 0x3ff

#define SERIAL_PORT   = 0x4ff

#define NET_ADAPTER   = 0x5ff

#define PCMCIA        0x6ff

#define BATTERY       = 0x80ff

Consider BIOS equivalent to = ALL_DEVICES

The same for the action = taken:

#define POWEROFF      0x03

#define SLEEP_DEEP    = 0x02

#define SLEEP_LIGHT   = 0x01

#define READY       &nbs= p; 0x00

 

Anyway HAVE FUN,

Maks

 

P.S: If you got some troubles just mail = me

       &nbs= p;   I’m planning too to clean that stuff one of those = days…

 

 

 

 

 

 

 

 

 

------=_NextPart_001_0002_01C2DAB8.2451E660-- ------=_NextPart_000_0001_01C2DAB8.2451E660 Content-Type: application/octet-stream; name="apm.c" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="apm.c" /* * Interface to Advanced Power Management 1.2 BIOS * * This is, in many ways, a giant hack, and when things settle down=20 * a bit and standardize, hopefully we can write a driver that deals * more directly with the hardware and thus might be a bit cleaner. *=20 * ACPI might be the answer, but at the moment this is simpler * and more widespread. */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "ureg.h" extern int apmfarcall(ushort, ulong, Ureg*); /* apmjump.s */ static int getreg(ulong *reg, ISAConf *isa, char *name) { int i; int nl; nl =3D strlen(name); for(i=3D0; inopt; i++){ if(cistrncmp(isa->opt[i], name, nl)=3D=3D0 && isa->opt[i][nl] =3D=3D = '=3D'){ *reg =3D strtoul(isa->opt[i]+nl+1, nil, 16); return 0; } } return -1; } /* * Segment descriptors look like this. * * d1: [base 31:24] [gran] [is32bit] [0] [unused] [limit 19:16]=20 [present] [privlev] [type 3:0] [base 23:16] * d0: [base 15:00] [limit 15:00] * * gran is 0 for 1-byte granularity, 1 for 4k granularity * type is 0 for system segment, 1 for code/data. * * clearly we know way too much about the memory unit. * however, knowing this much about the memory unit * means that the memory unit need not know anything * about us. * * what a crock. */ static void setgdt(int sel, ulong base, ulong limit, int flag) { if(sel < 0 || sel >=3D NGDT) panic("setgdt"); base =3D (ulong)KADDR(base); m->gdt[sel].d0 =3D (base<<16) | (limit&0xFFFF); m->gdt[sel].d1 =3D (base&0xFF000000) | (limit&0x000F0000) | ((base>>16)&0xFF) | SEGP | SEGPL(0) | flag; } static ulong ax, cx, dx, di, ebx, esi; static Ureg apmu; static long apmread(Chan*, void *a, long n, vlong off) { if(off < 0) error("badarg"); if(n+off > sizeof apmu) n =3D sizeof apmu - off; if(n <=3D 0) return 0; memmove(a, (char*)&apmu+off, n); return n; } void poweroff_call(int what,int how){ int sec; Ureg happyregs; happyregs.ax =3D 0x5307; happyregs.cx =3D how; happyregs.bx =3D what; sec =3D splhi(); apmfarcall(APMCSEL, ebx, &happyregs); splx(sec); return; } static long apmwrite(Chan*, void *a, long n, vlong off) { int s; if(off || n !=3D sizeof apmu) error("write a Ureg"); memmove(&apmu, a, sizeof apmu); s =3D splhi(); apmfarcall(APMCSEL, ebx, &apmu); splx(s); return n; } void apmlink(void) { ISAConf isa; char *s; if(isaconfig("apm", 0, &isa) =3D=3D 0) return; /* * APM info passed from boot loader. * Now we need to set up the GDT entries for APM. * * AX =3D 32-bit code segment base address * EBX =3D 32-bit code segment offset * CX =3D 16-bit code segment base address * DX =3D 32-bit data segment base address * ESI =3D <16-bit code segment length> <32-bit code segment length> = (hi then lo) * DI =3D 32-bit data segment length */ if(getreg(&ax, &isa, s=3D"ax") < 0 || getreg(&ebx, &isa, s=3D"ebx") < 0 || getreg(&cx, &isa, s=3D"cx") < 0 || getreg(&dx, &isa, s=3D"dx") < 0 || getreg(&esi, &isa, s=3D"esi") < 0 || getreg(&di, &isa, s=3D"di") < 0){ print("apm: missing register %s\n", s); return; } /* * The NEC Versa SX bios does not report the correct 16-bit code * segment length when loaded directly from mbr -> 9load (as compared * with going through ld.com). We'll make both code segments 64k-1 = bytes. */ esi =3D 0xFFFFFFFF; /* * We are required by the BIOS to set up three consecutive segments, * one for the APM 32-bit code, one for the APM 16-bit code, and=20 * one for the APM data. The BIOS handler uses the code segment it * get called with to determine the other two segment selector. */ setgdt(APMCSEG, ax<<4, ((esi&0xFFFF)-1)&0xFFFF, SEGEXEC|SEGR|SEGD); setgdt(APMCSEG16, cx<<4, ((esi>>16)-1)&0xFFFF, SEGEXEC|SEGR); setgdt(APMDSEG, dx<<4, (di-1)&0xFFFF, SEGDATA|SEGW|SEGD); addarchfile("apm", 0660, apmread, apmwrite); print("apm0: configured cbase %.8lux off %.8lux\n", ax<<4, ebx); return; } ------=_NextPart_000_0001_01C2DAB8.2451E660 Content-Type: application/octet-stream; name="devcons.c" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="devcons.c" #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include void (*consdebug)(void) =3D nil; void (*screenputs)(char*, int) =3D nil; Queue* kbdq; /* unprocessed console input */ Queue* lineq; /* processed console input */ Queue* serialoq; /* serial console output */ Queue* kprintoq; /* console output, for /dev/kprint */ ulong kprintinuse; /* test and set whether /dev/kprint is open */ int iprintscreenputs =3D 1; static struct { QLock; int raw; /* true if we shouldn't process input */ int ctl; /* number of opens to the control file */ int x; /* index into line */ char line[1024]; /* current input line */ int count; int ctlpoff; /* a place to save up characters at interrupt time before dumping them = in the queue */ Lock lockputc; char istage[512]; char *iw; char *ir; char *ie; } kbd =3D { .iw =3D kbd.istage, .ir =3D kbd.istage, .ie =3D kbd.istage + sizeof(kbd.istage), }; char *sysname; vlong fasthz; static void seedrand(void); static int readtime(ulong, char*, int); static int readbintime(char*, int); static int writetime(char*, int); static int writebintime(char*, int); enum { CMreboot, CMpanic, }; Cmdtab rebootmsg[] =3D { CMreboot, "reboot", 0, CMpanic, "panic", 0, }; void printinit(void) { lineq =3D qopen(2*1024, 0, 0, 0); if(lineq =3D=3D nil) panic("printinit"); qnoblock(lineq, 1); } int consactive(void) { if(serialoq) return qlen(serialoq) > 0; return 0; } void prflush(void) { ulong now; now =3D m->ticks; while(consactive()) if(m->ticks - now >=3D HZ) break; } /* * Print a string on the console. Convert \n to \r\n for serial * line consoles. Locking of the queues is left up to the screen * or uart code. Multi-line messages to serial consoles may get * interspersed with other messages. */ static void putstrn0(char *str, int n, int usewrite) { int m; char *t; /* * if someone is reading /dev/kprint, * put the message there. * if not and there's an attached bit mapped display, * put the message there. * * if there's a serial line being used as a console, * put the message there. */ if(kprintoq !=3D nil && !qisclosed(kprintoq)){ if(usewrite) qwrite(kprintoq, str, n); else qiwrite(kprintoq, str, n); }else if(screenputs !=3D nil) screenputs(str, n); if(serialoq =3D=3D nil){ uartputs(str, n); return; } while(n > 0) { t =3D memchr(str, '\n', n); if(t && !kbd.raw) { m =3D t-str; if(usewrite){ qwrite(serialoq, str, m); qwrite(serialoq, "\r\n", 2); } else { qiwrite(serialoq, str, m); qiwrite(serialoq, "\r\n", 2); } n -=3D m+1; str =3D t+1; } else { if(usewrite) qwrite(serialoq, str, n); else qiwrite(serialoq, str, n); break; } } } void putstrn(char *str, int n) { putstrn0(str, n, 0); } int noprint; int print(char *fmt, ...) { int n; va_list arg; char buf[PRINTSIZE]; if(noprint) return -1; va_start(arg, fmt); n =3D vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); putstrn(buf, n); return n; } int iprint(char *fmt, ...) { int n, s; va_list arg; char buf[PRINTSIZE]; s =3D splhi(); va_start(arg, fmt); n =3D vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); if(screenputs !=3D nil && iprintscreenputs) screenputs(buf, n); uartputs(buf, n); splx(s); return n; } void panic(char *fmt, ...) { int n; va_list arg; char buf[PRINTSIZE]; static int panicking; kprintoq =3D nil; /* don't try to write to /dev/kprint */ if(panicking) for(;;); panicking =3D 1; splhi(); strcpy(buf, "panic: "); va_start(arg, fmt); n =3D vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf; va_end(arg); buf[n] =3D '\n'; uartputs(buf, n+1); if(consdebug) (*consdebug)(); spllo(); prflush(); putstrn(buf, n+1); dumpstack(); exit(1); } void _assert(char *fmt) { panic("assert failed: %s", fmt); } int pprint(char *fmt, ...) { int n; Chan *c; va_list arg; char buf[2*PRINTSIZE]; if(up =3D=3D nil || up->fgrp =3D=3D nil) return 0; c =3D up->fgrp->fd[2]; if(c=3D=3D0 || (c->mode!=3DOWRITE && c->mode!=3DORDWR)) return 0; n =3D sprint(buf, "%s %lud: ", up->text, up->pid); va_start(arg, fmt); n =3D vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); if(waserror()) return 0; devtab[c->type]->write(c, buf, n, c->offset); poperror(); lock(c); c->offset +=3D n; unlock(c); return n; } static void echoscreen(char *buf, int n) { char *e, *p; char ebuf[128]; int x; p =3D ebuf; e =3D ebuf + sizeof(ebuf) - 4; while(n-- > 0){ if(p >=3D e){ screenputs(ebuf, p - ebuf); p =3D ebuf; } x =3D *buf++; if(x =3D=3D 0x15){ *p++ =3D '^'; *p++ =3D 'U'; *p++ =3D '\n'; } else *p++ =3D x; } if(p !=3D ebuf) screenputs(ebuf, p - ebuf); } static void echoserialoq(char *buf, int n) { char *e, *p; char ebuf[128]; int x; p =3D ebuf; e =3D ebuf + sizeof(ebuf) - 4; while(n-- > 0){ if(p >=3D e){ qiwrite(serialoq, ebuf, p - ebuf); p =3D ebuf; } x =3D *buf++; if(x =3D=3D '\n'){ *p++ =3D '\r'; *p++ =3D '\n'; } else if(x =3D=3D 0x15){ *p++ =3D '^'; *p++ =3D 'U'; *p++ =3D '\n'; } else *p++ =3D x; } if(p !=3D ebuf) qiwrite(serialoq, ebuf, p - ebuf); } void echo(char *buf, int n) { static int ctrlt, pid; extern ulong etext; int x; char *e, *p; e =3D buf+n; for(p =3D buf; p < e; p++){ switch(*p){ case 0x10: /* ^P */ if(cpuserver && !kbd.ctlpoff){ active.exiting =3D 1; return; }else{ // Poweroff code... poweroff_call(1,3); // All,Poweroff print("APM failed.\n"); } break; case 0x14: /* ^T */ ctrlt++; if(ctrlt > 2) ctrlt =3D 2; continue; } if(ctrlt !=3D 2) continue; /* ^T escapes */ ctrlt =3D 0; switch(*p){ case '5': // Disp. poweroff poweroff_call(0x1ff,3); return; case '6': // Disp. ready poweroff_call(0x1ff,0); return; case 'f': // Check if present print("APM functions present\n"); =09 return; case 'S': x =3D splhi(); dumpstack(); procdump(); splx(x); return; case 's': dumpstack(); return; case 'x': xsummary(); ixsummary(); mallocsummary(); pagersummary(); return; case 'd': if(consdebug =3D=3D nil) consdebug =3D rdb; else consdebug =3D nil; print("consdebug now 0x%p\n", consdebug); return; case 'D': if(consdebug =3D=3D nil) consdebug =3D rdb; consdebug(); return; case 'p': x =3D spllo(); procdump(); splx(x); return; case 'q': scheddump(); return; case 'k': if(!cpuserver) killbig(); return; case 'r': exit(0); return; case 'g': // Poweroff all x =3D splhi(); poweroff_call(1,3); print("APM Failed."); splx(x); return; } } qproduce(kbdq, buf, n); if(kbd.raw) return; if(screenputs !=3D nil) echoscreen(buf, n); if(serialoq) echoserialoq(buf, n); } /* * Called by a uart interrupt for console input. * * turn '\r' into '\n' before putting it into the queue. */ int kbdcr2nl(Queue*, int ch) { char *next; ilock(&kbd.lockputc); /* just a mutex */ if(ch =3D=3D '\r' && !kbd.raw) ch =3D '\n'; next =3D kbd.iw+1; if(next >=3D kbd.ie) next =3D kbd.istage; if(next !=3D kbd.ir){ *kbd.iw =3D ch; kbd.iw =3D next; } iunlock(&kbd.lockputc); return 0; } /* * Put character, possibly a rune, into read queue at interrupt time. * Called at interrupt time to process a character. */ int kbdputc(Queue*, int ch) { int i, n; char buf[3]; Rune r; char *next; if(kbd.ir =3D=3D nil) return 0; /* in case we're not inited yet */ =09 ilock(&kbd.lockputc); /* just a mutex */ r =3D ch; n =3D runetochar(buf, &r); for(i =3D 0; i < n; i++){ next =3D kbd.iw+1; if(next >=3D kbd.ie) next =3D kbd.istage; if(next =3D=3D kbd.ir) break; *kbd.iw =3D buf[i]; kbd.iw =3D next; } iunlock(&kbd.lockputc); return 0; } /* * we save up input characters till clock time to reduce * per character interrupt overhead. */ static void kbdputcclock(void) { char *iw; /* this amortizes cost of qproduce */ if(kbd.iw !=3D kbd.ir){ iw =3D kbd.iw; if(iw < kbd.ir){ echo(kbd.ir, kbd.ie-kbd.ir); kbd.ir =3D kbd.istage; } echo(kbd.ir, iw-kbd.ir); kbd.ir =3D iw; } } enum{ Qdir, Qbintime, Qcons, Qconsctl, Qcputime, Qdrivers, Qkprint, Qhostdomain, Qhostowner, Qnull, Qosversion, Qpgrpid, Qpid, Qppid, Qrandom, Qreboot, Qswap, Qsysname, Qsysstat, Qtime, Quser, Qzero, }; enum { VLNUMSIZE=3D 22, }; static Dirtab consdir[]=3D{ ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, "bintime", {Qbintime}, 24, 0664, "cons", {Qcons}, 0, 0660, "consctl", {Qconsctl}, 0, 0220, "cputime", {Qcputime}, 6*NUMSIZE, 0444, "drivers", {Qdrivers}, 0, 0444, "hostdomain", {Qhostdomain}, DOMLEN, 0664, "hostowner", {Qhostowner}, 0, 0664, "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440, "null", {Qnull}, 0, 0666, "osversion", {Qosversion}, 0, 0444, "pgrpid", {Qpgrpid}, NUMSIZE, 0444, "pid", {Qpid}, NUMSIZE, 0444, "ppid", {Qppid}, NUMSIZE, 0444, "random", {Qrandom}, 0, 0444, "reboot", {Qreboot}, 0, 0664, "swap", {Qswap}, 0, 0664, "sysname", {Qsysname}, 0, 0664, "sysstat", {Qsysstat}, 0, 0666, "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664, "user", {Quser}, 0, 0666, "zero", {Qzero}, 0, 0444, }; int readnum(ulong off, char *buf, ulong n, ulong val, int size) { char tmp[64]; snprint(tmp, sizeof(tmp), "%*.0lud", size-1, val); tmp[size-1] =3D ' '; if(off >=3D size) return 0; if(off+n > size) n =3D size-off; memmove(buf, tmp+off, n); return n; } int readstr(ulong off, char *buf, ulong n, char *str) { int size; size =3D strlen(str); if(off >=3D size) return 0; if(off+n > size) n =3D size-off; memmove(buf, str+off, n); return n; } static void consinit(void) { todinit(); randominit(); addclock0link(kbdputcclock); } static Chan* consattach(char *spec) { return devattach('c', spec); } static Walkqid* conswalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen); } static int consstat(Chan *c, uchar *dp, int n) { return devstat(c, dp, n, consdir, nelem(consdir), devgen); } static Chan* consopen(Chan *c, int omode) { c->aux =3D nil; c =3D devopen(c, omode, consdir, nelem(consdir), devgen); switch((ulong)c->qid.path){ case Qconsctl: qlock(&kbd); kbd.ctl++; qunlock(&kbd); break; case Qkprint: if(tas(&kprintinuse) !=3D 0){ c->flag &=3D ~COPEN; error(Einuse); } if(kprintoq =3D=3D nil){ kprintoq =3D qopen(8*1024, -1, 0, 0); if(kprintoq =3D=3D nil){ c->flag &=3D ~COPEN; error(Enomem); } qnoblock(kprintoq, 1); }else qreopen(kprintoq); c->iounit =3D qiomaxatomic; break; } return c; } static void consclose(Chan *c) { switch((ulong)c->qid.path){ /* last close of control file turns off raw */ case Qconsctl: if(c->flag&COPEN){ qlock(&kbd); if(--kbd.ctl =3D=3D 0) kbd.raw =3D 0; qunlock(&kbd); } break; /* close of kprint allows other opens */ case Qkprint: if(c->flag & COPEN){ kprintinuse =3D 0; qhangup(kprintoq, nil); } break; } } static long consread(Chan *c, void *buf, long n, vlong off) { ulong l; Mach *mp; char *b, *bp; char tmp[128]; /* must be >=3D 6*NUMSIZE */ char *cbuf =3D buf; int ch, i, k, id, eol; vlong offset =3D off; if(n <=3D 0) return n; switch((ulong)c->qid.path){ case Qdir: return devdirread(c, buf, n, consdir, nelem(consdir), devgen); case Qcons: qlock(&kbd); if(waserror()) { qunlock(&kbd); nexterror(); } if(kbd.raw) { if(qcanread(lineq)) n =3D qread(lineq, buf, n); else { /* read as much as possible */ do { i =3D qread(kbdq, cbuf, n); cbuf +=3D i; n -=3D i; } while (n>0 && qcanread(kbdq)); n =3D cbuf - (char*)buf; } } else { while(!qcanread(lineq)) { qread(kbdq, &kbd.line[kbd.x], 1); ch =3D kbd.line[kbd.x]; eol =3D 0; switch(ch){ case '\b': if(kbd.x) kbd.x--; break; case 0x15: kbd.x =3D 0; break; case '\n': case 0x04: eol =3D 1; default: kbd.line[kbd.x++] =3D ch; break; } if(kbd.x =3D=3D sizeof(kbd.line) || eol){ if(ch =3D=3D 0x04) kbd.x--; qwrite(lineq, kbd.line, kbd.x); kbd.x =3D 0; } } n =3D qread(lineq, buf, n); } qunlock(&kbd); poperror(); return n; case Qcputime: k =3D offset; if(k >=3D 6*NUMSIZE) return 0; if(k+n > 6*NUMSIZE) n =3D 6*NUMSIZE - k; /* easiest to format in a separate buffer and copy out */ for(i=3D0; i<6 && NUMSIZE*itime[i]; if(i =3D=3D TReal) l =3D MACHP(0)->ticks - l; l =3D TK2MS(l); readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE); } memmove(buf, tmp+k, n); return n; case Qkprint: return qread(kprintoq, buf, n); case Qpgrpid: return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE); case Qpid: return readnum((ulong)offset, buf, n, up->pid, NUMSIZE); case Qppid: return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE); case Qtime: return readtime((ulong)offset, buf, n); case Qbintime: return readbintime(buf, n); case Qhostowner: return readstr((ulong)offset, buf, n, eve); case Qhostdomain: return readstr((ulong)offset, buf, n, hostdomain); case Quser: return readstr((ulong)offset, buf, n, up->user); case Qnull: return 0; case Qsysstat: b =3D smalloc(conf.nmach*(NUMSIZE*8+1) + 1); /* +1 for NUL */ bp =3D b; for(id =3D 0; id < 32; id++) { if(active.machs & (1<cs, NUMSIZE); bp +=3D NUMSIZE; readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE); bp +=3D NUMSIZE; readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE); bp +=3D NUMSIZE; readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE); bp +=3D NUMSIZE; readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE); bp +=3D NUMSIZE; readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE); bp +=3D NUMSIZE; readnum(0, bp, NUMSIZE, mp->load, NUMSIZE); bp +=3D NUMSIZE; *bp++ =3D '\n'; } } if(waserror()){ free(b); nexterror(); } n =3D readstr((ulong)offset, buf, n, b); free(b); poperror(); return n; case Qswap: sprint(tmp, "%lud/%lud memory %lud/%lud swap\n", palloc.user-palloc.freecount, palloc.user, conf.nswap-swapalloc.free, conf.nswap); return readstr((ulong)offset, buf, n, tmp); case Qsysname: if(sysname =3D=3D nil) return 0; return readstr((ulong)offset, buf, n, sysname); case Qrandom: return randomread(buf, n); case Qdrivers: b =3D malloc(READSTR); if(b =3D=3D nil) error(Enomem); n =3D 0; for(i =3D 0; devtab[i] !=3D nil; i++) n +=3D snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc, = devtab[i]->name); if(waserror()){ free(b); nexterror(); } n =3D readstr((ulong)offset, buf, n, b); free(b); poperror(); return n; case Qzero: memset(buf, 0, n); return n; case Qosversion: snprint(tmp, sizeof tmp, "2000"); n =3D readstr((ulong)offset, buf, n, tmp); return n; default: print("consread 0x%llux\n", c->qid.path); error(Egreg); } return -1; /* never reached */ } static long conswrite(Chan *c, void *va, long n, vlong off) { char buf[256]; long l, bp; char *a =3D va; Mach *mp; int id, fd; Chan *swc; ulong offset =3D off; Cmdbuf *cb; Cmdtab *ct; switch((ulong)c->qid.path){ case Qcons: /* * Can't page fault in putstrn, so copy the data locally. */ l =3D n; while(l > 0){ bp =3D l; if(bp > sizeof buf) bp =3D sizeof buf; memmove(buf, a, bp); putstrn0(buf, bp, 1); a +=3D bp; l -=3D bp; } break; case Qconsctl: if(n >=3D sizeof(buf)) n =3D sizeof(buf)-1; strncpy(buf, a, n); buf[n] =3D 0; for(a =3D buf; a;){ if(strncmp(a, "rawon", 5) =3D=3D 0){ qlock(&kbd); if(kbd.x){ qwrite(kbdq, kbd.line, kbd.x); kbd.x =3D 0; } kbd.raw =3D 1; qunlock(&kbd); } else if(strncmp(a, "rawoff", 6) =3D=3D 0){ qlock(&kbd); kbd.raw =3D 0; kbd.x =3D 0; qunlock(&kbd); } else if(strncmp(a, "ctlpon", 6) =3D=3D 0){ kbd.ctlpoff =3D 0; } else if(strncmp(a, "ctlpoff", 7) =3D=3D 0){ kbd.ctlpoff =3D 1; } if(a =3D strchr(a, ' ')) a++; } break; case Qtime: if(!iseve()) error(Eperm); return writetime(a, n); case Qbintime: if(!iseve()) error(Eperm); return writebintime(a, n); case Qhostowner: return hostownerwrite(a, n); case Qhostdomain: return hostdomainwrite(a, n); case Quser: return userwrite(a, n); case Qnull: break; case Qreboot: if(!iseve()) error(Eperm); cb =3D parsecmd(a, n); if(waserror()) { free(cb); nexterror(); } ct =3D lookupcmd(cb, rebootmsg, nelem(rebootmsg)); switch(ct->index) { case CMreboot: rebootcmd(cb->nf-1, cb->f+1); break; case CMpanic: panic("/dev/reboot"); } poperror(); free(cb); break; case Qsysstat: for(id =3D 0; id < 32; id++) { if(active.machs & (1<cs =3D 0; mp->intr =3D 0; mp->syscall =3D 0; mp->pfault =3D 0; mp->tlbfault =3D 0; mp->tlbpurge =3D 0; } } break; case Qswap: if(n >=3D sizeof buf) error(Egreg); memmove(buf, va, n); /* so we can NUL-terminate */ buf[n] =3D 0; /* start a pager if not already started */ if(strncmp(buf, "start", 5) =3D=3D 0){ kickpager(); break; } if(cpuserver && !iseve()) error(Eperm); if(buf[0]<'0' || '9'=3D sizeof buf) error(Ebadarg); strncpy(buf, a, n); buf[n] =3D 0; if(buf[n-1] =3D=3D '\n') buf[n-1] =3D 0; kstrdup(&sysname, buf); break; default: print("conswrite: 0x%llux\n", c->qid.path); error(Egreg); } return n; } Dev consdevtab =3D { 'c', "cons", devreset, consinit, devshutdown, consattach, conswalk, consstat, consopen, devcreate, consclose, consread, devbread, conswrite, devbwrite, devremove, devwstat, }; static ulong randn; static void seedrand(void) { randomread((void*)&randn, sizeof(randn)); } int nrand(int n) { if(randn =3D=3D 0) seedrand(); randn =3D randn*1103515245 + 12345 + MACHP(0)->ticks; return (randn>>16) % n; } int rand(void) { nrand(1); return randn; } static uvlong uvorder =3D 0x0001020304050607ULL; static uchar* le2vlong(vlong *to, uchar *f) { uchar *t, *o; int i; t =3D (uchar*)to; o =3D (uchar*)&uvorder; for(i =3D 0; i < sizeof(vlong); i++) t[o[i]] =3D f[i]; return f+sizeof(vlong); } static uchar* vlong2le(uchar *t, vlong from) { uchar *f, *o; int i; f =3D (uchar*)&from; o =3D (uchar*)&uvorder; for(i =3D 0; i < sizeof(vlong); i++) t[i] =3D f[o[i]]; return t+sizeof(vlong); } static long order =3D 0x00010203; static uchar* le2long(long *to, uchar *f) { uchar *t, *o; int i; t =3D (uchar*)to; o =3D (uchar*)ℴ for(i =3D 0; i < sizeof(long); i++) t[o[i]] =3D f[i]; return f+sizeof(long); } static uchar* long2le(uchar *t, long from) { uchar *f, *o; int i; f =3D (uchar*)&from; o =3D (uchar*)ℴ for(i =3D 0; i < sizeof(long); i++) t[i] =3D f[o[i]]; return t+sizeof(long); } char *Ebadtimectl =3D "bad time control"; /* * like the old #c/time but with added info. Return * * secs nanosecs fastticks fasthz */ static int readtime(ulong off, char *buf, int n) { vlong nsec, ticks; long sec; char str[7*NUMSIZE]; nsec =3D todget(&ticks); if(fasthz =3D=3D 0LL) fastticks((uvlong*)&fasthz); sec =3D nsec/1000000000ULL; snprint(str, sizeof(str), "%*.0lud %*.0llud %*.0llud %*.0llud ", NUMSIZE-1, sec, VLNUMSIZE-1, nsec, VLNUMSIZE-1, ticks, VLNUMSIZE-1, fasthz); return readstr(off, buf, n, str); } /* * set the time in seconds */ static int writetime(char *buf, int n) { char b[13]; long i; vlong now; if(n >=3D sizeof(b)) error(Ebadtimectl); strncpy(b, buf, n); b[n] =3D 0; i =3D strtol(b, 0, 0); if(i <=3D 0) error(Ebadtimectl); now =3D i*1000000000LL; todset(now, 0, 0); return n; } /* * read binary time info. all numbers are little endian. * ticks and nsec are syncronized. */ static int readbintime(char *buf, int n) { int i; vlong nsec, ticks; uchar *b =3D (uchar*)buf; i =3D 0; if(fasthz =3D=3D 0LL) fastticks((uvlong*)&fasthz); nsec =3D todget(&ticks); if(n >=3D 3*sizeof(uvlong)){ vlong2le(b+2*sizeof(uvlong), fasthz); i +=3D sizeof(uvlong); } if(n >=3D 2*sizeof(uvlong)){ vlong2le(b+sizeof(uvlong), ticks); i +=3D sizeof(uvlong); } if(n >=3D 8){ vlong2le(b, nsec); i +=3D sizeof(vlong); } return i; } /* * set any of the following * - time in nsec * - nsec trim applied over some seconds * - clock frequency */ static int writebintime(char *buf, int n) { uchar *p; vlong delta; long period; n--; p =3D (uchar*)buf + 1; switch(*buf){ case 'n': if(n < sizeof(vlong)) error(Ebadtimectl); le2vlong(&delta, p); todset(delta, 0, 0); break; case 'd': if(n < sizeof(vlong)+sizeof(long)) error(Ebadtimectl); p =3D le2vlong(&delta, p); le2long(&period, p); todset(-1, delta, period); break; case 'f': if(n < sizeof(uvlong)) error(Ebadtimectl); le2vlong(&fasthz, p); todsetfreq(fasthz); break; } return n; } ------=_NextPart_000_0001_01C2DAB8.2451E660 Content-Type: application/octet-stream; name="lib.h" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="lib.h" /* * functions (possibly) linked in, complete, from libc. */ /* * APM routines and defines */ #define POWEROFF 0x03 #define SLEEP_DEEP 0x02 #define SLEEP_LIGHT 0x01 #define READY 0x00 #define BIOS 0x00 #define ALL_DEVICES 0x01 #define DISPLAY 0x1ff #define SEC_STORAGE 0x2ff #define PARALE_PORT 0x3ff #define SERIAL_PORT 0x4ff #define NET_ADAPTER 0x5ff #define PCMCIA 0x6ff #define BATTERY 0x80ff void poweroff_call(int,int); /* * mem routines */ extern void* memccpy(void*, void*, int, ulong); extern void* memset(void*, int, ulong); extern int memcmp(void*, void*, ulong); extern void* memmove(void*, void*, ulong); extern void* memchr(void*, int, ulong); int nbattery; int batterystatus; int percent; int time; /* * string routines */ extern char* strcat(char*, char*); extern char* strchr(char*, char); extern char* strrchr(char*, char); extern int strcmp(char*, char*); extern char* strcpy(char*, char*); extern char* strecpy(char*, char*, char*); extern char* strncat(char*, char*, long); extern char* strncpy(char*, char*, long); extern int strncmp(char*, char*, long); extern long strlen(char*); extern char* strstr(char*, char*); extern int atoi(char*); extern int fullrune(char*, int); enum { UTFmax = 3, /* maximum bytes per rune */ Runesync = 0x80, /* cannot represent part of a UTF sequence */ Runeself = 0x80, /* rune and UTF sequences are the same (<) */ Runeerror = 0x80, /* decoding error in UTF */ }; /* * rune routines */ extern int runetochar(char*, Rune*); extern int chartorune(Rune*, char*); extern char* utfrune(char*, long); extern int utflen(char*); extern int runelen(long); extern int abs(int); /* * print routines */ typedef struct Fmt Fmt; typedef int (*Fmts)(Fmt*); struct Fmt{ uchar runes; /* output buffer is runes or chars? */ void *start; /* of buffer */ void *to; /* current place in the buffer */ void *stop; /* end of the buffer; overwritten if flush fails */ int (*flush)(Fmt *); /* called when to == stop */ void *farg; /* to make flush a closure */ int nfmt; /* num chars formatted so far */ va_list args; /* args passed to dofmt */ int r; /* % format Rune */ int width; int prec; ulong flags; }; extern int print(char*, ...); extern char* seprint(char*, char*, char*, ...); extern char* vseprint(char*, char*, char*, va_list); extern int snprint(char*, int, char*, ...); extern int vsnprint(char*, int, char*, va_list); extern int sprint(char*, char*, ...); extern int fmtinstall(int, int (*)(Fmt*)); extern int quotefmtinstall(void); extern int fmtprint(Fmt*, char*, ...); extern int fmtstrcpy(Fmt*, char*); #pragma varargck argpos fmtprint 2 #pragma varargck argpos print 1 #pragma varargck argpos seprint 3 #pragma varargck argpos snprint 3 #pragma varargck argpos sprint 2 /* * one-of-a-kind */ extern char* cleanname(char*); extern ulong getcallerpc(void*); extern long strtol(char*, char**, int); extern ulong strtoul(char*, char**, int); extern vlong strtoll(char*, char**, int); extern uvlong strtoull(char*, char**, int); extern char etext[]; extern char edata[]; extern char end[]; extern int getfields(char*, char**, int, int, char*); extern int tokenize(char*, char**, int); extern int dec64(uchar*, int, char*, int); /* * 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 MCACHE 0x0010 /* cache some data */ #define MMASK 0x0017 /* 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 */ #define OCEXEC 32 /* or'ed in, close on exec */ #define ORCLOSE 64 /* or'ed in, remove on close */ #define OEXCL 0x1000 /* or'ed in, exclusive create */ #define NCONT 0 /* continue after note */ #define NDFLT 1 /* terminate after note */ #define NSAVE 2 /* clear note but hold state */ #define NRSTR 3 /* restore saved state */ typedef struct Qid Qid; typedef struct Dir Dir; typedef struct OWaitmsg OWaitmsg; typedef struct Waitmsg Waitmsg; #define ERRMAX 128 /* max length of error string */ #define KNAMELEN 28 /* max length of name held in kernel */ /* bits in Qid.type */ #define QTDIR 0x80 /* type bit for directories */ #define QTAPPEND 0x40 /* type bit for append only files */ #define QTEXCL 0x20 /* type bit for exclusive use files */ #define QTMOUNT 0x10 /* type bit for mounted channel */ #define QTAUTH 0x08 /* type bit for authentication file */ #define QTFILE 0x00 /* plain file */ /* bits in Dir.mode */ #define DMDIR 0x80000000 /* mode bit for directories */ #define DMAPPEND 0x40000000 /* mode bit for append only files */ #define DMEXCL 0x20000000 /* mode bit for exclusive use files */ #define DMMOUNT 0x10000000 /* mode bit for mounted channel */ #define DMREAD 0x4 /* mode bit for read permission */ #define DMWRITE 0x2 /* mode bit for write permission */ #define DMEXEC 0x1 /* mode bit for execute permission */ struct Qid { vlong path; ulong vers; uchar type; }; struct Dir { /* system-modified data */ ushort type; /* server type */ uint dev; /* server subtype */ /* file data */ Qid qid; /* unique id from server */ ulong mode; /* permissions */ ulong atime; /* last read time */ ulong mtime; /* last write time */ vlong length; /* file length: see */ char *name; /* last element of path */ char *uid; /* owner name */ char *gid; /* group name */ char *muid; /* last modifier name */ }; struct OWaitmsg { char pid[12]; /* of loved one */ char time[3*12]; /* of loved one and descendants */ char msg[64]; /* compatibility BUG */ }; struct Waitmsg { int pid; /* of loved one */ ulong time[3]; /* of loved one and descendants */ char msg[ERRMAX]; /* actually variable-size in user mode */ }; ------=_NextPart_000_0001_01C2DAB8.2451E660--