freebsd-dev/sys/gnu/i386/fpemul/get_address.c

203 lines
6.0 KiB
C
Raw Normal View History

/*
* get_address.c
*
* Get the effective address from an FPU instruction.
*
*
* Copyright (C) 1992,1993,1994
* W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
* Australia. E-mail billm@vaxc.cc.monash.edu.au
* All rights reserved.
*
* This copyright notice covers the redistribution and use of the
* FPU emulator developed by W. Metzenthen. It covers only its use
* in the 386BSD, FreeBSD and NetBSD operating systems. Any other
* use is not permitted under this copyright.
*
* 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 include information specifying
* that source code for the emulator is freely available and include
* either:
* a) an offer to provide the source code for a nominal distribution
* fee, or
* b) list at least two alternative methods whereby the source
* can be obtained, e.g. a publically accessible bulletin board
* and an anonymous ftp site from which the software can be
* downloaded.
* 3. All advertising materials specifically mentioning features or use of
* this emulator must acknowledge that it was developed by W. Metzenthen.
* 4. The name of W. Metzenthen may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED ``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
* W. METZENTHEN 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.
*
1994-04-29 21:16:27 +00:00
*
* The purpose of this copyright, based upon the Berkeley copyright, is to
* ensure that the covered software remains freely available to everyone.
*
* The software (with necessary differences) is also available, but under
* the terms of the GNU copyleft, for the Linux operating system and for
* the djgpp ms-dos extender.
*
* W. Metzenthen June 1994.
*
*
1999-08-28 01:08:13 +00:00
* $FreeBSD$
1994-04-29 21:16:27 +00:00
*
*/
/*---------------------------------------------------------------------------+
| Note: |
| The file contains code which accesses user memory. |
| Emulator static data may change when user memory is accessed, due to |
| other processes using the emulator while swapping is in progress. |
+---------------------------------------------------------------------------*/
1996-09-10 08:32:01 +00:00
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <machine/cpu.h>
1996-09-10 08:32:01 +00:00
#include <machine/pcb.h>
#include <machine/reg.h>
1996-09-10 08:32:01 +00:00
#include <gnu/i386/fpemul/fpu_emu.h>
#include <gnu/i386/fpemul/fpu_system.h>
#include <gnu/i386/fpemul/exception.h>
static int reg_offset[] = {
tEAX, tECX, tEDX, tEBX, tESP, tEBP, tESI, tEDI};
#define REG_(x) (*(((int*)FPU_info) + reg_offset[(x)]))
void *FPU_data_address;
/* Decode the SIB byte. This function assumes mod != 0 */
static void *
sib(int mod)
{
unsigned char ss, index, base;
long offset;
REENTRANT_CHECK(OFF);
base = fubyte((char *) FPU_EIP); /* The SIB byte */
REENTRANT_CHECK(ON);
FPU_EIP++;
ss = base >> 6;
index = (base >> 3) & 7;
base &= 7;
if ((mod == 0) && (base == 5))
offset = 0; /* No base register */
else
offset = REG_(base);
if (index == 4) {
/* No index register */
/* A non-zero ss is illegal */
if (ss)
EXCEPTION(EX_Invalid);
} else {
offset += (REG_(index)) << ss;
}
if (mod == 1) {
/* 8 bit signed displacement */
REENTRANT_CHECK(OFF);
offset += (signed char) fubyte((char *) FPU_EIP);
REENTRANT_CHECK(ON);
FPU_EIP++;
} else
if (mod == 2 || base == 5) { /* The second condition also
* has mod==0 */
/* 32 bit displacment */
REENTRANT_CHECK(OFF);
offset += (signed) fuword((unsigned long *) FPU_EIP);
REENTRANT_CHECK(ON);
FPU_EIP += 4;
}
return (void *) (intptr_t) offset;
}
/*
MOD R/M byte: MOD == 3 has a special use for the FPU
SIB byte used iff R/M = 100b
7 6 5 4 3 2 1 0
..... ......... .........
MOD OPCODE(2) R/M
SIB byte
7 6 5 4 3 2 1 0
..... ......... .........
SS INDEX BASE
*/
void
get_address(unsigned char FPU_modrm)
{
unsigned char mod;
long *cpu_reg_ptr;
int offset = 0; /* Initialized just to stop compiler warnings. */
mod = (FPU_modrm >> 6) & 3;
if (FPU_rm == 4 && mod != 3) {
FPU_data_address = sib(mod);
return;
}
cpu_reg_ptr = (long *) &REG_(FPU_rm);
switch (mod) {
case 0:
if (FPU_rm == 5) {
/* Special case: disp32 */
REENTRANT_CHECK(OFF);
offset = fuword((unsigned long *) FPU_EIP);
REENTRANT_CHECK(ON);
FPU_EIP += 4;
FPU_data_address = (void *) offset;
return;
} else {
/* Just return the contents of the cpu register */
FPU_data_address = (void *) (intptr_t) *cpu_reg_ptr;
return;
}
case 1:
/* 8 bit signed displacement */
REENTRANT_CHECK(OFF);
offset = (signed char) fubyte((char *) FPU_EIP);
REENTRANT_CHECK(ON);
FPU_EIP++;
break;
case 2:
/* 32 bit displacement */
REENTRANT_CHECK(OFF);
offset = (signed) fuword((unsigned long *) FPU_EIP);
REENTRANT_CHECK(ON);
FPU_EIP += 4;
break;
case 3:
/* Not legal for the FPU */
EXCEPTION(EX_Invalid);
}
FPU_data_address = (void *) (intptr_t) (offset + *cpu_reg_ptr);
}