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