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