direct-io.hg

view xen/arch/ia64/xen/fw_emul.c @ 12409:01b257e72d5e

[IA64] Revert PAL_VM_SUMMARY and PAL_VM_INFO handling for VTI domain

Use info from call on physical CPU and only modify virtualized fields.

Signed-off-by: Anthony Xu <anthony.xu@intel.com>
author awilliam@xenbuild.aw
date Sun Oct 29 11:05:53 2006 -0700 (2006-10-29)
parents d246b79986d1
children e28beea6d228
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/vmx_vcpu.h>
30 #include <asm/dom_fw.h>
31 #include <asm/uaccess.h>
32 #include <xen/console.h>
33 #include <xen/hypercall.h>
35 extern unsigned long running_on_sim;
37 struct sal_ret_values
38 sal_emulator (long index, unsigned long in1, unsigned long in2,
39 unsigned long in3, unsigned long in4, unsigned long in5,
40 unsigned long in6, unsigned long in7)
41 {
42 unsigned long r9 = 0;
43 unsigned long r10 = 0;
44 long r11 = 0;
45 long status;
47 status = 0;
48 switch (index) {
49 case SAL_FREQ_BASE:
50 if (!running_on_sim)
51 status = ia64_sal_freq_base(in1,&r9,&r10);
52 else switch (in1) {
53 case SAL_FREQ_BASE_PLATFORM:
54 r9 = 200000000;
55 break;
57 case SAL_FREQ_BASE_INTERVAL_TIMER:
58 r9 = 700000000;
59 break;
61 case SAL_FREQ_BASE_REALTIME_CLOCK:
62 r9 = 1;
63 break;
65 default:
66 status = -1;
67 break;
68 }
69 break;
70 case SAL_PCI_CONFIG_READ:
71 if (current->domain == dom0) {
72 u64 value;
73 // note that args 2&3 are swapped!!
74 status = ia64_sal_pci_config_read(in1,in3,in2,&value);
75 r9 = value;
76 }
77 else
78 printk("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_READ\n");
79 break;
80 case SAL_PCI_CONFIG_WRITE:
81 if (current->domain == dom0) {
82 if (((in1 & ~0xffffffffUL) && (in4 == 0)) ||
83 (in4 > 1) ||
84 (in2 > 8) || (in2 & (in2-1)))
85 printk("*** SAL_PCI_CONF_WRITE?!?(adr=0x%lx,typ=0x%lx,sz=0x%lx,val=0x%lx)\n",
86 in1,in4,in2,in3);
87 // note that args are in a different order!!
88 status = ia64_sal_pci_config_write(in1,in4,in2,in3);
89 }
90 else
91 printk("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_WRITE\n");
92 break;
93 case SAL_SET_VECTORS:
94 if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) {
95 if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) {
96 /* Sanity check: cs_length1 must be 0,
97 second vector is reserved. */
98 status = -2;
99 }
100 else {
101 struct domain *d = current->domain;
102 d->arch.sal_data->boot_rdv_ip = in2;
103 d->arch.sal_data->boot_rdv_r1 = in3;
104 }
105 }
106 else
107 printk("*** CALLED SAL_SET_VECTORS %lu. IGNORED...\n",
108 in1);
109 break;
110 case SAL_GET_STATE_INFO:
111 /* No more info. */
112 status = -5;
113 r9 = 0;
114 break;
115 case SAL_GET_STATE_INFO_SIZE:
116 /* Return a dummy size. */
117 status = 0;
118 r9 = 128;
119 break;
120 case SAL_CLEAR_STATE_INFO:
121 /* Noop. */
122 break;
123 case SAL_MC_RENDEZ:
124 printk("*** CALLED SAL_MC_RENDEZ. IGNORED...\n");
125 break;
126 case SAL_MC_SET_PARAMS:
127 printk("*** CALLED SAL_MC_SET_PARAMS. IGNORED...\n");
128 break;
129 case SAL_CACHE_FLUSH:
130 if (1) {
131 /* Flush using SAL.
132 This method is faster but has a side effect on
133 other vcpu running on this cpu. */
134 status = ia64_sal_cache_flush (in1);
135 }
136 else {
137 /* Flush with fc all the domain.
138 This method is slower but has no side effects. */
139 domain_cache_flush (current->domain, in1 == 4 ? 1 : 0);
140 status = 0;
141 }
142 break;
143 case SAL_CACHE_INIT:
144 printk("*** CALLED SAL_CACHE_INIT. IGNORED...\n");
145 break;
146 case SAL_UPDATE_PAL:
147 printk("*** CALLED SAL_UPDATE_PAL. IGNORED...\n");
148 break;
149 default:
150 printk("*** CALLED SAL_ WITH UNKNOWN INDEX. IGNORED...\n");
151 status = -1;
152 break;
153 }
154 return ((struct sal_ret_values) {status, r9, r10, r11});
155 }
157 struct ia64_pal_retval
158 xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3)
159 {
160 unsigned long r9 = 0;
161 unsigned long r10 = 0;
162 unsigned long r11 = 0;
163 long status = PAL_STATUS_UNIMPLEMENTED;
165 if (running_on_sim)
166 return pal_emulator_static(index);
168 // pal code must be mapped by a TR when pal is called, however
169 // calls are rare enough that we will map it lazily rather than
170 // at every context switch
171 //efi_map_pal_code();
172 switch (index) {
173 case PAL_MEM_ATTRIB:
174 status = ia64_pal_mem_attrib(&r9);
175 break;
176 case PAL_FREQ_BASE:
177 status = ia64_pal_freq_base(&r9);
178 if (status == PAL_STATUS_UNIMPLEMENTED) {
179 status = ia64_sal_freq_base(0, &r9, &r10);
180 r10 = 0;
181 }
182 break;
183 case PAL_PROC_GET_FEATURES:
184 status = ia64_pal_proc_get_features(&r9,&r10,&r11);
185 break;
186 case PAL_BUS_GET_FEATURES:
187 status = ia64_pal_bus_get_features(
188 (pal_bus_features_u_t *) &r9,
189 (pal_bus_features_u_t *) &r10,
190 (pal_bus_features_u_t *) &r11);
191 break;
192 case PAL_FREQ_RATIOS:
193 status = ia64_pal_freq_ratios(
194 (struct pal_freq_ratio *) &r9,
195 (struct pal_freq_ratio *) &r10,
196 (struct pal_freq_ratio *) &r11);
197 break;
198 case PAL_PTCE_INFO:
199 {
200 // return hard-coded xen-specific values because ptc.e
201 // is emulated on xen to always flush everything
202 // these values result in only one ptc.e instruction
203 status = 0; r9 = 0; r10 = (1L << 32) | 1L; r11 = 0;
204 }
205 break;
206 case PAL_VERSION:
207 status = ia64_pal_version(
208 (pal_version_u_t *) &r9,
209 (pal_version_u_t *) &r10);
210 break;
211 case PAL_VM_PAGE_SIZE:
212 status = ia64_pal_vm_page_size(&r9,&r10);
213 break;
214 case PAL_DEBUG_INFO:
215 status = ia64_pal_debug_info(&r9,&r10);
216 break;
217 case PAL_CACHE_SUMMARY:
218 status = ia64_pal_cache_summary(&r9,&r10);
219 break;
220 case PAL_VM_SUMMARY:
221 if (VMX_DOMAIN(current)) {
222 pal_vm_info_1_u_t v1;
223 pal_vm_info_2_u_t v2;
224 status = ia64_pal_vm_summary((pal_vm_info_1_u_t *)&v1,
225 (pal_vm_info_2_u_t *)&v2);
226 v1.pal_vm_info_1_s.max_itr_entry = NITRS - 1;
227 v1.pal_vm_info_1_s.max_dtr_entry = NDTRS - 1;
228 v2.pal_vm_info_2_s.impl_va_msb -= 1;
229 v2.pal_vm_info_2_s.rid_size =
230 current->domain->arch.rid_bits;
231 r9 = v1.pvi1_val;
232 r10 = v2.pvi2_val;
233 } else {
234 /* Use xen-specific values.
235 hash_tag_id is somewhat random! */
236 static const pal_vm_info_1_u_t v1 =
237 {.pal_vm_info_1_s =
238 { .vw = 1,
239 .phys_add_size = 44,
240 .key_size = 16,
241 .max_pkr = 15,
242 .hash_tag_id = 0x30,
243 .max_dtr_entry = NDTRS - 1,
244 .max_itr_entry = NITRS - 1,
245 #ifdef VHPT_GLOBAL
246 .max_unique_tcs = 3,
247 .num_tc_levels = 2
248 #else
249 .max_unique_tcs = 2,
250 .num_tc_levels = 1
251 #endif
252 }};
253 pal_vm_info_2_u_t v2;
254 v2.pvi2_val = 0;
255 v2.pal_vm_info_2_s.rid_size =
256 current->domain->arch.rid_bits;
257 v2.pal_vm_info_2_s.impl_va_msb = 50;
258 r9 = v1.pvi1_val;
259 r10 = v2.pvi2_val;
260 status = PAL_STATUS_SUCCESS;
261 }
262 break;
263 case PAL_VM_INFO:
264 if (VMX_DOMAIN(current)) {
265 status = ia64_pal_vm_info(in1, in2,
266 (pal_tc_info_u_t *)&r9, &r10);
267 break;
268 }
269 #ifdef VHPT_GLOBAL
270 if (in1 == 0 && in2 == 2) {
271 /* Level 1: VHPT */
272 const pal_tc_info_u_t v =
273 { .pal_tc_info_s = {.num_sets = 128,
274 .associativity = 1,
275 .num_entries = 128,
276 .pf = 1,
277 .unified = 1,
278 .reduce_tr = 0,
279 .reserved = 0}};
280 r9 = v.pti_val;
281 /* Only support PAGE_SIZE tc. */
282 r10 = PAGE_SIZE;
283 status = PAL_STATUS_SUCCESS;
284 }
285 #endif
286 else if (
287 #ifdef VHPT_GLOBAL
288 in1 == 1 /* Level 2. */
289 #else
290 in1 == 0 /* Level 1. */
291 #endif
292 && (in2 == 1 || in2 == 2))
293 {
294 /* itlb/dtlb, 1 entry. */
295 const pal_tc_info_u_t v =
296 { .pal_tc_info_s = {.num_sets = 1,
297 .associativity = 1,
298 .num_entries = 1,
299 .pf = 1,
300 .unified = 0,
301 .reduce_tr = 0,
302 .reserved = 0}};
303 r9 = v.pti_val;
304 /* Only support PAGE_SIZE tc. */
305 r10 = PAGE_SIZE;
306 status = PAL_STATUS_SUCCESS;
307 }
308 else
309 status = PAL_STATUS_EINVAL;
310 break;
311 case PAL_RSE_INFO:
312 status = ia64_pal_rse_info(
313 &r9,
314 (pal_hints_u_t *) &r10);
315 break;
316 case PAL_REGISTER_INFO:
317 status = ia64_pal_register_info(in1, &r9, &r10);
318 break;
319 case PAL_CACHE_FLUSH:
320 /* Always call Host Pal in int=0 */
321 in2 &= ~PAL_CACHE_FLUSH_CHK_INTRS;
323 /*
324 * Call Host PAL cache flush
325 * Clear psr.ic when call PAL_CACHE_FLUSH
326 */
327 r10 = in3;
328 status = ia64_pal_cache_flush(in1, in2, &r10, &r9);
330 if (status != 0)
331 panic_domain(NULL, "PAL_CACHE_FLUSH ERROR, "
332 "status %lx", status);
334 break;
335 case PAL_PERF_MON_INFO:
336 {
337 unsigned long pm_buffer[16];
338 status = ia64_pal_perf_mon_info(
339 pm_buffer,
340 (pal_perf_mon_info_u_t *) &r9);
341 if (status != 0) {
342 while(1)
343 printk("PAL_PERF_MON_INFO fails ret=%ld\n", status);
344 break;
345 }
346 if (copy_to_user((void __user *)in1,pm_buffer,128)) {
347 while(1)
348 printk("xen_pal_emulator: PAL_PERF_MON_INFO "
349 "can't copy to user!!!!\n");
350 status = PAL_STATUS_UNIMPLEMENTED;
351 break;
352 }
353 }
354 break;
355 case PAL_CACHE_INFO:
356 {
357 pal_cache_config_info_t ci;
358 status = ia64_pal_cache_config_info(in1,in2,&ci);
359 if (status != 0) break;
360 r9 = ci.pcci_info_1.pcci1_data;
361 r10 = ci.pcci_info_2.pcci2_data;
362 }
363 break;
364 case PAL_VM_TR_READ: /* FIXME: vcpu_get_tr?? */
365 printk("PAL_VM_TR_READ NOT IMPLEMENTED, IGNORED!\n");
366 break;
367 case PAL_HALT_INFO:
368 {
369 /* 1000 cycles to enter/leave low power state,
370 consumes 10 mW, implemented and cache/TLB coherent. */
371 unsigned long res = 1000UL | (1000UL << 16) | (10UL << 32)
372 | (1UL << 61) | (1UL << 60);
373 if (copy_to_user ((void *)in1, &res, sizeof (res)))
374 status = PAL_STATUS_EINVAL;
375 else
376 status = PAL_STATUS_SUCCESS;
377 }
378 break;
379 case PAL_HALT:
380 if (current->domain == dom0) {
381 printk ("Domain0 halts the machine\n");
382 console_start_sync();
383 (*efi.reset_system)(EFI_RESET_SHUTDOWN,0,0,NULL);
384 }
385 else
386 domain_shutdown(current->domain, SHUTDOWN_poweroff);
387 break;
388 case PAL_HALT_LIGHT:
389 if (VMX_DOMAIN(current)) {
390 /* Called by VTI. */
391 if (!is_unmasked_irq(current))
392 do_sched_op_compat(SCHEDOP_block, 0);
393 status = PAL_STATUS_SUCCESS;
394 }
395 break;
396 case PAL_PLATFORM_ADDR:
397 if (VMX_DOMAIN(current))
398 status = PAL_STATUS_SUCCESS;
399 break;
400 default:
401 printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %lu!!!!\n",
402 index);
403 break;
404 }
405 return ((struct ia64_pal_retval) {status, r9, r10, r11});
406 }
408 // given a current domain (virtual or metaphysical) address, return the virtual address
409 static unsigned long
410 efi_translate_domain_addr(unsigned long domain_addr, IA64FAULT *fault,
411 struct page_info** page)
412 {
413 struct vcpu *v = current;
414 unsigned long mpaddr = domain_addr;
415 unsigned long virt;
416 *fault = IA64_NO_FAULT;
418 again:
419 if (v->domain->arch.sal_data->efi_virt_mode) {
420 *fault = vcpu_tpa(v, domain_addr, &mpaddr);
421 if (*fault != IA64_NO_FAULT) return 0;
422 }
424 virt = (unsigned long)domain_mpa_to_imva(v->domain, mpaddr);
425 *page = virt_to_page(virt);
426 if (get_page(*page, current->domain) == 0) {
427 if (page_get_owner(*page) != current->domain) {
428 // which code is appropriate?
429 *fault = IA64_FAULT;
430 return 0;
431 }
432 goto again;
433 }
435 return virt;
436 }
438 static efi_status_t
439 efi_emulate_get_time(
440 unsigned long tv_addr, unsigned long tc_addr,
441 IA64FAULT *fault)
442 {
443 unsigned long tv, tc = 0;
444 struct page_info *tv_page = NULL;
445 struct page_info *tc_page = NULL;
446 efi_status_t status = 0;
448 //printk("efi_get_time(%016lx,%016lx) called\n", tv_addr, tc_addr);
449 tv = efi_translate_domain_addr(tv_addr, fault, &tv_page);
450 if (*fault != IA64_NO_FAULT)
451 goto errout;
452 if (tc_addr) {
453 tc = efi_translate_domain_addr(tc_addr, fault, &tc_page);
454 if (*fault != IA64_NO_FAULT)
455 goto errout;
456 }
458 //printk("efi_get_time(%016lx,%016lx) translated to xen virtual address\n", tv, tc);
459 status = (*efi.get_time)((efi_time_t *) tv, (efi_time_cap_t *) tc);
460 //printk("efi_get_time returns %lx\n", status);
462 errout:
463 if (tc_page != NULL)
464 put_page(tc_page);
465 if (tv_page != NULL)
466 put_page(tv_page);
468 return status;
469 }
471 static efi_status_t
472 efi_emulate_set_time(
473 unsigned long tv_addr, IA64FAULT *fault)
474 {
475 unsigned long tv;
476 struct page_info *tv_page = NULL;
477 efi_status_t status = 0;
479 if (current->domain != dom0)
480 return EFI_UNSUPPORTED;
482 tv = efi_translate_domain_addr(tv_addr, fault, &tv_page);
483 if (*fault != IA64_NO_FAULT)
484 goto errout;
486 status = (*efi.set_time)((efi_time_t *)tv);
488 errout:
489 if (tv_page != NULL)
490 put_page(tv_page);
492 return status;
493 }
495 static efi_status_t
496 efi_emulate_get_wakeup_time(
497 unsigned long e_addr, unsigned long p_addr,
498 unsigned long tv_addr, IA64FAULT *fault)
499 {
500 unsigned long enabled, pending, tv;
501 struct page_info *e_page = NULL, *p_page = NULL,
502 *tv_page = NULL;
503 efi_status_t status = 0;
505 if (current->domain != dom0)
506 return EFI_UNSUPPORTED;
508 if (!e_addr || !p_addr || !tv_addr)
509 return EFI_INVALID_PARAMETER;
511 enabled = efi_translate_domain_addr(e_addr, fault, &e_page);
512 if (*fault != IA64_NO_FAULT)
513 goto errout;
514 pending = efi_translate_domain_addr(p_addr, fault, &p_page);
515 if (*fault != IA64_NO_FAULT)
516 goto errout;
517 tv = efi_translate_domain_addr(tv_addr, fault, &tv_page);
518 if (*fault != IA64_NO_FAULT)
519 goto errout;
521 status = (*efi.get_wakeup_time)((efi_bool_t *)enabled,
522 (efi_bool_t *)pending,
523 (efi_time_t *)tv);
525 errout:
526 if (e_page != NULL)
527 put_page(e_page);
528 if (p_page != NULL)
529 put_page(p_page);
530 if (tv_page != NULL)
531 put_page(tv_page);
533 return status;
534 }
536 static efi_status_t
537 efi_emulate_set_wakeup_time(
538 unsigned long enabled, unsigned long tv_addr,
539 IA64FAULT *fault)
540 {
541 unsigned long tv = 0;
542 struct page_info *tv_page = NULL;
543 efi_status_t status = 0;
545 if (current->domain != dom0)
546 return EFI_UNSUPPORTED;
548 if (tv_addr) {
549 tv = efi_translate_domain_addr(tv_addr, fault, &tv_page);
550 if (*fault != IA64_NO_FAULT)
551 goto errout;
552 }
554 status = (*efi.set_wakeup_time)((efi_bool_t)enabled,
555 (efi_time_t *)tv);
557 errout:
558 if (tv_page != NULL)
559 put_page(tv_page);
561 return status;
562 }
564 static efi_status_t
565 efi_emulate_get_variable(
566 unsigned long name_addr, unsigned long vendor_addr,
567 unsigned long attr_addr, unsigned long data_size_addr,
568 unsigned long data_addr, IA64FAULT *fault)
569 {
570 unsigned long name, vendor, attr = 0, data_size, data;
571 struct page_info *name_page = NULL, *vendor_page = NULL,
572 *attr_page = NULL, *data_size_page = NULL,
573 *data_page = NULL;
574 efi_status_t status = 0;
576 if (current->domain != dom0)
577 return EFI_UNSUPPORTED;
579 name = efi_translate_domain_addr(name_addr, fault, &name_page);
580 if (*fault != IA64_NO_FAULT)
581 goto errout;
582 vendor = efi_translate_domain_addr(vendor_addr, fault, &vendor_page);
583 if (*fault != IA64_NO_FAULT)
584 goto errout;
585 data_size = efi_translate_domain_addr(data_size_addr, fault,
586 &data_size_page);
587 if (*fault != IA64_NO_FAULT)
588 goto errout;
589 data = efi_translate_domain_addr(data_addr, fault, &data_page);
590 if (*fault != IA64_NO_FAULT)
591 goto errout;
592 if (attr_addr) {
593 attr = efi_translate_domain_addr(attr_addr, fault, &attr_page);
594 if (*fault != IA64_NO_FAULT)
595 goto errout;
596 }
598 status = (*efi.get_variable)((efi_char16_t *)name,
599 (efi_guid_t *)vendor,
600 (u32 *)attr,
601 (unsigned long *)data_size,
602 (void *)data);
604 errout:
605 if (name_page != NULL)
606 put_page(name_page);
607 if (vendor_page != NULL)
608 put_page(vendor_page);
609 if (attr_page != NULL)
610 put_page(attr_page);
611 if (data_size_page != NULL)
612 put_page(data_size_page);
613 if (data_page != NULL)
614 put_page(data_page);
616 return status;
617 }
619 static efi_status_t
620 efi_emulate_get_next_variable(
621 unsigned long name_size_addr, unsigned long name_addr,
622 unsigned long vendor_addr, IA64FAULT *fault)
623 {
624 unsigned long name_size, name, vendor;
625 struct page_info *name_size_page = NULL, *name_page = NULL,
626 *vendor_page = NULL;
627 efi_status_t status = 0;
629 if (current->domain != dom0)
630 return EFI_UNSUPPORTED;
632 name_size = efi_translate_domain_addr(name_size_addr, fault,
633 &name_size_page);
634 if (*fault != IA64_NO_FAULT)
635 goto errout;
636 name = efi_translate_domain_addr(name_addr, fault, &name_page);
637 if (*fault != IA64_NO_FAULT)
638 goto errout;
639 vendor = efi_translate_domain_addr(vendor_addr, fault, &vendor_page);
640 if (*fault != IA64_NO_FAULT)
641 goto errout;
643 status = (*efi.get_next_variable)((unsigned long *)name_size,
644 (efi_char16_t *)name,
645 (efi_guid_t *)vendor);
647 errout:
648 if (name_size_page != NULL)
649 put_page(name_size_page);
650 if (name_page != NULL)
651 put_page(name_page);
652 if (vendor_page != NULL)
653 put_page(vendor_page);
655 return status;
656 }
658 static efi_status_t
659 efi_emulate_set_variable(
660 unsigned long name_addr, unsigned long vendor_addr,
661 unsigned long attr, unsigned long data_size,
662 unsigned long data_addr, IA64FAULT *fault)
663 {
664 unsigned long name, vendor, data;
665 struct page_info *name_page = NULL, *vendor_page = NULL,
666 *data_page = NULL;
667 efi_status_t status = 0;
669 if (current->domain != dom0)
670 return EFI_UNSUPPORTED;
672 name = efi_translate_domain_addr(name_addr, fault, &name_page);
673 if (*fault != IA64_NO_FAULT)
674 goto errout;
675 vendor = efi_translate_domain_addr(vendor_addr, fault, &vendor_page);
676 if (*fault != IA64_NO_FAULT)
677 goto errout;
678 data = efi_translate_domain_addr(data_addr, fault, &data_page);
679 if (*fault != IA64_NO_FAULT)
680 goto errout;
682 status = (*efi.set_variable)((efi_char16_t *)name,
683 (efi_guid_t *)vendor,
684 attr,
685 data_size,
686 (void *)data);
688 errout:
689 if (name_page != NULL)
690 put_page(name_page);
691 if (vendor_page != NULL)
692 put_page(vendor_page);
693 if (data_page != NULL)
694 put_page(data_page);
696 return status;
697 }
699 static efi_status_t
700 efi_emulate_set_virtual_address_map(
701 unsigned long memory_map_size, unsigned long descriptor_size,
702 u32 descriptor_version, efi_memory_desc_t *virtual_map)
703 {
704 void *efi_map_start, *efi_map_end, *p;
705 efi_memory_desc_t entry, *md = &entry;
706 u64 efi_desc_size;
708 unsigned long *vfn;
709 struct domain *d = current->domain;
710 efi_runtime_services_t *efi_runtime = d->arch.efi_runtime;
711 fpswa_interface_t *fpswa_inf = d->arch.fpswa_inf;
713 if (descriptor_version != EFI_MEMDESC_VERSION) {
714 printk ("efi_emulate_set_virtual_address_map: memory "
715 "descriptor version unmatched (%d vs %d)\n",
716 (int)descriptor_version, EFI_MEMDESC_VERSION);
717 return EFI_INVALID_PARAMETER;
718 }
720 if (descriptor_size != sizeof(efi_memory_desc_t)) {
721 printk ("efi_emulate_set_virtual_address_map: memory descriptor size unmatched\n");
722 return EFI_INVALID_PARAMETER;
723 }
725 if (d->arch.sal_data->efi_virt_mode)
726 return EFI_UNSUPPORTED;
728 efi_map_start = virtual_map;
729 efi_map_end = efi_map_start + memory_map_size;
730 efi_desc_size = sizeof(efi_memory_desc_t);
732 for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
733 if (copy_from_user(&entry, p, sizeof(efi_memory_desc_t))) {
734 printk ("efi_emulate_set_virtual_address_map: copy_from_user() fault. addr=0x%p\n", p);
735 return EFI_UNSUPPORTED;
736 }
738 /* skip over non-PAL_CODE memory descriptors; EFI_RUNTIME is included in PAL_CODE. */
739 if (md->type != EFI_PAL_CODE)
740 continue;
742 #define EFI_HYPERCALL_PATCH_TO_VIRT(tgt,call) \
743 do { \
744 vfn = (unsigned long *) domain_mpa_to_imva(d, tgt); \
745 *vfn++ = FW_HYPERCALL_##call##_INDEX * 16UL + md->virt_addr; \
746 *vfn++ = 0; \
747 } while (0)
749 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_time,EFI_GET_TIME);
750 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->set_time,EFI_SET_TIME);
751 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_wakeup_time,EFI_GET_WAKEUP_TIME);
752 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->set_wakeup_time,EFI_SET_WAKEUP_TIME);
753 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->set_virtual_address_map,EFI_SET_VIRTUAL_ADDRESS_MAP);
754 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_variable,EFI_GET_VARIABLE);
755 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_next_variable,EFI_GET_NEXT_VARIABLE);
756 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->set_variable,EFI_SET_VARIABLE);
757 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_next_high_mono_count,EFI_GET_NEXT_HIGH_MONO_COUNT);
758 EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->reset_system,EFI_RESET_SYSTEM);
760 vfn = (unsigned long *) domain_mpa_to_imva(d, (unsigned long) fpswa_inf->fpswa);
761 *vfn++ = FW_HYPERCALL_FPSWA_PATCH_INDEX * 16UL + md->virt_addr;
762 *vfn = 0;
763 fpswa_inf->fpswa = (void *) (FW_HYPERCALL_FPSWA_ENTRY_INDEX * 16UL + md->virt_addr);
764 break;
765 }
767 /* The virtual address map has been applied. */
768 d->arch.sal_data->efi_virt_mode = 1;
770 return EFI_SUCCESS;
771 }
773 efi_status_t
774 efi_emulator (struct pt_regs *regs, IA64FAULT *fault)
775 {
776 struct vcpu *v = current;
777 efi_status_t status;
779 *fault = IA64_NO_FAULT;
781 switch (regs->r2) {
782 case FW_HYPERCALL_EFI_RESET_SYSTEM:
783 {
784 u8 reason;
785 unsigned long val = vcpu_get_gr(v,32);
786 switch (val)
787 {
788 case EFI_RESET_SHUTDOWN:
789 reason = SHUTDOWN_poweroff;
790 break;
791 case EFI_RESET_COLD:
792 case EFI_RESET_WARM:
793 default:
794 reason = SHUTDOWN_reboot;
795 break;
796 }
797 domain_shutdown (current->domain, reason);
798 }
799 status = EFI_UNSUPPORTED;
800 break;
801 case FW_HYPERCALL_EFI_GET_TIME:
802 status = efi_emulate_get_time (
803 vcpu_get_gr(v,32),
804 vcpu_get_gr(v,33),
805 fault);
806 break;
807 case FW_HYPERCALL_EFI_SET_TIME:
808 status = efi_emulate_set_time (
809 vcpu_get_gr(v,32),
810 fault);
811 break;
812 case FW_HYPERCALL_EFI_GET_WAKEUP_TIME:
813 status = efi_emulate_get_wakeup_time (
814 vcpu_get_gr(v,32),
815 vcpu_get_gr(v,33),
816 vcpu_get_gr(v,34),
817 fault);
818 break;
819 case FW_HYPERCALL_EFI_SET_WAKEUP_TIME:
820 status = efi_emulate_set_wakeup_time (
821 vcpu_get_gr(v,32),
822 vcpu_get_gr(v,33),
823 fault);
824 break;
825 case FW_HYPERCALL_EFI_GET_VARIABLE:
826 status = efi_emulate_get_variable (
827 vcpu_get_gr(v,32),
828 vcpu_get_gr(v,33),
829 vcpu_get_gr(v,34),
830 vcpu_get_gr(v,35),
831 vcpu_get_gr(v,36),
832 fault);
833 break;
834 case FW_HYPERCALL_EFI_GET_NEXT_VARIABLE:
835 status = efi_emulate_get_next_variable (
836 vcpu_get_gr(v,32),
837 vcpu_get_gr(v,33),
838 vcpu_get_gr(v,34),
839 fault);
840 break;
841 case FW_HYPERCALL_EFI_SET_VARIABLE:
842 status = efi_emulate_set_variable (
843 vcpu_get_gr(v,32),
844 vcpu_get_gr(v,33),
845 vcpu_get_gr(v,34),
846 vcpu_get_gr(v,35),
847 vcpu_get_gr(v,36),
848 fault);
849 break;
850 case FW_HYPERCALL_EFI_SET_VIRTUAL_ADDRESS_MAP:
851 status = efi_emulate_set_virtual_address_map (
852 vcpu_get_gr(v,32),
853 vcpu_get_gr(v,33),
854 (u32) vcpu_get_gr(v,34),
855 (efi_memory_desc_t *) vcpu_get_gr(v,35));
856 break;
857 case FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT:
858 // FIXME: need fixes in efi.h from 2.6.9
859 status = EFI_UNSUPPORTED;
860 break;
861 default:
862 printk("unknown ia64 fw hypercall %lx\n", regs->r2);
863 status = EFI_UNSUPPORTED;
864 }
866 return status;
867 }
869 void
870 do_ssc(unsigned long ssc, struct pt_regs *regs)
871 {
872 unsigned long arg0, arg1, arg2, arg3, retval;
873 char buf[2];
874 /**/ static int last_fd, last_count; // FIXME FIXME FIXME
875 /**/ // BROKEN FOR MULTIPLE DOMAINS & SMP
876 /**/ struct ssc_disk_stat { int fd; unsigned count;} *stat, last_stat;
878 arg0 = vcpu_get_gr(current,32);
879 switch(ssc) {
880 case SSC_PUTCHAR:
881 buf[0] = arg0;
882 buf[1] = '\0';
883 printk(buf);
884 break;
885 case SSC_GETCHAR:
886 retval = ia64_ssc(0,0,0,0,ssc);
887 vcpu_set_gr(current,8,retval,0);
888 break;
889 case SSC_WAIT_COMPLETION:
890 if (arg0) { // metaphysical address
892 arg0 = translate_domain_mpaddr(arg0, NULL);
893 /**/ stat = (struct ssc_disk_stat *)__va(arg0);
894 ///**/ if (stat->fd == last_fd) stat->count = last_count;
895 /**/ stat->count = last_count;
896 //if (last_count >= PAGE_SIZE) printk("ssc_wait: stat->fd=%d,last_fd=%d,last_count=%d\n",stat->fd,last_fd,last_count);
897 ///**/ retval = ia64_ssc(arg0,0,0,0,ssc);
898 /**/ retval = 0;
899 }
900 else retval = -1L;
901 vcpu_set_gr(current,8,retval,0);
902 break;
903 case SSC_OPEN:
904 arg1 = vcpu_get_gr(current,33); // access rights
905 if (!running_on_sim) { printk("SSC_OPEN, not implemented on hardware. (ignoring...)\n"); arg0 = 0; }
906 if (arg0) { // metaphysical address
907 arg0 = translate_domain_mpaddr(arg0, NULL);
908 retval = ia64_ssc(arg0,arg1,0,0,ssc);
909 }
910 else retval = -1L;
911 vcpu_set_gr(current,8,retval,0);
912 break;
913 case SSC_WRITE:
914 case SSC_READ:
915 //if (ssc == SSC_WRITE) printk("DOING AN SSC_WRITE\n");
916 arg1 = vcpu_get_gr(current,33);
917 arg2 = vcpu_get_gr(current,34);
918 arg3 = vcpu_get_gr(current,35);
919 if (arg2) { // metaphysical address of descriptor
920 struct ssc_disk_req *req;
921 unsigned long mpaddr;
922 long len;
924 arg2 = translate_domain_mpaddr(arg2, NULL);
925 req = (struct ssc_disk_req *) __va(arg2);
926 req->len &= 0xffffffffL; // avoid strange bug
927 len = req->len;
928 /**/ last_fd = arg1;
929 /**/ last_count = len;
930 mpaddr = req->addr;
931 //if (last_count >= PAGE_SIZE) printk("do_ssc: read fd=%d, addr=%p, len=%lx ",last_fd,mpaddr,len);
932 retval = 0;
933 if ((mpaddr & PAGE_MASK) != ((mpaddr+len-1) & PAGE_MASK)) {
934 // do partial page first
935 req->addr = translate_domain_mpaddr(mpaddr, NULL);
936 req->len = PAGE_SIZE - (req->addr & ~PAGE_MASK);
937 len -= req->len; mpaddr += req->len;
938 retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc);
939 arg3 += req->len; // file offset
940 /**/ last_stat.fd = last_fd;
941 /**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION);
942 //if (last_count >= PAGE_SIZE) printk("ssc(%p,%lx)[part]=%x ",req->addr,req->len,retval);
943 }
944 if (retval >= 0) while (len > 0) {
945 req->addr = translate_domain_mpaddr(mpaddr, NULL);
946 req->len = (len > PAGE_SIZE) ? PAGE_SIZE : len;
947 len -= PAGE_SIZE; mpaddr += PAGE_SIZE;
948 retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc);
949 arg3 += req->len; // file offset
950 // TEMP REMOVED AGAIN arg3 += req->len; // file offset
951 /**/ last_stat.fd = last_fd;
952 /**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION);
953 //if (last_count >= PAGE_SIZE) printk("ssc(%p,%lx)=%x ",req->addr,req->len,retval);
954 }
955 // set it back to the original value
956 req->len = last_count;
957 }
958 else retval = -1L;
959 vcpu_set_gr(current,8,retval,0);
960 //if (last_count >= PAGE_SIZE) printk("retval=%x\n",retval);
961 break;
962 case SSC_CONNECT_INTERRUPT:
963 arg1 = vcpu_get_gr(current,33);
964 arg2 = vcpu_get_gr(current,34);
965 arg3 = vcpu_get_gr(current,35);
966 if (!running_on_sim) { printk("SSC_CONNECT_INTERRUPT, not implemented on hardware. (ignoring...)\n"); break; }
967 (void)ia64_ssc(arg0,arg1,arg2,arg3,ssc);
968 break;
969 case SSC_NETDEV_PROBE:
970 vcpu_set_gr(current,8,-1L,0);
971 break;
972 default:
973 printk("ia64_handle_break: bad ssc code %lx, iip=0x%lx, b0=0x%lx... spinning\n",
974 ssc, regs->cr_iip, regs->b0);
975 while(1);
976 break;
977 }
978 vcpu_increment_iip(current);
979 }