/* * caller must zero or otherwise initialise *rp, * other than ax, bx, dx, si & ds. */ static int biosdiskcall(Ureg *up, uchar op, ulong bx, ulong dx, ulong si) { int s; uchar err; s = splhi(); /* don't let the bios call be interrupted */ up->ax = op << 8; up->bx = bx; up->dx = dx; /* often drive id */ /* * ensure that dap addr fits in a short. */ if((si & 0xffff0000) != 0) print("biosdiskcall: dap address %#lux not a short\n", si); /* assume si is in first 64K */ if((si & 0xffff0000) != ((si + 512 - 1) & 0xffff0000)) print("biosdiskcall: dap address %#lux too near segment boundary\n", si); up->si = si; /* ds:si forms data access packet addr */ up->ds = 0; up->di = 0; /* * *up is copied into low memory (realmoderegs) and thence into * the machine registers before the BIOS call, and the registers are * copied into realmoderegs and thence into *up after. * * realmode loads these registers: di, si, ax, bx, cx, dx, ds, es. */ realmode(0x13, up); splx(s); if (up->flags & CF) { if (Debug && dx == Baseid) { err = up->ax >> 8; print("\nbiosdiskcall: int 0x13 op %#ux drive %#lux " "failed, ah error code %#ux (%s)\n", op, dx, err, strerr(err)); } return -1; }
Proc* runproc(void) { Mach *m = machp(); Schedq *rq; Proc *p; uint32_t start, now; if(nosmp) return singlerunproc(); //NIX modeset cannot work without halt every cpu at boot //if(sys->nmach <= AMPmincores) else return smprunproc(); start = perfticks(); run.preempts++; rq = nil; if(m->machno != 0){ do{ spllo(); while(m->proc == nil) idlehands(); now = perfticks(); m->perf.inidle += now-start; start = now; splhi(); p = m->proc; }while(p == nil); p->state = Scheding; p->mp = sys->machptr[m->machno]; if(edflock(p)){ edfrun(p, rq == &run.runq[PriEdf]); /* start deadline timer and do admin */ edfunlock(); } if(p->trace) proctrace(p, SRun, 0); return p; } mach0sched(); return nil; /* not reached */ }
int iprint(char *fmt, ...) { int n, s; va_list arg; char buf[PRINTSIZE]; s = splhi(); va_start(arg, fmt); n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); if(screenputs != nil && iprintscreenputs) screenputs(buf, n); uartputs(buf, n); splx(s); return n; }
/* * Tval is supposed to be in fastticks units. * One fasttick unit is 1/Basetickfreq seconds. */ void timerset(Tval next) { int x; long period; if(next == 0) return; x = splhi(); /* don't let us get scheduled */ period = next - fastticks(nil); if(period > m->maxperiod - m->minperiod) period = m->maxperiod; else if(period < m->minperiod) period = m->minperiod; wrcompare(rdcount()+period); silencewdog(); splx(x); }
int wakeup(Rendez *r) { Proc *p; int s; s = splhi(); lock(r); p = r->p; if(p){ r->p = nil; if(p->state != Wakeme) panic("wakeup: state"); ready(p); } unlock(r); splx(s); return p != nil; }
void flushmmu(void) { int s, i; ulong p; ulong *l1; l1 = KADDR(L1PT); s = splhi(); for(i = 0; i < nelem(up->l1); i++){ p = l1[i]; if(p & Small) free(KADDR(ROUNDDN(p, BY2PG))); } memset(up->l1, 0, sizeof up->l1); memset(l1, 0, sizeof up->l1); flushtlb(); splx(s); }
void sched(void) { if(up) { splhi(); procsave(up); if(setlabel(&up->sched)) { /* procrestore(up); */ spllo(); return; } gotolabel(&m->sched); } up = runproc(); up->state = Running; up->mach = MACHP(m->machno); /* m might be a fixed address; use MACHP */ m->proc = up; gotolabel(&up->sched); }
/* estimate instructions/s. */ static int guessmips(long (*loop)(void), char *) { int s; long cyc; do { s = splhi(); cyc = loop(); splx(s); if (cyc < 0) iprint("again..."); } while (cyc < 0); /* * Instrs instructions took cyc cycles @ Basetickfreq Hz. * round the result. */ return (((vlong)Basetickfreq * Instrs) / cyc + Mhz/2) / Mhz; }
void swcursorclock(void) { int x; if(!swenabled) return; if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers) return; x = splhi(); if(swenabled) if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers) if(canqlock(&drawlock)){ swcursorhide(); swcursordraw(); qunlock(&drawlock); } splx(x); }
vm_offset_t himem_convert( vm_offset_t phys_addr, vm_size_t length, int io_op, hil_t *hil) { hil_t h; spl_t ipl; vm_offset_t offset = phys_addr & (I386_PGBYTES - 1); assert (offset + length <= I386_PGBYTES); ipl = splhi(); simple_lock(&hil_lock); while (!(h = hil_head)) { printf("WARNING: out of HIMEM pages\n"); thread_sleep_simple_lock((event_t)&hil_head, simple_lock_addr(hil_lock), FALSE); simple_lock (&hil_lock); } hil_head = hil_head->next; simple_unlock(&hil_lock); splx(ipl); h->high_addr = phys_addr; if (io_op == D_WRITE) { bcopy((char *)phystokv(phys_addr), (char *)phystokv(h->low_page + offset), length); h->length = 0; } else { h->length = length; } h->offset = offset; assert(!*hil || (*hil)->high_addr); h->next = *hil; *hil = h; return(h->low_page + offset); }
/* * map a physical addresses at pa to va, with the given attributes. * the virtual address must not be mapped already. * if va is nil, map it at pa in virtual space. */ void* kmapphys(void *va, ulong pa, ulong nb, ulong attr, ulong le) { int s, i; ulong size; if(va == nil) va = (void*)pa; /* simplest is to use a 1-1 map */ size = 1024; for(i = 0; i < 8 && size < nb; i++) size <<= 2; if(i >= 8) return nil; s = splhi(); tlbwelo(tlbx, pa | TLBZONE(0) | attr); tlbwehi(tlbx, (ulong)va | (i<<7) | TLBVALID | le); tlbx++; splx(s); return va; }
uint_t read_rtc(struct rtc_t *rtc) { int s; uint_t rtc_readable = 0; s = splhi(); /* * If UIP bit is not set we have at least 274us * to read the values. Otherwise we have up to * 336us to wait before we can read it */ if (!(RTC_GET8(RTC_A) & RTC_UIP)) { rtc_readable = 1; rtc->rtc_sec = RTC_GET8(RTC_SEC); rtc->rtc_asec = RTC_GET8(RTC_ASEC); rtc->rtc_min = RTC_GET8(RTC_MIN); rtc->rtc_amin = RTC_GET8(RTC_AMIN); rtc->rtc_hrs = RTC_GET8(RTC_HRS); rtc->rtc_ahrs = RTC_GET8(RTC_AHRS); rtc->rtc_dow = RTC_GET8(RTC_DOW); rtc->rtc_dom = RTC_GET8(RTC_DOM); rtc->rtc_adom = RTC_GET8(RTC_D) & 0x3f; rtc->rtc_mon = RTC_GET8(RTC_MON); rtc->rtc_year = RTC_GET8(RTC_YEAR); rtc->rtc_century = RTC_GET8(RTC_CENTURY); rtc->rtc_amon = 0; /* Clear wakeup data */ rtc->apc_wdwr = 0; rtc->apc_wdmr = 0; rtc->apc_wmr = 0; rtc->apc_wyr = 0; rtc->apc_wcr = 0; } splx(s); return (rtc_readable); }
/* * called splhi() by notify(). See comment in notify for the * reasoning. */ void procctl(void) { char *state; ulong s; switch(up->procctl) { case Proc_exitbig: spllo(); pprint("Killed: Insufficient physical memory\n"); pexit("Killed: Insufficient physical memory", 1); case Proc_exitme: spllo(); /* pexit has locks in it */ pexit("Killed", 1); case Proc_traceme: if(up->nnote == 0) return; /* No break */ case Proc_stopme: up->procctl = 0; state = up->psstate; up->psstate = "Stopped"; /* free a waiting debugger */ s = spllo(); qlock(&up->debug); if(up->pdbg != nil) { wakeup(&up->pdbg->sleep); up->pdbg = nil; } qunlock(&up->debug); splhi(); up->state = Stopped; sched(); up->psstate = state; splx(s); return; } }
void mpshutdown(void) { /* * To be done... */ if(!canlock(&mpshutdownlock)){ /* * If this processor received the CTRL-ALT-DEL from * the keyboard, acknowledge it. Send an INIT to self. */ #ifdef FIXTHIS if(lapicisr(VectorKBD)) lapiceoi(VectorKBD); #endif /* FIX THIS */ idle(); } print("apshutdown: active = 0x%2.2uX\n", active.machs); delay(1000); splhi(); /* * INIT all excluding self. */ lapicicrw(0, 0x000C0000|ApicINIT); #ifdef notdef /* * Often the BIOS hangs during restart if a conventional 8042 * warm-boot sequence is tried. The following is Intel specific and * seems to perform a cold-boot, but at least it comes back. */ *(ushort*)KADDR(0x472) = 0x1234; /* BIOS warm-boot flag */ outb(0xCF9, 0x02); outb(0xCF9, 0x06); #else pcireset(); i8042reset(); #endif /* notdef */ }
void archreboot(void) { Clkrst *clk = (Clkrst *)soc.clkrst; assert(m->machno == 0); iprint("archreboot: reset!\n"); delay(20); clk->rstdevl |= Sysreset; coherence(); delay(500); /* shouldn't get here */ splhi(); iprint("awaiting reset"); for(;;) { delay(1000); print("."); } }
int canpage(Proc *p) { int ok; Sched *sch; splhi(); sch = procsched(p); lock(sch); /* Only reliable way to see if we are Running */ if(p->mach == 0) { p->newtlb = 1; ok = 1; } else ok = 0; unlock(sch); spllo(); return ok; }
int qbgetc(Queue *q) { Block *b; int s, c; c = -1; s = splhi(); while(c < 0 && (b = q->first) != nil){ if(b->rp < b->wp){ c = *b->rp++; q->len--; } if(b->rp >= b->wp){ q->first = b->next; b->next = nil; } } splx(s); return c; }
uvlong fastticks(uvlong *hz) { Systimers *tn; ulong lo, hi; uvlong now; int s; if(hz) *hz = SystimerFreq; tn = (Systimers*)SYSTIMERS; s = splhi(); do{ hi = tn->chi; lo = tn->clo; }while(tn->chi != hi); now = (uvlong)hi<<32 | lo; m->fastclock = now; splx(s); return m->fastclock; }
/* estimate instructions/s. using 32kHz clock */ static void guessmips(long (*loop)(void), char *lab) { int s; long tcks; do { s = splhi(); tcks = loop(); splx(s); if (tcks < 0) iprint("again..."); } while (tcks < 0); /* * Instrs instructions took tcks ticks @ Clockfreqbase Hz. */ s = ((vlong)Clockfreqbase * Instrs) / tcks / 1000000; if (Debug) iprint("%ud mips (%s-issue)", s, lab); USED(s); }
/* * here at the end of non-clock interrupts to see if we should preempt the * current process. Returns 1 if preempted, 0 otherwise. */ int preempted(void) { if(up && up->state == Running) if(up->preempted == 0) if(anyhigher()) if(!active.exiting){ /* Core 0 is dispatching all interrupts, so no core * actually running a user process is ever going call preempted, unless * we consider IPIs for preemption or we distribute interrupts. * But we are going to use SMP for machines with few cores. panic("preemted used"); */ up->preempted = 1; sched(); splhi(); up->preempted = 0; return 1; } return 0; }
KMap* kmap(Page *page) { uintptr *pte, pa, va; int x; pa = page->pa; if(cankaddr(pa) != 0) return (KMap*)KADDR(pa); x = splhi(); va = KMAP + ((uintptr)up->kmapindex << PGSHIFT); pte = mmuwalk(m->pml4, va, 0, 1); if(pte == 0 || *pte & PTEVALID) panic("kmap: pa=%#p va=%#p", pa, va); *pte = pa | PTEWRITE|PTEVALID; up->kmapindex = (up->kmapindex + 1) % (1<<PTSHIFT); if(up->kmapindex == 0) mmuflushtlb(); splx(x); return (KMap*)va; }
static void schedready(Sched *sch, Proc *p, int locked) { Mpl pl; int pri; Schedq *rq; pl = splhi(); if(edfready(p)){ splx(pl); return; } updatecpu(p); pri = reprioritize(p); p->priority = pri; rq = &sch->runq[pri]; p->state = Ready; queueproc(sch, rq, p, locked); if(p->trace) proctrace(p, SReady, 0); splx(pl); }
Block* allocb(int size) { Block *b; /* * Check in a process and wait until successful. * Can still error out of here, though. */ if(up == nil) panic("allocb without up: %#p", getcallerpc(&size)); if((b = _allocb(size)) == nil){ splhi(); xsummary(); mallocsummary(); delay(500); panic("allocb: no memory for %d bytes; caller %#p", size, getcallerpc(&size)); } setmalloctag(b, getcallerpc(&size)); return b; }
/* * microseconds delay */ void microdelay(int l) { int s; ulong x, cyc, cnt, speed; speed = m->speed; if (speed == 0) speed = cpufreq / Mhz; cyc = (ulong)l * (speed / Cyccntres); s = splhi(); cnt = rdcount(); x = cnt + cyc; if (x < cnt || x >= ~0ul - cpufreq/Cyccntres) { /* counter will wrap between now and x, or x is too near ~0 */ wrcount(0); /* somewhat drastic */ wrcompare(rdcompare() - cnt); /* match new count */ x = cyc; } while(rdcount() < x) ; splx(s); }
/* * if the controller or a specific drive is in a confused state, * reset it and get back to a kown state */ static void floppyrevive(void) { FDrive *dp; /* * reset the controller if it's confused */ if(fl.confused) { DPRINT("floppyrevive in\n"); fldump(); /* reset controller and turn all motors off */ splhi(); fl.ncmd = 1; fl.cmd[0] = 0; outb(Pdor, 0); delay(10); outb(Pdor, Fintena|Fena); delay(10); spllo(); fl.motor = 0; fl.confused = 0; floppywait(0); /* mark all drives in an unknown state */ for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++) dp->confused = 1; /* set rate to a known value */ outb(Pdsr, 0); fl.rate = 0; DPRINT("floppyrevive out\n"); fldump(); } }
void mmuswitch(Proc* proc) { Proc *up = externup(); PTE *pte; Page *page; Mpl pl; pl = splhi(); if(proc->newtlb){ /* * NIX: We cannot clear our page tables if they are going to * be used in the AC */ if(proc->ac == nil) mmuptpfree(proc, 1); proc->newtlb = 0; } if(machp()->pml4->daddr){ memset(UINT2PTR(machp()->pml4->va), 0, machp()->pml4->daddr*sizeof(PTE)); machp()->pml4->daddr = 0; } pte = UINT2PTR(machp()->pml4->va); for(page = proc->mmuptp[3]; page != nil; page = page->next){ pte[page->daddr] = PPN(page->pa)|PteU|PteRW|PteP; if(page->daddr >= machp()->pml4->daddr) machp()->pml4->daddr = page->daddr+1; page->prev = machp()->pml4; } tssrsp0(machp(), STACKALIGN(PTR2UINT(proc->kstack+KSTACK))); cr3put(machp()->pml4->pa); splx(pl); }
int mmuwalk(PTE* pml4, uintptr_t va, int level, PTE** ret, uint64_t (*alloc)(usize)) { Proc *up = externup(); int l; uintmem pa; PTE *pte; Mpl pl; pl = splhi(); if(DBGFLG > 1) DBG("mmuwalk%d: va %#p level %d\n", machp()->machno, va, level); pte = &pml4[PTLX(va, 3)]; for(l = 3; l >= 0; l--){ if(l == level) break; if(!(*pte & PteP)){ if(alloc == nil) break; pa = alloc(PTSZ); if(pa == ~0) return -1; memset(UINT2PTR(KADDR(pa)), 0, PTSZ); *pte = pa|PteRW|PteP; } else if(*pte & PtePS) break; pte = UINT2PTR(KADDR(PPN(*pte))); pte += PTLX(va, l-1); } *ret = pte; splx(pl); return l; }
static void i8250putc(Uart* uart, int c) { int i; Ctlr *ctlr; if (!normalprint) { /* too early; use brute force */ int s = splhi(); while (!(((ulong *)PHYSCONS)[Lsr] & Thre)) ; ((ulong *)PHYSCONS)[Thr] = c; coherence(); splx(s); return; } ctlr = uart->regs; for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++) delay(1); csr8o(ctlr, Thr, (uchar)c); for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++) delay(1); }
/* * The rewriting of compare in this routine shouldn't be necessary. * However, we lose clock interrupts if I don't, either a chip bug * or one of ours -- presotto */ uvlong fastticks(uvlong *hz) { int x; ulong delta, count; if(hz) *hz = basetickfreq; /* avoid reentry on interrupt or trap, to prevent recursion */ x = splhi(); count = rdcount(); if(rdcompare() - count > m->maxperiod) wrcompare(count+m->maxperiod); if (count < m->lastcount) /* wrapped around? */ delta = count + ((1ull<<32) - m->lastcount); else delta = count - m->lastcount; m->lastcount = count; m->fastticks += delta; splx(x); return m->fastticks; }
outb(0xcf9, 0x06); for(;;) idle(); } /* * 386 has no compare-and-swap instruction. * Run it with interrupts turned off instead. */ static int cmpswap386(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;