ia64/xen-unstable

annotate xen/arch/ia64/xen/hypercall.c @ 9768:63af1c14fa18

[IA64] missed chunk of Kevin's hypercall cleanup patch

Missed this chunk of Kevin's patch when merging with dom0vp changes

Signed-off-by Kevin Tian <kevin.tian@intel.com>
author awilliam@xenbuild.aw
date Tue Apr 25 22:30:07 2006 -0600 (2006-04-25)
parents 46597f27a0f5
children 4e1b8be54311
rev   line source
djm@6458 1 /*
djm@6458 2 * Hypercall implementations
djm@6458 3 *
djm@6458 4 * Copyright (C) 2005 Hewlett-Packard Co.
djm@6458 5 * Dan Magenheimer (dan.magenheimer@hp.com)
djm@6458 6 *
djm@6458 7 */
djm@6458 8
djm@6458 9 #include <xen/config.h>
djm@6458 10 #include <xen/sched.h>
kaf24@8704 11 #include <xen/hypercall.h>
awilliam@8775 12 #include <xen/multicall.h>
kaf24@9183 13 #include <xen/guest_access.h>
djm@6458 14
djm@6458 15 #include <linux/efi.h> /* FOR EFI_UNIMPLEMENTED */
djm@6458 16 #include <asm/sal.h> /* FOR struct ia64_sal_retval */
djm@6458 17
djm@6458 18 #include <asm/vcpu.h>
djm@6458 19 #include <asm/dom_fw.h>
awilliam@9005 20 #include <public/dom0_ops.h>
awilliam@9005 21 #include <public/event_channel.h>
djm@6858 22 #include <public/memory.h>
djm@7279 23 #include <public/sched.h>
awilliam@9747 24 #include <xen/irq.h>
awilliam@9747 25 #include <asm/hw_irq.h>
awilliam@9747 26 #include <public/physdev.h>
awilliam@9767 27 #include <xen/domain.h>
djm@6458 28
djm@6458 29 extern unsigned long translate_domain_mpaddr(unsigned long);
awilliam@9747 30 static long do_physdev_op(GUEST_HANDLE(physdev_op_t) uop);
awilliam@9005 31 /* FIXME: where these declarations should be there ? */
awilliam@9005 32 extern int dump_privop_counts_to_user(char *, int);
awilliam@9005 33 extern int zero_privop_counts_to_user(char *, int);
djm@6458 34
djm@6458 35 unsigned long idle_when_pending = 0;
djm@6458 36 unsigned long pal_halt_light_count = 0;
djm@6458 37
awilliam@8775 38 hypercall_t ia64_hypercall_table[] =
awilliam@8775 39 {
awilliam@8775 40 (hypercall_t)do_ni_hypercall, /* do_set_trap_table */ /* 0 */
awilliam@8775 41 (hypercall_t)do_ni_hypercall, /* do_mmu_update */
awilliam@8775 42 (hypercall_t)do_ni_hypercall, /* do_set_gdt */
awilliam@8775 43 (hypercall_t)do_ni_hypercall, /* do_stack_switch */
awilliam@8775 44 (hypercall_t)do_ni_hypercall, /* do_set_callbacks */
awilliam@8775 45 (hypercall_t)do_ni_hypercall, /* do_fpu_taskswitch */ /* 5 */
kaf24@9566 46 (hypercall_t)do_sched_op_compat,
awilliam@8775 47 (hypercall_t)do_dom0_op,
awilliam@8775 48 (hypercall_t)do_ni_hypercall, /* do_set_debugreg */
awilliam@8775 49 (hypercall_t)do_ni_hypercall, /* do_get_debugreg */
awilliam@8775 50 (hypercall_t)do_ni_hypercall, /* do_update_descriptor */ /* 10 */
awilliam@8775 51 (hypercall_t)do_ni_hypercall, /* do_ni_hypercall */
awilliam@8775 52 (hypercall_t)do_memory_op,
awilliam@8775 53 (hypercall_t)do_multicall,
awilliam@8775 54 (hypercall_t)do_ni_hypercall, /* do_update_va_mapping */
awilliam@8775 55 (hypercall_t)do_ni_hypercall, /* do_set_timer_op */ /* 15 */
awilliam@8775 56 (hypercall_t)do_event_channel_op,
awilliam@8775 57 (hypercall_t)do_xen_version,
awilliam@8775 58 (hypercall_t)do_console_io,
awilliam@9767 59 (hypercall_t)do_physdev_op,
awilliam@8775 60 (hypercall_t)do_grant_table_op, /* 20 */
awilliam@8775 61 (hypercall_t)do_ni_hypercall, /* do_vm_assist */
awilliam@8775 62 (hypercall_t)do_ni_hypercall, /* do_update_va_mapping_otherdomain */
awilliam@8775 63 (hypercall_t)do_ni_hypercall, /* (x86 only) */
awilliam@8775 64 (hypercall_t)do_ni_hypercall, /* do_vcpu_op */
awilliam@8775 65 (hypercall_t)do_ni_hypercall, /* (x86_64 only) */ /* 25 */
awilliam@8775 66 (hypercall_t)do_ni_hypercall, /* do_mmuext_op */
awilliam@8775 67 (hypercall_t)do_ni_hypercall, /* do_acm_op */
awilliam@8775 68 (hypercall_t)do_ni_hypercall, /* do_nmi_op */
kaf24@9566 69 (hypercall_t)do_sched_op,
awilliam@8775 70 (hypercall_t)do_ni_hypercall, /* */ /* 30 */
awilliam@8775 71 (hypercall_t)do_ni_hypercall /* */
awilliam@8775 72 };
awilliam@8775 73
awilliam@9768 74 uint32_t nr_hypercalls =
awilliam@9768 75 sizeof(ia64_hypercall_table) / sizeof(hypercall_t);
awilliam@9768 76
awilliam@9317 77 static int
awilliam@9317 78 xen_hypercall (struct pt_regs *regs)
awilliam@9317 79 {
awilliam@9767 80 uint32_t cmd = (uint32_t)regs->r2;
awilliam@9747 81
awilliam@9767 82 if (cmd < nr_hypercalls)
awilliam@9767 83 regs->r8 = (*ia64_hypercall_table[cmd])(
awilliam@9767 84 regs->r14,
awilliam@9767 85 regs->r15,
awilliam@9767 86 regs->r16,
awilliam@9767 87 regs->r17,
awilliam@9767 88 regs->r18,
awilliam@9767 89 regs->r19);
awilliam@9767 90 else
awilliam@9759 91 #ifdef CONFIG_XEN_IA64_DOM0_VP
awilliam@9767 92 if (cmd == __HYPERVISOR_ia64_dom0vp_op)
awilliam@9759 93 regs->r8 = do_dom0vp_op(regs->r14, regs->r15, regs->r16,
awilliam@9759 94 regs->r17, regs->r18);
awilliam@9767 95 else
awilliam@9759 96 #endif
awilliam@9767 97 regs->r8 = -ENOSYS;
awilliam@9767 98
awilliam@9317 99 return 1;
awilliam@9317 100 }
awilliam@9317 101
awilliam@9317 102
awilliam@9752 103 static void
awilliam@9752 104 fw_hypercall_ipi (struct pt_regs *regs)
awilliam@9752 105 {
awilliam@9752 106 int cpu = regs->r14;
awilliam@9752 107 int vector = regs->r15;
awilliam@9752 108 struct vcpu *targ;
awilliam@9752 109
awilliam@9752 110 if (0 && vector == 254)
awilliam@9752 111 printf ("send_ipi from %d to %d vector=%d\n",
awilliam@9752 112 current->vcpu_id, cpu, vector);
awilliam@9752 113
awilliam@9752 114 if (cpu > MAX_VIRT_CPUS)
awilliam@9752 115 return;
awilliam@9752 116
awilliam@9752 117 targ = current->domain->vcpu[cpu];
awilliam@9752 118 if (targ == NULL)
awilliam@9752 119 return;
awilliam@9752 120
awilliam@9752 121 if (vector == XEN_SAL_BOOT_RENDEZ_VEC
awilliam@9752 122 && !test_bit(_VCPUF_initialised, &targ->vcpu_flags)) {
awilliam@9752 123 struct pt_regs *targ_regs = vcpu_regs (targ);
awilliam@9752 124 struct vcpu_guest_context c;
awilliam@9752 125
awilliam@9752 126 printf ("arch_boot_vcpu: %p %p\n",
awilliam@9752 127 (void *)targ_regs->cr_iip,
awilliam@9752 128 (void *)targ_regs->r1);
awilliam@9752 129 memset (&c, 0, sizeof (c));
awilliam@9752 130 /* Copy regs. */
awilliam@9752 131 c.regs.cr_iip = targ_regs->cr_iip;
awilliam@9752 132 c.regs.r1 = targ_regs->r1;
awilliam@9752 133
awilliam@9752 134 /* Copy from vcpu 0. */
awilliam@9752 135 c.vcpu.evtchn_vector =
awilliam@9752 136 current->domain->vcpu[0]->vcpu_info->arch.evtchn_vector;
awilliam@9752 137 if (arch_set_info_guest (targ, &c) != 0) {
awilliam@9752 138 printf ("arch_boot_vcpu: failure\n");
awilliam@9752 139 return;
awilliam@9752 140 }
awilliam@9752 141 if (test_and_clear_bit(_VCPUF_down,
awilliam@9752 142 &targ->vcpu_flags)) {
awilliam@9752 143 vcpu_wake(targ);
awilliam@9752 144 printf ("arch_boot_vcpu: vcpu %d awaken %016lx!\n",
awilliam@9752 145 targ->vcpu_id, targ_regs->cr_iip);
awilliam@9752 146 }
awilliam@9752 147 else
awilliam@9752 148 printf ("arch_boot_vcpu: huu, already awaken!");
awilliam@9752 149 }
awilliam@9752 150 else {
awilliam@9752 151 int running = test_bit(_VCPUF_running,
awilliam@9752 152 &targ->vcpu_flags);
awilliam@9752 153
awilliam@9752 154 vcpu_pend_interrupt(targ, vector);
awilliam@9752 155 vcpu_unblock(targ);
awilliam@9752 156 if (running)
awilliam@9752 157 smp_send_event_check_cpu(targ->processor);
awilliam@9752 158 }
awilliam@9752 159 return;
awilliam@9752 160 }
awilliam@9752 161
awilliam@9317 162 static int
awilliam@9317 163 fw_hypercall (struct pt_regs *regs)
djm@6458 164 {
awilliam@8832 165 struct vcpu *v = current;
djm@7930 166 struct sal_ret_values x;
djm@6458 167 unsigned long *tv, *tc;
djm@6458 168
djm@6458 169 switch (regs->r2) {
djm@6458 170 case FW_HYPERCALL_PAL_CALL:
djm@6458 171 //printf("*** PAL hypercall: index=%d\n",regs->r28);
djm@6458 172 //FIXME: This should call a C routine
djm@6458 173 #if 0
djm@6458 174 // This is very conservative, but avoids a possible
djm@6458 175 // (and deadly) freeze in paravirtualized domains due
djm@6458 176 // to a yet-to-be-found bug where pending_interruption
djm@6458 177 // is zero when it shouldn't be. Since PAL is called
djm@6458 178 // in the idle loop, this should resolve it
djm@6458 179 VCPU(v,pending_interruption) = 1;
djm@6458 180 #endif
djm@6458 181 if (regs->r28 == PAL_HALT_LIGHT) {
awilliam@9317 182 int pi;
djm@6458 183 #define SPURIOUS_VECTOR 15
djm@6458 184 pi = vcpu_check_pending_interrupts(v);
djm@6458 185 if (pi != SPURIOUS_VECTOR) {
djm@6458 186 if (!VCPU(v,pending_interruption))
djm@6458 187 idle_when_pending++;
djm@6458 188 vcpu_pend_unspecified_interrupt(v);
djm@6458 189 //printf("idle w/int#%d pending!\n",pi);
djm@6458 190 //this shouldn't happen, but it apparently does quite a bit! so don't
djm@6458 191 //allow it to happen... i.e. if a domain has an interrupt pending and
djm@6458 192 //it tries to halt itself because it thinks it is idle, just return here
djm@6458 193 //as deliver_pending_interrupt is called on the way out and will deliver it
djm@6458 194 }
djm@6458 195 else {
djm@6458 196 pal_halt_light_count++;
kaf24@9563 197 do_sched_op_compat(SCHEDOP_yield, 0);
djm@6458 198 }
djm@7930 199 regs->r8 = 0;
djm@7930 200 regs->r9 = 0;
djm@7930 201 regs->r10 = 0;
djm@7930 202 regs->r11 = 0;
djm@6458 203 }
djm@7930 204 else {
djm@7930 205 struct ia64_pal_retval y;
djm@7930 206
djm@7930 207 if (regs->r28 >= PAL_COPY_PAL)
djm@7930 208 y = xen_pal_emulator
djm@7930 209 (regs->r28, vcpu_get_gr (v, 33),
djm@7930 210 vcpu_get_gr (v, 34),
djm@7930 211 vcpu_get_gr (v, 35));
djm@7930 212 else
djm@7930 213 y = xen_pal_emulator(regs->r28,regs->r29,
djm@7930 214 regs->r30,regs->r31);
djm@7930 215 regs->r8 = y.status; regs->r9 = y.v0;
djm@7930 216 regs->r10 = y.v1; regs->r11 = y.v2;
djm@6458 217 }
djm@6458 218 break;
djm@6458 219 case FW_HYPERCALL_SAL_CALL:
djm@6458 220 x = sal_emulator(vcpu_get_gr(v,32),vcpu_get_gr(v,33),
djm@6458 221 vcpu_get_gr(v,34),vcpu_get_gr(v,35),
djm@6458 222 vcpu_get_gr(v,36),vcpu_get_gr(v,37),
djm@6458 223 vcpu_get_gr(v,38),vcpu_get_gr(v,39));
djm@7930 224 regs->r8 = x.r8; regs->r9 = x.r9;
djm@7930 225 regs->r10 = x.r10; regs->r11 = x.r11;
djm@6458 226 break;
djm@6458 227 case FW_HYPERCALL_EFI_RESET_SYSTEM:
djm@6458 228 printf("efi.reset_system called ");
djm@6458 229 if (current->domain == dom0) {
djm@6458 230 printf("(by dom0)\n ");
djm@6458 231 (*efi.reset_system)(EFI_RESET_WARM,0,0,NULL);
djm@6458 232 }
awilliam@9319 233 else
awilliam@9319 234 domain_shutdown (current->domain, SHUTDOWN_reboot);
djm@6458 235 regs->r8 = EFI_UNSUPPORTED;
djm@6458 236 break;
djm@6458 237 case FW_HYPERCALL_EFI_GET_TIME:
awilliam@9005 238 tv = (unsigned long *) vcpu_get_gr(v,32);
awilliam@9005 239 tc = (unsigned long *) vcpu_get_gr(v,33);
djm@6458 240 //printf("efi_get_time(%p,%p) called...",tv,tc);
awilliam@9005 241 tv = (unsigned long *) __va(translate_domain_mpaddr((unsigned long) tv));
awilliam@9005 242 if (tc) tc = (unsigned long *) __va(translate_domain_mpaddr((unsigned long) tc));
awilliam@9005 243 regs->r8 = (*efi.get_time)((efi_time_t *) tv, (efi_time_cap_t *) tc);
djm@6458 244 //printf("and returns %lx\n",regs->r8);
djm@6458 245 break;
djm@6458 246 case FW_HYPERCALL_EFI_SET_TIME:
djm@6458 247 case FW_HYPERCALL_EFI_GET_WAKEUP_TIME:
djm@6458 248 case FW_HYPERCALL_EFI_SET_WAKEUP_TIME:
djm@6458 249 // FIXME: need fixes in efi.h from 2.6.9
djm@6458 250 case FW_HYPERCALL_EFI_SET_VIRTUAL_ADDRESS_MAP:
djm@6458 251 // FIXME: WARNING!! IF THIS EVER GETS IMPLEMENTED
djm@6458 252 // SOME OF THE OTHER EFI EMULATIONS WILL CHANGE AS
djm@6458 253 // POINTER ARGUMENTS WILL BE VIRTUAL!!
djm@6458 254 case FW_HYPERCALL_EFI_GET_VARIABLE:
djm@6458 255 // FIXME: need fixes in efi.h from 2.6.9
djm@6458 256 case FW_HYPERCALL_EFI_GET_NEXT_VARIABLE:
djm@6458 257 case FW_HYPERCALL_EFI_SET_VARIABLE:
djm@6458 258 case FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT:
djm@6458 259 // FIXME: need fixes in efi.h from 2.6.9
djm@6458 260 regs->r8 = EFI_UNSUPPORTED;
djm@6458 261 break;
awilliam@9752 262 case FW_HYPERCALL_IPI:
awilliam@9752 263 fw_hypercall_ipi (regs);
awilliam@9752 264 break;
djm@6458 265 default:
awilliam@9317 266 printf("unknown ia64 fw hypercall %lx\n", regs->r2);
awilliam@8775 267 regs->r8 = do_ni_hypercall();
djm@6458 268 }
djm@6458 269 return 1;
djm@6458 270 }
awilliam@9317 271
awilliam@9318 272 /* opt_unsafe_hypercall: If true, unsafe debugging hypercalls are allowed.
awilliam@9318 273 These can create security hole. */
awilliam@9318 274 static int opt_unsafe_hypercall = 0;
awilliam@9318 275 boolean_param("unsafe_hypercall", opt_unsafe_hypercall);
awilliam@9318 276
awilliam@9317 277 int
awilliam@9317 278 ia64_hypercall (struct pt_regs *regs)
awilliam@9317 279 {
awilliam@9317 280 struct vcpu *v = current;
awilliam@9317 281 unsigned long index = regs->r2;
awilliam@9318 282 int privlvl = (regs->cr_ipsr & IA64_PSR_CPL) >> IA64_PSR_CPL0_BIT;
awilliam@9317 283
awilliam@9317 284 if (index >= FW_HYPERCALL_FIRST_USER) {
awilliam@9318 285 /* Note: user hypercalls are not safe, since Xen doesn't
awilliam@9318 286 check memory access privilege: Xen does not deny reading
awilliam@9318 287 or writing to kernel memory. */
awilliam@9318 288 if (!opt_unsafe_hypercall) {
awilliam@9318 289 printf("user xen/ia64 hypercalls disabled\n");
awilliam@9318 290 regs->r8 = -1;
awilliam@9318 291 }
awilliam@9318 292 else switch (index) {
awilliam@9317 293 case 0xffff:
awilliam@9317 294 regs->r8 = dump_privop_counts_to_user(
awilliam@9317 295 (char *) vcpu_get_gr(v,32),
awilliam@9317 296 (int) vcpu_get_gr(v,33));
awilliam@9317 297 break;
awilliam@9317 298 case 0xfffe:
awilliam@9317 299 regs->r8 = zero_privop_counts_to_user(
awilliam@9317 300 (char *) vcpu_get_gr(v,32),
awilliam@9317 301 (int) vcpu_get_gr(v,33));
awilliam@9317 302 break;
awilliam@9317 303 default:
awilliam@9317 304 printf("unknown user xen/ia64 hypercall %lx\n", index);
awilliam@9317 305 regs->r8 = do_ni_hypercall();
awilliam@9317 306 }
awilliam@9317 307 return 1;
awilliam@9317 308 }
awilliam@9317 309
awilliam@9318 310 /* Hypercalls are only allowed by kernel.
awilliam@9318 311 Kernel checks memory accesses. */
awilliam@9318 312 if (privlvl != 2) {
awilliam@9318 313 /* FIXME: Return a better error value ?
awilliam@9318 314 Reflection ? Illegal operation ? */
awilliam@9318 315 regs->r8 = -1;
awilliam@9318 316 return 1;
awilliam@9318 317 }
awilliam@9318 318
awilliam@9318 319 if (index >= FW_HYPERCALL_FIRST_ARCH)
awilliam@9318 320 return fw_hypercall (regs);
awilliam@9318 321 else
awilliam@9317 322 return xen_hypercall (regs);
awilliam@9317 323 }
awilliam@9747 324
awilliam@9747 325 /* Need make this function common */
awilliam@9747 326 extern int
awilliam@9747 327 iosapic_guest_read(
awilliam@9747 328 unsigned long physbase, unsigned int reg, u32 *pval);
awilliam@9747 329 extern int
awilliam@9747 330 iosapic_guest_write(
awilliam@9747 331 unsigned long physbase, unsigned int reg, u32 pval);
awilliam@9747 332
awilliam@9747 333 static long do_physdev_op(GUEST_HANDLE(physdev_op_t) uop)
awilliam@9747 334 {
awilliam@9747 335 struct physdev_op op;
awilliam@9747 336 long ret;
awilliam@9747 337 int irq;
awilliam@9747 338
awilliam@9747 339 if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
awilliam@9747 340 return -EFAULT;
awilliam@9747 341
awilliam@9747 342 switch ( op.cmd )
awilliam@9747 343 {
awilliam@9747 344 case PHYSDEVOP_IRQ_UNMASK_NOTIFY:
awilliam@9747 345 ret = pirq_guest_unmask(current->domain);
awilliam@9747 346 break;
awilliam@9747 347
awilliam@9747 348 case PHYSDEVOP_IRQ_STATUS_QUERY:
awilliam@9747 349 irq = op.u.irq_status_query.irq;
awilliam@9747 350 ret = -EINVAL;
awilliam@9747 351 if ( (irq < 0) || (irq >= NR_IRQS) )
awilliam@9747 352 break;
awilliam@9747 353 op.u.irq_status_query.flags = 0;
awilliam@9747 354 /* Edge-triggered interrupts don't need an explicit unmask downcall. */
awilliam@9747 355 if ( !strstr(irq_desc[irq_to_vector(irq)].handler->typename, "edge") )
awilliam@9747 356 op.u.irq_status_query.flags |= PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY;
awilliam@9747 357 ret = 0;
awilliam@9747 358 break;
awilliam@9747 359
awilliam@9747 360 case PHYSDEVOP_APIC_READ:
awilliam@9747 361 ret = -EPERM;
awilliam@9747 362 if ( !IS_PRIV(current->domain) )
awilliam@9747 363 break;
awilliam@9747 364 ret = iosapic_guest_read(
awilliam@9747 365 op.u.apic_op.apic_physbase,
awilliam@9747 366 op.u.apic_op.reg,
awilliam@9747 367 &op.u.apic_op.value);
awilliam@9747 368 break;
awilliam@9747 369
awilliam@9747 370 case PHYSDEVOP_APIC_WRITE:
awilliam@9747 371 ret = -EPERM;
awilliam@9747 372 if ( !IS_PRIV(current->domain) )
awilliam@9747 373 break;
awilliam@9747 374 ret = iosapic_guest_write(
awilliam@9747 375 op.u.apic_op.apic_physbase,
awilliam@9747 376 op.u.apic_op.reg,
awilliam@9747 377 op.u.apic_op.value);
awilliam@9747 378 break;
awilliam@9747 379
awilliam@9747 380 case PHYSDEVOP_ASSIGN_VECTOR:
awilliam@9747 381 if ( !IS_PRIV(current->domain) )
awilliam@9747 382 return -EPERM;
awilliam@9747 383
awilliam@9747 384 if ( (irq = op.u.irq_op.irq) >= NR_IRQS )
awilliam@9747 385 return -EINVAL;
awilliam@9747 386
awilliam@9747 387 op.u.irq_op.vector = assign_irq_vector(irq);
awilliam@9747 388 ret = 0;
awilliam@9747 389 break;
awilliam@9747 390
awilliam@9747 391 default:
awilliam@9747 392 ret = -EINVAL;
awilliam@9747 393 break;
awilliam@9747 394 }
awilliam@9747 395
awilliam@9747 396 if ( copy_to_guest(uop, &op, 1) )
awilliam@9747 397 ret = -EFAULT;
awilliam@9747 398
awilliam@9747 399 return ret;
awilliam@9747 400 }