NetBSD/sys/arch/arm32/fpe-arm/armfpe_init.c

294 lines
7.6 KiB
C

/* $NetBSD: armfpe_init.c,v 1.9 1996/08/21 20:21:05 mark Exp $ */
/*
* Copyright (C) 1996 Mark Brinicombe
* Copyright (C) 1995 Neil A Carson.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Mark Brinicombe.
* 4. The name of the company nor the name of the author may be used to
* endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* RiscBSD kernel project
*
* arm_fpe.c
*
* Stuff needed to interface the ARM floating point emulator module to RiscBSD.
*
* Created : 22/10/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/acct.h>
#include <vm/vm.h>
#include <vm/vm_kern.h>
#include <vm/vm_param.h>
#include <machine/cpu.h>
#include <machine/cpus.h>
#include <machine/katelib.h>
#include <machine/frame.h>
#include "armfpe.h" /* Prototypes for things */
extern int want_resched;
extern u_int fpe_nexthandler;
void undefinedinstruction_bounce __P(());
void arm_fpe_exception_glue __P((int exception));
void arm_fpe_panic __P(());
void undefined_entry __P(());
void arm_fpe_post_proc_glue __P(());
/*
* A module header, pointing into the module
*/
extern u_int fpe_arm_start[];
extern arm_fpe_mod_hdr_t fpe_arm_header;
extern u_int undefined_handler_address;
/*
* Error messages for the various exceptions, numbered 0-5
*/
static char *exception_errors[] = {
"Floating point invalid operation",
"Floating point division by zero (0)",
"Floating point overflow",
"Floating point underflow",
"Floating point operation inexact",
"Floating point major faliure... core fault trapped... not good!"
};
/*
* Initialisation point. The kernel calls this during the configuration of the cpu
* in order to install the FPE.
* The FPE specification needs to be filled in the specified cpu_t structure
* and the FPE needs to be installed on the CPU undefined instruction vector.
*/
int
initialise_arm_fpe(cpu)
cpu_t *cpu;
{
int error;
cpu->fpu_class = FPU_CLASS_FPE;
cpu->fpu_type = FPU_TYPE_ARMLTD_FPE;
strcpy(cpu->fpu_model, "Advanced RISC Machines floating point emulator");
error = arm_fpe_boot(cpu);
if (error != 0) {
strcat(cpu->fpu_model, " - boot failed");
return(1);
}
/* Return with start failure so the old FPE is installed */
/* strcat(cpu->fpu_model, " - boot aborted");*/
return(0);
}
/*
* The actual FPE boot routine.
* This has to do a number of things :
* 1. Relocate the FPE - Note this requires write access to the kernel text area
* 2. Allocated memory for the FPE
* 3. Initialise the FPE
*/
int
arm_fpe_boot(cpu)
cpu_t *cpu;
{
u_int workspace;
int id;
/* First things first ... Relocate the FPE pointers */
#ifdef DEBUG
/* Print a bit of debugging info */
printf("FPE: base=%08x\n", (u_int)fpe_arm_start);
printf("FPE: global workspace size = %d bytes, context size = %d bytes\n",
fpe_arm_header.WorkspaceLength, fpe_arm_header.ContextLength);
#endif
/* Now we must do some memory allocation */
workspace = (u_int)malloc(fpe_arm_header.WorkspaceLength, M_DEVBUF, M_NOWAIT);
if (!workspace)
return(ENOMEM);
*fpe_arm_header.main_ws_ptr_addr = workspace;
*fpe_arm_header.local_handler_ptr_addr = (u_int)&undefined_handler_address;
*fpe_arm_header.old_handler_ptr_addr = undefined_handler_address;
/* Initialise out gloable workspace */
id = arm_fpe_core_initws(workspace, (u_int)&fpe_nexthandler, (u_int)&fpe_nexthandler);
if (id == FPU_TYPE_FPA11) {
cpu->fpu_class = FPU_CLASS_FPA;
cpu->fpu_type = FPU_TYPE_FPA11;
}
#ifdef DEBUG
printf("fpe id=%08x\n", id);
#endif
/* Set up an exception handler */
*fpe_arm_header.exc_handler_ptr_addr = (u_int)arm_fpe_exception_glue;
/* Set up post instruction handler */
#if defined(CPU_ARM6) || defined(CPU_ARM7) || defined(CPU_ARM7500)
*fpe_arm_header.fp_post_proc_addr = (((((u_int)arm_fpe_post_proc_glue -
(u_int)fpe_arm_header.fp_post_proc_addr - 8)>>2) & 0x00ffffff) | 0xea000000);
#ifdef DEBUG
printf("fpe_arm_header.fp_post_proc_addr = %08x (%08x)",
(u_int)fpe_arm_header.fp_post_proc_addr,
(u_int)*fpe_arm_header.fp_post_proc_addr);
#endif
#else
#error ARMFPE currently only supports ARM6 and ARM7 cores
#endif
/* Initialise proc0's FPE context */
arm_fpe_core_initcontext(FP_CONTEXT(&proc0));
arm_fpe_core_changecontext(FP_CONTEXT(&proc0));
return(0);
}
/*
* Callback routine from the FPE when instruction emulation completes
*/
void
arm_fpe_postproc(fpframe, frame)
u_int fpframe;
struct trapframe *frame;
{
register u_int s;
register int sig;
register struct proc *p;
p = curproc;
p->p_md.md_regs = frame;
/* take pending signals */
while ((sig = (CURSIG(p))) != 0) {
postsig(sig);
}
p->p_priority = p->p_usrpri;
if (want_resched) {
/*
* Since we are curproc, a clock interrupt could
* change our priority without changing run queues
* (the running process is not kept on a run queue).
* If this happened after we setrunqueue ourselves but
* before we switch()'ed, we might not be on the queue
* indicated by our priority
*/
s = splstatclock();
setrunqueue(p);
p->p_stats->p_ru.ru_nivcsw++;
mi_switch();
(void)splx(s);
while ((sig = (CURSIG(p))) != 0) {
postsig(sig);
}
}
/* Profiling. */
if (p->p_flag & P_PROFIL) {
extern int psratio;
u_int pc;
pc = ReadWord(fpframe + 15*4);
#ifdef DIAGNOSTIC
if (pc < 0x1000 || pc > 0xefc00000)
panic("armfpe_postproc: pc=%08x\n", pc);
#endif
addupc_task(p, pc, (int)(p->p_sticks - p->p_sticks) * psratio);
}
curpriority = p->p_priority;
}
/*
* Callback routine from the FPE when an exception occurs.
*/
void
arm_fpe_exception(exception, pc, fpframe)
int exception;
u_int pc;
u_int fpframe;
{
if (exception >= 0 && exception < 6)
printf("fpe exception: %d - %s\n", exception, exception_errors[exception]);
else
printf("fpe exception: %d - unknown\n", exception);
trapsignal(curproc, SIGFPE, exception);
printf("PC=%08x\n", ReadWord(fpframe + 60));
userret(curproc, pc, curproc->p_sticks);
}
void
arm_fpe_copycontext(c1, c2)
u_int c1;
u_int c2;
{
fp_context_frame_t fpcontext;
arm_fpe_core_savecontext(c1, (int *)&fpcontext, 0);
arm_fpe_core_loadcontext(c2, (int *)&fpcontext);
}
/* End of armfpe_init.c */