2 * PAL/SAL call delegation
4 * Copyright (c) 2004 Li Susie <susie.li@intel.com>
5 * Copyright (c) 2005 Yu Ke <ke.yu@intel.com>
6 * Copyright (c) 2007 Xiantao Zhang <xiantao.zhang@intel.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place - Suite 330, Boston, MA 02111-1307 USA.
22 #include <linux/kvm_host.h>
23 #include <linux/smp.h>
33 * Handy macros to make sure that the PAL return values start out
34 * as something meaningful.
36 #define INIT_PAL_STATUS_UNIMPLEMENTED(x) \
38 x.status = PAL_STATUS_UNIMPLEMENTED; \
44 #define INIT_PAL_STATUS_SUCCESS(x) \
46 x.status = PAL_STATUS_SUCCESS; \
52 static void kvm_get_pal_call_data(struct kvm_vcpu
*vcpu
,
53 u64
*gr28
, u64
*gr29
, u64
*gr30
, u64
*gr31
) {
54 struct exit_ctl_data
*p
;
57 p
= &vcpu
->arch
.exit_data
;
58 if (p
->exit_reason
== EXIT_REASON_PAL_CALL
) {
59 *gr28
= p
->u
.pal_data
.gr28
;
60 *gr29
= p
->u
.pal_data
.gr29
;
61 *gr30
= p
->u
.pal_data
.gr30
;
62 *gr31
= p
->u
.pal_data
.gr31
;
66 printk(KERN_DEBUG
"Failed to get vcpu pal data!!!\n");
69 static void set_pal_result(struct kvm_vcpu
*vcpu
,
70 struct ia64_pal_retval result
) {
72 struct exit_ctl_data
*p
;
74 p
= kvm_get_exit_data(vcpu
);
75 if (p
&& p
->exit_reason
== EXIT_REASON_PAL_CALL
) {
76 p
->u
.pal_data
.ret
= result
;
79 INIT_PAL_STATUS_UNIMPLEMENTED(p
->u
.pal_data
.ret
);
82 static void set_sal_result(struct kvm_vcpu
*vcpu
,
83 struct sal_ret_values result
) {
84 struct exit_ctl_data
*p
;
86 p
= kvm_get_exit_data(vcpu
);
87 if (p
&& p
->exit_reason
== EXIT_REASON_SAL_CALL
) {
88 p
->u
.sal_data
.ret
= result
;
91 printk(KERN_WARNING
"Failed to set sal result!!\n");
94 struct cache_flush_args
{
101 cpumask_t cpu_cache_coherent_map
;
103 static void remote_pal_cache_flush(void *data
)
105 struct cache_flush_args
*args
= data
;
107 u64 progress
= args
->progress
;
109 status
= ia64_pal_cache_flush(args
->cache_type
, args
->operation
,
112 args
->status
= status
;
115 static struct ia64_pal_retval
pal_cache_flush(struct kvm_vcpu
*vcpu
)
117 u64 gr28
, gr29
, gr30
, gr31
;
118 struct ia64_pal_retval result
= {0, 0, 0, 0};
119 struct cache_flush_args args
= {0, 0, 0, 0};
122 gr28
= gr29
= gr30
= gr31
= 0;
123 kvm_get_pal_call_data(vcpu
, &gr28
, &gr29
, &gr30
, &gr31
);
126 printk(KERN_ERR
"vcpu:%p called cache_flush error!\n", vcpu
);
128 /* Always call Host Pal in int=1 */
129 gr30
&= ~PAL_CACHE_FLUSH_CHK_INTRS
;
130 args
.cache_type
= gr29
;
131 args
.operation
= gr30
;
132 smp_call_function(remote_pal_cache_flush
,
134 if (args
.status
!= 0)
135 printk(KERN_ERR
"pal_cache_flush error!,"
136 "status:0x%lx\n", args
.status
);
138 * Call Host PAL cache flush
139 * Clear psr.ic when call PAL_CACHE_FLUSH
142 result
.status
= ia64_pal_cache_flush(gr29
, gr30
, &result
.v1
,
144 local_irq_restore(psr
);
145 if (result
.status
!= 0)
146 printk(KERN_ERR
"vcpu:%p crashed due to cache_flush err:%ld"
148 vcpu
, result
.status
, gr29
, gr30
);
151 if (gr29
== PAL_CACHE_TYPE_COHERENT
) {
152 cpus_setall(vcpu
->arch
.cache_coherent_map
);
153 cpu_clear(vcpu
->cpu
, vcpu
->arch
.cache_coherent_map
);
154 cpus_setall(cpu_cache_coherent_map
);
155 cpu_clear(vcpu
->cpu
, cpu_cache_coherent_map
);
161 struct ia64_pal_retval
pal_cache_summary(struct kvm_vcpu
*vcpu
)
164 struct ia64_pal_retval result
;
166 PAL_CALL(result
, PAL_CACHE_SUMMARY
, 0, 0, 0);
170 static struct ia64_pal_retval
pal_freq_base(struct kvm_vcpu
*vcpu
)
173 struct ia64_pal_retval result
;
175 PAL_CALL(result
, PAL_FREQ_BASE
, 0, 0, 0);
178 * PAL_FREQ_BASE may not be implemented in some platforms,
181 if (result
.v0
== 0) {
182 result
.status
= ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM
,
191 static struct ia64_pal_retval
pal_freq_ratios(struct kvm_vcpu
*vcpu
)
194 struct ia64_pal_retval result
;
196 PAL_CALL(result
, PAL_FREQ_RATIOS
, 0, 0, 0);
200 static struct ia64_pal_retval
pal_logical_to_physica(struct kvm_vcpu
*vcpu
)
202 struct ia64_pal_retval result
;
204 INIT_PAL_STATUS_UNIMPLEMENTED(result
);
208 static struct ia64_pal_retval
pal_platform_addr(struct kvm_vcpu
*vcpu
)
211 struct ia64_pal_retval result
;
213 INIT_PAL_STATUS_SUCCESS(result
);
217 static struct ia64_pal_retval
pal_proc_get_features(struct kvm_vcpu
*vcpu
)
220 struct ia64_pal_retval result
= {0, 0, 0, 0};
221 long in0
, in1
, in2
, in3
;
223 kvm_get_pal_call_data(vcpu
, &in0
, &in1
, &in2
, &in3
);
224 result
.status
= ia64_pal_proc_get_features(&result
.v0
, &result
.v1
,
230 static struct ia64_pal_retval
pal_cache_info(struct kvm_vcpu
*vcpu
)
233 pal_cache_config_info_t ci
;
235 unsigned long in0
, in1
, in2
, in3
, r9
, r10
;
237 kvm_get_pal_call_data(vcpu
, &in0
, &in1
, &in2
, &in3
);
238 status
= ia64_pal_cache_config_info(in1
, in2
, &ci
);
239 r9
= ci
.pcci_info_1
.pcci1_data
;
240 r10
= ci
.pcci_info_2
.pcci2_data
;
241 return ((struct ia64_pal_retval
){status
, r9
, r10
, 0});
244 #define GUEST_IMPL_VA_MSB 59
245 #define GUEST_RID_BITS 18
247 static struct ia64_pal_retval
pal_vm_summary(struct kvm_vcpu
*vcpu
)
250 pal_vm_info_1_u_t vminfo1
;
251 pal_vm_info_2_u_t vminfo2
;
252 struct ia64_pal_retval result
;
254 PAL_CALL(result
, PAL_VM_SUMMARY
, 0, 0, 0);
255 if (!result
.status
) {
256 vminfo1
.pvi1_val
= result
.v0
;
257 vminfo1
.pal_vm_info_1_s
.max_itr_entry
= 8;
258 vminfo1
.pal_vm_info_1_s
.max_dtr_entry
= 8;
259 result
.v0
= vminfo1
.pvi1_val
;
260 vminfo2
.pal_vm_info_2_s
.impl_va_msb
= GUEST_IMPL_VA_MSB
;
261 vminfo2
.pal_vm_info_2_s
.rid_size
= GUEST_RID_BITS
;
262 result
.v1
= vminfo2
.pvi2_val
;
268 static struct ia64_pal_retval
pal_vm_info(struct kvm_vcpu
*vcpu
)
270 struct ia64_pal_retval result
;
272 INIT_PAL_STATUS_UNIMPLEMENTED(result
);
277 static u64
kvm_get_pal_call_index(struct kvm_vcpu
*vcpu
)
280 struct exit_ctl_data
*p
;
282 p
= kvm_get_exit_data(vcpu
);
283 if (p
&& (p
->exit_reason
== EXIT_REASON_PAL_CALL
))
284 index
= p
->u
.pal_data
.gr28
;
289 static void prepare_for_halt(struct kvm_vcpu
*vcpu
)
291 vcpu
->arch
.timer_pending
= 1;
292 vcpu
->arch
.timer_fired
= 0;
295 int kvm_pal_emul(struct kvm_vcpu
*vcpu
, struct kvm_run
*run
)
299 struct ia64_pal_retval result
;
302 gr28
= kvm_get_pal_call_index(vcpu
);
303 /*printk("pal_call index:%lx\n",gr28);*/
305 case PAL_CACHE_FLUSH
:
306 result
= pal_cache_flush(vcpu
);
308 case PAL_CACHE_SUMMARY
:
309 result
= pal_cache_summary(vcpu
);
313 INIT_PAL_STATUS_SUCCESS(result
);
314 prepare_for_halt(vcpu
);
315 if (kvm_highest_pending_irq(vcpu
) == -1)
316 ret
= kvm_emulate_halt(vcpu
);
320 case PAL_FREQ_RATIOS
:
321 result
= pal_freq_ratios(vcpu
);
325 result
= pal_freq_base(vcpu
);
328 case PAL_LOGICAL_TO_PHYSICAL
:
329 result
= pal_logical_to_physica(vcpu
);
332 case PAL_VM_SUMMARY
:
333 result
= pal_vm_summary(vcpu
);
337 result
= pal_vm_info(vcpu
);
339 case PAL_PLATFORM_ADDR
:
340 result
= pal_platform_addr(vcpu
);
343 result
= pal_cache_info(vcpu
);
346 INIT_PAL_STATUS_SUCCESS(result
);
347 result
.v1
= (1L << 32) | 1L;
349 case PAL_VM_PAGE_SIZE
:
350 result
.status
= ia64_pal_vm_page_size(&result
.v0
,
354 result
.status
= ia64_pal_rse_info(&result
.v0
,
355 (pal_hints_u_t
*)&result
.v1
);
357 case PAL_PROC_GET_FEATURES
:
358 result
= pal_proc_get_features(vcpu
);
361 result
.status
= ia64_pal_debug_info(&result
.v0
,
365 result
.status
= ia64_pal_version(
366 (pal_version_u_t
*)&result
.v0
,
367 (pal_version_u_t
*)&result
.v1
);
371 result
.status
= PAL_STATUS_SUCCESS
;
372 result
.v0
= vcpu
->vcpu_id
;
375 INIT_PAL_STATUS_UNIMPLEMENTED(result
);
376 printk(KERN_WARNING
"kvm: Unsupported pal call,"
377 " index:0x%lx\n", gr28
);
379 set_pal_result(vcpu
, result
);
383 static struct sal_ret_values
sal_emulator(struct kvm
*kvm
,
384 long index
, unsigned long in1
,
385 unsigned long in2
, unsigned long in3
,
386 unsigned long in4
, unsigned long in5
,
387 unsigned long in6
, unsigned long in7
)
389 unsigned long r9
= 0;
390 unsigned long r10
= 0;
397 status
= ia64_sal_freq_base(in1
, &r9
, &r10
);
399 case SAL_PCI_CONFIG_READ
:
400 printk(KERN_WARNING
"kvm: Not allowed to call here!"
401 " SAL_PCI_CONFIG_READ\n");
403 case SAL_PCI_CONFIG_WRITE
:
404 printk(KERN_WARNING
"kvm: Not allowed to call here!"
405 " SAL_PCI_CONFIG_WRITE\n");
407 case SAL_SET_VECTORS
:
408 if (in1
== SAL_VECTOR_OS_BOOT_RENDEZ
) {
409 if (in4
!= 0 || in5
!= 0 || in6
!= 0 || in7
!= 0) {
412 kvm
->arch
.rdv_sal_data
.boot_ip
= in2
;
413 kvm
->arch
.rdv_sal_data
.boot_gp
= in3
;
415 printk("Rendvous called! iip:%lx\n\n", in2
);
417 printk(KERN_WARNING
"kvm: CALLED SAL_SET_VECTORS %lu."
418 "ignored...\n", in1
);
420 case SAL_GET_STATE_INFO
:
425 case SAL_GET_STATE_INFO_SIZE
:
426 /* Return a dummy size. */
430 case SAL_CLEAR_STATE_INFO
:
435 "kvm: called SAL_MC_RENDEZ. ignored...\n");
437 case SAL_MC_SET_PARAMS
:
439 "kvm: called SAL_MC_SET_PARAMS.ignored!\n");
441 case SAL_CACHE_FLUSH
:
444 This method is faster but has a side
445 effect on other vcpu running on
447 status
= ia64_sal_cache_flush(in1
);
449 /*Maybe need to implement the method
450 without side effect!*/
456 "kvm: called SAL_CACHE_INIT. ignored...\n");
460 "kvm: CALLED SAL_UPDATE_PAL. ignored...\n");
463 printk(KERN_WARNING
"kvm: called SAL_CALL with unknown index."
464 " index:%ld\n", index
);
468 return ((struct sal_ret_values
) {status
, r9
, r10
, r11
});
471 static void kvm_get_sal_call_data(struct kvm_vcpu
*vcpu
, u64
*in0
, u64
*in1
,
472 u64
*in2
, u64
*in3
, u64
*in4
, u64
*in5
, u64
*in6
, u64
*in7
){
474 struct exit_ctl_data
*p
;
476 p
= kvm_get_exit_data(vcpu
);
479 if (p
->exit_reason
== EXIT_REASON_SAL_CALL
) {
480 *in0
= p
->u
.sal_data
.in0
;
481 *in1
= p
->u
.sal_data
.in1
;
482 *in2
= p
->u
.sal_data
.in2
;
483 *in3
= p
->u
.sal_data
.in3
;
484 *in4
= p
->u
.sal_data
.in4
;
485 *in5
= p
->u
.sal_data
.in5
;
486 *in6
= p
->u
.sal_data
.in6
;
487 *in7
= p
->u
.sal_data
.in7
;
494 void kvm_sal_emul(struct kvm_vcpu
*vcpu
)
497 struct sal_ret_values result
;
498 u64 index
, in1
, in2
, in3
, in4
, in5
, in6
, in7
;
500 kvm_get_sal_call_data(vcpu
, &index
, &in1
, &in2
,
501 &in3
, &in4
, &in5
, &in6
, &in7
);
502 result
= sal_emulator(vcpu
->kvm
, index
, in1
, in2
, in3
,
504 set_sal_result(vcpu
, result
);