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