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 = ®_(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