From 6a4f3f2dc304dbe9bbe26d7339082be13944add7 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 20 Aug 1999 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1999-08-20 --- pc/archgeneric.c | 236 ------------------ pc/devarch.c | 594 ++++++++++++++++++++++++++++++++++++++++++++++ pc/main.c | 2 + port/chan.c | 2 +- port/devcons.c | 20 ++ port/devns16552.c | 121 +++++++++- port/portfns.h | 3 + port/rdb.c | 103 ++++++++ port/sysproc.c | 13 + 9 files changed, 856 insertions(+), 238 deletions(-) delete mode 100644 pc/archgeneric.c create mode 100644 pc/devarch.c create mode 100644 port/rdb.c diff --git a/pc/archgeneric.c b/pc/archgeneric.c deleted file mode 100644 index 3b98688058457a152f57f8ce80f80e1751dda963..0000000000000000000000000000000000000000 --- a/pc/archgeneric.c +++ /dev/null @@ -1,236 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" - -static int -unimplemented(int) -{ - return 0; -} - -static void -nop(void) -{ -} - -void (*coherence)(void) = nop; -void cycletimerinit(void); -uvlong cycletimer(uvlong*); - -PCArch* arch; -extern PCArch* knownarch[]; - -PCArch archgeneric = { - "generic", /* id */ - 0, /* ident */ - i8042reset, /* reset */ - unimplemented, /* serialpower */ - unimplemented, /* modempower */ - - i8259init, /* intrinit */ - i8259enable, /* intrenable */ - - i8253enable, /* clockenable */ - - i8253read, /* read the standard timer */ -}; - -typedef struct { - int family; - int model; - int aalcycles; - char* name; -} X86type; - -static X86type x86intel[] = -{ - { 4, 0, 22, "486DX", }, /* known chips */ - { 4, 1, 22, "486DX50", }, - { 4, 2, 22, "486SX", }, - { 4, 3, 22, "486DX2", }, - { 4, 4, 22, "486SL", }, - { 4, 5, 22, "486SX2", }, - { 4, 7, 22, "DX2WB", }, /* P24D */ - { 4, 8, 22, "DX4", }, /* P24C */ - { 4, 9, 22, "DX4WB", }, /* P24CT */ - { 5, 0, 23, "P5", }, - { 5, 1, 23, "P5", }, - { 5, 2, 23, "P54C", }, - { 5, 3, 23, "P24T", }, - { 5, 4, 23, "P55C MMX", }, - { 5, 7, 23, "P54C VRT", }, - { 6, 1, 16, "PentiumPro", },/* determined by trial and error */ - { 6, 3, 16, "PentiumII", }, - { 6, 5, 16, "PentiumII/Xeon", }, - - { 3, -1, 32, "386", }, /* family defaults */ - { 4, -1, 22, "486", }, - { 5, -1, 23, "P5", }, - { 6, -1, 16, "P6", }, - - { -1, -1, 23, "unknown", }, /* total default */ -}; - -/* - * The AMD processors all implement the CPUID instruction. - * The later ones also return the processor name via functions - * 0x80000002, 0x80000003 and 0x80000004 in registers AX, BX, CX - * and DX: - * K5 "AMD-K5(tm) Processor" - * K6 "AMD-K6tm w/ multimedia extensions" - * K6 3D "AMD-K6(tm) 3D processor" - * K6 3D+ ? - */ -static X86type x86amd[] = -{ - { 5, 0, 23, "AMD-K5", }, /* guesswork */ - { 5, 1, 23, "AMD-K5", }, /* guesswork */ - { 5, 2, 23, "AMD-K5", }, /* guesswork */ - { 5, 3, 23, "AMD-K5", }, /* guesswork */ - { 5, 6, 11, "AMD-K6", }, /* determined by trial and error */ - { 5, 7, 11, "AMD-K6", }, /* determined by trial and error */ - { 5, 8, 11, "AMD-K6 3D", }, /* guesswork */ - { 5, 9, 11, "AMD-K6 3D+", },/* guesswork */ - - { 4, -1, 22, "Am486", }, /* guesswork */ - { 5, -1, 23, "AMD-K5/K6", }, /* guesswork */ - - { -1, -1, 23, "unknown", }, /* total default */ -}; - -void -cpuidprint(void) -{ - int i; - char buf[128]; - - i = sprint(buf, "cpu%d: %dMHz ", m->machno, m->cpumhz); - if(m->cpuidid[0]) - i += sprint(buf+i, "%s ", m->cpuidid); - sprint(buf+i, "%s (cpuid: AX 0x%4.4uX DX 0x%4.4uX)\n", - m->cpuidtype, m->cpuidax, m->cpuiddx); - print(buf); -} - -int -cpuidentify(void) -{ - int family, model; - X86type *t; - ulong cr4; - vlong mct; - - cpuid(m->cpuidid, &m->cpuidax, &m->cpuiddx); - if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0) - t = x86amd; - else - t = x86intel; - family = X86FAMILY(m->cpuidax); - model = X86MODEL(m->cpuidax); - while(t->name){ - if((t->family == family && t->model == model) - || (t->family == family && t->model == -1) - || (t->family == -1)) - break; - t++; - } - m->cpuidtype = t->name; - i8253init(t->aalcycles, t->family >= 5); - - /* - * If machine check exception or page size extensions are supported - * enable them in CR4 and clear any other set extensions. - * If machine check was enabled clear out any lingering status. - */ - if(m->cpuiddx & 0x88){ - cr4 = 0; - if(m->cpuiddx & 0x08) - cr4 |= 0x10; /* page size extensions */ - if(m->cpuiddx & 0x80) - cr4 |= 0x40; /* machine check enable */ - putcr4(cr4); - if(m->cpuiddx & 0x80) - rdmsr(0x01, &mct); - } - - return t->family; -} - -void -archinit(void) -{ - PCArch **p; - - arch = 0; - for(p = knownarch; *p; p++){ - if((*p)->ident && (*p)->ident() == 0){ - arch = *p; - break; - } - } - if(arch == 0) - arch = &archgeneric; - else{ - if(arch->id == 0) - arch->id = archgeneric.id; - if(arch->reset == 0) - arch->reset = archgeneric.reset; - if(arch->serialpower == 0) - arch->serialpower = archgeneric.serialpower; - if(arch->modempower == 0) - arch->modempower = archgeneric.modempower; - - if(arch->intrinit == 0) - arch->intrinit = archgeneric.intrinit; - if(arch->intrenable == 0) - arch->intrenable = archgeneric.intrenable; - } - - /* pick the better timer */ - if(X86FAMILY(m->cpuidax) >= 5){ - cycletimerinit(); - arch->fastclock = cycletimer; - } - - /* - * Decide whether to use copy-on-reference (386 and mp). - */ - if(X86FAMILY(m->cpuidax) == 3 || conf.nmach > 1) - conf.copymode = 1; - - if(X86FAMILY(m->cpuidax) >= 5) - coherence = wbflush; -} - -static uvlong fasthz; - -void -cycletimerinit(void) -{ - wrmsr(0x10, 0); - fasthz = m->cpuhz; -} - -/* - * return the most precise clock we have - */ -uvlong -cycletimer(uvlong *hz) -{ - uvlong tsc; - - rdmsr(0x10, (vlong*)&tsc); - m->fastclock = tsc; - if(hz != nil) - *hz = fasthz; - return tsc; -} - -vlong -fastticks(uvlong *hz) -{ - return (*arch->fastclock)(hz); -} diff --git a/pc/devarch.c b/pc/devarch.c new file mode 100644 index 0000000000000000000000000000000000000000..bd00951ab2c66f7a5b34d364de44e4372f55ed4f --- /dev/null +++ b/pc/devarch.c @@ -0,0 +1,594 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" +#include "../port/error.h" + + +typedef struct IOMap IOMap; +struct IOMap +{ + IOMap *next; + char tag[13]; + ulong start; + ulong end; +}; + +static struct +{ + Lock; + IOMap *m; + IOMap *free; + IOMap maps[32]; // some initial free maps + + QLock ql; // lock for reading map +} iomap; + +enum { + Qdir, + Qcputype, + Qioalloc, + Qiob, + Qiow, + Qiol, + Qirqalloc, +}; + +static Dirtab ioallocdir[] = { + "cputype", { Qcputype, 0 }, 0, 0444, + "ioalloc", { Qioalloc, 0 }, 0, 0444, + "iob", { Qiob, 0 }, 0, 0660, + "iow", { Qiow, 0 }, 0, 0660, + "iol", { Qiol, 0 }, 0, 0660, + "irqalloc", { Qirqalloc, 0}, 0, 0444, +}; + +void +ioinit(void) +{ + int i; + + for(i = 0; i < nelem(iomap.maps)-1; i++) + iomap.maps[i].next = &iomap.maps[i+1]; + iomap.maps[i].next = nil; + iomap.free = iomap.maps; + + // a dummy entry at 2^16 + ioalloc(0x1000000, 1, 0, "dummy"); +} + +static long cputyperead(char*, int, ulong); + +// +// alloc some io port space and remember who it was +// alloced to. if port < 0, find a free region. +// +int +ioalloc(int port, int size, int align, char *tag) +{ + IOMap *m, **l; + int i; + + lock(&iomap); + if(port < 0){ + // find a free port above 0x400 and below 0x1000 + port = 0x400; + for(l = &iomap.m; *l; l = &(*l)->next){ + m = *l; + i = m->start - port; + if(i > size) + break; + if(align > 0) + port = ((port+align-1)/align)*align; + else + port = m->end; + } + if(*l == nil){ + unlock(&iomap); + return -1; + } + } else { + // see if the space clashes with previously alllocated ports + for(l = &iomap.m; *l; l = &(*l)->next){ + m = *l; + if(m->end <= port) + continue; + if(m->start >= port+size) + break; + unlock(&iomap); + return -1; + } + } + m = iomap.free; + if(m == nil){ + print("ioalloc: out of maps"); + unlock(&iomap); + return port; + } + iomap.free = m->next; + m->next = *l; + m->start = port; + m->end = port + size; + strncpy(m->tag, tag, sizeof(m->tag)); + m->tag[sizeof(m->tag)-1] = 0; + *l = m; + + ioallocdir[0].qid.vers++; + + unlock(&iomap); + return m->start; +} + +void +iofree(int port) +{ + IOMap *m, **l; + + lock(&iomap); + for(l = &iomap.m; *l; l = &(*l)->next){ + if((*l)->start == port){ + m = *l; + *l = m->next; + m->next = iomap.free; + iomap.free = m; + break; + } + if((*l)->start > port) + break; + } + ioallocdir[0].qid.vers++; + unlock(&iomap); +} + +int +iounused(int start, int end) +{ + IOMap *m; + + for(m = iomap.m; m; m = m->next){ + if(start >= m->start && start < m->end + || start <= m->start && end > m->start) + return 0; + } + return 1; +} + +static void +checkport(int start, int end) +{ + /* standard vga regs are OK */ + if(start >= 0x2b0 && end <= 0x2df+1) + return; + if(start >= 0x3c0 && end <= 0x3da+1) + return; + + if(iounused(start, end)) + return; + error(Eperm); +} + +static Chan* +archattach(char* spec) +{ + return devattach('P', spec); +} + +int +archwalk(Chan* c, char* name) +{ + return devwalk(c, name, ioallocdir, nelem(ioallocdir), devgen); +} + +static void +archstat(Chan* c, char* dp) +{ + devstat(c, dp, ioallocdir, nelem(ioallocdir), devgen); +} + +static Chan* +archopen(Chan* c, int omode) +{ + return devopen(c, omode, ioallocdir, nelem(ioallocdir), devgen); +} + +static void +archclose(Chan*) +{ +} + +enum +{ + Linelen= 31, +}; + +static long +archread(Chan *c, void *a, long n, vlong offset) +{ + char *p; + IOMap *m; + char buf[Linelen+1]; + int port; + ushort *sp; + ulong *lp; + + switch(c->qid.path & ~CHDIR){ + + case Qdir: + return devdirread(c, a, n, ioallocdir, nelem(ioallocdir), devgen); + + case Qiob: + port = offset; + checkport(offset, offset+n); + for(p = a; port < offset+n; port++) + *p++ = inb(port); + return n; + + case Qiow: + if((n & 0x01) || (offset & 0x01)) + error(Ebadarg); + checkport(offset, offset+n+1); + n /= 2; + sp = a; + for(port = offset; port < offset+n; port += 2) + *sp++ = ins(port); + return n*2; + + case Qiol: + if((n & 0x03) || (offset & 0x03)) + error(Ebadarg); + checkport(offset, offset+n+3); + n /= 4; + lp = a; + for(port = offset; port < offset+n; port += 4) + *lp++ = inl(port); + return n*4; + + case Qioalloc: + break; + + case Qirqalloc: + return irqallocread(a, n, offset); + + case Qcputype: + return cputyperead(a, n, offset); + + default: + error(Eperm); + break; + } + + offset = offset/Linelen; + n = n/Linelen; + p = a; + lock(&iomap); + for(m = iomap.m; n > 0 && m != nil; m = m->next){ + if(offset-- > 0) + continue; + if(strcmp(m->tag, "dummy") == 0) + break; + sprint(buf, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag); + memmove(p, buf, Linelen); + p += Linelen; + n--; + } + unlock(&iomap); + + return p - (char*)a; +} + +static long +archwrite(Chan *c, void *a, long n, vlong offset) +{ + int port; + ushort *sp; + ulong *lp; + char *p; + + switch(c->qid.path & ~CHDIR){ + + case Qiob: + p = a; + checkport(offset, offset+n); + for(port = offset; port < offset+n; port++) + outb(port, *p++); + return n; + + case Qiow: + if((n & 01) || (offset & 01)) + error(Ebadarg); + checkport(offset, offset+n+1); + n /= 2; + sp = a; + for(port = offset; port < offset+n; port += 2) + outs(port, *sp++); + return n*2; + + case Qiol: + if((n & 0x03) || (offset & 0x03)) + error(Ebadarg); + checkport(offset, offset+n+3); + n /= 4; + lp = a; + for(port = offset; port < offset+n; port += 4) + outl(port, *lp++); + return n*4; + + default: + error(Eperm); + break; + } + return 0; +} + +Dev archdevtab = { + 'P', + "arch", + + devreset, + devinit, + archattach, + devclone, + archwalk, + archstat, + archopen, + devcreate, + archclose, + archread, + devbread, + archwrite, + devbwrite, + devremove, + devwstat, +}; + +/* + * the following is a generic version of the + * architecture specific stuff + */ + +static int +unimplemented(int) +{ + return 0; +} + +static void +nop(void) +{ +} + +void (*coherence)(void) = nop; +void cycletimerinit(void); +uvlong cycletimer(uvlong*); + +PCArch* arch; +extern PCArch* knownarch[]; + +PCArch archgeneric = { + "generic", /* id */ + 0, /* ident */ + i8042reset, /* reset */ + unimplemented, /* serialpower */ + unimplemented, /* modempower */ + + i8259init, /* intrinit */ + i8259enable, /* intrenable */ + + i8253enable, /* clockenable */ + + i8253read, /* read the standard timer */ +}; + +typedef struct { + int family; + int model; + int aalcycles; + char* name; +} X86type; + +static X86type x86intel[] = +{ + { 4, 0, 22, "486DX", }, /* known chips */ + { 4, 1, 22, "486DX50", }, + { 4, 2, 22, "486SX", }, + { 4, 3, 22, "486DX2", }, + { 4, 4, 22, "486SL", }, + { 4, 5, 22, "486SX2", }, + { 4, 7, 22, "DX2WB", }, /* P24D */ + { 4, 8, 22, "DX4", }, /* P24C */ + { 4, 9, 22, "DX4WB", }, /* P24CT */ + { 5, 0, 23, "P5", }, + { 5, 1, 23, "P5", }, + { 5, 2, 23, "P54C", }, + { 5, 3, 23, "P24T", }, + { 5, 4, 23, "P55C MMX", }, + { 5, 7, 23, "P54C VRT", }, + { 6, 1, 16, "PentiumPro", },/* determined by trial and error */ + { 6, 3, 16, "PentiumII", }, + { 6, 5, 16, "PentiumII/Xeon", }, + + { 3, -1, 32, "386", }, /* family defaults */ + { 4, -1, 22, "486", }, + { 5, -1, 23, "P5", }, + { 6, -1, 16, "P6", }, + + { -1, -1, 23, "unknown", }, /* total default */ +}; + +/* + * The AMD processors all implement the CPUID instruction. + * The later ones also return the processor name via functions + * 0x80000002, 0x80000003 and 0x80000004 in registers AX, BX, CX + * and DX: + * K5 "AMD-K5(tm) Processor" + * K6 "AMD-K6tm w/ multimedia extensions" + * K6 3D "AMD-K6(tm) 3D processor" + * K6 3D+ ? + */ +static X86type x86amd[] = +{ + { 5, 0, 23, "AMD-K5", }, /* guesswork */ + { 5, 1, 23, "AMD-K5", }, /* guesswork */ + { 5, 2, 23, "AMD-K5", }, /* guesswork */ + { 5, 3, 23, "AMD-K5", }, /* guesswork */ + { 5, 6, 11, "AMD-K6", }, /* determined by trial and error */ + { 5, 7, 11, "AMD-K6", }, /* determined by trial and error */ + { 5, 8, 11, "AMD-K6 3D", }, /* guesswork */ + { 5, 9, 11, "AMD-K6 3D+", },/* guesswork */ + + { 4, -1, 22, "Am486", }, /* guesswork */ + { 5, -1, 23, "AMD-K5/K6", }, /* guesswork */ + + { -1, -1, 23, "unknown", }, /* total default */ +}; + +static uvlong fasthz; +static X86type *cputype; + +void +cpuidprint(void) +{ + int i; + char buf[128]; + + i = sprint(buf, "cpu%d: %dMHz ", m->machno, m->cpumhz); + if(m->cpuidid[0]) + i += sprint(buf+i, "%s ", m->cpuidid); + sprint(buf+i, "%s (cpuid: AX 0x%4.4uX DX 0x%4.4uX)\n", + m->cpuidtype, m->cpuidax, m->cpuiddx); + print(buf); +} + +int +cpuidentify(void) +{ + int family, model; + X86type *t; + ulong cr4; + vlong mct; + + cpuid(m->cpuidid, &m->cpuidax, &m->cpuiddx); + if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0) + t = x86amd; + else + t = x86intel; + family = X86FAMILY(m->cpuidax); + model = X86MODEL(m->cpuidax); + while(t->name){ + if((t->family == family && t->model == model) + || (t->family == family && t->model == -1) + || (t->family == -1)) + break; + t++; + } + m->cpuidtype = t->name; + i8253init(t->aalcycles, t->family >= 5); + + /* + * If machine check exception or page size extensions are supported + * enable them in CR4 and clear any other set extensions. + * If machine check was enabled clear out any lingering status. + */ + if(m->cpuiddx & 0x88){ + cr4 = 0; + if(m->cpuiddx & 0x08) + cr4 |= 0x10; /* page size extensions */ + if(m->cpuiddx & 0x80) + cr4 |= 0x40; /* machine check enable */ + putcr4(cr4); + if(m->cpuiddx & 0x80) + rdmsr(0x01, &mct); + } + + cputype = t; + return t->family; +} + +static long +cputyperead(char *a, int n, ulong offset) +{ + char str[32]; + ulong mhz; + + mhz = (m->cpuhz+999999)/1000000; + + snprint(str, sizeof(str), "%s %lud\n", cputype->name, mhz); + return readstr(offset, a, n, str); +} + +void +archinit(void) +{ + PCArch **p; + + arch = 0; + for(p = knownarch; *p; p++){ + if((*p)->ident && (*p)->ident() == 0){ + arch = *p; + break; + } + } + if(arch == 0) + arch = &archgeneric; + else{ + if(arch->id == 0) + arch->id = archgeneric.id; + if(arch->reset == 0) + arch->reset = archgeneric.reset; + if(arch->serialpower == 0) + arch->serialpower = archgeneric.serialpower; + if(arch->modempower == 0) + arch->modempower = archgeneric.modempower; + + if(arch->intrinit == 0) + arch->intrinit = archgeneric.intrinit; + if(arch->intrenable == 0) + arch->intrenable = archgeneric.intrenable; + } + + /* pick the better timer */ + if(X86FAMILY(m->cpuidax) >= 5){ + cycletimerinit(); + arch->fastclock = cycletimer; + } + + /* + * Decide whether to use copy-on-reference (386 and mp). + */ + if(X86FAMILY(m->cpuidax) == 3 || conf.nmach > 1) + conf.copymode = 1; + + if(X86FAMILY(m->cpuidax) >= 5) + coherence = wbflush; +} + +void +cycletimerinit(void) +{ + wrmsr(0x10, 0); + fasthz = m->cpuhz; +} + +/* + * return the most precise clock we have + */ +uvlong +cycletimer(uvlong *hz) +{ + uvlong tsc; + + rdmsr(0x10, (vlong*)&tsc); + m->fastclock = tsc; + if(hz != nil) + *hz = fasthz; + return tsc; +} + +vlong +fastticks(uvlong *hz) +{ + return (*arch->fastclock)(hz); +} diff --git a/pc/main.c b/pc/main.c index 6a2ba27cb8ea42f4a9cd73e0b0dd20788599e293..dfc6112152cd4a3bea617e8f81579f775b4227d2 100644 --- a/pc/main.c +++ b/pc/main.c @@ -709,6 +709,7 @@ isaconfig(char *class, int ctlrno, ISAConf *isa) return 0; } +/* int iprint(char *fmt, ...) { @@ -724,6 +725,7 @@ iprint(char *fmt, ...) return n; } +*/ int cistrcmp(char *a, char *b) diff --git a/port/chan.c b/port/chan.c index 4b2f015bb3622f5467a6a10dd404efbb30a028de..1c54b323d10739b7d16cc25a0716bec414a77eaf 100644 --- a/port/chan.c +++ b/port/chan.c @@ -517,7 +517,7 @@ walk(Chan **cp, char *name, int domnt) *cp = undomount(c); } if(domnt) - *cp = domount(c); + *cp = domount(*cp); return 0; } diff --git a/port/devcons.c b/port/devcons.c index 100300981eafe577ff1c05b440308e0bff455172..32e8372cc0bda85dd10887925995a6be183bde0f 100644 --- a/port/devcons.c +++ b/port/devcons.c @@ -156,6 +156,23 @@ print(char *fmt, ...) return n; } +int +iprint(char *fmt, ...) +{ + int n, s; + va_list arg; + char buf[PRINTSIZE]; + + s = splhi(); + va_start(arg, fmt); + n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf; + va_end(arg); + serialputs(buf, n); + splx(s); + + return n; +} + void panic(char *fmt, ...) { @@ -244,6 +261,9 @@ echo(Rune r, char *buf, int n) if(consdebug != nil) consdebug(); return; + case 'D': + consdebug = rdb; + return; case 'p': x = spllo(); procdump(); diff --git a/port/devns16552.c b/port/devns16552.c index 4251c8cfa553ca20ed6a3e36f8542542ebeb2515..c337dc76ab569e3f1265465935c2fdd7d77b1fc3 100644 --- a/port/devns16552.c +++ b/port/devns16552.c @@ -97,6 +97,7 @@ struct Uart char name[NAMELEN]; uchar sticky[8]; /* sticky write register values */ + uchar osticky[8]; /* kernel saved sticky write register values */ ulong port; /* io ports */ ulong freq; /* clock frequency */ uchar mask; /* bits/char */ @@ -136,6 +137,8 @@ struct Uart int hup_dsr, hup_dcd; /* send hangup upstream? */ int dohup; + int kinuse; /* device in use by kernel */ + Rendez r; }; @@ -149,6 +152,11 @@ struct Uartalloc { void ns16552intr(int); +/* + * means the kernel is using this for debugging output + */ +static char Ekinuse[] = "device in use by kernel"; + /* * pick up architecture specific routines and definitions */ @@ -319,7 +327,6 @@ static void ns16552mflow(Uart *p, int n) { - ilock(&p->tlock); if(n){ if(p->type == Ns650){ @@ -827,6 +834,8 @@ ns16552open(Chan *c, int omode) case Nctlqid: case Ndataqid: p = uart[NETID(c->qid.path)]; + if(p->kinuse) + error(Ekinuse); qlock(p); if(p->opens++ == 0){ ns16552enable(p); @@ -853,6 +862,8 @@ ns16552close(Chan *c) case Ndataqid: case Nctlqid: p = uart[NETID(c->qid.path)]; + if(p->kinuse) + error(Ekinuse); qlock(p); if(--(p->opens) == 0){ ns16552disable(p); @@ -915,6 +926,8 @@ ns16552read(Chan *c, void *buf, long n, vlong off) } p = uart[NETID(c->qid.path)]; + if(p->kinuse) + error(Ekinuse); switch(NETTYPE(c->qid.path)){ case Ndataqid: return qread(p->iq, buf, n); @@ -1025,6 +1038,8 @@ ns16552write(Chan *c, void *buf, long n, vlong) error(Eperm); p = uart[NETID(c->qid.path)]; + if(p->kinuse) + error(Ekinuse); /* * The fifo's turn themselves off sometimes. @@ -1087,3 +1102,107 @@ Dev ns16552devtab = { devremove, ns16552wstat, }; + +/* + * Polling I/O routines for kernel debugging helps. + */ +static void +ns16552setuppoll(Uart *p, int rate) +{ + ulong brconst; + + /* + * 8 bits/character, 1 stop bit; + * set rate to rate baud; + * turn on Rts and Dtr. + */ + memmove(p->osticky, p->sticky, sizeof p->osticky); + + p->sticky[Format] = Bits8; + uartwrreg(p, Format, 0); + + brconst = (UartFREQ+8*rate-1)/(16*rate); + uartwrreg(p, Format, Dra); + outb(p->port+Dmsb, (brconst>>8) & 0xff); + outb(p->port+Dlsb, brconst & 0xff); + uartwrreg(p, Format, 0); + + p->sticky[Mctl] = Rts|Dtr; + uartwrreg(p, Mctl, 0); + + p->kinuse = 1; +} + +/* + * Restore serial state from before kernel took over. + */ +static void +ns16552restore(Uart *p) +{ + ulong brconst; + + memmove(p->sticky, p->osticky, sizeof p->sticky); + uartwrreg(p, Format, 0); + + brconst = (UartFREQ+8*p->baud-1)/(16*p->baud); + uartwrreg(p, Format, Dra); + outb(p->port+Dmsb, (brconst>>8) & 0xff); + outb(p->port+Dlsb, brconst & 0xff); + uartwrreg(p, Format, 0); + + uartwrreg(p, Mctl, 0); + p->kinuse = 0; +} + +/* BUG should be configurable */ +enum { + WHICH = 0, + RATE = 9600, +}; + +int +serialgetc(void) +{ + Uart *p; + int c; + + if((p=uart[WHICH]) == nil) + return -1; + if(!p->kinuse) + ns16552setuppoll(p, RATE); + + while((uartrdreg(p, Lstat)&Inready) == 0) + ; + c = inb(p->port+Data) & 0xFF; + return c; + // there should be a restore here but i think it will slow things down too much. +} + +static void +serialputc(Uart *p, int c) +{ + while((uartrdreg(p, Lstat)&Outready) == 0) + ; + outb(p->port+Data, c); + while((uartrdreg(p, Lstat)&Outready) == 0) + ; +} + +void +serialputs(char *s, int n) +{ + Uart *p; + + if((p=uart[WHICH]) == nil) + return; + if(!p->kinuse) + ns16552setuppoll(p, RATE); + + while(n-- > 0){ + serialputc(p, *s); + if(*s == '\n') + serialputc(p, '\r'); + s++; + } + ns16552restore(p); +} diff --git a/port/portfns.h b/port/portfns.h index f9873ccf434a27305807b8d323bd7b938602c3be..21e88bda44a9d607da2f5e0c2a987d0b5f404139 100644 --- a/port/portfns.h +++ b/port/portfns.h @@ -253,6 +253,7 @@ int qwrite(Queue*, void*, int); void qsetlimit(Queue*, int); void qnoblock(Queue*, int); int rand(void); +void rdb(void); int readnum(ulong, char*, ulong, ulong, int); int readstr(ulong, char*, ulong, char*); void ready(Proc*); @@ -290,6 +291,8 @@ long seconds(void); ulong segattach(Proc*, ulong, char *, ulong, ulong); void segclock(ulong); void segpage(Segment*, Page*); +int serialgetc(void); +void serialputs(char*, int); int setcolor(ulong, ulong, ulong, ulong); void setkernur(Ureg*, Proc*); int setlabel(Label*); diff --git a/port/rdb.c b/port/rdb.c new file mode 100644 index 0000000000000000000000000000000000000000..f48a50bc9bfc21bdf59ea893b5a2a39d9fc39fac --- /dev/null +++ b/port/rdb.c @@ -0,0 +1,103 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" + +extern Queue *printq; + +#define DBG if(0)scrprint +#pragma varargck argpos scrprint 1 +static Ureg ureg; + +static void +scrprint(char *fmt, ...) +{ + char buf[128]; + va_list va; + int n; + + va_start(va, fmt); + n = doprint(buf, buf+sizeof buf, fmt, va)-buf; + va_end(va); + putstrn(buf, n); +} + +static char* +getline(void) +{ + static char buf[128]; + int i, c; + + for(;;){ + for(i=0; i 4){ + mesg(Rerr, Ecount); + break; + } + a = addr(min+0); + scrprint("mput %.8lux\n", a); + memmove(a, min+5, n); + mesg(Rmput, mout); + break; + * + */ + default: + DBG("unknown %c\n", *req); + iprint("Eunknown message\n"); + break; + } + } +} + +void +rdb(void) +{ + splhi(); + iprint("rdb..."); + callwithureg(talkrdb); +} diff --git a/port/sysproc.c b/port/sysproc.c index 4d5c60f52f0490c4e87ddcc8c2ee82e8dc22619c..dcd113372ca5b929cc2f504f33f7d82117b8af79 100644 --- a/port/sysproc.c +++ b/port/sysproc.c @@ -534,6 +534,19 @@ sysdeath(ulong*) return 0; /* not reached */ } +void +werrstr(char *fmt, ...) +{ + va_list va; + + if(up == nil) + return; + + va_start(va, fmt); + doprint(up->error, up->error+ERRLEN, fmt, va); + va_end(va); +} + long syserrstr(ulong *arg) {