KVM: ia64: Implement some pal calls needed for windows 2008
[linux-2.6.git] / arch / ia64 / kvm / kvm_fw.c
1 /*
2  * PAL/SAL call delegation
3  *
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>
7  *
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.
11  *
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
15  * more details.
16  *
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.
20  */
21
22 #include <linux/kvm_host.h>
23 #include <linux/smp.h>
24
25 #include "vti.h"
26 #include "misc.h"
27
28 #include <asm/pal.h>
29 #include <asm/sal.h>
30 #include <asm/tlb.h>
31
32 /*
33  * Handy macros to make sure that the PAL return values start out
34  * as something meaningful.
35  */
36 #define INIT_PAL_STATUS_UNIMPLEMENTED(x)                \
37         {                                               \
38                 x.status = PAL_STATUS_UNIMPLEMENTED;    \
39                 x.v0 = 0;                               \
40                 x.v1 = 0;                               \
41                 x.v2 = 0;                               \
42         }
43
44 #define INIT_PAL_STATUS_SUCCESS(x)                      \
45         {                                               \
46                 x.status = PAL_STATUS_SUCCESS;          \
47                 x.v0 = 0;                               \
48                 x.v1 = 0;                               \
49                 x.v2 = 0;                               \
50     }
51
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;
55
56         if (vcpu) {
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;
63                         return ;
64                 }
65         }
66         printk(KERN_DEBUG"Failed to get vcpu pal data!!!\n");
67 }
68
69 static void set_pal_result(struct kvm_vcpu *vcpu,
70                 struct ia64_pal_retval result) {
71
72         struct exit_ctl_data *p;
73
74         p = kvm_get_exit_data(vcpu);
75         if (p && p->exit_reason == EXIT_REASON_PAL_CALL) {
76                 p->u.pal_data.ret = result;
77                 return ;
78         }
79         INIT_PAL_STATUS_UNIMPLEMENTED(p->u.pal_data.ret);
80 }
81
82 static void set_sal_result(struct kvm_vcpu *vcpu,
83                 struct sal_ret_values result) {
84         struct exit_ctl_data *p;
85
86         p = kvm_get_exit_data(vcpu);
87         if (p && p->exit_reason == EXIT_REASON_SAL_CALL) {
88                 p->u.sal_data.ret = result;
89                 return ;
90         }
91         printk(KERN_WARNING"Failed to set sal result!!\n");
92 }
93
94 struct cache_flush_args {
95         u64 cache_type;
96         u64 operation;
97         u64 progress;
98         long status;
99 };
100
101 cpumask_t cpu_cache_coherent_map;
102
103 static void remote_pal_cache_flush(void *data)
104 {
105         struct cache_flush_args *args = data;
106         long status;
107         u64 progress = args->progress;
108
109         status = ia64_pal_cache_flush(args->cache_type, args->operation,
110                                         &progress, NULL);
111         if (status != 0)
112         args->status = status;
113 }
114
115 static struct ia64_pal_retval pal_cache_flush(struct kvm_vcpu *vcpu)
116 {
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};
120         long psr;
121
122         gr28 = gr29 = gr30 = gr31 = 0;
123         kvm_get_pal_call_data(vcpu, &gr28, &gr29, &gr30, &gr31);
124
125         if (gr31 != 0)
126                 printk(KERN_ERR"vcpu:%p called cache_flush error!\n", vcpu);
127
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,
133                                 (void *)&args, 1);
134         if (args.status != 0)
135                 printk(KERN_ERR"pal_cache_flush error!,"
136                                 "status:0x%lx\n", args.status);
137         /*
138          * Call Host PAL cache flush
139          * Clear psr.ic when call PAL_CACHE_FLUSH
140          */
141         local_irq_save(psr);
142         result.status = ia64_pal_cache_flush(gr29, gr30, &result.v1,
143                                                 &result.v0);
144         local_irq_restore(psr);
145         if (result.status != 0)
146                 printk(KERN_ERR"vcpu:%p crashed due to cache_flush err:%ld"
147                                 "in1:%lx,in2:%lx\n",
148                                 vcpu, result.status, gr29, gr30);
149
150 #if 0
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);
156         }
157 #endif
158         return result;
159 }
160
161 struct ia64_pal_retval pal_cache_summary(struct kvm_vcpu *vcpu)
162 {
163
164         struct ia64_pal_retval result;
165
166         PAL_CALL(result, PAL_CACHE_SUMMARY, 0, 0, 0);
167         return result;
168 }
169
170 static struct ia64_pal_retval pal_freq_base(struct kvm_vcpu *vcpu)
171 {
172
173         struct ia64_pal_retval result;
174
175         PAL_CALL(result, PAL_FREQ_BASE, 0, 0, 0);
176
177         /*
178          * PAL_FREQ_BASE may not be implemented in some platforms,
179          * call SAL instead.
180          */
181         if (result.v0 == 0) {
182                 result.status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
183                                                         &result.v0,
184                                                         &result.v1);
185                 result.v2 = 0;
186         }
187
188         return result;
189 }
190
191 static struct ia64_pal_retval pal_freq_ratios(struct kvm_vcpu *vcpu)
192 {
193
194         struct ia64_pal_retval result;
195
196         PAL_CALL(result, PAL_FREQ_RATIOS, 0, 0, 0);
197         return result;
198 }
199
200 static struct ia64_pal_retval pal_logical_to_physica(struct kvm_vcpu *vcpu)
201 {
202         struct ia64_pal_retval result;
203
204         INIT_PAL_STATUS_UNIMPLEMENTED(result);
205         return result;
206 }
207
208 static struct ia64_pal_retval pal_platform_addr(struct kvm_vcpu *vcpu)
209 {
210
211         struct ia64_pal_retval result;
212
213         INIT_PAL_STATUS_SUCCESS(result);
214         return result;
215 }
216
217 static struct ia64_pal_retval pal_proc_get_features(struct kvm_vcpu *vcpu)
218 {
219
220         struct ia64_pal_retval result = {0, 0, 0, 0};
221         long in0, in1, in2, in3;
222
223         kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
224         result.status = ia64_pal_proc_get_features(&result.v0, &result.v1,
225                         &result.v2, in2);
226
227         return result;
228 }
229
230 static struct ia64_pal_retval pal_register_info(struct kvm_vcpu *vcpu)
231 {
232
233         struct ia64_pal_retval result = {0, 0, 0, 0};
234         long in0, in1, in2, in3;
235
236         kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
237         result.status = ia64_pal_register_info(in1, &result.v1, &result.v2);
238
239         return result;
240 }
241
242 static struct ia64_pal_retval pal_cache_info(struct kvm_vcpu *vcpu)
243 {
244
245         pal_cache_config_info_t ci;
246         long status;
247         unsigned long in0, in1, in2, in3, r9, r10;
248
249         kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
250         status = ia64_pal_cache_config_info(in1, in2, &ci);
251         r9 = ci.pcci_info_1.pcci1_data;
252         r10 = ci.pcci_info_2.pcci2_data;
253         return ((struct ia64_pal_retval){status, r9, r10, 0});
254 }
255
256 #define GUEST_IMPL_VA_MSB       59
257 #define GUEST_RID_BITS          18
258
259 static struct ia64_pal_retval pal_vm_summary(struct kvm_vcpu *vcpu)
260 {
261
262         pal_vm_info_1_u_t vminfo1;
263         pal_vm_info_2_u_t vminfo2;
264         struct ia64_pal_retval result;
265
266         PAL_CALL(result, PAL_VM_SUMMARY, 0, 0, 0);
267         if (!result.status) {
268                 vminfo1.pvi1_val = result.v0;
269                 vminfo1.pal_vm_info_1_s.max_itr_entry = 8;
270                 vminfo1.pal_vm_info_1_s.max_dtr_entry = 8;
271                 result.v0 = vminfo1.pvi1_val;
272                 vminfo2.pal_vm_info_2_s.impl_va_msb = GUEST_IMPL_VA_MSB;
273                 vminfo2.pal_vm_info_2_s.rid_size = GUEST_RID_BITS;
274                 result.v1 = vminfo2.pvi2_val;
275         }
276
277         return result;
278 }
279
280 static struct ia64_pal_retval pal_vm_info(struct kvm_vcpu *vcpu)
281 {
282         struct ia64_pal_retval result;
283         unsigned long in0, in1, in2, in3;
284
285         kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
286
287         result.status = ia64_pal_vm_info(in1, in2,
288                         (pal_tc_info_u_t *)&result.v1, &result.v2);
289
290         return result;
291 }
292
293 static  u64 kvm_get_pal_call_index(struct kvm_vcpu *vcpu)
294 {
295         u64 index = 0;
296         struct exit_ctl_data *p;
297
298         p = kvm_get_exit_data(vcpu);
299         if (p && (p->exit_reason == EXIT_REASON_PAL_CALL))
300                 index = p->u.pal_data.gr28;
301
302         return index;
303 }
304
305 static void prepare_for_halt(struct kvm_vcpu *vcpu)
306 {
307         vcpu->arch.timer_pending = 1;
308         vcpu->arch.timer_fired = 0;
309 }
310
311 static struct ia64_pal_retval pal_perf_mon_info(struct kvm_vcpu *vcpu)
312 {
313         long status;
314         unsigned long in0, in1, in2, in3, r9;
315         unsigned long pm_buffer[16];
316
317         kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
318         status = ia64_pal_perf_mon_info(pm_buffer,
319                                 (pal_perf_mon_info_u_t *) &r9);
320         if (status != 0) {
321                 printk(KERN_DEBUG"PAL_PERF_MON_INFO fails ret=%ld\n", status);
322         } else {
323                 if (in1)
324                         memcpy((void *)in1, pm_buffer, sizeof(pm_buffer));
325                 else {
326                         status = PAL_STATUS_EINVAL;
327                         printk(KERN_WARNING"Invalid parameters "
328                                                 "for PAL call:0x%lx!\n", in0);
329                 }
330         }
331         return (struct ia64_pal_retval){status, r9, 0, 0};
332 }
333
334 static struct ia64_pal_retval pal_halt_info(struct kvm_vcpu *vcpu)
335 {
336         unsigned long in0, in1, in2, in3;
337         long status;
338         unsigned long res = 1000UL | (1000UL << 16) | (10UL << 32)
339                                         | (1UL << 61) | (1UL << 60);
340
341         kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
342         if (in1) {
343                 memcpy((void *)in1, &res, sizeof(res));
344                 status = 0;
345         } else{
346                 status = PAL_STATUS_EINVAL;
347                 printk(KERN_WARNING"Invalid parameters "
348                                         "for PAL call:0x%lx!\n", in0);
349         }
350
351         return (struct ia64_pal_retval){status, 0, 0, 0};
352 }
353
354 static struct ia64_pal_retval pal_mem_attrib(struct kvm_vcpu *vcpu)
355 {
356         unsigned long r9;
357         long status;
358
359         status = ia64_pal_mem_attrib(&r9);
360
361         return (struct ia64_pal_retval){status, r9, 0, 0};
362 }
363
364 static void remote_pal_prefetch_visibility(void *v)
365 {
366         s64 trans_type = (s64)v;
367         ia64_pal_prefetch_visibility(trans_type);
368 }
369
370 static struct ia64_pal_retval pal_prefetch_visibility(struct kvm_vcpu *vcpu)
371 {
372         struct ia64_pal_retval result = {0, 0, 0, 0};
373         unsigned long in0, in1, in2, in3;
374         kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
375         result.status = ia64_pal_prefetch_visibility(in1);
376         if (result.status == 0) {
377                 /* Must be performed on all remote processors
378                 in the coherence domain. */
379                 smp_call_function(remote_pal_prefetch_visibility,
380                                         (void *)in1, 1);
381                 /* Unnecessary on remote processor for other vcpus!*/
382                 result.status = 1;
383         }
384         return result;
385 }
386
387 static void remote_pal_mc_drain(void *v)
388 {
389         ia64_pal_mc_drain();
390 }
391
392 static struct ia64_pal_retval pal_get_brand_info(struct kvm_vcpu *vcpu)
393 {
394         struct ia64_pal_retval result = {0, 0, 0, 0};
395         unsigned long in0, in1, in2, in3;
396
397         kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
398
399         if (in1 == 0 && in2) {
400                 char brand_info[128];
401                 result.status = ia64_pal_get_brand_info(brand_info);
402                 if (result.status == PAL_STATUS_SUCCESS)
403                         memcpy((void *)in2, brand_info, 128);
404         } else {
405                 result.status = PAL_STATUS_REQUIRES_MEMORY;
406                 printk(KERN_WARNING"Invalid parameters for "
407                                         "PAL call:0x%lx!\n", in0);
408         }
409
410         return result;
411 }
412
413 int kvm_pal_emul(struct kvm_vcpu *vcpu, struct kvm_run *run)
414 {
415
416         u64 gr28;
417         struct ia64_pal_retval result;
418         int ret = 1;
419
420         gr28 = kvm_get_pal_call_index(vcpu);
421         switch (gr28) {
422         case PAL_CACHE_FLUSH:
423                 result = pal_cache_flush(vcpu);
424                 break;
425         case PAL_MEM_ATTRIB:
426                 result = pal_mem_attrib(vcpu);
427                 break;
428         case PAL_CACHE_SUMMARY:
429                 result = pal_cache_summary(vcpu);
430                 break;
431         case PAL_PERF_MON_INFO:
432                 result = pal_perf_mon_info(vcpu);
433                 break;
434         case PAL_HALT_INFO:
435                 result = pal_halt_info(vcpu);
436                 break;
437         case PAL_HALT_LIGHT:
438         {
439                 INIT_PAL_STATUS_SUCCESS(result);
440                 prepare_for_halt(vcpu);
441                 if (kvm_highest_pending_irq(vcpu) == -1)
442                         ret = kvm_emulate_halt(vcpu);
443         }
444                 break;
445
446         case PAL_PREFETCH_VISIBILITY:
447                 result = pal_prefetch_visibility(vcpu);
448                 break;
449         case PAL_MC_DRAIN:
450                 result.status = ia64_pal_mc_drain();
451                 /* FIXME: All vcpus likely call PAL_MC_DRAIN.
452                    That causes the congestion. */
453                 smp_call_function(remote_pal_mc_drain, NULL, 1);
454                 break;
455
456         case PAL_FREQ_RATIOS:
457                 result = pal_freq_ratios(vcpu);
458                 break;
459
460         case PAL_FREQ_BASE:
461                 result = pal_freq_base(vcpu);
462                 break;
463
464         case PAL_LOGICAL_TO_PHYSICAL :
465                 result = pal_logical_to_physica(vcpu);
466                 break;
467
468         case PAL_VM_SUMMARY :
469                 result = pal_vm_summary(vcpu);
470                 break;
471
472         case PAL_VM_INFO :
473                 result = pal_vm_info(vcpu);
474                 break;
475         case PAL_PLATFORM_ADDR :
476                 result = pal_platform_addr(vcpu);
477                 break;
478         case PAL_CACHE_INFO:
479                 result = pal_cache_info(vcpu);
480                 break;
481         case PAL_PTCE_INFO:
482                 INIT_PAL_STATUS_SUCCESS(result);
483                 result.v1 = (1L << 32) | 1L;
484                 break;
485         case PAL_REGISTER_INFO:
486                 result = pal_register_info(vcpu);
487                 break;
488         case PAL_VM_PAGE_SIZE:
489                 result.status = ia64_pal_vm_page_size(&result.v0,
490                                                         &result.v1);
491                 break;
492         case PAL_RSE_INFO:
493                 result.status = ia64_pal_rse_info(&result.v0,
494                                         (pal_hints_u_t *)&result.v1);
495                 break;
496         case PAL_PROC_GET_FEATURES:
497                 result = pal_proc_get_features(vcpu);
498                 break;
499         case PAL_DEBUG_INFO:
500                 result.status = ia64_pal_debug_info(&result.v0,
501                                                         &result.v1);
502                 break;
503         case PAL_VERSION:
504                 result.status = ia64_pal_version(
505                                 (pal_version_u_t *)&result.v0,
506                                 (pal_version_u_t *)&result.v1);
507                 break;
508         case PAL_FIXED_ADDR:
509                 result.status = PAL_STATUS_SUCCESS;
510                 result.v0 = vcpu->vcpu_id;
511                 break;
512         case PAL_BRAND_INFO:
513                 result = pal_get_brand_info(vcpu);
514                 break;
515         case PAL_GET_PSTATE:
516         case PAL_CACHE_SHARED_INFO:
517                 INIT_PAL_STATUS_UNIMPLEMENTED(result);
518                 break;
519         default:
520                 INIT_PAL_STATUS_UNIMPLEMENTED(result);
521                 printk(KERN_WARNING"kvm: Unsupported pal call,"
522                                         " index:0x%lx\n", gr28);
523         }
524         set_pal_result(vcpu, result);
525         return ret;
526 }
527
528 static struct sal_ret_values sal_emulator(struct kvm *kvm,
529                                 long index, unsigned long in1,
530                                 unsigned long in2, unsigned long in3,
531                                 unsigned long in4, unsigned long in5,
532                                 unsigned long in6, unsigned long in7)
533 {
534         unsigned long r9  = 0;
535         unsigned long r10 = 0;
536         long r11 = 0;
537         long status;
538
539         status = 0;
540         switch (index) {
541         case SAL_FREQ_BASE:
542                 status = ia64_sal_freq_base(in1, &r9, &r10);
543                 break;
544         case SAL_PCI_CONFIG_READ:
545                 printk(KERN_WARNING"kvm: Not allowed to call here!"
546                         " SAL_PCI_CONFIG_READ\n");
547                 break;
548         case SAL_PCI_CONFIG_WRITE:
549                 printk(KERN_WARNING"kvm: Not allowed to call here!"
550                         " SAL_PCI_CONFIG_WRITE\n");
551                 break;
552         case SAL_SET_VECTORS:
553                 if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) {
554                         if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) {
555                                 status = -2;
556                         } else {
557                                 kvm->arch.rdv_sal_data.boot_ip = in2;
558                                 kvm->arch.rdv_sal_data.boot_gp = in3;
559                         }
560                         printk("Rendvous called! iip:%lx\n\n", in2);
561                 } else
562                         printk(KERN_WARNING"kvm: CALLED SAL_SET_VECTORS %lu."
563                                                         "ignored...\n", in1);
564                 break;
565         case SAL_GET_STATE_INFO:
566                 /* No more info.  */
567                 status = -5;
568                 r9 = 0;
569                 break;
570         case SAL_GET_STATE_INFO_SIZE:
571                 /* Return a dummy size.  */
572                 status = 0;
573                 r9 = 128;
574                 break;
575         case SAL_CLEAR_STATE_INFO:
576                 /* Noop.  */
577                 break;
578         case SAL_MC_RENDEZ:
579                 printk(KERN_WARNING
580                         "kvm: called SAL_MC_RENDEZ. ignored...\n");
581                 break;
582         case SAL_MC_SET_PARAMS:
583                 printk(KERN_WARNING
584                         "kvm: called  SAL_MC_SET_PARAMS.ignored!\n");
585                 break;
586         case SAL_CACHE_FLUSH:
587                 if (1) {
588                         /*Flush using SAL.
589                         This method is faster but has a side
590                         effect on other vcpu running on
591                         this cpu.  */
592                         status = ia64_sal_cache_flush(in1);
593                 } else {
594                         /*Maybe need to implement the method
595                         without side effect!*/
596                         status = 0;
597                 }
598                 break;
599         case SAL_CACHE_INIT:
600                 printk(KERN_WARNING
601                         "kvm: called SAL_CACHE_INIT.  ignored...\n");
602                 break;
603         case SAL_UPDATE_PAL:
604                 printk(KERN_WARNING
605                         "kvm: CALLED SAL_UPDATE_PAL.  ignored...\n");
606                 break;
607         default:
608                 printk(KERN_WARNING"kvm: called SAL_CALL with unknown index."
609                                                 " index:%ld\n", index);
610                 status = -1;
611                 break;
612         }
613         return ((struct sal_ret_values) {status, r9, r10, r11});
614 }
615
616 static void kvm_get_sal_call_data(struct kvm_vcpu *vcpu, u64 *in0, u64 *in1,
617                 u64 *in2, u64 *in3, u64 *in4, u64 *in5, u64 *in6, u64 *in7){
618
619         struct exit_ctl_data *p;
620
621         p = kvm_get_exit_data(vcpu);
622
623         if (p) {
624                 if (p->exit_reason == EXIT_REASON_SAL_CALL) {
625                         *in0 = p->u.sal_data.in0;
626                         *in1 = p->u.sal_data.in1;
627                         *in2 = p->u.sal_data.in2;
628                         *in3 = p->u.sal_data.in3;
629                         *in4 = p->u.sal_data.in4;
630                         *in5 = p->u.sal_data.in5;
631                         *in6 = p->u.sal_data.in6;
632                         *in7 = p->u.sal_data.in7;
633                         return ;
634                 }
635         }
636         *in0 = 0;
637 }
638
639 void kvm_sal_emul(struct kvm_vcpu *vcpu)
640 {
641
642         struct sal_ret_values result;
643         u64 index, in1, in2, in3, in4, in5, in6, in7;
644
645         kvm_get_sal_call_data(vcpu, &index, &in1, &in2,
646                         &in3, &in4, &in5, &in6, &in7);
647         result = sal_emulator(vcpu->kvm, index, in1, in2, in3,
648                                         in4, in5, in6, in7);
649         set_sal_result(vcpu, result);
650 }