ia64/xen-unstable

view xen/arch/ia64/process.c @ 4599:828a6e563cf1

bitkeeper revision 1.1277.1.9 (42669b73P7IEHFimy7hJD0wKH7v80w)

vcpu.c, process.c:
correct handling for cr.iha
author djm@kirby.fc.hp.com
date Wed Apr 20 18:12:03 2005 +0000 (2005-04-20)
parents 1f457fed92df
children 628d7ea9f439
line source
1 /*
2 * Miscellaneous process/domain related routines
3 *
4 * Copyright (C) 2004 Hewlett-Packard Co.
5 * Dan Magenheimer (dan.magenheimer@hp.com)
6 *
7 */
9 #include <xen/config.h>
10 #include <xen/lib.h>
11 #include <xen/errno.h>
12 #include <xen/sched.h>
13 #include <xen/smp.h>
14 #include <asm/ptrace.h>
15 #include <xen/delay.h>
17 #include <linux/efi.h> /* FOR EFI_UNIMPLEMENTED */
18 #include <asm/sal.h> /* FOR struct ia64_sal_retval */
20 #include <asm/system.h>
21 #include <asm/io.h>
22 #include <asm/processor.h>
23 #include <asm/desc.h>
24 //#include <asm/ldt.h>
25 #include <xen/irq.h>
26 #include <xen/event.h>
27 #include <asm/regionreg.h>
28 #include <asm/privop.h>
29 #include <asm/vcpu.h>
30 #include <asm/ia64_int.h>
31 #include <asm/hpsim_ssc.h>
32 #include <asm/dom_fw.h>
34 extern unsigned long vcpu_get_itir_on_fault(struct exec_domain *, UINT64);
35 extern struct ia64_sal_retval pal_emulator_static(UINT64);
36 extern struct ia64_sal_retval sal_emulator(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64);
38 extern unsigned long dom0_start, dom0_size;
40 #define IA64_PSR_CPL1 (__IA64_UL(1) << IA64_PSR_CPL1_BIT)
41 // note IA64_PSR_PK removed from following, why is this necessary?
42 #define DELIVER_PSR_SET (IA64_PSR_IC | IA64_PSR_I | \
43 IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_CPL1 | \
44 IA64_PSR_IT | IA64_PSR_BN)
46 #define DELIVER_PSR_CLR (IA64_PSR_AC | IA64_PSR_DFL | IA64_PSR_DFH | \
47 IA64_PSR_SP | IA64_PSR_DI | IA64_PSR_SI | \
48 IA64_PSR_DB | IA64_PSR_LP | IA64_PSR_TB | \
49 IA64_PSR_CPL | IA64_PSR_MC | IA64_PSR_IS | \
50 IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | \
51 IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | IA64_PSR_IA)
53 #define PSCB(x,y) x->vcpu_info->arch.y
55 extern unsigned long vcpu_verbose;
57 long do_iopl(domid_t domain, unsigned int new_io_pl)
58 {
59 dummy();
60 return 0;
61 }
63 void schedule_tail(struct exec_domain *next)
64 {
65 unsigned long rr7;
66 printk("current=%lx,shared_info=%lx\n",current,current->vcpu_info);
67 printk("next=%lx,shared_info=%lx\n",next,next->vcpu_info);
68 if (rr7 = load_region_regs(current)) {
69 printk("schedule_tail: change to rr7 not yet implemented\n");
70 }
71 }
73 extern TR_ENTRY *match_tr(struct exec_domain *ed, unsigned long ifa);
75 void tdpfoo(void) { }
77 // given a domain virtual address, pte and pagesize, extract the metaphysical
78 // address, convert the pte for a physical address for (possibly different)
79 // Xen PAGE_SIZE and return modified pte. (NOTE: TLB insert should use
80 // PAGE_SIZE!)
81 unsigned long translate_domain_pte(unsigned long pteval,
82 unsigned long address, unsigned long itir)
83 {
84 struct domain *d = current->domain;
85 unsigned long mask, pteval2, mpaddr;
86 unsigned long lookup_domain_mpa(struct domain *,unsigned long);
87 extern struct domain *dom0;
88 extern unsigned long dom0_start, dom0_size;
90 // FIXME address had better be pre-validated on insert
91 mask = (1L << ((itir >> 2) & 0x3f)) - 1;
92 mpaddr = ((pteval & _PAGE_PPN_MASK) & ~mask) | (address & mask);
93 if (d == dom0) {
94 if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
95 //printk("translate_domain_pte: out-of-bounds dom0 mpaddr %p! itc=%lx...\n",mpaddr,ia64_get_itc());
96 tdpfoo();
97 }
98 }
99 else if ((mpaddr >> PAGE_SHIFT) > d->max_pages) {
100 printf("translate_domain_pte: bad mpa=%p (> %p),vadr=%p,pteval=%p,itir=%p\n",
101 mpaddr,d->max_pages<<PAGE_SHIFT,address,pteval,itir);
102 tdpfoo();
103 }
104 pteval2 = lookup_domain_mpa(d,mpaddr);
105 pteval2 &= _PAGE_PPN_MASK; // ignore non-addr bits
106 pteval2 |= _PAGE_PL_2; // force PL0->2 (PL3 is unaffected)
107 pteval2 = (pteval & ~_PAGE_PPN_MASK) | pteval2;
108 return pteval2;
109 }
111 // given a current domain metaphysical address, return the physical address
112 unsigned long translate_domain_mpaddr(unsigned long mpaddr)
113 {
114 extern unsigned long lookup_domain_mpa(struct domain *,unsigned long);
115 unsigned long pteval;
117 if (current->domain == dom0) {
118 if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
119 printk("translate_domain_mpaddr: out-of-bounds dom0 mpaddr %p! continuing...\n",mpaddr);
120 tdpfoo();
121 }
122 }
123 pteval = lookup_domain_mpa(current->domain,mpaddr);
124 return ((pteval & _PAGE_PPN_MASK) | (mpaddr & ~PAGE_MASK));
125 }
127 void reflect_interruption(unsigned long ifa, unsigned long isr, unsigned long itiriim, struct pt_regs *regs, unsigned long vector)
128 {
129 unsigned long vcpu_get_ipsr_int_state(struct exec_domain *,unsigned long);
130 unsigned long vcpu_get_rr_ve(struct exec_domain *,unsigned long);
131 struct domain *d = current->domain;
132 struct exec_domain *ed = current;
134 if (vector == IA64_EXTINT_VECTOR) {
136 extern unsigned long vcpu_verbose, privop_trace;
137 static first_extint = 1;
138 if (first_extint) {
139 printf("Delivering first extint to domain: ifa=%p, isr=%p, itir=%p, iip=%p\n",ifa,isr,itiriim,regs->cr_iip);
140 //privop_trace = 1; vcpu_verbose = 1;
141 first_extint = 0;
142 }
143 }
144 if (!PSCB(ed,interrupt_collection_enabled)) {
145 if (!(PSCB(ed,ipsr) & IA64_PSR_DT)) {
146 panic_domain(regs,"psr.dt off, trying to deliver nested dtlb!\n");
147 }
148 vector &= ~0xf;
149 if (vector != IA64_DATA_TLB_VECTOR &&
150 vector != IA64_ALT_DATA_TLB_VECTOR) {
151 panic_domain(regs,"psr.ic off, delivering fault=%lx,iip=%p,ifa=%p,isr=%p,PSCB.iip=%p\n",
152 vector,regs->cr_iip,ifa,isr,PSCB(ed,iip));
154 }
155 //printf("Delivering NESTED DATA TLB fault\n");
156 vector = IA64_DATA_NESTED_TLB_VECTOR;
157 regs->cr_iip = ((unsigned long) PSCB(ed,iva) + vector) & ~0xffUL;
158 regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET;
159 // NOTE: nested trap must NOT pass PSCB address
160 //regs->r31 = (unsigned long) &PSCB(ed);
161 return;
163 }
164 if ((vector & 0xf) != IA64_FORCED_IFA) PSCB(ed,ifa) = ifa;
165 else ifa = PSCB(ed,ifa);
166 vector &= ~0xf;
167 // always deliver on ALT vector (for now?) because no VHPT
168 // if (!vcpu_get_rr_ve(ed,ifa)) {
169 if (vector == IA64_DATA_TLB_VECTOR)
170 vector = IA64_ALT_DATA_TLB_VECTOR;
171 else if (vector == IA64_INST_TLB_VECTOR)
172 vector = IA64_ALT_INST_TLB_VECTOR;
173 // }
174 if (vector == IA64_ALT_DATA_TLB_VECTOR ||
175 vector == IA64_ALT_INST_TLB_VECTOR) {
176 vcpu_thash(ed,ifa,&PSCB(ed,iha));
177 }
178 PSCB(ed,unat) = regs->ar_unat; // not sure if this is really needed?
179 PSCB(ed,precover_ifs) = regs->cr_ifs;
180 vcpu_bsw0(ed);
181 PSCB(ed,ipsr) = vcpu_get_ipsr_int_state(ed,regs->cr_ipsr);
182 if (vector == IA64_BREAK_VECTOR || vector == IA64_SPECULATION_VECTOR)
183 PSCB(ed,iim) = itiriim;
184 else PSCB(ed,itir) = vcpu_get_itir_on_fault(ed,ifa);
185 PSCB(ed,isr) = isr; // this is unnecessary except for interrupts!
186 PSCB(ed,iip) = regs->cr_iip;
187 PSCB(ed,ifs) = 0;
188 PSCB(ed,incomplete_regframe) = 0;
190 regs->cr_iip = ((unsigned long) PSCB(ed,iva) + vector) & ~0xffUL;
191 regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET;
192 #ifdef CONFIG_SMP
193 #error "sharedinfo doesn't handle smp yet"
194 #endif
195 regs->r31 = &((shared_info_t *)SHAREDINFO_ADDR)->vcpu_data[0].arch;
197 PSCB(ed,interrupt_delivery_enabled) = 0;
198 PSCB(ed,interrupt_collection_enabled) = 0;
199 }
201 void foodpi(void) {}
203 // ONLY gets called from ia64_leave_kernel
204 // ONLY call with interrupts disabled?? (else might miss one?)
205 // NEVER successful if already reflecting a trap/fault because psr.i==0
206 void deliver_pending_interrupt(struct pt_regs *regs)
207 {
208 struct domain *d = current->domain;
209 struct exec_domain *ed = current;
210 // FIXME: Will this work properly if doing an RFI???
211 if (!is_idle_task(d) && user_mode(regs)) {
212 //vcpu_poke_timer(ed);
213 if (vcpu_deliverable_interrupts(ed)) {
214 unsigned long isr = regs->cr_ipsr & IA64_PSR_RI;
215 if (vcpu_timer_pending_early(ed))
216 printf("*#*#*#* about to deliver early timer to domain %d!!!\n",ed->domain->id);
217 reflect_interruption(0,isr,0,regs,IA64_EXTINT_VECTOR);
218 }
219 }
220 }
222 int handle_lazy_cover(struct exec_domain *ed, unsigned long isr, struct pt_regs *regs)
223 {
224 if (!PSCB(ed,interrupt_collection_enabled)) {
225 if (isr & IA64_ISR_IR) {
226 // printf("Handling lazy cover\n");
227 PSCB(ed,ifs) = regs->cr_ifs;
228 PSCB(ed,incomplete_regframe) = 1;
229 regs->cr_ifs = 0;
230 return(1); // retry same instruction with cr.ifs off
231 }
232 }
233 return(0);
234 }
236 #define IS_XEN_ADDRESS(d,a) ((a >= d->xen_vastart) && (a <= d->xen_vaend))
238 void xen_handle_domain_access(unsigned long address, unsigned long isr, struct pt_regs *regs, unsigned long itir)
239 {
240 struct domain *d = (struct domain *) current->domain;
241 struct domain *ed = (struct exec_domain *) current;
242 TR_ENTRY *trp;
243 unsigned long psr = regs->cr_ipsr, mask, flags;
244 unsigned long iip = regs->cr_iip;
245 // FIXME should validate address here
246 unsigned long pteval, mpaddr, ps;
247 unsigned long lookup_domain_mpa(struct domain *,unsigned long);
248 unsigned long match_dtlb(struct exec_domain *,unsigned long, unsigned long *, unsigned long *);
249 IA64FAULT fault;
251 // NEED TO HANDLE THREE CASES:
252 // 1) domain is in metaphysical mode
253 // 2) domain address is in TR
254 // 3) domain address is not in TR (reflect data miss)
256 // got here trying to read a privop bundle
257 //if (d->metaphysical_mode) {
258 if (PSCB(current,metaphysical_mode) && !(address>>61)) { //FIXME
259 if (d == dom0) {
260 if (address < dom0_start || address >= dom0_start + dom0_size) {
261 printk("xen_handle_domain_access: out-of-bounds"
262 "dom0 mpaddr %p! continuing...\n",mpaddr);
263 tdpfoo();
264 }
265 }
266 pteval = lookup_domain_mpa(d,address);
267 //FIXME: check return value?
268 // would be nice to have a counter here
269 vcpu_itc_no_srlz(ed,2,address,pteval,-1UL,PAGE_SHIFT);
270 return;
271 }
272 if (address < 0x4000) printf("WARNING: page_fault @%p, iip=%p\n",address,iip);
274 // if we are fortunate enough to have it in the 1-entry TLB...
275 if (pteval = match_dtlb(ed,address,&ps,NULL)) {
276 vcpu_itc_no_srlz(ed,6,address,pteval,-1UL,ps);
277 return;
278 }
279 // look in the TRs
280 fault = vcpu_tpa(ed,address,&mpaddr);
281 if (fault != IA64_NO_FAULT) {
282 static int uacnt = 0;
283 // can't translate it, just fail (poor man's exception)
284 // which results in retrying execution
285 //printk("*** xen_handle_domain_access: poor man's exception cnt=%i iip=%p, addr=%p...\n",uacnt++,iip,address);
286 if (ia64_done_with_exception(regs)) {
287 //if (!(uacnt++ & 0x3ff)) printk("*** xen_handle_domain_access: successfully handled cnt=%d iip=%p, addr=%p...\n",uacnt,iip,address);
288 return;
289 }
290 else {
291 // should never happen. If it does, region 0 addr may
292 // indicate a bad xen pointer
293 printk("*** xen_handle_domain_access: exception table"
294 " lookup failed, iip=%p, addr=%p, spinning...\n",
295 iip,address);
296 panic_domain(regs,"*** xen_handle_domain_access: exception table"
297 " lookup failed, iip=%p, addr=%p, spinning...\n",
298 iip,address);
299 }
300 }
301 if (d == dom0) {
302 if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
303 printk("xen_handle_domain_access: vcpu_tpa returned out-of-bounds dom0 mpaddr %p! continuing...\n",mpaddr);
304 tdpfoo();
305 }
306 }
307 //printk("*** xen_handle_domain_access: tpa resolved miss @%p...\n",address);
308 pteval = lookup_domain_mpa(d,mpaddr);
309 // would be nice to have a counter here
310 //printf("Handling privop data TLB miss\n");
311 // FIXME, must be inlined or potential for nested fault here!
312 vcpu_itc_no_srlz(ed,2,address,pteval,-1UL,PAGE_SHIFT);
313 }
315 void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs, unsigned long itir)
316 {
317 struct domain *d = (struct domain *) current->domain;
318 TR_ENTRY *trp;
319 unsigned long psr = regs->cr_ipsr, mask, flags;
320 unsigned long iip = regs->cr_iip;
321 // FIXME should validate address here
322 unsigned long pteval, mpaddr;
323 unsigned long lookup_domain_mpa(struct domain *,unsigned long);
324 unsigned long is_data = !((isr >> IA64_ISR_X_BIT) & 1UL);
325 unsigned long vector;
326 IA64FAULT fault;
329 //The right way is put in VHPT and take another miss!
331 // weak attempt to avoid doing both I/D tlb insert to avoid
332 // problems for privop bundle fetch, doesn't work, deal with later
333 if (IS_XEN_ADDRESS(d,iip) && !IS_XEN_ADDRESS(d,address)) {
334 xen_handle_domain_access(address, isr, regs, itir);
336 return;
337 }
339 // FIXME: no need to pass itir in to this routine as we need to
340 // compute the virtual itir anyway (based on domain's RR.ps)
341 // AND ACTUALLY reflect_interruption doesn't use it anyway!
342 itir = vcpu_get_itir_on_fault(current,address);
344 if (PSCB(current,metaphysical_mode) && (is_data || !(address>>61))) { //FIXME
345 // FIXME should validate mpaddr here
346 if (d == dom0) {
347 if (address < dom0_start || address >= dom0_start + dom0_size) {
348 printk("ia64_do_page_fault: out-of-bounds dom0 mpaddr %p, iip=%p! continuing...\n",address,iip);
349 printk("ia64_do_page_fault: out-of-bounds dom0 mpaddr %p, old iip=%p!\n",address,current->vcpu_info->arch.iip);
350 tdpfoo();
351 }
352 }
353 pteval = lookup_domain_mpa(d,address);
354 // FIXME, must be inlined or potential for nested fault here!
355 vcpu_itc_no_srlz(current,is_data?2:1,address,pteval,-1UL,PAGE_SHIFT);
356 return;
357 }
358 if (trp = match_tr(current,address)) {
359 // FIXME address had better be pre-validated on insert
360 pteval = translate_domain_pte(trp->page_flags,address,trp->itir);
361 vcpu_itc_no_srlz(current,is_data?2:1,address,pteval,-1UL,(trp->itir>>2)&0x3f);
362 return;
363 }
364 vector = is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR;
365 if (handle_lazy_cover(current, isr, regs)) return;
366 if (!(address>>61)) {
367 panic_domain(0,"ia64_do_page_fault: @%p???, iip=%p, itc=%p (spinning...)\n",address,iip,ia64_get_itc());
368 }
369 if ((isr & IA64_ISR_SP)
370 || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH))
371 {
372 /*
373 * This fault was due to a speculative load or lfetch.fault, set the "ed"
374 * bit in the psr to ensure forward progress. (Target register will get a
375 * NaT for ld.s, lfetch will be canceled.)
376 */
377 ia64_psr(regs)->ed = 1;
378 return;
379 }
380 reflect_interruption(address, isr, itir, regs, vector);
381 }
383 void
384 ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
385 unsigned long iim, unsigned long itir, unsigned long arg5,
386 unsigned long arg6, unsigned long arg7, unsigned long stack)
387 {
388 struct pt_regs *regs = (struct pt_regs *) &stack;
389 unsigned long code, error = isr;
390 char buf[128];
391 int result, sig;
392 static const char *reason[] = {
393 "IA-64 Illegal Operation fault",
394 "IA-64 Privileged Operation fault",
395 "IA-64 Privileged Register fault",
396 "IA-64 Reserved Register/Field fault",
397 "Disabled Instruction Set Transition fault",
398 "Unknown fault 5", "Unknown fault 6", "Unknown fault 7", "Illegal Hazard fault",
399 "Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12",
400 "Unknown fault 13", "Unknown fault 14", "Unknown fault 15"
401 };
402 #if 0
403 printf("ia64_fault, vector=0x%p, ifa=%p, iip=%p, ipsr=%p, isr=%p\n",
404 vector, ifa, regs->cr_iip, regs->cr_ipsr, isr);
405 #endif
407 if ((isr & IA64_ISR_NA) && ((isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) {
408 /*
409 * This fault was due to lfetch.fault, set "ed" bit in the psr to cancel
410 * the lfetch.
411 */
412 ia64_psr(regs)->ed = 1;
413 printf("ia64_fault: handled lfetch.fault\n");
414 return;
415 }
417 switch (vector) {
418 case 24: /* General Exception */
419 code = (isr >> 4) & 0xf;
420 sprintf(buf, "General Exception: %s%s", reason[code],
421 (code == 3) ? ((isr & (1UL << 37))
422 ? " (RSE access)" : " (data access)") : "");
423 if (code == 8) {
424 # ifdef CONFIG_IA64_PRINT_HAZARDS
425 printk("%s[%d]: possible hazard @ ip=%016lx (pr = %016lx)\n",
426 current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri,
427 regs->pr);
428 # endif
429 printf("ia64_fault: returning on hazard\n");
430 return;
431 }
432 break;
434 case 25: /* Disabled FP-Register */
435 if (isr & 2) {
436 //disabled_fph_fault(regs);
437 //return;
438 }
439 sprintf(buf, "Disabled FPL fault---not supposed to happen!");
440 break;
442 case 26: /* NaT Consumption */
443 if (user_mode(regs)) {
444 void *addr;
446 if (((isr >> 4) & 0xf) == 2) {
447 /* NaT page consumption */
448 //sig = SIGSEGV;
449 //code = SEGV_ACCERR;
450 addr = (void *) ifa;
451 } else {
452 /* register NaT consumption */
453 //sig = SIGILL;
454 //code = ILL_ILLOPN;
455 addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
456 }
457 //siginfo.si_signo = sig;
458 //siginfo.si_code = code;
459 //siginfo.si_errno = 0;
460 //siginfo.si_addr = addr;
461 //siginfo.si_imm = vector;
462 //siginfo.si_flags = __ISR_VALID;
463 //siginfo.si_isr = isr;
464 //force_sig_info(sig, &siginfo, current);
465 //return;
466 } //else if (ia64_done_with_exception(regs))
467 //return;
468 sprintf(buf, "NaT consumption");
469 break;
471 case 31: /* Unsupported Data Reference */
472 if (user_mode(regs)) {
473 //siginfo.si_signo = SIGILL;
474 //siginfo.si_code = ILL_ILLOPN;
475 //siginfo.si_errno = 0;
476 //siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
477 //siginfo.si_imm = vector;
478 //siginfo.si_flags = __ISR_VALID;
479 //siginfo.si_isr = isr;
480 //force_sig_info(SIGILL, &siginfo, current);
481 //return;
482 }
483 sprintf(buf, "Unsupported data reference");
484 break;
486 case 29: /* Debug */
487 case 35: /* Taken Branch Trap */
488 case 36: /* Single Step Trap */
489 //if (fsys_mode(current, regs)) {}
490 switch (vector) {
491 case 29:
492 //siginfo.si_code = TRAP_HWBKPT;
493 #ifdef CONFIG_ITANIUM
494 /*
495 * Erratum 10 (IFA may contain incorrect address) now has
496 * "NoFix" status. There are no plans for fixing this.
497 */
498 if (ia64_psr(regs)->is == 0)
499 ifa = regs->cr_iip;
500 #endif
501 break;
502 case 35: ifa = 0; break;
503 case 36: ifa = 0; break;
504 //case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break;
505 //case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break;
506 }
507 //siginfo.si_signo = SIGTRAP;
508 //siginfo.si_errno = 0;
509 //siginfo.si_addr = (void *) ifa;
510 //siginfo.si_imm = 0;
511 //siginfo.si_flags = __ISR_VALID;
512 //siginfo.si_isr = isr;
513 //force_sig_info(SIGTRAP, &siginfo, current);
514 //return;
516 case 32: /* fp fault */
517 case 33: /* fp trap */
518 //result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr);
519 if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) {
520 //siginfo.si_signo = SIGFPE;
521 //siginfo.si_errno = 0;
522 //siginfo.si_code = FPE_FLTINV;
523 //siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
524 //siginfo.si_flags = __ISR_VALID;
525 //siginfo.si_isr = isr;
526 //siginfo.si_imm = 0;
527 //force_sig_info(SIGFPE, &siginfo, current);
528 }
529 //return;
530 sprintf(buf, "FP fault/trap");
531 break;
533 case 34:
534 if (isr & 0x2) {
535 /* Lower-Privilege Transfer Trap */
536 /*
537 * Just clear PSR.lp and then return immediately: all the
538 * interesting work (e.g., signal delivery is done in the kernel
539 * exit path).
540 */
541 //ia64_psr(regs)->lp = 0;
542 //return;
543 sprintf(buf, "Lower-Privilege Transfer trap");
544 } else {
545 /* Unimplemented Instr. Address Trap */
546 if (user_mode(regs)) {
547 //siginfo.si_signo = SIGILL;
548 //siginfo.si_code = ILL_BADIADDR;
549 //siginfo.si_errno = 0;
550 //siginfo.si_flags = 0;
551 //siginfo.si_isr = 0;
552 //siginfo.si_imm = 0;
553 //siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
554 //force_sig_info(SIGILL, &siginfo, current);
555 //return;
556 }
557 sprintf(buf, "Unimplemented Instruction Address fault");
558 }
559 break;
561 case 45:
562 printk(KERN_ERR "Unexpected IA-32 exception (Trap 45)\n");
563 printk(KERN_ERR " iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n",
564 regs->cr_iip, ifa, isr);
565 //force_sig(SIGSEGV, current);
566 break;
568 case 46:
569 printk(KERN_ERR "Unexpected IA-32 intercept trap (Trap 46)\n");
570 printk(KERN_ERR " iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx, iim - 0x%lx\n",
571 regs->cr_iip, ifa, isr, iim);
572 //force_sig(SIGSEGV, current);
573 return;
575 case 47:
576 sprintf(buf, "IA-32 Interruption Fault (int 0x%lx)", isr >> 16);
577 break;
579 default:
580 sprintf(buf, "Fault %lu", vector);
581 break;
582 }
583 //die_if_kernel(buf, regs, error);
584 printk("ia64_fault: %s: reflecting\n",buf);
585 reflect_interruption(ifa,isr,iim,regs,IA64_GENEX_VECTOR);
586 //while(1);
587 //force_sig(SIGILL, current);
588 }
590 unsigned long running_on_sim = 0;
592 void
593 do_ssc(unsigned long ssc, struct pt_regs *regs)
594 {
595 extern unsigned long lookup_domain_mpa(struct domain *,unsigned long);
596 unsigned long arg0, arg1, arg2, arg3, retval;
597 char buf[2];
598 /**/ static int last_fd, last_count; // FIXME FIXME FIXME
599 /**/ // BROKEN FOR MULTIPLE DOMAINS & SMP
600 /**/ struct ssc_disk_stat { int fd; unsigned count;} *stat, last_stat;
601 extern unsigned long vcpu_verbose, privop_trace;
603 arg0 = vcpu_get_gr(current,32);
604 switch(ssc) {
605 case SSC_PUTCHAR:
606 buf[0] = arg0;
607 buf[1] = '\0';
608 printf(buf);
609 break;
610 case SSC_GETCHAR:
611 retval = ia64_ssc(0,0,0,0,ssc);
612 vcpu_set_gr(current,8,retval);
613 break;
614 case SSC_WAIT_COMPLETION:
615 if (arg0) { // metaphysical address
617 arg0 = translate_domain_mpaddr(arg0);
618 /**/ stat = (struct ssc_disk_stat *)__va(arg0);
619 ///**/ if (stat->fd == last_fd) stat->count = last_count;
620 /**/ stat->count = last_count;
621 //if (last_count >= PAGE_SIZE) printf("ssc_wait: stat->fd=%d,last_fd=%d,last_count=%d\n",stat->fd,last_fd,last_count);
622 ///**/ retval = ia64_ssc(arg0,0,0,0,ssc);
623 /**/ retval = 0;
624 }
625 else retval = -1L;
626 vcpu_set_gr(current,8,retval);
627 break;
628 case SSC_OPEN:
629 arg1 = vcpu_get_gr(current,33); // access rights
630 if (!running_on_sim) { printf("SSC_OPEN, not implemented on hardware. (ignoring...)\n"); arg0 = 0; }
631 if (arg0) { // metaphysical address
632 arg0 = translate_domain_mpaddr(arg0);
633 retval = ia64_ssc(arg0,arg1,0,0,ssc);
634 }
635 else retval = -1L;
636 vcpu_set_gr(current,8,retval);
637 break;
638 case SSC_WRITE:
639 case SSC_READ:
640 //if (ssc == SSC_WRITE) printf("DOING AN SSC_WRITE\n");
641 arg1 = vcpu_get_gr(current,33);
642 arg2 = vcpu_get_gr(current,34);
643 arg3 = vcpu_get_gr(current,35);
644 if (arg2) { // metaphysical address of descriptor
645 struct ssc_disk_req *req;
646 unsigned long mpaddr, paddr;
647 long len;
649 arg2 = translate_domain_mpaddr(arg2);
650 req = (struct disk_req *)__va(arg2);
651 req->len &= 0xffffffffL; // avoid strange bug
652 len = req->len;
653 /**/ last_fd = arg1;
654 /**/ last_count = len;
655 mpaddr = req->addr;
656 //if (last_count >= PAGE_SIZE) printf("do_ssc: read fd=%d, addr=%p, len=%lx ",last_fd,mpaddr,len);
657 retval = 0;
658 if ((mpaddr & PAGE_MASK) != ((mpaddr+len-1) & PAGE_MASK)) {
659 // do partial page first
660 req->addr = translate_domain_mpaddr(mpaddr);
661 req->len = PAGE_SIZE - (req->addr & ~PAGE_MASK);
662 len -= req->len; mpaddr += req->len;
663 retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc);
664 arg3 += req->len; // file offset
665 /**/ last_stat.fd = last_fd;
666 /**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION);
667 //if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)[part]=%x ",req->addr,req->len,retval);
668 }
669 if (retval >= 0) while (len > 0) {
670 req->addr = translate_domain_mpaddr(mpaddr);
671 req->len = (len > PAGE_SIZE) ? PAGE_SIZE : len;
672 len -= PAGE_SIZE; mpaddr += PAGE_SIZE;
673 retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc);
674 arg3 += req->len; // file offset
675 // TEMP REMOVED AGAIN arg3 += req->len; // file offset
676 /**/ last_stat.fd = last_fd;
677 /**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION);
678 //if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)=%x ",req->addr,req->len,retval);
679 }
680 // set it back to the original value
681 req->len = last_count;
682 }
683 else retval = -1L;
684 vcpu_set_gr(current,8,retval);
685 //if (last_count >= PAGE_SIZE) printf("retval=%x\n",retval);
686 break;
687 case SSC_CONNECT_INTERRUPT:
688 arg1 = vcpu_get_gr(current,33);
689 arg2 = vcpu_get_gr(current,34);
690 arg3 = vcpu_get_gr(current,35);
691 if (!running_on_sim) { printf("SSC_CONNECT_INTERRUPT, not implemented on hardware. (ignoring...)\n"); break; }
692 (void)ia64_ssc(arg0,arg1,arg2,arg3,ssc);
693 break;
694 case SSC_NETDEV_PROBE:
695 vcpu_set_gr(current,8,-1L);
696 break;
697 default:
698 printf("ia64_handle_break: bad ssc code %lx\n",ssc);
699 break;
700 }
701 vcpu_increment_iip(current);
702 }
704 void
705 ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim)
706 {
707 static int first_time = 1;
708 struct domain *d = (struct domain *) current->domain;
709 struct exec_domain *ed = (struct domain *) current;
710 extern unsigned long running_on_sim;
712 if (first_time) {
713 if (platform_is_hp_ski()) running_on_sim = 1;
714 else running_on_sim = 0;
715 first_time = 0;
716 }
717 if (iim == 0x80001 || iim == 0x80002) { //FIXME: don't hardcode constant
718 if (running_on_sim) do_ssc(vcpu_get_gr(current,36), regs);
719 else do_ssc(vcpu_get_gr(current,36), regs);
720 }
721 else if (iim == d->breakimm) {
722 if (ia64_hypercall(regs))
723 vcpu_increment_iip(current);
724 }
725 else reflect_interruption(ifa,isr,iim,regs,IA64_BREAK_VECTOR);
726 }
728 void
729 ia64_handle_privop (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long itir)
730 {
731 IA64FAULT vector;
732 struct domain *d = current->domain;
733 struct exec_domain *ed = current;
734 // FIXME: no need to pass itir in to this routine as we need to
735 // compute the virtual itir anyway (based on domain's RR.ps)
736 // AND ACTUALLY reflect_interruption doesn't use it anyway!
737 itir = vcpu_get_itir_on_fault(ed,ifa);
738 vector = priv_emulate(current,regs,isr);
739 if (vector == IA64_RETRY) {
740 reflect_interruption(ifa,isr,itir,regs,
741 IA64_ALT_DATA_TLB_VECTOR | IA64_FORCED_IFA);
742 }
743 else if (vector != IA64_NO_FAULT && vector != IA64_RFI_IN_PROGRESS) {
744 reflect_interruption(ifa,isr,itir,regs,vector);
745 }
746 }
748 #define INTR_TYPE_MAX 10
749 UINT64 int_counts[INTR_TYPE_MAX];
751 void
752 ia64_handle_reflection (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim, unsigned long vector)
753 {
754 struct domain *d = (struct domain *) current->domain;
755 struct exec_domain *ed = (struct domain *) current;
756 unsigned long check_lazy_cover = 0;
757 unsigned long psr = regs->cr_ipsr;
758 unsigned long itir = vcpu_get_itir_on_fault(ed,ifa);
760 if (!(psr & IA64_PSR_CPL)) {
761 printk("ia64_handle_reflection: reflecting with priv=0!!\n");
762 }
763 // FIXME: no need to pass itir in to this routine as we need to
764 // compute the virtual itir anyway (based on domain's RR.ps)
765 // AND ACTUALLY reflect_interruption doesn't use it anyway!
766 itir = vcpu_get_itir_on_fault(ed,ifa);
767 switch(vector) {
768 case 8:
769 vector = IA64_DIRTY_BIT_VECTOR; break;
770 case 9:
771 vector = IA64_INST_ACCESS_BIT_VECTOR; break;
772 case 10:
773 check_lazy_cover = 1;
774 vector = IA64_DATA_ACCESS_BIT_VECTOR; break;
775 case 20:
776 check_lazy_cover = 1;
777 vector = IA64_PAGE_NOT_PRESENT_VECTOR; break;
778 case 22:
779 vector = IA64_INST_ACCESS_RIGHTS_VECTOR; break;
780 case 23:
781 check_lazy_cover = 1;
782 vector = IA64_DATA_ACCESS_RIGHTS_VECTOR; break;
783 case 25:
784 vector = IA64_DISABLED_FPREG_VECTOR; break;
785 case 26:
786 printf("*** NaT fault... attempting to handle as privop\n");
787 vector = priv_emulate(ed,regs,isr);
788 if (vector == IA64_NO_FAULT) {
789 printf("*** Handled privop masquerading as NaT fault\n");
790 return;
791 }
792 vector = IA64_NAT_CONSUMPTION_VECTOR; break;
793 case 27:
794 //printf("*** Handled speculation vector, itc=%lx!\n",ia64_get_itc());
795 itir = iim;
796 vector = IA64_SPECULATION_VECTOR; break;
797 case 30:
798 // FIXME: Should we handle unaligned refs in Xen??
799 vector = IA64_UNALIGNED_REF_VECTOR; break;
800 default:
801 printf("ia64_handle_reflection: unhandled vector=0x%lx\n",vector);
802 while(vector);
803 return;
804 }
805 if (check_lazy_cover && handle_lazy_cover(ed, isr, regs)) return;
806 reflect_interruption(ifa,isr,itir,regs,vector);
807 }