📄 devarch.c
字号:
static intunimplemented(int){ return 0;}static voidnop(void){}/* * 386 has no compare-and-swap instruction. * Run it with interrupts turned off instead. */static intcmpswap386(long *addr, long old, long new){ int r, s; s = splhi(); if(r = (*addr == old)) *addr = new; splx(s); return r;}/* * On a uniprocessor, you'd think that coherence could be nop, * but it can't. We still need a barrier when using coherence() in * device drivers. * * On VMware, it's safe (and a huge win) to set this to nop. * Aux/vmware does this via the #P/archctl file. */void (*coherence)(void) = nop;int (*cmpswap)(long*, long, long) = cmpswap386;PCArch* arch;extern PCArch* knownarch[];PCArch archgeneric = {.id= "generic",.ident= 0,.reset= i8042reset,.serialpower= unimplemented,.modempower= unimplemented,.intrinit= i8259init,.intrenable= i8259enable,.intrvecno= i8259vecno,.intrdisable= i8259disable,.intron= i8259on,.introff= i8259off,.clockenable= i8253enable,.fastclock= i8253read,.timerset= i8253timerset,};typedef struct X86type X86type;struct X86type { int family; int model; int aalcycles; char* name;};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", },/* trial and error */ { 6, 3, 16, "PentiumII", }, { 6, 5, 16, "PentiumII/Xeon", }, { 6, 6, 16, "Celeron", }, { 6, 7, 16, "PentiumIII/Xeon", }, { 6, 8, 16, "PentiumIII/Xeon", }, { 6, 0xB, 16, "PentiumIII/Xeon", }, { 0xF, 1, 16, "P4", }, /* P4 */ { 0xF, 2, 16, "PentiumIV/Xeon", }, { 3, -1, 32, "386", }, /* family defaults */ { 4, -1, 22, "486", }, { 5, -1, 23, "P5", }, { 6, -1, 16, "P6", }, { 0xF, -1, 16, "P4", }, /* P4 */ { -1, -1, 16, "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", }, /* trial and error */ { 5, 7, 11, "AMD-K6", }, /* trial and error */ { 5, 8, 11, "AMD-K6-2", }, /* trial and error */ { 5, 9, 11, "AMD-K6-III", },/* trial and error */ { 6, 1, 11, "AMD-Athlon", },/* trial and error */ { 6, 2, 11, "AMD-Athlon", },/* trial and error */ { 4, -1, 22, "Am486", }, /* guesswork */ { 5, -1, 23, "AMD-K5/K6", }, /* guesswork */ { 6, -1, 11, "AMD-Athlon", },/* guesswork */ { 0xF, -1, 11, "AMD64", }, /* guesswork */ { -1, -1, 11, "unknown", }, /* total default */};/* * WinChip 240MHz */static X86type x86winchip[] ={ {5, 4, 23, "Winchip",}, /* guesswork */ {6, 7, 23, "Via C3 Samuel 2 or Ezra",}, {6, 8, 23, "Via C3 Ezra-T",}, {6, 9, 23, "Via C3 Eden-N",}, { -1, -1, 23, "unknown", }, /* total default */};/* * SiS 55x */static X86type x86sis[] ={ {5, 0, 23, "SiS 55x",}, /* guesswork */ { -1, -1, 23, "unknown", }, /* total default */};static X86type *cputype;static void simplecycles(uvlong*);void (*cycles)(uvlong*) = simplecycles;void _cycles(uvlong*); /* in l.s */static voidsimplecycles(uvlong*x){ *x = m->ticks;}voidcpuidprint(void){ int i; char buf[128]; i = sprint(buf, "cpu%d: %dMHz ", m->machno, m->cpumhz); if(m->cpuidid[0]) i += sprint(buf+i, "%12.12s ", m->cpuidid); sprint(buf+i, "%s (cpuid: AX 0x%4.4uX DX 0x%4.4uX)\n", m->cpuidtype, m->cpuidax, m->cpuiddx); print(buf);}/* * figure out: * - cpu type * - whether or not we have a TSC (cycle counter) * - whether or not it supports page size extensions * (if so turn it on) * - whether or not it supports machine check exceptions * (if so turn it on) * - whether or not it supports the page global flag * (if so turn it on) */intcpuidentify(void){ char *p; int family, model, nomce; X86type *t, *tab; ulong cr4; vlong mca, mct; cpuid(m->cpuidid, &m->cpuidax, &m->cpuiddx); if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0) tab = x86amd; else if(strncmp(m->cpuidid, "CentaurHauls", 12) == 0) tab = x86winchip; else if(strncmp(m->cpuidid, "SiS SiS SiS ", 12) == 0) tab = x86sis; else tab = x86intel; family = X86FAMILY(m->cpuidax); model = X86MODEL(m->cpuidax); for(t=tab; t->name; t++) if((t->family == family && t->model == model) || (t->family == family && t->model == -1) || (t->family == -1)) break; m->cpuidtype = t->name; /* * if there is one, set tsc to a known value */ if(m->cpuiddx & 0x10){ m->havetsc = 1; cycles = _cycles; if(m->cpuiddx & 0x20) wrmsr(0x10, 0); } /* * use i8253 to guess our cpu speed */ guesscpuhz(t->aalcycles); /* * If machine check exception, page size extensions or page global bit * 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 & 0x2088){ cr4 = 0; if(m->cpuiddx & 0x08) cr4 |= 0x10; /* page size extensions */ if(p = getconf("*nomce")) nomce = strtoul(p, 0, 0); else nomce = 0; if((m->cpuiddx & 0x80) && !nomce){ cr4 |= 0x40; /* machine check enable */ if(family == 5){ rdmsr(0x00, &mca); rdmsr(0x01, &mct); } } /* * Detect whether the chip supports the global bit * in page directory and page table entries. When set * in a particular entry, it means ``don't bother removing * this from the TLB when CR3 changes.'' * * We flag all kernel pages with this bit. Doing so lessens the * overhead of switching processes on bare hardware, * even more so on VMware. See mmu.c:/^memglobal. * * For future reference, should we ever need to do a * full TLB flush, it can be accomplished by clearing * the PGE bit in CR4, writing to CR3, and then * restoring the PGE bit. */ if(m->cpuiddx & 0x2000){ cr4 |= 0x80; /* page global enable bit */ m->havepge = 1; } putcr4(cr4); if(m->cpuiddx & 0x80) rdmsr(0x01, &mct); } cputype = t; return t->family;}static longcputyperead(Chan*, void *a, long n, vlong 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);}static longarchctlread(Chan*, void *a, long nn, vlong offset){ char buf[256]; int n; n = snprint(buf, sizeof buf, "cpu %s %lud%s\n", cputype->name, (ulong)(m->cpuhz+999999)/1000000, m->havepge ? " pge" : ""); n += snprint(buf+n, sizeof buf-n, "pge %s\n", getcr4()&0x80 ? "on" : "off"); n += snprint(buf+n, sizeof buf-n, "coherence "); if(coherence == mb386) n += snprint(buf+n, sizeof buf-n, "mb386\n"); else if(coherence == mb586) n += snprint(buf+n, sizeof buf-n, "mb586\n"); else if(coherence == nop) n += snprint(buf+n, sizeof buf-n, "nop\n"); else n += snprint(buf+n, sizeof buf-n, "0x%p\n", coherence); n += snprint(buf+n, sizeof buf-n, "cmpswap "); if(cmpswap == cmpswap386) n += snprint(buf+n, sizeof buf-n, "cmpswap386\n"); else if(cmpswap == cmpswap486) n += snprint(buf+n, sizeof buf-n, "cmpswap486\n"); else n += snprint(buf+n, sizeof buf-n, "0x%p\n", cmpswap); n += snprint(buf+n, sizeof buf-n, "i8253set %s\n", doi8253set ? "on" : "off"); buf[n] = 0; return readstr(offset, a, nn, buf);}enum{ CMpge, CMcoherence, CMi8253set,};static Cmdtab archctlmsg[] ={ CMpge, "pge", 2, CMcoherence, "coherence", 2, CMi8253set, "i8253set", 2,};static longarchctlwrite(Chan*, void *a, long n, vlong){ Cmdbuf *cb; Cmdtab *ct; cb = parsecmd(a, n); if(waserror()){ free(cb); nexterror(); } ct = lookupcmd(cb, archctlmsg, nelem(archctlmsg)); switch(ct->index){ case CMpge: if(!m->havepge) error("processor does not support pge"); if(strcmp(cb->f[1], "on") == 0) putcr4(getcr4() | 0x80); else if(strcmp(cb->f[1], "off") == 0) putcr4(getcr4() & ~0x80); else cmderror(cb, "invalid pge ctl"); break; case CMcoherence: if(strcmp(cb->f[1], "mb386") == 0) coherence = mb386; else if(strcmp(cb->f[1], "mb586") == 0){ if(X86FAMILY(m->cpuidax) < 5) error("invalid coherence ctl on this cpu family"); coherence = mb586; } else if(strcmp(cb->f[1], "nop") == 0){ /* only safe on vmware */ if(conf.nmach > 1) error("cannot disable coherence on a multiprocessor"); coherence = nop; }else cmderror(cb, "invalid coherence ctl"); break; case CMi8253set: if(strcmp(cb->f[1], "on") == 0) doi8253set = 1; else if(strcmp(cb->f[1], "off") == 0){ doi8253set = 0; (*arch->timerset)(0); }else cmderror(cb, "invalid i2853set ctl"); break; } free(cb); poperror(); return n;}voidarchinit(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; } /* * Decide whether to use copy-on-reference (386 and mp). * We get another chance to set it in mpinit() for a * multiprocessor. */ if(X86FAMILY(m->cpuidax) == 3) conf.copymode = 1; if(X86FAMILY(m->cpuidax) >= 4) cmpswap = cmpswap486; if(X86FAMILY(m->cpuidax) >= 5) coherence = mb586; addarchfile("cputype", 0444, cputyperead, nil); addarchfile("archctl", 0664, archctlread, archctlwrite);}/* * call either the pcmcia or pccard device setup */intpcmspecial(char *idstr, ISAConf *isa){ return (_pcmspecial != nil)? _pcmspecial(idstr, isa): -1;}/* * call either the pcmcia or pccard device teardown */voidpcmspecialclose(int a){ if (_pcmspecialclose != nil) _pcmspecialclose(a);}/* * return value and speed of timer set in arch->clockenable */uvlongfastticks(uvlong *hz){ return (*arch->fastclock)(hz);}/* * set next timer interrupt */voidtimerset(uvlong x){ if(doi8253set) (*arch->timerset)(x);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -