multiprocessor support:
- Implement MP-safe halt.
- Make the FPU saving code more like Bill's on the i386 MP branch.
XXX This code will no doubt be revisited again.
- Pass the cpu_info and trapframe to IPI handlers, saving some work
in the handlers themselves, and also making it possible for the
"pause" handler to reference register state for DDB.
- Add "machine cpu" to DDB, making it possible to reference other
CPUs registers (and thus get e.g. a traceback) from whichever
CPU is actually running the debugger.
- Garbage-collect "machine halt" and "machine reboot" DDB commands.
They don't have a prayer of working properly in multiprocessor
kernels, and didn't really work all that well in uniprocessor kernels.
* move all exec-type specific information from struct emul to execsw[] and
provide single struct emul per emulation
* elf:
- kern/exec_elf32.c:probe_funcs[] is gone, execsw[] how has one entry
per emulation and contains pointer to respective probe function
- interp is allocated via MALLOC() rather than on stack
- elf_args structure is allocated via MALLOC() rather than malloc()
* ecoff: the per-emulation hooks moved from alpha and mips specific code
to OSF1 and Ultrix compat code as appropriate, execsw[] has one entry per
emulation supporting ecoff with appropriate probe function
* the makecmds/probe functions don't set emulation, pointer to emulation is
part of appropriate execsw[] entry
* constify couple of structures
as normal device interrupts. Because of this, we won't get IPIs while
servicing such interrupts. This can lead to the following deadlock
scenario as reported by Bill Sommerfeld:
- Process runs on cpu1, but has FP state on cpu0.
- Process executes FP-using insn, causing an FP trap, which causes
the kernel lock to be acquired.
- At roughly the same time, cpu0 receives a device interrupt, and attempts
to acquire the kernel lock, which blocks since cpu1 already has it.
- cpu1 sends cpu0 a SYNCH FPU IPI, and waits for cpu0 to release its
FP state.
- Since cpu0 cannot notice the IPI until it has processed the device
interrupt, which it cannot do because it cannot acquire the kernel
lock, we have deadlock.
Solve the problem by adding a spinlock interlock release hook which
checks for pending IPIs and processes them.
Idea from Bill Sommerfeld.
rather than assigning to the whole field, set or clear individual flags,
which implies that the B_BUSY and B_INVAL flags will remain set.
this allows us to make the assertion in brelse() that B_BUSY is set,
which is the purpose of all this.
CPU to handle interrupts, but prevents a whole slew of things
from working properly on the second CPU. It is no longer
necessary now that several other bugs have been fixed.
on it, and make sure to deactivate the old process's address space,
as this will not otherwise be done by cpu_switch() later once we're
on the idle PCB.
Also, update some comments related to when s0 (i.e. the old process)
is NULL in the context switching code.