2 * IA32 helper functions
4 * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
5 * Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com>
6 * Copyright (C) 2001-2002 Hewlett-Packard Co
7 * David Mosberger-Tang <davidm@hpl.hp.com>
9 * 06/16/00 A. Mallick added csd/ssd/tssd for ia32 thread context
10 * 02/19/01 D. Mosberger dropped tssd; it's not needed
11 * 09/14/01 D. Mosberger fixed memory management for gdt/tss page
12 * 09/29/01 D. Mosberger added ia32_load_segment_descriptors()
15 #include <linux/kernel.h>
16 #include <linux/init.h>
18 #include <linux/personality.h>
19 #include <linux/sched.h>
21 #include <asm/intrinsics.h>
23 #include <asm/pgtable.h>
24 #include <asm/system.h>
25 #include <asm/processor.h>
29 extern void die_if_kernel (char *str
, struct pt_regs
*regs
, long err
);
31 struct exec_domain ia32_exec_domain
;
32 struct page
*ia32_shared_page
[(2*IA32_PAGE_SIZE
+ PAGE_SIZE
- 1)/PAGE_SIZE
];
33 unsigned long *ia32_gdt
;
36 load_desc (u16 selector
)
38 unsigned long *table
, limit
, index
;
42 if (selector
& IA32_SEGSEL_TI
) {
43 table
= (unsigned long *) IA32_LDT_OFFSET
;
44 limit
= IA32_LDT_ENTRIES
;
47 limit
= IA32_PAGE_SIZE
/ sizeof(ia32_gdt
[0]);
49 index
= selector
>> IA32_SEGSEL_INDEX_SHIFT
;
52 return IA32_SEG_UNSCRAMBLE(table
[index
]);
56 ia32_load_segment_descriptors (struct task_struct
*task
)
58 struct pt_regs
*regs
= ia64_task_regs(task
);
60 /* Setup the segment descriptors */
61 regs
->r24
= load_desc(regs
->r16
>> 16); /* ESD */
62 regs
->r27
= load_desc(regs
->r16
>> 0); /* DSD */
63 regs
->r28
= load_desc(regs
->r16
>> 32); /* FSD */
64 regs
->r29
= load_desc(regs
->r16
>> 48); /* GSD */
65 regs
->ar_csd
= load_desc(regs
->r17
>> 0); /* CSD */
66 regs
->ar_ssd
= load_desc(regs
->r17
>> 16); /* SSD */
70 ia32_save_state (struct task_struct
*t
)
72 t
->thread
.eflag
= ia64_getreg(_IA64_REG_AR_EFLAG
);
73 t
->thread
.fsr
= ia64_getreg(_IA64_REG_AR_FSR
);
74 t
->thread
.fcr
= ia64_getreg(_IA64_REG_AR_FCR
);
75 t
->thread
.fir
= ia64_getreg(_IA64_REG_AR_FIR
);
76 t
->thread
.fdr
= ia64_getreg(_IA64_REG_AR_FDR
);
77 ia64_set_kr(IA64_KR_IO_BASE
, t
->thread
.old_iob
);
78 ia64_set_kr(IA64_KR_TSSD
, t
->thread
.old_k1
);
82 ia32_load_state (struct task_struct
*t
)
84 unsigned long eflag
, fsr
, fcr
, fir
, fdr
, tssd
;
85 struct pt_regs
*regs
= ia64_task_regs(t
);
86 int nr
= get_cpu(); /* LDT and TSS depend on CPU number: */
88 eflag
= t
->thread
.eflag
;
93 tssd
= load_desc(_TSS(nr
)); /* TSSD */
95 ia64_setreg(_IA64_REG_AR_EFLAG
, eflag
);
96 ia64_setreg(_IA64_REG_AR_FSR
, fsr
);
97 ia64_setreg(_IA64_REG_AR_FCR
, fcr
);
98 ia64_setreg(_IA64_REG_AR_FIR
, fir
);
99 ia64_setreg(_IA64_REG_AR_FDR
, fdr
);
100 current
->thread
.old_iob
= ia64_get_kr(IA64_KR_IO_BASE
);
101 current
->thread
.old_k1
= ia64_get_kr(IA64_KR_TSSD
);
102 ia64_set_kr(IA64_KR_IO_BASE
, IA32_IOBASE
);
103 ia64_set_kr(IA64_KR_TSSD
, tssd
);
105 regs
->r17
= (_TSS(nr
) << 48) | (_LDT(nr
) << 32) | (__u32
) regs
->r17
;
106 regs
->r30
= load_desc(_LDT(nr
)); /* LDTD */
111 * Setup IA32 GDT and TSS
117 unsigned long ldt_size
;
120 ia32_shared_page
[0] = alloc_page(GFP_KERNEL
);
121 ia32_gdt
= page_address(ia32_shared_page
[0]);
122 tss
= ia32_gdt
+ IA32_PAGE_SIZE
/sizeof(ia32_gdt
[0]);
124 if (IA32_PAGE_SIZE
== PAGE_SIZE
) {
125 ia32_shared_page
[1] = alloc_page(GFP_KERNEL
);
126 tss
= page_address(ia32_shared_page
[1]);
129 /* CS descriptor in IA-32 (scrambled) format */
130 ia32_gdt
[__USER_CS
>> 3] = IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET
-1) >> IA32_PAGE_SHIFT
,
131 0xb, 1, 3, 1, 1, 1, 1);
133 /* DS descriptor in IA-32 (scrambled) format */
134 ia32_gdt
[__USER_DS
>> 3] = IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET
-1) >> IA32_PAGE_SHIFT
,
135 0x3, 1, 3, 1, 1, 1, 1);
137 /* We never change the TSS and LDT descriptors, so we can share them across all CPUs. */
138 ldt_size
= PAGE_ALIGN(IA32_LDT_ENTRIES
*IA32_LDT_ENTRY_SIZE
);
139 for (nr
= 0; nr
< NR_CPUS
; ++nr
) {
140 ia32_gdt
[_TSS(nr
) >> IA32_SEGSEL_INDEX_SHIFT
]
141 = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET
, 235,
142 0xb, 0, 3, 1, 1, 1, 0);
143 ia32_gdt
[_LDT(nr
) >> IA32_SEGSEL_INDEX_SHIFT
]
144 = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET
, ldt_size
- 1,
145 0x2, 0, 3, 1, 1, 1, 0);
150 * Handle bad IA32 interrupt via syscall
153 ia32_bad_interrupt (unsigned long int_num
, struct pt_regs
*regs
)
157 die_if_kernel("Bad IA-32 interrupt", regs
, int_num
);
159 siginfo
.si_signo
= SIGTRAP
;
160 siginfo
.si_errno
= int_num
; /* XXX is it OK to abuse si_errno like this? */
161 siginfo
.si_flags
= 0;
165 siginfo
.si_code
= TRAP_BRKPT
;
166 force_sig_info(SIGTRAP
, &siginfo
, current
);
172 /* initialize global ia32 state - CR0 and CR4 */
173 ia64_setreg(_IA64_REG_AR_CFLAG
, (((ulong
) IA32_CR4
<< 32) | IA32_CR0
));
179 ia32_exec_domain
.name
= "Linux/x86";
180 ia32_exec_domain
.handler
= NULL
;
181 ia32_exec_domain
.pers_low
= PER_LINUX32
;
182 ia32_exec_domain
.pers_high
= PER_LINUX32
;
183 ia32_exec_domain
.signal_map
= default_exec_domain
.signal_map
;
184 ia32_exec_domain
.signal_invmap
= default_exec_domain
.signal_invmap
;
185 register_exec_domain(&ia32_exec_domain
);
189 __initcall(ia32_init
);