OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [i386/] [math-emu/] [get_address.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1623 jcastillo
/*---------------------------------------------------------------------------+
2
 |  get_address.c                                                            |
3
 |                                                                           |
4
 | Get the effective address from an FPU instruction.                        |
5
 |                                                                           |
6
 | Copyright (C) 1992,1993,1994                                              |
7
 |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
8
 |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
9
 |                                                                           |
10
 |                                                                           |
11
 +---------------------------------------------------------------------------*/
12
 
13
/*---------------------------------------------------------------------------+
14
 | Note:                                                                     |
15
 |    The file contains code which accesses user memory.                     |
16
 |    Emulator static data may change when user memory is accessed, due to   |
17
 |    other processes using the emulator while swapping is in progress.      |
18
 +---------------------------------------------------------------------------*/
19
 
20
 
21
#include <linux/stddef.h>
22
#include <linux/head.h>
23
 
24
#include <asm/segment.h>
25
 
26
#include "fpu_system.h"
27
#include "exception.h"
28
#include "fpu_emu.h"
29
 
30
 
31
#define FPU_WRITE_BIT 0x10
32
 
33
static int reg_offset[] = {
34
        offsetof(struct info,___eax),
35
        offsetof(struct info,___ecx),
36
        offsetof(struct info,___edx),
37
        offsetof(struct info,___ebx),
38
        offsetof(struct info,___esp),
39
        offsetof(struct info,___ebp),
40
        offsetof(struct info,___esi),
41
        offsetof(struct info,___edi)
42
};
43
 
44
#define REG_(x) (*(long *)(reg_offset[(x)]+(char *) FPU_info))
45
 
46
static int reg_offset_vm86[] = {
47
        offsetof(struct info,___cs),
48
        offsetof(struct info,___vm86_ds),
49
        offsetof(struct info,___vm86_es),
50
        offsetof(struct info,___vm86_fs),
51
        offsetof(struct info,___vm86_gs),
52
        offsetof(struct info,___ss),
53
        offsetof(struct info,___vm86_ds)
54
      };
55
 
56
#define VM86_REG_(x) (*(unsigned short *) \
57
                      (reg_offset_vm86[((unsigned)x)]+(char *) FPU_info))
58
 
59
static int reg_offset_pm[] = {
60
        offsetof(struct info,___cs),
61
        offsetof(struct info,___ds),
62
        offsetof(struct info,___es),
63
        offsetof(struct info,___fs),
64
        offsetof(struct info,___gs),
65
        offsetof(struct info,___ss),
66
        offsetof(struct info,___ds)
67
      };
68
 
69
#define PM_REG_(x) (*(unsigned short *) \
70
                      (reg_offset_pm[((unsigned)x)]+(char *) FPU_info))
71
 
72
 
73
/* Decode the SIB byte. This function assumes mod != 0 */
74
static int sib(int mod, unsigned long *fpu_eip)
75
{
76
  unsigned char ss,index,base;
77
  long offset;
78
 
79
  RE_ENTRANT_CHECK_OFF;
80
  FPU_code_verify_area(1);
81
  base = get_fs_byte((char *) (*fpu_eip));   /* The SIB byte */
82
  RE_ENTRANT_CHECK_ON;
83
  (*fpu_eip)++;
84
  ss = base >> 6;
85
  index = (base >> 3) & 7;
86
  base &= 7;
87
 
88
  if ((mod == 0) && (base == 5))
89
    offset = 0;              /* No base register */
90
  else
91
    offset = REG_(base);
92
 
93
  if (index == 4)
94
    {
95
      /* No index register */
96
      /* A non-zero ss is illegal */
97
      if ( ss )
98
        EXCEPTION(EX_Invalid);
99
    }
100
  else
101
    {
102
      offset += (REG_(index)) << ss;
103
    }
104
 
105
  if (mod == 1)
106
    {
107
      /* 8 bit signed displacement */
108
      RE_ENTRANT_CHECK_OFF;
109
      FPU_code_verify_area(1);
110
      offset += (signed char) get_fs_byte((char *) (*fpu_eip));
111
      RE_ENTRANT_CHECK_ON;
112
      (*fpu_eip)++;
113
    }
114
  else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
115
    {
116
      /* 32 bit displacement */
117
      RE_ENTRANT_CHECK_OFF;
118
      FPU_code_verify_area(4);
119
      offset += (signed) get_fs_long((unsigned long *) (*fpu_eip));
120
      RE_ENTRANT_CHECK_ON;
121
      (*fpu_eip) += 4;
122
    }
123
 
124
  return offset;
125
}
126
 
127
 
128
static unsigned long vm86_segment(unsigned char segment,
129
                                  unsigned short *selector)
130
{
131
  segment--;
132
#ifdef PARANOID
133
  if ( segment > PREFIX_SS_ )
134
    {
135
      EXCEPTION(EX_INTERNAL|0x130);
136
      math_abort(FPU_info,SIGSEGV);
137
    }
138
#endif PARANOID
139
  *selector = VM86_REG_(segment);
140
  return (unsigned long)VM86_REG_(segment) << 4;
141
}
142
 
143
 
144
/* This should work for 16 and 32 bit protected mode. */
145
static long pm_address(unsigned char FPU_modrm, unsigned char segment,
146
                       unsigned short *selector, long offset)
147
{
148
  struct desc_struct descriptor;
149
  unsigned long base_address, limit, address, seg_top;
150
 
151
  segment--;
152
#ifdef PARANOID
153
  if ( segment > PREFIX_SS_ )
154
    {
155
      EXCEPTION(EX_INTERNAL|0x132);
156
      math_abort(FPU_info,SIGSEGV);
157
    }
158
#endif PARANOID
159
 
160
  *selector = PM_REG_(segment);
161
 
162
  descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
163
  base_address = SEG_BASE_ADDR(descriptor);
164
  address = base_address + offset;
165
  limit = base_address
166
        + (SEG_LIMIT(descriptor)+1) * SEG_GRANULARITY(descriptor) - 1;
167
  if ( limit < base_address ) limit = 0xffffffff;
168
 
169
  if ( SEG_EXPAND_DOWN(descriptor) )
170
    {
171
      if ( SEG_G_BIT(descriptor) )
172
        seg_top = 0xffffffff;
173
      else
174
        {
175
          seg_top = base_address + (1 << 20);
176
          if ( seg_top < base_address ) seg_top = 0xffffffff;
177
        }
178
      access_limit =
179
        (address <= limit) || (address >= seg_top) ? 0 :
180
          ((seg_top-address) >= 255 ? 255 : seg_top-address);
181
    }
182
  else
183
    {
184
      access_limit =
185
        (address > limit) || (address < base_address) ? 0 :
186
          ((limit-address) >= 254 ? 255 : limit-address+1);
187
    }
188
  if ( SEG_EXECUTE_ONLY(descriptor) ||
189
      (!SEG_WRITE_PERM(descriptor) && (FPU_modrm & FPU_WRITE_BIT)) )
190
    {
191
      access_limit = 0;
192
    }
193
  return address;
194
}
195
 
196
 
197
/*
198
       MOD R/M byte:  MOD == 3 has a special use for the FPU
199
                      SIB byte used iff R/M = 100b
200
 
201
       7   6   5   4   3   2   1   0
202
       .....   .........   .........
203
        MOD    OPCODE(2)     R/M
204
 
205
 
206
       SIB byte
207
 
208
       7   6   5   4   3   2   1   0
209
       .....   .........   .........
210
        SS      INDEX        BASE
211
 
212
*/
213
 
214
void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
215
                  struct address *addr,
216
/*                unsigned short *selector, unsigned long *offset, */
217
                  fpu_addr_modes addr_modes)
218
{
219
  unsigned char mod;
220
  unsigned rm = FPU_modrm & 7;
221
  long *cpu_reg_ptr;
222
  int address = 0;     /* Initialized just to stop compiler warnings. */
223
 
224
  /* Memory accessed via the cs selector is write protected
225
     in `non-segmented' 32 bit protected mode. */
226
  if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
227
      && (addr_modes.override.segment == PREFIX_CS_) )
228
    {
229
      math_abort(FPU_info,SIGSEGV);
230
    }
231
 
232
  addr->selector = FPU_DS;   /* Default, for 32 bit non-segmented mode. */
233
 
234
  mod = (FPU_modrm >> 6) & 3;
235
 
236
  if (rm == 4 && mod != 3)
237
    {
238
      address = sib(mod, fpu_eip);
239
    }
240
  else
241
    {
242
      cpu_reg_ptr = & REG_(rm);
243
      switch (mod)
244
        {
245
        case 0:
246
          if (rm == 5)
247
            {
248
              /* Special case: disp32 */
249
              RE_ENTRANT_CHECK_OFF;
250
              FPU_code_verify_area(4);
251
              address = get_fs_long((unsigned long *) (*fpu_eip));
252
              (*fpu_eip) += 4;
253
              RE_ENTRANT_CHECK_ON;
254
              addr->offset = address;
255
              return (void *) address;
256
            }
257
          else
258
            {
259
              address = *cpu_reg_ptr;  /* Just return the contents
260
                                          of the cpu register */
261
              addr->offset = address;
262
              return (void *) address;
263
            }
264
        case 1:
265
          /* 8 bit signed displacement */
266
          RE_ENTRANT_CHECK_OFF;
267
          FPU_code_verify_area(1);
268
          address = (signed char) get_fs_byte((char *) (*fpu_eip));
269
          RE_ENTRANT_CHECK_ON;
270
          (*fpu_eip)++;
271
          break;
272
        case 2:
273
          /* 32 bit displacement */
274
          RE_ENTRANT_CHECK_OFF;
275
          FPU_code_verify_area(4);
276
          address = (signed) get_fs_long((unsigned long *) (*fpu_eip));
277
          (*fpu_eip) += 4;
278
          RE_ENTRANT_CHECK_ON;
279
          break;
280
        case 3:
281
          /* Not legal for the FPU */
282
          EXCEPTION(EX_Invalid);
283
        }
284
      address += *cpu_reg_ptr;
285
    }
286
 
287
  addr->offset = address;
288
 
289
  switch ( addr_modes.default_mode )
290
    {
291
    case 0:
292
      break;
293
    case VM86:
294
      address += vm86_segment(addr_modes.override.segment,
295
                              (unsigned short *)&(addr->selector));
296
      break;
297
    case PM16:
298
    case SEG32:
299
      address = pm_address(FPU_modrm, addr_modes.override.segment,
300
                           (unsigned short *)&(addr->selector), address);
301
      break;
302
    default:
303
      EXCEPTION(EX_INTERNAL|0x133);
304
    }
305
 
306
  return (void *)address;
307
}
308
 
309
 
310
void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
311
                     struct address *addr,
312
/*                   unsigned short *selector, unsigned long *offset, */
313
                     fpu_addr_modes addr_modes)
314
{
315
  unsigned char mod;
316
  unsigned rm = FPU_modrm & 7;
317
  int address = 0;     /* Default used for mod == 0 */
318
 
319
  /* Memory accessed via the cs selector is write protected
320
     in `non-segmented' 32 bit protected mode. */
321
  if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
322
      && (addr_modes.override.segment == PREFIX_CS_) )
323
    {
324
      math_abort(FPU_info,SIGSEGV);
325
    }
326
 
327
  addr->selector = FPU_DS;   /* Default, for 32 bit non-segmented mode. */
328
 
329
  mod = (FPU_modrm >> 6) & 3;
330
 
331
  switch (mod)
332
    {
333
    case 0:
334
      if (rm == 6)
335
        {
336
          /* Special case: disp16 */
337
          RE_ENTRANT_CHECK_OFF;
338
          FPU_code_verify_area(2);
339
          address = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip));
340
          (*fpu_eip) += 2;
341
          RE_ENTRANT_CHECK_ON;
342
          goto add_segment;
343
        }
344
      break;
345
    case 1:
346
      /* 8 bit signed displacement */
347
      RE_ENTRANT_CHECK_OFF;
348
      FPU_code_verify_area(1);
349
      address = (signed char) get_fs_byte((signed char *) (*fpu_eip));
350
      RE_ENTRANT_CHECK_ON;
351
      (*fpu_eip)++;
352
      break;
353
    case 2:
354
      /* 16 bit displacement */
355
      RE_ENTRANT_CHECK_OFF;
356
      FPU_code_verify_area(2);
357
      address = (unsigned) get_fs_word((unsigned short *) (*fpu_eip));
358
      (*fpu_eip) += 2;
359
      RE_ENTRANT_CHECK_ON;
360
      break;
361
    case 3:
362
      /* Not legal for the FPU */
363
      EXCEPTION(EX_Invalid);
364
      break;
365
    }
366
  switch ( rm )
367
    {
368
    case 0:
369
      address += FPU_info->___ebx + FPU_info->___esi;
370
      break;
371
    case 1:
372
      address += FPU_info->___ebx + FPU_info->___edi;
373
      break;
374
    case 2:
375
      address += FPU_info->___ebp + FPU_info->___esi;
376
      if ( addr_modes.override.segment == PREFIX_DEFAULT )
377
        addr_modes.override.segment = PREFIX_SS_;
378
      break;
379
    case 3:
380
      address += FPU_info->___ebp + FPU_info->___edi;
381
      if ( addr_modes.override.segment == PREFIX_DEFAULT )
382
        addr_modes.override.segment = PREFIX_SS_;
383
      break;
384
    case 4:
385
      address += FPU_info->___esi;
386
      break;
387
    case 5:
388
      address += FPU_info->___edi;
389
      break;
390
    case 6:
391
      address += FPU_info->___ebp;
392
      if ( addr_modes.override.segment == PREFIX_DEFAULT )
393
        addr_modes.override.segment = PREFIX_SS_;
394
      break;
395
    case 7:
396
      address += FPU_info->___ebx;
397
      break;
398
    }
399
 
400
 add_segment:
401
  address &= 0xffff;
402
 
403
  addr->offset = address;
404
 
405
  switch ( addr_modes.default_mode )
406
    {
407
    case 0:
408
      break;
409
    case VM86:
410
      address += vm86_segment(addr_modes.override.segment,
411
                              (unsigned short *)&(addr->selector));
412
      break;
413
    case PM16:
414
    case SEG32:
415
      address = pm_address(FPU_modrm, addr_modes.override.segment,
416
                           (unsigned short *)&(addr->selector), address);
417
      break;
418
    default:
419
      EXCEPTION(EX_INTERNAL|0x131);
420
    }
421
 
422
  return (void *)address ;
423
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.