jehanne/sys/src/kern/amd64/arch.c

129 lines
2.8 KiB
C

/* Copyright (C) Charles Forsyth
* See /doc/license/NOTICE.Plan9-9k.txt for details about the licensing.
*/
/* Portions of this file are Copyright (C) 9front's team.
* See /doc/license/9front-mit for details about the licensing.
* See http://git.9front.org/plan9front/plan9front/HEAD/info.html for a list of authors.
*/
/*
* EPISODE 12B
* How to recognise different types of trees from quite a long way away.
* NO. 1
* THE LARCH
*/
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
void
procrestore(Proc *p)
{
uint64_t t;
if(p->kp)
return;
cycles(&t);
p->pcycles -= t;
}
/*
* Save the mach dependent part of the process state.
*/
void
procsave(Proc *p)
{
uint64_t t;
cycles(&t);
p->pcycles += t;
if(p->fpstate == FPactive){
if(p->state == Moribund)
fpclear();
else{
/*
* Fpsave() stores without handling pending
* unmasked exeptions. Postnote() can't be called
* here as sleep() already has up->rlock, so
* the handling of pending exceptions is delayed
* until the process runs again and generates an
* emulation fault to activate the FPU.
*/
fpsave(&p->fpsave);
}
p->fpstate = FPinactive;
}
/*
* While this processor is in the scheduler, the process could run
* on another processor and exit, returning the page tables to
* the free list where they could be reallocated and overwritten.
* When this processor eventually has to get an entry from the
* trashed page tables it will crash.
*
* If there's only one processor, this can't happen.
* You might think it would be a win not to do this in that case,
* especially on VMware, but it turns out not to matter.
*/
mmuflushtlb();
}
static void
linkproc(void)
{
spllo();
up->kpfun(up->kparg);
pexit("kproc dying", 0);
}
void
kprocchild(Proc* p, void (*func)(void*), void* arg)
{
/*
* gotolabel() needs a word on the stack in
* which to place the return PC used to jump
* to linkproc().
*/
p->sched.pc = PTR2UINT(linkproc);
p->sched.sp = PTR2UINT(p->kstack+KSTACK-BY2SE);
p->sched.sp = STACKALIGN(p->sched.sp);
p->kpfun = func;
p->kparg = arg;
}
static int spinOnIdle;
void
onIdleSpin(void)
{
spinOnIdle = 1;
}
/*
* put the processor in the halt state if we've no processes to run.
* an interrupt will get us going again.
*
* halting in an smp system can result in a startup latency for
* processes that become ready.
* if idle_spin is zero, we care more about saving energy
* than reducing this latency.
*
* the performance loss with idle_spin == 0 seems to be slight
* and it reduces lock contention (thus system time and real time)
* on many-core systems with large values of NPROC.
*/
void
idlehands(void)
{
extern int nrdy;
if(sys->nmach == 1)
halt();
else if (SUPPORT_MWAIT)
mwait32(&nrdy, 0);
else if(!spinOnIdle)
halt();
}