My first commit.
[dragonfly.git] / sys / platform / pc32 / gnu / fpemul / get_address.c
1 /*
2  *  get_address.c
3  *
4  * Get the effective address from an FPU instruction.
5  *
6  *
7  * Copyright (C) 1992,1993,1994
8  *                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
9  *                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au
10  * All rights reserved.
11  *
12  * This copyright notice covers the redistribution and use of the
13  * FPU emulator developed by W. Metzenthen. It covers only its use
14  * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
15  * use is not permitted under this copyright.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must include information specifying
23  *    that source code for the emulator is freely available and include
24  *    either:
25  *      a) an offer to provide the source code for a nominal distribution
26  *         fee, or
27  *      b) list at least two alternative methods whereby the source
28  *         can be obtained, e.g. a publically accessible bulletin board
29  *         and an anonymous ftp site from which the software can be
30  *         downloaded.
31  * 3. All advertising materials specifically mentioning features or use of
32  *    this emulator must acknowledge that it was developed by W. Metzenthen.
33  * 4. The name of W. Metzenthen may not be used to endorse or promote
34  *    products derived from this software without specific prior written
35  *    permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
38  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
39  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
40  * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
41  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
42  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
43  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
44  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
45  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
46  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  *
48  *
49  * The purpose of this copyright, based upon the Berkeley copyright, is to
50  * ensure that the covered software remains freely available to everyone.
51  *
52  * The software (with necessary differences) is also available, but under
53  * the terms of the GNU copyleft, for the Linux operating system and for
54  * the djgpp ms-dos extender.
55  *
56  * W. Metzenthen   June 1994.
57  *
58  *
59  * $FreeBSD: src/sys/gnu/i386/fpemul/get_address.c,v 1.10 1999/10/12 02:23:14 msmith Exp $
60  * $DragonFly: src/sys/platform/pc32/gnu/fpemul/Attic/get_address.c,v 1.3 2003/08/07 21:17:20 dillon Exp $
61  *
62  */
63
64 /*---------------------------------------------------------------------------+
65  | Note:                                                                     |
66  |    The file contains code which accesses user memory.                     |
67  |    Emulator static data may change when user memory is accessed, due to   |
68  |    other processes using the emulator while swapping is in progress.      |
69  +---------------------------------------------------------------------------*/
70
71 #include <sys/param.h>
72 #include <sys/proc.h>
73 #include <sys/systm.h>
74 #include <machine/cpu.h>
75 #include <machine/pcb.h>
76 #include <machine/reg.h>
77
78 #include "fpu_emu.h"
79 #include "fpu_system.h"
80 #include "exception.h"
81
82 static int reg_offset[] = {
83 tEAX, tECX, tEDX, tEBX, tESP, tEBP, tESI, tEDI};
84 #define REG_(x) (*(((int*)FPU_info) + reg_offset[(x)]))
85
86 void   *FPU_data_address;
87
88
89 /* Decode the SIB byte. This function assumes mod != 0 */
90 static void *
91 sib(int mod)
92 {
93         unsigned char ss, index, base;
94         long    offset;
95
96         REENTRANT_CHECK(OFF);
97         base = fubyte((char *) FPU_EIP);        /* The SIB byte */
98         REENTRANT_CHECK(ON);
99         FPU_EIP++;
100         ss = base >> 6;
101         index = (base >> 3) & 7;
102         base &= 7;
103
104         if ((mod == 0) && (base == 5))
105                 offset = 0;     /* No base register */
106         else
107                 offset = REG_(base);
108
109         if (index == 4) {
110                 /* No index register */
111                 /* A non-zero ss is illegal */
112                 if (ss)
113                         EXCEPTION(EX_Invalid);
114         } else {
115                 offset += (REG_(index)) << ss;
116         }
117
118         if (mod == 1) {
119                 /* 8 bit signed displacement */
120                 REENTRANT_CHECK(OFF);
121                 offset += (signed char) fubyte((char *) FPU_EIP);
122                 REENTRANT_CHECK(ON);
123                 FPU_EIP++;
124         } else
125                 if (mod == 2 || base == 5) {    /* The second condition also
126                                                  * has mod==0 */
127                         /* 32 bit displacment */
128                         REENTRANT_CHECK(OFF);
129                         offset += (signed) fuword((unsigned long *) FPU_EIP);
130                         REENTRANT_CHECK(ON);
131                         FPU_EIP += 4;
132                 }
133         return (void *) (intptr_t) offset;
134 }
135
136
137 /*
138        MOD R/M byte:  MOD == 3 has a special use for the FPU
139                       SIB byte used iff R/M = 100b
140
141        7   6   5   4   3   2   1   0
142        .....   .........   .........
143         MOD    OPCODE(2)     R/M
144
145
146        SIB byte
147
148        7   6   5   4   3   2   1   0
149        .....   .........   .........
150         SS      INDEX        BASE
151
152 */
153
154 void
155 get_address(unsigned char FPU_modrm)
156 {
157         unsigned char mod;
158         long   *cpu_reg_ptr;
159         int     offset = 0;     /* Initialized just to stop compiler warnings. */
160
161         mod = (FPU_modrm >> 6) & 3;
162
163         if (FPU_rm == 4 && mod != 3) {
164                 FPU_data_address = sib(mod);
165                 return;
166         }
167         cpu_reg_ptr = (long *) &REG_(FPU_rm);
168         switch (mod) {
169         case 0:
170                 if (FPU_rm == 5) {
171                         /* Special case: disp32 */
172                         REENTRANT_CHECK(OFF);
173                         offset = fuword((unsigned long *) FPU_EIP);
174                         REENTRANT_CHECK(ON);
175                         FPU_EIP += 4;
176                         FPU_data_address = (void *) offset;
177                         return;
178                 } else {
179                         /* Just return the contents of the cpu register */
180                         FPU_data_address = (void *) (intptr_t) *cpu_reg_ptr;
181                         return;
182                 }
183         case 1:
184                 /* 8 bit signed displacement */
185                 REENTRANT_CHECK(OFF);
186                 offset = (signed char) fubyte((char *) FPU_EIP);
187                 REENTRANT_CHECK(ON);
188                 FPU_EIP++;
189                 break;
190         case 2:
191                 /* 32 bit displacement */
192                 REENTRANT_CHECK(OFF);
193                 offset = (signed) fuword((unsigned long *) FPU_EIP);
194                 REENTRANT_CHECK(ON);
195                 FPU_EIP += 4;
196                 break;
197         case 3:
198                 /* Not legal for the FPU */
199                 EXCEPTION(EX_Invalid);
200         }
201
202         FPU_data_address = (void *) (intptr_t) (offset + *cpu_reg_ptr);
203 }