SMP - lazy FPU

- when a process is migrated to a different CPU it may have an active
  FPU context in the processor registers. We must save it and migrate
  it together with the process.
This commit is contained in:
Tomas Hruby
2010-09-15 14:11:25 +00:00
parent 1f89845bb2
commit 5b8b623765
17 changed files with 142 additions and 60 deletions

View File

@@ -60,6 +60,7 @@ PRIVATE phys_bytes copy_trampoline(void)
tramp_size = (unsigned) &__trampoline_end - (unsigned)&trampoline;
s = env_get("memory");
s = (char *) get_value(params_buffer, "memory");
if (!s)
return 0;
@@ -238,6 +239,7 @@ PRIVATE void ap_finish_booting(void)
printf("CPU %d paging is on\n", cpu);
lapic_enable(cpu);
fpu_init();
if (app_cpu_init_timer(system_hz)) {
panic("FATAL : failed to initialize timer interrupts CPU %d, "

View File

@@ -205,7 +205,7 @@ PUBLIC void arch_get_aout_headers(const int i, struct exec *h)
phys_copy(aout + i * A_MINHDR, vir2phys(h), (phys_bytes) A_MINHDR);
}
PRIVATE void fpu_init(void)
PUBLIC void fpu_init(void)
{
unsigned short cw, sw;
@@ -219,10 +219,8 @@ PRIVATE void fpu_init(void)
* Set CR0_NE and CR0_MP to handle fpu exceptions
* in native mode. */
write_cr0(read_cr0() | CR0_MP_NE);
fpu_presence = 1;
get_cpulocal_var(fpu_presence) = 1;
if(_cpufeature(_CPUF_I386_FXSR)) {
register struct proc *rp;
phys_bytes aligned_fp_area;
u32_t cr4 = read_cr4() | CR4_OSFXSR; /* Enable FXSR. */
/* OSXMMEXCPT if supported
@@ -233,35 +231,18 @@ PRIVATE void fpu_init(void)
write_cr4(cr4);
osfxsr_feature = 1;
for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; ++rp) {
/* FXSR requires 16-byte alignment of memory
* image, but unfortunately some old tools
* (probably linker) ignores ".balign 16"
* applied to our memory image.
* Thus we have to do manual alignment.
*/
aligned_fp_area =
(phys_bytes) &rp->p_fpu_state.fpu_image;
if(aligned_fp_area % FPUALIGN) {
aligned_fp_area += FPUALIGN -
(aligned_fp_area % FPUALIGN);
}
rp->p_fpu_state.fpu_save_area_p =
(void *) aligned_fp_area;
}
} else {
osfxsr_feature = 0;
}
} else {
/* No FPU presents. */
fpu_presence = 0;
get_cpulocal_var(fpu_presence) = 0;
osfxsr_feature = 0;
return;
}
}
PUBLIC void save_fpu(struct proc *pr)
PUBLIC void save_local_fpu(struct proc *pr)
{
if(!fpu_presence)
return;
@@ -275,6 +256,34 @@ PUBLIC void save_fpu(struct proc *pr)
}
}
PUBLIC void save_fpu(struct proc *pr)
{
#if CONFIG_SMP
if (cpuid == pr->p_cpu) {
save_local_fpu(pr);
}
else {
int stopped;
/* remember if the process was already stopped */
stopped = RTS_ISSET(pr, RTS_PROC_STOP);
/* stop the remote process and force it's context to be saved */
smp_schedule_stop_proc_save_ctx(pr);
/*
* If the process wasn't stopped let the process run again. The
* process is kept block by the fact that the kernel cannot run
* on its cpu
*/
if (!stopped)
RTS_UNSET(pr, RTS_PROC_STOP);
}
#else
save_local_fpu(pr);
#endif
}
PUBLIC void restore_fpu(struct proc *pr)
{
if(!proc_used_fpu(pr)) {
@@ -328,8 +337,6 @@ PUBLIC void arch_init(void)
BOOT_VERBOSE(printf("APIC not present, using legacy PIC\n"));
}
#endif
fpu_init();
}
PUBLIC void ser_putc(char c)