Files
Arquivotheca.SunOS-4.1.4/sys/sun/fpu.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

313 lines
7.5 KiB
C

/* @(#)fpu.c 1.1 94/10/31 SMI; from UCB 4.3 83/06/14 */
#include <sys/types.h>
#include <machine/reg.h>
#include <machine/psl.h>
#include <machine/buserr.h>
#include <machine/trap.h>
#include <sun/fault.h>
#include <m68k/frame.h>
#include <sundev/fpareg.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/file.h>
#include <sys/proc.h>
#include <sys/map.h>
#include <sys/user.h>
#include <sys/core.h>
#include "fpa.h"
#include <sys/ptrace.h>
#ifdef FPU
#if NFPA > 0
enum fpa_state fpa_state = FPA_SINGLE_USER;
#endif NFPA > 0
fpu_fork_context(p, pnfp, pnew_context)
struct proc *p;
struct file **pnfp;
int *pnew_context;
{
#if NFPA > 0
if (u.u_pcb.u_fpa_flags)
if (fpa_fork_context(p, pnfp, pnew_context) < 0) {
/* no FPA context, inode, or file, error quit */
u.u_error = EAGAIN;
return (0);
}
#endif NFPA > 0
return (1);
}
fpu_newproc(nfp, new_context, childu)
struct file *nfp;
int new_context;
struct user *childu;
{
#if NFPA > 0
#define u_fpas_state u_fpa_status.fpas_state
if (childu->u_pcb.u_fpa_flags) {
/*
* If the parent had the FPA open, but the FPA is not
* initialized, the child does not inherit FPA access
*/
if (fpa_state == FPA_SINGLE_USER)
{
childu->u_ofile[u.u_pcb.u_fpa_flags & U_FPA_FDBITS] = NULL;
childu->u_pcb.u_fpa_flags = 0;
return;
}
/*
* All FPA registers including the pipe are in
* child u and have been restored to the FPA board.
* Set up childu->u_ofile[] to the opened FPA file
* and childu->u_fpa_state to the new FPA context
* number for the child process.
*/
fpa_save(childu); /* make sure pipe is still ready */
childu->u_ofile[childu->u_pcb.u_fpa_flags & U_FPA_FDBITS] = nfp;
childu->u_pcb.u_fpas_state =
(childu->u_pcb.u_fpas_state & FPA_PBITS) | (long)new_context;
fpa_dorestore(childu); /* state reg is written here */
}
#endif NFPA > 0
}
fpu_core(corep)
struct core *corep;
{
u.u_pcb.u_fp_status.fps_flags = EXT_FPS_FLAGS(&u.u_pcb.u_fp_istate);
corep->c_fpu.f_fpstatus = u.u_pcb.u_fp_status;
#if NFPA > 0
/*
* Dump FPA regs only when u.u_fpa_flags is nonzero and
* FPA_LOAD_BIT is off.
* The reason is that if FPA_LOAD_BIT is on, it means that there
* is no microcode in FPA board, we cannot access FPA data regs.
*/
if ((corep->c_fpu.f_fparegs.fpar_flags = u.u_pcb.u_fpa_flags) &&
!(fpa->fp_state & FPA_LOAD_BIT)) {
/* loop until FPA pipe become stable */
CDELAY(fpa->fp_pipe_status & FPA_STABLE, 300);
if (fpa->fp_pipe_status & FPA_STABLE) {
corep->c_fpu.f_fparegs.fpar_status =
*((struct fpa_status *) &fpa->fp_state);
fpa->fp_clear_pipe = 0; /* clear pipe to read data */
lcopy((char *)fpa->fp_data,
(char *)corep->c_fpu.f_fparegs.fpar_data,
sizeof (fpa->fp_data)/4);
} else {
fpa_shutdown();
printf("FPA not stable in core(), FPA is shutdown!\n");
}
}
#endif NFPA > 0
}
fpu_setregs()
{
extern struct proc *fpprocp;
/*
* Clear any external and internal fpp state.
* If this process was the last one to load its
* external fpp state, erase that fact also.
*/
bzero((caddr_t)&u.u_pcb.u_fp_status, sizeof (u.u_pcb.u_fp_status));
bzero((caddr_t)&u.u_pcb.u_fp_istate, sizeof (u.u_pcb.u_fp_istate));
if (u.u_procp == fpprocp)
fpprocp = (struct proc *)0;
}
#ifdef sun3x
fpu_berror(be, locregs, fmt, mmube)
#else
fpu_berror(be, locregs, fmt)
#endif
u_char be;
struct stkfmt fmt;
register struct regs *locregs;
#ifdef sun3x
u_short mmube;
#endif
{
#if NFPA > 0
/*
* If enable register is not turned on, panic.
* In case of FPA bus error in the kernel mode, shutdown
* FPA, instead of panicing the system.
*/
if (be & BE_FPAENA)
panic("FPA not enabled");
if (be & BE_FPABERR) {
#ifdef sun3x
showregs("FPA KERNEL BUS ERROR", fmt.f_vector, locregs,
&fmt, be, mmube);
#else
showregs("FPA KERNEL BUS ERROR", fmt.f_vector, locregs,
&fmt, be);
#endif
traceback((long)locregs->r_areg[6],
(long)locregs->r_sp);
printf("FPA BUS ERROR: IERR == %x\n", fpa->fp_ierr);
fpa_shutdown();
return (SIGSEGV);
}
#endif NFPA > 0
return (0);
}
fpu_user_berror(be)
u_char be;
{
#if NFPA > 0
if (u.u_pcb.u_fpa_flags && (be & (BE_FPAENA | BE_FPABERR))) {
u.u_code = (be & BE_FPAENA) ? FPE_FPA_ENABLE : FPE_FPA_ERROR;
return (SIGFPE);
}
#endif NFPA > 0
return (0);
}
fpu_ptrace(req, p, ipc)
enum ptracereq req;
struct proc *p;
struct ipc *ipc;
{
switch (req) {
case PTRACE_GETFPREGS:
runchild(p);
if (copyout((caddr_t)&(ipc->ip_fpu.f_fpstatus), ipc->ip_addr,
sizeof (struct fp_status)) != 0) {
ipc->ip_error = 1;
}
break;
case PTRACE_SETFPREGS:
if (copyin(ipc->ip_addr, (caddr_t)&(ipc->ip_fpu.f_fpstatus),
sizeof (struct fp_status)) != 0) {
ipc->ip_error = 1;
}
runchild(p);
break;
#if NFPA > 0
case PTRACE_GETFPAREGS:
runchild(p);
if (copyout((caddr_t)&ipc->ip_fpu.f_fparegs, ipc->ip_addr,
sizeof (struct fpa_regs)) != 0) {
ipc->ip_error = 1;
}
break;
case PTRACE_SETFPAREGS:
if (copyin(ipc->ip_addr, (caddr_t)&ipc->ip_fpu.f_fparegs,
sizeof (struct fpa_regs)) != 0) {
ipc->ip_error = 1;
}
runchild(p);
break;
#endif NFPA > 0
}
}
/*ARGSUSED*/
fpu_procxmt(req, ipc)
enum ptracereq req;
struct ipc *ipc;
{
extern short fppstate;
switch (req) {
/*
* Read floating point registers -
* Copy from the u area to the ipc buffer,
* after setting the fps_flags
* from the internal fpp info.
*/
case PTRACE_GETFPREGS:
if (fppstate == 0) {
ipc->ip_error = 1;
} else {
u.u_pcb.u_fp_status.fps_flags =
EXT_FPS_FLAGS(&u.u_pcb.u_fp_istate);
ipc->ip_fpu.f_fpstatus = u.u_pcb.u_fp_status;
}
break;
/*
* Write floating point registers -
* Copy from the ipc buffer to the u area,
* and set u.u_code from the code in fp_status,
* then initialize the fpp registers.
*/
case PTRACE_SETFPREGS:
if (fppstate == 0) {
ipc->ip_error = 1;
} else {
u.u_pcb.u_fp_status = ipc->ip_fpu.f_fpstatus;
fsave(&u.u_pcb.u_fp_istate);
setfppregs();
frestore(&u.u_pcb.u_fp_istate);
}
break;
#if NFPA > 0
/* Read FPA registers from u area and FPA board to ipc buffer. */
case PTRACE_GETFPAREGS:
if ((!u.u_pcb.u_fpa_flags) || (fpa->fp_pipe_status & FPA_WAIT2))
return (-1);
ipc->ip_fpa_flags = u.u_pcb.u_fpa_flags;
fpa_save(&u); /* force a save to u area */
ipc->ip_fpa_status = u.u_pcb.u_fpa_status;
fpa->fp_clear_pipe = 0; /* clear FPA pipe to read data regs */
lcopy((char *)fpa->fp_data, (char *)ipc->ip_fpa_data,
sizeof (fpa->fp_data)/4); /* copy from fpa */
fpa_dorestore(&u); /* restore u area to FPA */
break;
/*
* Write FPA registers from ipc buffer to the U area and FPA
* board. U.u_fpa_flags, FPA STATE register, and WSTATUS register
* are protected from being written.
* Fpa_restore() is needed, o/w u.u_fpa_status is erased by
* fpa context save during the coming context switch.
*/
case PTRACE_SETFPAREGS:
if ((!u.u_pcb.u_fpa_flags) || (fpa->fp_pipe_status & FPA_WAIT2))
return (-1);
/* STATE reg is protected from being modified */
ipc->ip_fpa_state = u.u_pcb.u_fpa_status.fpas_state;
u.u_pcb.u_fpa_status = ipc->ip_fpa_status;
fpa->fp_clear_pipe = 0; /* clear FPA pipe to read data regs */
lcopy((char *)ipc->ip_fpa_data, (char *)fpa->fp_data,
sizeof (fpa->fp_data)/4); /* copy to fpa */
fpa_dorestore(&u);
break;
#endif NFPA > 0
}
return (0);
}
fpu_ofile()
{
#if NFPA > 0
/*
* F_count associated with /dev/fpa should not be
* incremented in the above for loop.
*/
if (u.u_pcb.u_fpa_flags)
u.u_ofile[u.u_pcb.u_fpa_flags & U_FPA_FDBITS]->f_count--;
#endif NFPA > 0
}
#endif FPU