1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
/*
* IA32 helper functions
*
* 06/16/00 A. Mallick added csd/ssd/tssd for ia32 thread context
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/processor.h>
#include <asm/ia32.h>
extern unsigned long *ia32_gdt_table, *ia32_tss;
extern void die_if_kernel (char *str, struct pt_regs *regs, long err);
void
ia32_save_state (struct thread_struct *thread)
{
unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd;
asm ("mov %0=ar.eflag;"
"mov %1=ar.fsr;"
"mov %2=ar.fcr;"
"mov %3=ar.fir;"
"mov %4=ar.fdr;"
"mov %5=ar.csd;"
"mov %6=ar.ssd;"
"mov %7=ar.k1"
: "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr),
"=r"(csd), "=r"(ssd), "=r"(tssd));
thread->eflag = eflag;
thread->fsr = fsr;
thread->fcr = fcr;
thread->fir = fir;
thread->fdr = fdr;
thread->csd = csd;
thread->ssd = ssd;
thread->tssd = tssd;
asm ("mov ar.k0=%0 ;;" :: "r"(thread->old_iob));
}
void
ia32_load_state (struct thread_struct *thread)
{
unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd;
eflag = thread->eflag;
fsr = thread->fsr;
fcr = thread->fcr;
fir = thread->fir;
fdr = thread->fdr;
csd = thread->csd;
ssd = thread->ssd;
tssd = thread->tssd;
asm volatile ("mov ar.eflag=%0;"
"mov ar.fsr=%1;"
"mov ar.fcr=%2;"
"mov ar.fir=%3;"
"mov ar.fdr=%4;"
"mov ar.csd=%5;"
"mov ar.ssd=%6;"
"mov ar.k1=%7"
:: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr),
"r"(csd), "r"(ssd), "r"(tssd));
asm ("mov %0=ar.k0 ;;" : "=r"(thread->old_iob));
asm ("mov ar.k0=%0 ;;" :: "r"(IA32_IOBASE));
}
/*
* Setup IA32 GDT and TSS
*/
void
ia32_gdt_init(void)
{
unsigned long gdt_and_tss_page;
/* allocate two IA-32 pages of memory: */
gdt_and_tss_page = __get_free_pages(GFP_KERNEL,
(IA32_PAGE_SHIFT < PAGE_SHIFT)
? 0 : (IA32_PAGE_SHIFT + 1) - PAGE_SHIFT);
ia32_gdt_table = (unsigned long *) gdt_and_tss_page;
ia32_tss = (unsigned long *) (gdt_and_tss_page + IA32_PAGE_SIZE);
/* Zero the gdt and tss */
memset((void *) gdt_and_tss_page, 0, 2*IA32_PAGE_SIZE);
/* CS descriptor in IA-32 format */
ia32_gdt_table[4] = IA32_SEG_DESCRIPTOR(0L, 0xBFFFFFFFL, 0xBL, 1L,
3L, 1L, 1L, 1L, 1L);
/* DS descriptor in IA-32 format */
ia32_gdt_table[5] = IA32_SEG_DESCRIPTOR(0L, 0xBFFFFFFFL, 0x3L, 1L,
3L, 1L, 1L, 1L, 1L);
}
/*
* Handle bad IA32 interrupt via syscall
*/
void
ia32_bad_interrupt (unsigned long int_num, struct pt_regs *regs)
{
siginfo_t siginfo;
die_if_kernel("Bad IA-32 interrupt", regs, int_num);
siginfo.si_signo = SIGTRAP;
siginfo.si_errno = int_num; /* XXX is it legal to abuse si_errno like this? */
siginfo.si_code = TRAP_BRKPT;
force_sig_info(SIGTRAP, &siginfo, current);
}
|