direct-io.hg

view xen/arch/ia64/xen/fw_emul.c @ 10764:93e8817694ab

[IA64] sync console before reset

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author awilliam@xenbuild.aw
date Mon Jul 03 08:35:05 2006 -0600 (2006-07-03)
parents 8314141cfe54
children 75b4a0ff27b8
line source
1 /*
2 * fw_emul.c:
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 *
17 */
18 #include <xen/config.h>
19 #include <asm/system.h>
20 #include <asm/pgalloc.h>
22 #include <linux/efi.h>
23 #include <asm/pal.h>
24 #include <asm/sal.h>
26 #include <public/sched.h>
27 #include "hpsim_ssc.h"
28 #include <asm/vcpu.h>
29 #include <asm/dom_fw.h>
31 extern unsigned long running_on_sim;
33 struct sal_ret_values
34 sal_emulator (long index, unsigned long in1, unsigned long in2,
35 unsigned long in3, unsigned long in4, unsigned long in5,
36 unsigned long in6, unsigned long in7)
37 {
38 unsigned long r9 = 0;
39 unsigned long r10 = 0;
40 long r11 = 0;
41 long status;
43 status = 0;
44 switch (index) {
45 case SAL_FREQ_BASE:
46 if (!running_on_sim)
47 status = ia64_sal_freq_base(in1,&r9,&r10);
48 else switch (in1) {
49 case SAL_FREQ_BASE_PLATFORM:
50 r9 = 200000000;
51 break;
53 case SAL_FREQ_BASE_INTERVAL_TIMER:
54 r9 = 700000000;
55 break;
57 case SAL_FREQ_BASE_REALTIME_CLOCK:
58 r9 = 1;
59 break;
61 default:
62 status = -1;
63 break;
64 }
65 break;
66 case SAL_PCI_CONFIG_READ:
67 if (current->domain == dom0) {
68 u64 value;
69 // note that args 2&3 are swapped!!
70 status = ia64_sal_pci_config_read(in1,in3,in2,&value);
71 r9 = value;
72 }
73 else
74 printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_READ\n");
75 break;
76 case SAL_PCI_CONFIG_WRITE:
77 if (current->domain == dom0) {
78 if (((in1 & ~0xffffffffUL) && (in4 == 0)) ||
79 (in4 > 1) ||
80 (in2 > 8) || (in2 & (in2-1)))
81 printf("*** SAL_PCI_CONF_WRITE?!?(adr=0x%lx,typ=0x%lx,sz=0x%lx,val=0x%lx)\n",
82 in1,in4,in2,in3);
83 // note that args are in a different order!!
84 status = ia64_sal_pci_config_write(in1,in4,in2,in3);
85 }
86 else
87 printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_WRITE\n");
88 break;
89 case SAL_SET_VECTORS:
90 if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) {
91 if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) {
92 /* Sanity check: cs_length1 must be 0,
93 second vector is reserved. */
94 status = -2;
95 }
96 else {
97 struct domain *d = current->domain;
98 d->arch.boot_rdv_ip = in2;
99 d->arch.boot_rdv_r1 = in3;
100 }
101 }
102 else
103 printf("*** CALLED SAL_SET_VECTORS %lu. IGNORED...\n",
104 in1);
105 break;
106 case SAL_GET_STATE_INFO:
107 /* No more info. */
108 status = -5;
109 r9 = 0;
110 break;
111 case SAL_GET_STATE_INFO_SIZE:
112 /* Return a dummy size. */
113 status = 0;
114 r9 = 128;
115 break;
116 case SAL_CLEAR_STATE_INFO:
117 /* Noop. */
118 break;
119 case SAL_MC_RENDEZ:
120 printf("*** CALLED SAL_MC_RENDEZ. IGNORED...\n");
121 break;
122 case SAL_MC_SET_PARAMS:
123 printf("*** CALLED SAL_MC_SET_PARAMS. IGNORED...\n");
124 break;
125 case SAL_CACHE_FLUSH:
126 if (1) {
127 /* Flush using SAL.
128 This method is faster but has a side effect on
129 other vcpu running on this cpu. */
130 status = ia64_sal_cache_flush (in1);
131 }
132 else {
133 /* Flush with fc all the domain.
134 This method is slower but has no side effects. */
135 domain_cache_flush (current->domain, in1 == 4 ? 1 : 0);
136 status = 0;
137 }
138 break;
139 case SAL_CACHE_INIT:
140 printf("*** CALLED SAL_CACHE_INIT. IGNORED...\n");
141 break;
142 case SAL_UPDATE_PAL:
143 printf("*** CALLED SAL_UPDATE_PAL. IGNORED...\n");
144 break;
145 default:
146 printf("*** CALLED SAL_ WITH UNKNOWN INDEX. IGNORED...\n");
147 status = -1;
148 break;
149 }
150 return ((struct sal_ret_values) {status, r9, r10, r11});
151 }
153 struct ia64_pal_retval
154 xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3)
155 {
156 unsigned long r9 = 0;
157 unsigned long r10 = 0;
158 unsigned long r11 = 0;
159 long status = PAL_STATUS_UNIMPLEMENTED;
161 if (running_on_sim)
162 return pal_emulator_static(index);
164 // pal code must be mapped by a TR when pal is called, however
165 // calls are rare enough that we will map it lazily rather than
166 // at every context switch
167 //efi_map_pal_code();
168 switch (index) {
169 case PAL_MEM_ATTRIB:
170 status = ia64_pal_mem_attrib(&r9);
171 break;
172 case PAL_FREQ_BASE:
173 status = ia64_pal_freq_base(&r9);
174 break;
175 case PAL_PROC_GET_FEATURES:
176 status = ia64_pal_proc_get_features(&r9,&r10,&r11);
177 break;
178 case PAL_BUS_GET_FEATURES:
179 status = ia64_pal_bus_get_features(
180 (pal_bus_features_u_t *) &r9,
181 (pal_bus_features_u_t *) &r10,
182 (pal_bus_features_u_t *) &r11);
183 break;
184 case PAL_FREQ_RATIOS:
185 status = ia64_pal_freq_ratios(
186 (struct pal_freq_ratio *) &r9,
187 (struct pal_freq_ratio *) &r10,
188 (struct pal_freq_ratio *) &r11);
189 break;
190 case PAL_PTCE_INFO:
191 {
192 // return hard-coded xen-specific values because ptc.e
193 // is emulated on xen to always flush everything
194 // these values result in only one ptc.e instruction
195 status = 0; r9 = 0; r10 = (1L << 32) | 1L; r11 = 0;
196 }
197 break;
198 case PAL_VERSION:
199 status = ia64_pal_version(
200 (pal_version_u_t *) &r9,
201 (pal_version_u_t *) &r10);
202 break;
203 case PAL_VM_PAGE_SIZE:
204 status = ia64_pal_vm_page_size(&r9,&r10);
205 break;
206 case PAL_DEBUG_INFO:
207 status = ia64_pal_debug_info(&r9,&r10);
208 break;
209 case PAL_CACHE_SUMMARY:
210 status = ia64_pal_cache_summary(&r9,&r10);
211 break;
212 case PAL_VM_SUMMARY:
213 {
214 /* Use xen-specific values.
215 hash_tag_id is somewhat random! */
216 const pal_vm_info_1_u_t v1 =
217 {.pal_vm_info_1_s =
218 { .vw = 1,
219 .phys_add_size = 44,
220 .key_size = 16,
221 .max_pkr = 15,
222 .hash_tag_id = 0x30,
223 .max_dtr_entry = NDTRS - 1,
224 .max_itr_entry = NITRS - 1,
225 #ifdef VHPT_GLOBAL
226 .max_unique_tcs = 3,
227 .num_tc_levels = 2
228 #else
229 .max_unique_tcs = 2,
230 .num_tc_levels = 1
231 #endif
232 }};
233 const pal_vm_info_2_u_t v2 =
234 { .pal_vm_info_2_s =
235 { .impl_va_msb = 50,
236 .rid_size = current->domain->arch.rid_bits,
237 .reserved = 0 }};
238 r9 = v1.pvi1_val;
239 r10 = v2.pvi2_val;
240 status = PAL_STATUS_SUCCESS;
241 }
242 break;
243 case PAL_VM_INFO:
244 #ifdef VHPT_GLOBAL
245 if (in1 == 0 && in2 == 2) {
246 /* Level 1: VHPT */
247 const pal_tc_info_u_t v =
248 { .pal_tc_info_s = {.num_sets = 128,
249 .associativity = 1,
250 .num_entries = 128,
251 .pf = 1,
252 .unified = 1,
253 .reduce_tr = 0,
254 .reserved = 0}};
255 r9 = v.pti_val;
256 /* Only support PAGE_SIZE tc. */
257 r10 = PAGE_SIZE;
258 status = PAL_STATUS_SUCCESS;
259 }
260 #endif
261 else if (
262 #ifdef VHPT_GLOBAL
263 in1 == 1 /* Level 2. */
264 #else
265 in1 == 0 /* Level 1. */
266 #endif
267 && (in2 == 1 || in2 == 2))
268 {
269 /* itlb/dtlb, 1 entry. */
270 const pal_tc_info_u_t v =
271 { .pal_tc_info_s = {.num_sets = 1,
272 .associativity = 1,
273 .num_entries = 1,
274 .pf = 1,
275 .unified = 0,
276 .reduce_tr = 0,
277 .reserved = 0}};
278 r9 = v.pti_val;
279 /* Only support PAGE_SIZE tc. */
280 r10 = PAGE_SIZE;
281 status = PAL_STATUS_SUCCESS;
282 }
283 else
284 status = PAL_STATUS_EINVAL;
285 break;
286 case PAL_RSE_INFO:
287 status = ia64_pal_rse_info(
288 &r9,
289 (pal_hints_u_t *) &r10);
290 break;
291 case PAL_REGISTER_INFO:
292 status = ia64_pal_register_info(in1, &r9, &r10);
293 break;
294 case PAL_CACHE_FLUSH:
295 /* FIXME */
296 printk("PAL_CACHE_FLUSH NOT IMPLEMENTED!\n");
297 BUG();
298 break;
299 case PAL_PERF_MON_INFO:
300 {
301 unsigned long pm_buffer[16];
302 status = ia64_pal_perf_mon_info(
303 pm_buffer,
304 (pal_perf_mon_info_u_t *) &r9);
305 if (status != 0) {
306 while(1)
307 printk("PAL_PERF_MON_INFO fails ret=%ld\n", status);
308 break;
309 }
310 if (copy_to_user((void __user *)in1,pm_buffer,128)) {
311 while(1)
312 printk("xen_pal_emulator: PAL_PERF_MON_INFO "
313 "can't copy to user!!!!\n");
314 status = PAL_STATUS_UNIMPLEMENTED;
315 break;
316 }
317 }
318 break;
319 case PAL_CACHE_INFO:
320 {
321 pal_cache_config_info_t ci;
322 status = ia64_pal_cache_config_info(in1,in2,&ci);
323 if (status != 0) break;
324 r9 = ci.pcci_info_1.pcci1_data;
325 r10 = ci.pcci_info_2.pcci2_data;
326 }
327 break;
328 case PAL_VM_TR_READ: /* FIXME: vcpu_get_tr?? */
329 printk("PAL_VM_TR_READ NOT IMPLEMENTED, IGNORED!\n");
330 break;
331 case PAL_HALT_INFO:
332 {
333 /* 1000 cycles to enter/leave low power state,
334 consumes 10 mW, implemented and cache/TLB coherent. */
335 unsigned long res = 1000UL | (1000UL << 16) | (10UL << 32)
336 | (1UL << 61) | (1UL << 60);
337 if (copy_to_user ((void *)in1, &res, sizeof (res)))
338 status = PAL_STATUS_EINVAL;
339 else
340 status = PAL_STATUS_SUCCESS;
341 }
342 break;
343 case PAL_HALT:
344 if (current->domain == dom0) {
345 printf ("Domain0 halts the machine\n");
346 console_start_sync();
347 (*efi.reset_system)(EFI_RESET_SHUTDOWN,0,0,NULL);
348 }
349 else
350 domain_shutdown (current->domain,
351 SHUTDOWN_poweroff);
352 break;
353 default:
354 printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %lu!!!!\n",
355 index);
356 break;
357 }
358 return ((struct ia64_pal_retval) {status, r9, r10, r11});
359 }
361 // given a current domain (virtual or metaphysical) address, return the virtual address
362 static unsigned long
363 efi_translate_domain_addr(unsigned long domain_addr, IA64FAULT *fault,
364 struct page_info** page)
365 {
366 struct vcpu *v = current;
367 unsigned long mpaddr = domain_addr;
368 unsigned long virt;
369 *fault = IA64_NO_FAULT;
371 again:
372 if (v->domain->arch.efi_virt_mode) {
373 *fault = vcpu_tpa(v, domain_addr, &mpaddr);
374 if (*fault != IA64_NO_FAULT) return 0;
375 }
377 virt = (unsigned long)domain_mpa_to_imva(v->domain, mpaddr);
378 *page = virt_to_page(virt);
379 if (get_page(*page, current->domain) == 0) {
380 if (page_get_owner(*page) != current->domain) {
381 // which code is appropriate?
382 *fault = IA64_FAULT;
383 return 0;
384 }
385 goto again;
386 }
388 return virt;
389 }
391 static efi_status_t
392 efi_emulate_get_time(
393 unsigned long tv_addr, unsigned long tc_addr,
394 IA64FAULT *fault)
395 {
396 unsigned long tv = 0, tc = 0;
397 struct page_info *tv_page = NULL;
398 struct page_info *tc_page = NULL;
399 efi_status_t status;
401 //printf("efi_get_time(%016lx,%016lx) called\n", tv_addr, tc_addr);
402 tv = efi_translate_domain_addr(tv_addr, fault, &tv_page);
403 if (*fault != IA64_NO_FAULT)
404 return 0;
405 if (tc_addr) {
406 tc = efi_translate_domain_addr(tc_addr, fault, &tc_page);
407 if (*fault != IA64_NO_FAULT) {
408 put_page(tv_page);
409 return 0;
410 }
411 }
412 //printf("efi_get_time(%016lx,%016lx) translated to xen virtual address\n", tv, tc);
413 status = (*efi.get_time)((efi_time_t *) tv, (efi_time_cap_t *) tc);
414 //printf("efi_get_time returns %lx\n", status);
415 if (tc_page != NULL)
416 put_page(tc_page);
417 put_page(tv_page);
418 return status;
419 }
421 static efi_status_t
422 efi_emulate_set_virtual_address_map(
423 unsigned long memory_map_size, unsigned long descriptor_size,
424 u32 descriptor_version, efi_memory_desc_t *virtual_map)
425 {
426 void *efi_map_start, *efi_map_end, *p;
427 efi_memory_desc_t entry, *md = &entry;
428 u64 efi_desc_size;
430 unsigned long *vfn;
431 struct domain *d = current->domain;
432 efi_runtime_services_t *efi_runtime = d->arch.efi_runtime;
433 fpswa_interface_t *fpswa_inf = d->arch.fpswa_inf;
435 if (descriptor_version != EFI_MEMDESC_VERSION) {
436 printf ("efi_emulate_set_virtual_address_map: memory descriptor version unmatched\n");
437 return EFI_INVALID_PARAMETER;
438 }
440 if (descriptor_size != sizeof(efi_memory_desc_t)) {
441 printf ("efi_emulate_set_virtual_address_map: memory descriptor size unmatched\n");
442 return EFI_INVALID_PARAMETER;
443 }
445 if (d->arch.efi_virt_mode) return EFI_UNSUPPORTED;
447 efi_map_start = virtual_map;
448 efi_map_end = efi_map_start + memory_map_size;
449 efi_desc_size = sizeof(efi_memory_desc_t);
451 for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
452 if (copy_from_user(&entry, p, sizeof(efi_memory_desc_t))) {
453 printf ("efi_emulate_set_virtual_address_map: copy_from_user() fault. addr=0x%p\n", p);
454 return EFI_UNSUPPORTED;
455 }
457 /* skip over non-PAL_CODE memory descriptors; EFI_RUNTIME is included in PAL_CODE. */
458 if (md->type != EFI_PAL_CODE)
459 continue;
461 #define EFI_HYPERCALL_PATCH_TO_VIRT(tgt,call) \
462 do { \
463 vfn = (unsigned long *) domain_mpa_to_imva(d, tgt); \
464 *vfn++ = FW_HYPERCALL_##call##_INDEX * 16UL + md->virt_addr; \
465 *vfn++ = 0; \
466 } while (0)
468 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_time,EFI_GET_TIME);
469 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->set_time,EFI_SET_TIME);
470 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_wakeup_time,EFI_GET_WAKEUP_TIME);
471 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->set_wakeup_time,EFI_SET_WAKEUP_TIME);
472 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->set_virtual_address_map,EFI_SET_VIRTUAL_ADDRESS_MAP);
473 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_variable,EFI_GET_VARIABLE);
474 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_next_variable,EFI_GET_NEXT_VARIABLE);
475 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->set_variable,EFI_SET_VARIABLE);
476 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_next_high_mono_count,EFI_GET_NEXT_HIGH_MONO_COUNT);
477 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->reset_system,EFI_RESET_SYSTEM);
479 vfn = (unsigned long *) domain_mpa_to_imva(d, (unsigned long) fpswa_inf->fpswa);
480 *vfn++ = FW_HYPERCALL_FPSWA_PATCH_INDEX * 16UL + md->virt_addr;
481 *vfn = 0;
482 fpswa_inf->fpswa = (void *) (FW_HYPERCALL_FPSWA_ENTRY_INDEX * 16UL + md->virt_addr);
483 break;
484 }
486 /* The virtual address map has been applied. */
487 d->arch.efi_virt_mode = 1;
489 return EFI_SUCCESS;
490 }
492 efi_status_t
493 efi_emulator (struct pt_regs *regs, IA64FAULT *fault)
494 {
495 struct vcpu *v = current;
496 efi_status_t status;
498 *fault = IA64_NO_FAULT;
500 switch (regs->r2) {
501 case FW_HYPERCALL_EFI_RESET_SYSTEM:
502 {
503 u8 reason;
504 unsigned long val = vcpu_get_gr(v,32);
505 switch (val)
506 {
507 case EFI_RESET_SHUTDOWN:
508 reason = SHUTDOWN_poweroff;
509 break;
510 case EFI_RESET_COLD:
511 case EFI_RESET_WARM:
512 default:
513 reason = SHUTDOWN_reboot;
514 break;
515 }
516 domain_shutdown (current->domain, reason);
517 }
518 status = EFI_UNSUPPORTED;
519 break;
520 case FW_HYPERCALL_EFI_GET_TIME:
521 status = efi_emulate_get_time (
522 vcpu_get_gr(v,32),
523 vcpu_get_gr(v,33),
524 fault);
525 break;
526 case FW_HYPERCALL_EFI_SET_VIRTUAL_ADDRESS_MAP:
527 status = efi_emulate_set_virtual_address_map (
528 vcpu_get_gr(v,32),
529 vcpu_get_gr(v,33),
530 (u32) vcpu_get_gr(v,34),
531 (efi_memory_desc_t *) vcpu_get_gr(v,35));
532 break;
533 case FW_HYPERCALL_EFI_SET_TIME:
534 case FW_HYPERCALL_EFI_GET_WAKEUP_TIME:
535 case FW_HYPERCALL_EFI_SET_WAKEUP_TIME:
536 // FIXME: need fixes in efi.h from 2.6.9
537 case FW_HYPERCALL_EFI_GET_VARIABLE:
538 // FIXME: need fixes in efi.h from 2.6.9
539 case FW_HYPERCALL_EFI_GET_NEXT_VARIABLE:
540 case FW_HYPERCALL_EFI_SET_VARIABLE:
541 case FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT:
542 // FIXME: need fixes in efi.h from 2.6.9
543 status = EFI_UNSUPPORTED;
544 break;
545 default:
546 printf("unknown ia64 fw hypercall %lx\n", regs->r2);
547 status = EFI_UNSUPPORTED;
548 }
550 return status;
551 }
553 void
554 do_ssc(unsigned long ssc, struct pt_regs *regs)
555 {
556 unsigned long arg0, arg1, arg2, arg3, retval;
557 char buf[2];
558 /**/ static int last_fd, last_count; // FIXME FIXME FIXME
559 /**/ // BROKEN FOR MULTIPLE DOMAINS & SMP
560 /**/ struct ssc_disk_stat { int fd; unsigned count;} *stat, last_stat;
562 arg0 = vcpu_get_gr(current,32);
563 switch(ssc) {
564 case SSC_PUTCHAR:
565 buf[0] = arg0;
566 buf[1] = '\0';
567 printf(buf);
568 break;
569 case SSC_GETCHAR:
570 retval = ia64_ssc(0,0,0,0,ssc);
571 vcpu_set_gr(current,8,retval,0);
572 break;
573 case SSC_WAIT_COMPLETION:
574 if (arg0) { // metaphysical address
576 arg0 = translate_domain_mpaddr(arg0, NULL);
577 /**/ stat = (struct ssc_disk_stat *)__va(arg0);
578 ///**/ if (stat->fd == last_fd) stat->count = last_count;
579 /**/ stat->count = last_count;
580 //if (last_count >= PAGE_SIZE) printf("ssc_wait: stat->fd=%d,last_fd=%d,last_count=%d\n",stat->fd,last_fd,last_count);
581 ///**/ retval = ia64_ssc(arg0,0,0,0,ssc);
582 /**/ retval = 0;
583 }
584 else retval = -1L;
585 vcpu_set_gr(current,8,retval,0);
586 break;
587 case SSC_OPEN:
588 arg1 = vcpu_get_gr(current,33); // access rights
589 if (!running_on_sim) { printf("SSC_OPEN, not implemented on hardware. (ignoring...)\n"); arg0 = 0; }
590 if (arg0) { // metaphysical address
591 arg0 = translate_domain_mpaddr(arg0, NULL);
592 retval = ia64_ssc(arg0,arg1,0,0,ssc);
593 }
594 else retval = -1L;
595 vcpu_set_gr(current,8,retval,0);
596 break;
597 case SSC_WRITE:
598 case SSC_READ:
599 //if (ssc == SSC_WRITE) printf("DOING AN SSC_WRITE\n");
600 arg1 = vcpu_get_gr(current,33);
601 arg2 = vcpu_get_gr(current,34);
602 arg3 = vcpu_get_gr(current,35);
603 if (arg2) { // metaphysical address of descriptor
604 struct ssc_disk_req *req;
605 unsigned long mpaddr;
606 long len;
608 arg2 = translate_domain_mpaddr(arg2, NULL);
609 req = (struct ssc_disk_req *) __va(arg2);
610 req->len &= 0xffffffffL; // avoid strange bug
611 len = req->len;
612 /**/ last_fd = arg1;
613 /**/ last_count = len;
614 mpaddr = req->addr;
615 //if (last_count >= PAGE_SIZE) printf("do_ssc: read fd=%d, addr=%p, len=%lx ",last_fd,mpaddr,len);
616 retval = 0;
617 if ((mpaddr & PAGE_MASK) != ((mpaddr+len-1) & PAGE_MASK)) {
618 // do partial page first
619 req->addr = translate_domain_mpaddr(mpaddr, NULL);
620 req->len = PAGE_SIZE - (req->addr & ~PAGE_MASK);
621 len -= req->len; mpaddr += req->len;
622 retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc);
623 arg3 += req->len; // file offset
624 /**/ last_stat.fd = last_fd;
625 /**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION);
626 //if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)[part]=%x ",req->addr,req->len,retval);
627 }
628 if (retval >= 0) while (len > 0) {
629 req->addr = translate_domain_mpaddr(mpaddr, NULL);
630 req->len = (len > PAGE_SIZE) ? PAGE_SIZE : len;
631 len -= PAGE_SIZE; mpaddr += PAGE_SIZE;
632 retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc);
633 arg3 += req->len; // file offset
634 // TEMP REMOVED AGAIN arg3 += req->len; // file offset
635 /**/ last_stat.fd = last_fd;
636 /**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION);
637 //if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)=%x ",req->addr,req->len,retval);
638 }
639 // set it back to the original value
640 req->len = last_count;
641 }
642 else retval = -1L;
643 vcpu_set_gr(current,8,retval,0);
644 //if (last_count >= PAGE_SIZE) printf("retval=%x\n",retval);
645 break;
646 case SSC_CONNECT_INTERRUPT:
647 arg1 = vcpu_get_gr(current,33);
648 arg2 = vcpu_get_gr(current,34);
649 arg3 = vcpu_get_gr(current,35);
650 if (!running_on_sim) { printf("SSC_CONNECT_INTERRUPT, not implemented on hardware. (ignoring...)\n"); break; }
651 (void)ia64_ssc(arg0,arg1,arg2,arg3,ssc);
652 break;
653 case SSC_NETDEV_PROBE:
654 vcpu_set_gr(current,8,-1L,0);
655 break;
656 default:
657 printf("ia64_handle_break: bad ssc code %lx, iip=0x%lx, b0=0x%lx... spinning\n",
658 ssc, regs->cr_iip, regs->b0);
659 while(1);
660 break;
661 }
662 vcpu_increment_iip(current);
663 }