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/sched.h>
20 #include <asm/intrinsics.h>
22 #include <asm/pgtable.h>
23 #include <asm/system.h>
24 #include <asm/processor.h>
25 #include <asm/uaccess.h>
29 extern int die_if_kernel (char *str
, struct pt_regs
*regs
, long err
);
31 struct page
*ia32_shared_page
[NR_CPUS
];
32 unsigned long *ia32_boot_gdt
;
33 unsigned long *cpu_gdt_table
[NR_CPUS
];
34 struct page
*ia32_gate_page
;
37 load_desc (u16 selector
)
39 unsigned long *table
, limit
, index
;
43 if (selector
& IA32_SEGSEL_TI
) {
44 table
= (unsigned long *) IA32_LDT_OFFSET
;
45 limit
= IA32_LDT_ENTRIES
;
47 table
= cpu_gdt_table
[smp_processor_id()];
48 limit
= IA32_PAGE_SIZE
/ sizeof(ia32_boot_gdt
[0]);
50 index
= selector
>> IA32_SEGSEL_INDEX_SHIFT
;
53 return IA32_SEG_UNSCRAMBLE(table
[index
]);
57 ia32_load_segment_descriptors (struct task_struct
*task
)
59 struct pt_regs
*regs
= task_pt_regs(task
);
61 /* Setup the segment descriptors */
62 regs
->r24
= load_desc(regs
->r16
>> 16); /* ESD */
63 regs
->r27
= load_desc(regs
->r16
>> 0); /* DSD */
64 regs
->r28
= load_desc(regs
->r16
>> 32); /* FSD */
65 regs
->r29
= load_desc(regs
->r16
>> 48); /* GSD */
66 regs
->ar_csd
= load_desc(regs
->r17
>> 0); /* CSD */
67 regs
->ar_ssd
= load_desc(regs
->r17
>> 16); /* SSD */
71 ia32_clone_tls (struct task_struct
*child
, struct pt_regs
*childregs
)
73 struct desc_struct
*desc
;
74 struct ia32_user_desc info
;
77 if (copy_from_user(&info
, (void __user
*)(childregs
->r14
& 0xffffffff), sizeof(info
)))
82 idx
= info
.entry_number
;
83 if (idx
< GDT_ENTRY_TLS_MIN
|| idx
> GDT_ENTRY_TLS_MAX
)
86 desc
= child
->thread
.tls_array
+ idx
- GDT_ENTRY_TLS_MIN
;
87 desc
->a
= LDT_entry_a(&info
);
88 desc
->b
= LDT_entry_b(&info
);
90 /* XXX: can this be done in a cleaner way ? */
91 load_TLS(&child
->thread
, smp_processor_id());
92 ia32_load_segment_descriptors(child
);
93 load_TLS(¤t
->thread
, smp_processor_id());
99 ia32_save_state (struct task_struct
*t
)
101 t
->thread
.eflag
= ia64_getreg(_IA64_REG_AR_EFLAG
);
102 t
->thread
.fsr
= ia64_getreg(_IA64_REG_AR_FSR
);
103 t
->thread
.fcr
= ia64_getreg(_IA64_REG_AR_FCR
);
104 t
->thread
.fir
= ia64_getreg(_IA64_REG_AR_FIR
);
105 t
->thread
.fdr
= ia64_getreg(_IA64_REG_AR_FDR
);
106 ia64_set_kr(IA64_KR_IO_BASE
, t
->thread
.old_iob
);
107 ia64_set_kr(IA64_KR_TSSD
, t
->thread
.old_k1
);
111 ia32_load_state (struct task_struct
*t
)
113 unsigned long eflag
, fsr
, fcr
, fir
, fdr
, tssd
;
114 struct pt_regs
*regs
= task_pt_regs(t
);
116 eflag
= t
->thread
.eflag
;
121 tssd
= load_desc(_TSS
); /* TSSD */
123 ia64_setreg(_IA64_REG_AR_EFLAG
, eflag
);
124 ia64_setreg(_IA64_REG_AR_FSR
, fsr
);
125 ia64_setreg(_IA64_REG_AR_FCR
, fcr
);
126 ia64_setreg(_IA64_REG_AR_FIR
, fir
);
127 ia64_setreg(_IA64_REG_AR_FDR
, fdr
);
128 current
->thread
.old_iob
= ia64_get_kr(IA64_KR_IO_BASE
);
129 current
->thread
.old_k1
= ia64_get_kr(IA64_KR_TSSD
);
130 ia64_set_kr(IA64_KR_IO_BASE
, IA32_IOBASE
);
131 ia64_set_kr(IA64_KR_TSSD
, tssd
);
133 regs
->r17
= (_TSS
<< 48) | (_LDT
<< 32) | (__u32
) regs
->r17
;
134 regs
->r30
= load_desc(_LDT
); /* LDTD */
135 load_TLS(&t
->thread
, smp_processor_id());
139 * Setup IA32 GDT and TSS
144 int cpu
= smp_processor_id();
146 ia32_shared_page
[cpu
] = alloc_page(GFP_KERNEL
);
147 if (!ia32_shared_page
[cpu
])
148 panic("failed to allocate ia32_shared_page[%d]\n", cpu
);
150 cpu_gdt_table
[cpu
] = page_address(ia32_shared_page
[cpu
]);
152 /* Copy from the boot cpu's GDT */
153 memcpy(cpu_gdt_table
[cpu
], ia32_boot_gdt
, PAGE_SIZE
);
158 * Setup IA32 GDT and TSS
161 ia32_boot_gdt_init (void)
163 unsigned long ldt_size
;
165 ia32_shared_page
[0] = alloc_page(GFP_KERNEL
);
166 if (!ia32_shared_page
[0])
167 panic("failed to allocate ia32_shared_page[0]\n");
169 ia32_boot_gdt
= page_address(ia32_shared_page
[0]);
170 cpu_gdt_table
[0] = ia32_boot_gdt
;
172 /* CS descriptor in IA-32 (scrambled) format */
173 ia32_boot_gdt
[__USER_CS
>> 3]
174 = IA32_SEG_DESCRIPTOR(0, (IA32_GATE_END
-1) >> IA32_PAGE_SHIFT
,
175 0xb, 1, 3, 1, 1, 1, 1);
177 /* DS descriptor in IA-32 (scrambled) format */
178 ia32_boot_gdt
[__USER_DS
>> 3]
179 = IA32_SEG_DESCRIPTOR(0, (IA32_GATE_END
-1) >> IA32_PAGE_SHIFT
,
180 0x3, 1, 3, 1, 1, 1, 1);
182 ldt_size
= PAGE_ALIGN(IA32_LDT_ENTRIES
*IA32_LDT_ENTRY_SIZE
);
183 ia32_boot_gdt
[TSS_ENTRY
] = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET
, 235,
184 0xb, 0, 3, 1, 1, 1, 0);
185 ia32_boot_gdt
[LDT_ENTRY
] = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET
, ldt_size
- 1,
186 0x2, 0, 3, 1, 1, 1, 0);
190 ia32_gate_page_init(void)
194 ia32_gate_page
= alloc_page(GFP_KERNEL
);
195 sr
= page_address(ia32_gate_page
);
196 /* This is popl %eax ; movl $,%eax ; int $0x80 */
197 *sr
++ = 0xb858 | (__IA32_NR_sigreturn
<< 16) | (0x80cdUL
<< 48);
199 /* This is movl $,%eax ; int $0x80 */
200 *sr
= 0xb8 | (__IA32_NR_rt_sigreturn
<< 8) | (0x80cdUL
<< 40);
206 ia32_boot_gdt_init();
207 ia32_gate_page_init();
211 * Handle bad IA32 interrupt via syscall
214 ia32_bad_interrupt (unsigned long int_num
, struct pt_regs
*regs
)
218 if (die_if_kernel("Bad IA-32 interrupt", regs
, int_num
))
221 siginfo
.si_signo
= SIGTRAP
;
222 siginfo
.si_errno
= int_num
; /* XXX is it OK to abuse si_errno like this? */
223 siginfo
.si_flags
= 0;
225 siginfo
.si_addr
= NULL
;
227 siginfo
.si_code
= TRAP_BRKPT
;
228 force_sig_info(SIGTRAP
, &siginfo
, current
);
234 /* initialize global ia32 state - CR0 and CR4 */
235 ia64_setreg(_IA64_REG_AR_CFLAG
, (((ulong
) IA32_CR4
<< 32) | IA32_CR0
));
241 #if PAGE_SHIFT > IA32_PAGE_SHIFT
243 extern struct kmem_cache
*ia64_partial_page_cachep
;
245 ia64_partial_page_cachep
= kmem_cache_create("ia64_partial_page_cache",
246 sizeof(struct ia64_partial_page
),
247 0, SLAB_PANIC
, NULL
);
253 __initcall(ia32_init
);