marcel 7db6a715d6 Cleanup <machine/cpu.h> by moving MD prototypes to <machine/md_var.h>
like we have on other platforms. Move savectx() to <machine/pcb.h>.
A lot of files got these MD prototypes through the indirect inclusion
of <machine/cpu.h> and now need to include <machine/md_var.h>. The
number of which is unexpectedly large...

osf1_misc.c especially is tricky because szsigcode is redefined in
one of the osf1 header files. Reordering of the include files was
needed.

linprocfs.c now needs an explicit extern declaration.

Tested with: LINT
2003-08-17 06:42:08 +00:00

416 lines
11 KiB
C

/*-
* Copyright (c) 1998 Doug Rabson
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
#include <sys/sysent.h>
#include <sys/proc.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/user.h>
#include <vm/vm.h>
#include <vm/vm_kern.h>
#include <vm/vm_page.h>
#include <vm/vm_map.h>
#include <vm/vm_extern.h>
#include <vm/vm_object.h>
#include <vm/vm_pager.h>
#include <machine/fpu.h>
#include <machine/inst.h>
#include <machine/md_var.h>
#include <machine/reg.h>
#include <alpha/alpha/ieee_float.h>
#define GETREG(regs, i) (*(fp_register_t*) &regs->fpr_regs[i])
#define PUTREG(regs, i, v) (*(fp_register_t*) &regs->fpr_regs[i] = v)
typedef fp_register_t fp_opcode_handler(union alpha_instruction ins,
int src, int rnd,
u_int64_t fp_control,
u_int64_t *status,
struct fpreg *fpregs);
static fp_register_t fp_add(union alpha_instruction ins,
int src, int rnd,
u_int64_t control, u_int64_t *status,
struct fpreg *fpregs)
{
return ieee_add(GETREG(fpregs, ins.f_format.fa),
GETREG(fpregs, ins.f_format.fb),
src, rnd, control, status);
}
static fp_register_t fp_sub(union alpha_instruction ins,
int src, int rnd,
u_int64_t control, u_int64_t *status,
struct fpreg *fpregs)
{
return ieee_sub(GETREG(fpregs, ins.f_format.fa),
GETREG(fpregs, ins.f_format.fb),
src, rnd, control, status);
}
static fp_register_t fp_mul(union alpha_instruction ins,
int src, int rnd,
u_int64_t control, u_int64_t *status,
struct fpreg *fpregs)
{
return ieee_mul(GETREG(fpregs, ins.f_format.fa),
GETREG(fpregs, ins.f_format.fb),
src, rnd, control, status);
}
static fp_register_t fp_div(union alpha_instruction ins,
int src, int rnd,
u_int64_t control, u_int64_t *status,
struct fpreg *fpregs)
{
return ieee_div(GETREG(fpregs, ins.f_format.fa),
GETREG(fpregs, ins.f_format.fb),
src, rnd, control, status);
}
static fp_register_t fp_cmpun(union alpha_instruction ins,
int src, int rnd,
u_int64_t control, u_int64_t *status,
struct fpreg *fpregs)
{
return ieee_cmpun(GETREG(fpregs, ins.f_format.fa),
GETREG(fpregs, ins.f_format.fb),
status);
}
static fp_register_t fp_cmpeq(union alpha_instruction ins,
int src, int rnd,
u_int64_t control, u_int64_t *status,
struct fpreg *fpregs)
{
return ieee_cmpeq(GETREG(fpregs, ins.f_format.fa),
GETREG(fpregs, ins.f_format.fb),
status);
}
static fp_register_t fp_cmplt(union alpha_instruction ins,
int src, int rnd,
u_int64_t control, u_int64_t *status,
struct fpreg *fpregs)
{
return ieee_cmplt(GETREG(fpregs, ins.f_format.fa),
GETREG(fpregs, ins.f_format.fb),
status);
}
static fp_register_t fp_cmple(union alpha_instruction ins,
int src, int rnd,
u_int64_t control, u_int64_t *status,
struct fpreg *fpregs)
{
return ieee_cmple(GETREG(fpregs, ins.f_format.fa),
GETREG(fpregs, ins.f_format.fb),
status);
}
static fp_register_t fp_cvts(union alpha_instruction ins,
int src, int rnd,
u_int64_t control, u_int64_t *status,
struct fpreg *fpregs)
{
switch (src) {
case T_FORMAT:
return ieee_convert_T_S(GETREG(fpregs, ins.f_format.fb),
rnd, control, status);
case Q_FORMAT:
return ieee_convert_Q_S(GETREG(fpregs, ins.f_format.fb),
rnd, control, status);
default:
*status |= FPCR_INV;
return GETREG(fpregs, ins.f_format.fc);
}
}
static fp_register_t fp_cvtt(union alpha_instruction ins,
int src, int rnd,
u_int64_t control, u_int64_t *status,
struct fpreg *fpregs)
{
switch (src) {
case S_FORMAT:
return ieee_convert_S_T(GETREG(fpregs, ins.f_format.fb),
rnd, control, status);
break;
case Q_FORMAT:
return ieee_convert_Q_T(GETREG(fpregs, ins.f_format.fb),
rnd, control, status);
break;
default:
*status |= FPCR_INV;
return GETREG(fpregs, ins.f_format.fc);
}
}
static fp_register_t fp_cvtq(union alpha_instruction ins,
int src, int rnd,
u_int64_t control, u_int64_t *status,
struct fpreg *fpregs)
{
switch (src) {
case S_FORMAT:
return ieee_convert_S_Q(GETREG(fpregs, ins.f_format.fb),
rnd, control, status);
break;
case T_FORMAT:
return ieee_convert_T_Q(GETREG(fpregs, ins.f_format.fb),
rnd, control, status);
break;
default:
*status |= FPCR_INV;
return GETREG(fpregs, ins.f_format.fc);
}
}
static fp_register_t fp_reserved(union alpha_instruction ins,
int src, int rnd,
u_int64_t control, u_int64_t *status,
struct fpreg *fpregs)
{
*status |= FPCR_INV;
return GETREG(fpregs, ins.f_format.fc);
}
static fp_register_t fp_cvtql(union alpha_instruction ins,
int src, int rnd,
u_int64_t control, u_int64_t *status,
struct fpreg *fpregs)
{
fp_register_t fb = GETREG(fpregs, ins.f_format.fb);
fp_register_t ret;
*status |= FPCR_INV;
ret.q = ((fb.q & 0xc0000000) << 32 | (fb.q & 0x3fffffff) << 29);
return ret;
}
static int fp_emulate(union alpha_instruction ins, struct thread *td)
{
u_int64_t control = td->td_pcb->pcb_fp_control;
struct fpreg *fpregs = &td->td_pcb->pcb_fp;
static fp_opcode_handler *ops[16] = {
fp_add, /* 0 */
fp_sub, /* 1 */
fp_mul, /* 2 */
fp_div, /* 3 */
fp_cmpun, /* 4 */
fp_cmpeq, /* 5 */
fp_cmplt, /* 6 */
fp_cmple, /* 7 */
fp_reserved, /* 8 */
fp_reserved, /* 9 */
fp_reserved, /* 10 */
fp_reserved, /* 11 */
fp_cvts, /* 12 */
fp_reserved, /* 13 */
fp_cvtt, /* 14 */
fp_cvtq, /* 15 */
};
int src, rnd;
fp_register_t result;
u_int64_t status;
/*
* Only attempt to emulate ieee instructions & integer overflow
*/
if ((ins.common.opcode != op_flti) &&
(ins.f_format.function != fltl_cvtqlsv)){
printf("fp_emulate: unhandled opcode = 0x%x, fun = 0x%x\n",ins.common.opcode,ins.f_format.function);
return 0;
}
/*
* Dump the float registers into the pcb so we can get at
* them. We are potentially going to modify the fp state, so
* cancel fpcurproc too.
*/
alpha_fpstate_save(td, 1);
/*
* Decode and execute the instruction.
*/
src = (ins.f_format.function >> 4) & 3;
rnd = (ins.f_format.function >> 6) & 3;
if (rnd == 3)
rnd = (fpregs->fpr_cr >> FPCR_DYN_SHIFT) & 3;
status = 0;
if (ins.common.opcode == op_fltl
&& ins.f_format.function == fltl_cvtqlsv)
result = fp_cvtql(ins, src, rnd, control, &status,
fpregs);
else
result = ops[ins.f_format.function & 0xf](ins, src, rnd,
control, &status,
fpregs);
/*
* Handle exceptions.
*/
if (status) {
u_int64_t fpcr;
/* Record the exception in the software control word. */
control |= (status >> IEEE_STATUS_TO_FPCR_SHIFT);
td->td_pcb->pcb_fp_control = control;
/* Regenerate the control register */
fpcr = fpregs->fpr_cr & FPCR_DYN_MASK;
fpcr |= ((control & IEEE_STATUS_MASK)
<< IEEE_STATUS_TO_FPCR_SHIFT);
if (!(control & IEEE_TRAP_ENABLE_INV))
fpcr |= FPCR_INVD;
if (!(control & IEEE_TRAP_ENABLE_DZE))
fpcr |= FPCR_DZED;
if (!(control & IEEE_TRAP_ENABLE_OVF))
fpcr |= FPCR_OVFD;
if (!(control & IEEE_TRAP_ENABLE_UNF))
fpcr |= FPCR_UNFD;
if (!(control & IEEE_TRAP_ENABLE_INE))
fpcr |= FPCR_INED;
if (control & IEEE_STATUS_MASK)
fpcr |= FPCR_SUM;
fpregs->fpr_cr = fpcr;
/* Check the trap enable */
if ((control >> IEEE_STATUS_TO_EXCSUM_SHIFT)
& (control & IEEE_TRAP_ENABLE_MASK))
return 0;
}
PUTREG(fpregs, ins.f_format.fc, result);
return 1;
}
/*
* Attempt to complete a floating point instruction which trapped by
* emulating it in software. Return non-zero if the completion was
* successful, otherwise zero.
*/
int fp_software_completion(u_int64_t regmask, struct thread *td)
{
struct trapframe *frame = td->td_frame;
u_int64_t pc = frame->tf_regs[FRAME_PC];
int error;
/*
* First we must search back through the trap shadow to find which
* instruction was responsible for generating the trap.
*/
pc -= 4;
while (regmask) {
union alpha_instruction ins;
/*
* Read the instruction and figure out the destination
* register and opcode.
*/
error = copyin((caddr_t) pc, &ins, sizeof(ins));
if (error)
return 0;
switch (ins.common.opcode) {
case op_call_pal:
case op_jsr:
case op_br ... op_bgt:
/*
* Condition 6: the trap shadow may not
* include any branch instructions. Also,
* the trap shadow is bounded by EXCB, TRAPB
* and CALL_PAL.
*/
return 0;
case op_misc:
switch (ins.memory_format.function) {
case misc_trapb:
case misc_excb:
return 0;
}
break;
case op_inta:
case op_intl:
case op_ints:
/*
* The first 32 bits of the register mask
* represents integer registers which were
* modified in the trap shadow.
*/
regmask &= ~(1LL << ins.o_format.rc);
break;
case op_fltv:
case op_flti:
case op_fltl:
/*
* The second 32 bits of the register mask
* represents float registers which were
* modified in the trap shadow.
*/
regmask &= ~(1LL << (ins.f_format.fc + 32));
break;
}
if (regmask == 0) {
/*
* We have traced back through all the
* instructions in the trap shadow, so this
* must be the one which generated the trap.
*/
if (fp_emulate(ins, td)) {
/*
* Restore pc to the first instruction
* in the trap shadow.
*/
frame->tf_regs[FRAME_PC] = pc + 4;
return 1;
} else
return 0;
}
pc -= 4;
}
return 0;
}