| Jeremy Fitzhardinge | a42089d | 2007-07-17 18:37:04 -0700 | [diff] [blame] | 1 | /****************************************************************************** | 
 | 2 |  * hypercall.h | 
 | 3 |  * | 
 | 4 |  * Linux-specific hypervisor handling. | 
 | 5 |  * | 
 | 6 |  * Copyright (c) 2002-2004, K A Fraser | 
 | 7 |  * | 
 | 8 |  * This program is free software; you can redistribute it and/or | 
 | 9 |  * modify it under the terms of the GNU General Public License version 2 | 
 | 10 |  * as published by the Free Software Foundation; or, when distributed | 
 | 11 |  * separately from the Linux kernel or incorporated into other | 
 | 12 |  * software packages, subject to the following license: | 
 | 13 |  * | 
 | 14 |  * Permission is hereby granted, free of charge, to any person obtaining a copy | 
 | 15 |  * of this source file (the "Software"), to deal in the Software without | 
 | 16 |  * restriction, including without limitation the rights to use, copy, modify, | 
 | 17 |  * merge, publish, distribute, sublicense, and/or sell copies of the Software, | 
 | 18 |  * and to permit persons to whom the Software is furnished to do so, subject to | 
 | 19 |  * the following conditions: | 
 | 20 |  * | 
 | 21 |  * The above copyright notice and this permission notice shall be included in | 
 | 22 |  * all copies or substantial portions of the Software. | 
 | 23 |  * | 
 | 24 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
 | 25 |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
 | 26 |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | 
 | 27 |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
 | 28 |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | 
 | 29 |  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | 
 | 30 |  * IN THE SOFTWARE. | 
 | 31 |  */ | 
 | 32 |  | 
 | 33 | #ifndef __HYPERCALL_H__ | 
 | 34 | #define __HYPERCALL_H__ | 
 | 35 |  | 
 | 36 | #include <linux/errno.h> | 
 | 37 | #include <linux/string.h> | 
 | 38 |  | 
 | 39 | #include <xen/interface/xen.h> | 
 | 40 | #include <xen/interface/sched.h> | 
 | 41 | #include <xen/interface/physdev.h> | 
 | 42 |  | 
 | 43 | extern struct { char _entry[32]; } hypercall_page[]; | 
 | 44 |  | 
 | 45 | #define _hypercall0(type, name)						\ | 
 | 46 | ({									\ | 
 | 47 | 	long __res;							\ | 
 | 48 | 	asm volatile (							\ | 
 | 49 | 		"call %[call]"						\ | 
 | 50 | 		: "=a" (__res)						\ | 
 | 51 | 		: [call] "m" (hypercall_page[__HYPERVISOR_##name])	\ | 
 | 52 | 		: "memory" );						\ | 
 | 53 | 	(type)__res;							\ | 
 | 54 | }) | 
 | 55 |  | 
 | 56 | #define _hypercall1(type, name, a1)					\ | 
 | 57 | ({									\ | 
 | 58 | 	long __res, __ign1;						\ | 
 | 59 | 	asm volatile (							\ | 
 | 60 | 		"call %[call]"						\ | 
 | 61 | 		: "=a" (__res), "=b" (__ign1)				\ | 
 | 62 | 		: "1" ((long)(a1)),					\ | 
 | 63 | 		  [call] "m" (hypercall_page[__HYPERVISOR_##name])	\ | 
 | 64 | 		: "memory" );						\ | 
 | 65 | 	(type)__res;							\ | 
 | 66 | }) | 
 | 67 |  | 
 | 68 | #define _hypercall2(type, name, a1, a2)					\ | 
 | 69 | ({									\ | 
 | 70 | 	long __res, __ign1, __ign2;					\ | 
 | 71 | 	asm volatile (							\ | 
 | 72 | 		"call %[call]"						\ | 
 | 73 | 		: "=a" (__res), "=b" (__ign1), "=c" (__ign2)		\ | 
 | 74 | 		: "1" ((long)(a1)), "2" ((long)(a2)),			\ | 
 | 75 | 		  [call] "m" (hypercall_page[__HYPERVISOR_##name])	\ | 
 | 76 | 		: "memory" );						\ | 
 | 77 | 	(type)__res;							\ | 
 | 78 | }) | 
 | 79 |  | 
 | 80 | #define _hypercall3(type, name, a1, a2, a3)				\ | 
 | 81 | ({									\ | 
 | 82 | 	long __res, __ign1, __ign2, __ign3;				\ | 
 | 83 | 	asm volatile (							\ | 
 | 84 | 		"call %[call]"						\ | 
 | 85 | 		: "=a" (__res), "=b" (__ign1), "=c" (__ign2),		\ | 
 | 86 | 		"=d" (__ign3)						\ | 
 | 87 | 		: "1" ((long)(a1)), "2" ((long)(a2)),			\ | 
 | 88 | 		  "3" ((long)(a3)),					\ | 
 | 89 | 		  [call] "m" (hypercall_page[__HYPERVISOR_##name])	\ | 
 | 90 | 		: "memory" );						\ | 
 | 91 | 	(type)__res;							\ | 
 | 92 | }) | 
 | 93 |  | 
 | 94 | #define _hypercall4(type, name, a1, a2, a3, a4)				\ | 
 | 95 | ({									\ | 
 | 96 | 	long __res, __ign1, __ign2, __ign3, __ign4;			\ | 
 | 97 | 	asm volatile (							\ | 
 | 98 | 		"call %[call]"						\ | 
 | 99 | 		: "=a" (__res), "=b" (__ign1), "=c" (__ign2),		\ | 
 | 100 | 		"=d" (__ign3), "=S" (__ign4)				\ | 
 | 101 | 		: "1" ((long)(a1)), "2" ((long)(a2)),			\ | 
 | 102 | 		  "3" ((long)(a3)), "4" ((long)(a4)),			\ | 
 | 103 | 		  [call] "m" (hypercall_page[__HYPERVISOR_##name])	\ | 
 | 104 | 		: "memory" );						\ | 
 | 105 | 	(type)__res;							\ | 
 | 106 | }) | 
 | 107 |  | 
 | 108 | #define _hypercall5(type, name, a1, a2, a3, a4, a5)			\ | 
 | 109 | ({									\ | 
 | 110 | 	long __res, __ign1, __ign2, __ign3, __ign4, __ign5;		\ | 
 | 111 | 	asm volatile (							\ | 
 | 112 | 		"call %[call]"						\ | 
 | 113 | 		: "=a" (__res), "=b" (__ign1), "=c" (__ign2),		\ | 
 | 114 | 		"=d" (__ign3), "=S" (__ign4), "=D" (__ign5)		\ | 
 | 115 | 		: "1" ((long)(a1)), "2" ((long)(a2)),			\ | 
 | 116 | 		  "3" ((long)(a3)), "4" ((long)(a4)),			\ | 
 | 117 | 		  "5" ((long)(a5)),					\ | 
 | 118 | 		  [call] "m" (hypercall_page[__HYPERVISOR_##name])	\ | 
 | 119 | 		: "memory" );						\ | 
 | 120 | 	(type)__res;							\ | 
 | 121 | }) | 
 | 122 |  | 
 | 123 | static inline int | 
 | 124 | HYPERVISOR_set_trap_table(struct trap_info *table) | 
 | 125 | { | 
 | 126 | 	return _hypercall1(int, set_trap_table, table); | 
 | 127 | } | 
 | 128 |  | 
 | 129 | static inline int | 
 | 130 | HYPERVISOR_mmu_update(struct mmu_update *req, int count, | 
 | 131 | 		      int *success_count, domid_t domid) | 
 | 132 | { | 
 | 133 | 	return _hypercall4(int, mmu_update, req, count, success_count, domid); | 
 | 134 | } | 
 | 135 |  | 
 | 136 | static inline int | 
 | 137 | HYPERVISOR_mmuext_op(struct mmuext_op *op, int count, | 
 | 138 | 		     int *success_count, domid_t domid) | 
 | 139 | { | 
 | 140 | 	return _hypercall4(int, mmuext_op, op, count, success_count, domid); | 
 | 141 | } | 
 | 142 |  | 
 | 143 | static inline int | 
 | 144 | HYPERVISOR_set_gdt(unsigned long *frame_list, int entries) | 
 | 145 | { | 
 | 146 | 	return _hypercall2(int, set_gdt, frame_list, entries); | 
 | 147 | } | 
 | 148 |  | 
 | 149 | static inline int | 
 | 150 | HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp) | 
 | 151 | { | 
 | 152 | 	return _hypercall2(int, stack_switch, ss, esp); | 
 | 153 | } | 
 | 154 |  | 
 | 155 | static inline int | 
 | 156 | HYPERVISOR_set_callbacks(unsigned long event_selector, | 
 | 157 | 			 unsigned long event_address, | 
 | 158 | 			 unsigned long failsafe_selector, | 
 | 159 | 			 unsigned long failsafe_address) | 
 | 160 | { | 
 | 161 | 	return _hypercall4(int, set_callbacks, | 
 | 162 | 			   event_selector, event_address, | 
 | 163 | 			   failsafe_selector, failsafe_address); | 
 | 164 | } | 
 | 165 |  | 
 | 166 | static inline int | 
 | 167 | HYPERVISOR_fpu_taskswitch(int set) | 
 | 168 | { | 
 | 169 | 	return _hypercall1(int, fpu_taskswitch, set); | 
 | 170 | } | 
 | 171 |  | 
 | 172 | static inline int | 
 | 173 | HYPERVISOR_sched_op(int cmd, unsigned long arg) | 
 | 174 | { | 
 | 175 | 	return _hypercall2(int, sched_op, cmd, arg); | 
 | 176 | } | 
 | 177 |  | 
 | 178 | static inline long | 
 | 179 | HYPERVISOR_set_timer_op(u64 timeout) | 
 | 180 | { | 
 | 181 | 	unsigned long timeout_hi = (unsigned long)(timeout>>32); | 
 | 182 | 	unsigned long timeout_lo = (unsigned long)timeout; | 
 | 183 | 	return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi); | 
 | 184 | } | 
 | 185 |  | 
 | 186 | static inline int | 
 | 187 | HYPERVISOR_set_debugreg(int reg, unsigned long value) | 
 | 188 | { | 
 | 189 | 	return _hypercall2(int, set_debugreg, reg, value); | 
 | 190 | } | 
 | 191 |  | 
 | 192 | static inline unsigned long | 
 | 193 | HYPERVISOR_get_debugreg(int reg) | 
 | 194 | { | 
 | 195 | 	return _hypercall1(unsigned long, get_debugreg, reg); | 
 | 196 | } | 
 | 197 |  | 
 | 198 | static inline int | 
 | 199 | HYPERVISOR_update_descriptor(u64 ma, u64 desc) | 
 | 200 | { | 
 | 201 | 	return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32); | 
 | 202 | } | 
 | 203 |  | 
 | 204 | static inline int | 
 | 205 | HYPERVISOR_memory_op(unsigned int cmd, void *arg) | 
 | 206 | { | 
 | 207 | 	return _hypercall2(int, memory_op, cmd, arg); | 
 | 208 | } | 
 | 209 |  | 
 | 210 | static inline int | 
 | 211 | HYPERVISOR_multicall(void *call_list, int nr_calls) | 
 | 212 | { | 
 | 213 | 	return _hypercall2(int, multicall, call_list, nr_calls); | 
 | 214 | } | 
 | 215 |  | 
 | 216 | static inline int | 
 | 217 | HYPERVISOR_update_va_mapping(unsigned long va, pte_t new_val, | 
 | 218 | 			     unsigned long flags) | 
 | 219 | { | 
 | 220 | 	unsigned long pte_hi = 0; | 
 | 221 | #ifdef CONFIG_X86_PAE | 
 | 222 | 	pte_hi = new_val.pte_high; | 
 | 223 | #endif | 
 | 224 | 	return _hypercall4(int, update_va_mapping, va, | 
 | 225 | 			   new_val.pte_low, pte_hi, flags); | 
 | 226 | } | 
 | 227 |  | 
 | 228 | static inline int | 
 | 229 | HYPERVISOR_event_channel_op(int cmd, void *arg) | 
 | 230 | { | 
 | 231 | 	int rc = _hypercall2(int, event_channel_op, cmd, arg); | 
 | 232 | 	if (unlikely(rc == -ENOSYS)) { | 
 | 233 | 		struct evtchn_op op; | 
 | 234 | 		op.cmd = cmd; | 
 | 235 | 		memcpy(&op.u, arg, sizeof(op.u)); | 
 | 236 | 		rc = _hypercall1(int, event_channel_op_compat, &op); | 
 | 237 | 		memcpy(arg, &op.u, sizeof(op.u)); | 
 | 238 | 	} | 
 | 239 | 	return rc; | 
 | 240 | } | 
 | 241 |  | 
 | 242 | static inline int | 
 | 243 | HYPERVISOR_xen_version(int cmd, void *arg) | 
 | 244 | { | 
 | 245 | 	return _hypercall2(int, xen_version, cmd, arg); | 
 | 246 | } | 
 | 247 |  | 
 | 248 | static inline int | 
 | 249 | HYPERVISOR_console_io(int cmd, int count, char *str) | 
 | 250 | { | 
 | 251 | 	return _hypercall3(int, console_io, cmd, count, str); | 
 | 252 | } | 
 | 253 |  | 
 | 254 | static inline int | 
 | 255 | HYPERVISOR_physdev_op(int cmd, void *arg) | 
 | 256 | { | 
 | 257 | 	int rc = _hypercall2(int, physdev_op, cmd, arg); | 
 | 258 | 	if (unlikely(rc == -ENOSYS)) { | 
 | 259 | 		struct physdev_op op; | 
 | 260 | 		op.cmd = cmd; | 
 | 261 | 		memcpy(&op.u, arg, sizeof(op.u)); | 
 | 262 | 		rc = _hypercall1(int, physdev_op_compat, &op); | 
 | 263 | 		memcpy(arg, &op.u, sizeof(op.u)); | 
 | 264 | 	} | 
 | 265 | 	return rc; | 
 | 266 | } | 
 | 267 |  | 
 | 268 | static inline int | 
 | 269 | HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count) | 
 | 270 | { | 
 | 271 | 	return _hypercall3(int, grant_table_op, cmd, uop, count); | 
 | 272 | } | 
 | 273 |  | 
 | 274 | static inline int | 
 | 275 | HYPERVISOR_update_va_mapping_otherdomain(unsigned long va, pte_t new_val, | 
 | 276 | 					 unsigned long flags, domid_t domid) | 
 | 277 | { | 
 | 278 | 	unsigned long pte_hi = 0; | 
 | 279 | #ifdef CONFIG_X86_PAE | 
 | 280 | 	pte_hi = new_val.pte_high; | 
 | 281 | #endif | 
 | 282 | 	return _hypercall5(int, update_va_mapping_otherdomain, va, | 
 | 283 | 			   new_val.pte_low, pte_hi, flags, domid); | 
 | 284 | } | 
 | 285 |  | 
 | 286 | static inline int | 
 | 287 | HYPERVISOR_vm_assist(unsigned int cmd, unsigned int type) | 
 | 288 | { | 
 | 289 | 	return _hypercall2(int, vm_assist, cmd, type); | 
 | 290 | } | 
 | 291 |  | 
 | 292 | static inline int | 
 | 293 | HYPERVISOR_vcpu_op(int cmd, int vcpuid, void *extra_args) | 
 | 294 | { | 
 | 295 | 	return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args); | 
 | 296 | } | 
 | 297 |  | 
 | 298 | static inline int | 
 | 299 | HYPERVISOR_suspend(unsigned long srec) | 
 | 300 | { | 
 | 301 | 	return _hypercall3(int, sched_op, SCHEDOP_shutdown, | 
 | 302 | 			   SHUTDOWN_suspend, srec); | 
 | 303 | } | 
 | 304 |  | 
 | 305 | static inline int | 
 | 306 | HYPERVISOR_nmi_op(unsigned long op, unsigned long arg) | 
 | 307 | { | 
 | 308 | 	return _hypercall2(int, nmi_op, op, arg); | 
 | 309 | } | 
 | 310 |  | 
 | 311 | static inline void | 
 | 312 | MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va, | 
 | 313 | 			pte_t new_val, unsigned long flags) | 
 | 314 | { | 
 | 315 | 	mcl->op = __HYPERVISOR_update_va_mapping; | 
 | 316 | 	mcl->args[0] = va; | 
 | 317 | #ifdef CONFIG_X86_PAE | 
 | 318 | 	mcl->args[1] = new_val.pte_low; | 
 | 319 | 	mcl->args[2] = new_val.pte_high; | 
 | 320 | #else | 
 | 321 | 	mcl->args[1] = new_val.pte_low; | 
 | 322 | 	mcl->args[2] = 0; | 
 | 323 | #endif | 
 | 324 | 	mcl->args[3] = flags; | 
 | 325 | } | 
 | 326 |  | 
 | 327 | static inline void | 
 | 328 | MULTI_grant_table_op(struct multicall_entry *mcl, unsigned int cmd, | 
 | 329 | 		     void *uop, unsigned int count) | 
 | 330 | { | 
 | 331 | 	mcl->op = __HYPERVISOR_grant_table_op; | 
 | 332 | 	mcl->args[0] = cmd; | 
 | 333 | 	mcl->args[1] = (unsigned long)uop; | 
 | 334 | 	mcl->args[2] = count; | 
 | 335 | } | 
 | 336 |  | 
 | 337 | static inline void | 
 | 338 | MULTI_update_va_mapping_otherdomain(struct multicall_entry *mcl, unsigned long va, | 
 | 339 | 				    pte_t new_val, unsigned long flags, | 
 | 340 | 				    domid_t domid) | 
 | 341 | { | 
 | 342 | 	mcl->op = __HYPERVISOR_update_va_mapping_otherdomain; | 
 | 343 | 	mcl->args[0] = va; | 
 | 344 | #ifdef CONFIG_X86_PAE | 
 | 345 | 	mcl->args[1] = new_val.pte_low; | 
 | 346 | 	mcl->args[2] = new_val.pte_high; | 
 | 347 | #else | 
 | 348 | 	mcl->args[1] = new_val.pte_low; | 
 | 349 | 	mcl->args[2] = 0; | 
 | 350 | #endif | 
 | 351 | 	mcl->args[3] = flags; | 
 | 352 | 	mcl->args[4] = domid; | 
 | 353 | } | 
 | 354 |  | 
 | 355 | static inline void | 
 | 356 | MULTI_update_descriptor(struct multicall_entry *mcl, u64 maddr, | 
 | 357 | 			struct desc_struct desc) | 
 | 358 | { | 
 | 359 | 	mcl->op = __HYPERVISOR_update_descriptor; | 
 | 360 | 	mcl->args[0] = maddr; | 
 | 361 | 	mcl->args[1] = maddr >> 32; | 
 | 362 | 	mcl->args[2] = desc.a; | 
 | 363 | 	mcl->args[3] = desc.b; | 
 | 364 | } | 
 | 365 |  | 
 | 366 | static inline void | 
 | 367 | MULTI_memory_op(struct multicall_entry *mcl, unsigned int cmd, void *arg) | 
 | 368 | { | 
 | 369 | 	mcl->op = __HYPERVISOR_memory_op; | 
 | 370 | 	mcl->args[0] = cmd; | 
 | 371 | 	mcl->args[1] = (unsigned long)arg; | 
 | 372 | } | 
 | 373 |  | 
 | 374 | static inline void | 
 | 375 | MULTI_mmu_update(struct multicall_entry *mcl, struct mmu_update *req, | 
 | 376 | 		 int count, int *success_count, domid_t domid) | 
 | 377 | { | 
 | 378 | 	mcl->op = __HYPERVISOR_mmu_update; | 
 | 379 | 	mcl->args[0] = (unsigned long)req; | 
 | 380 | 	mcl->args[1] = count; | 
 | 381 | 	mcl->args[2] = (unsigned long)success_count; | 
 | 382 | 	mcl->args[3] = domid; | 
 | 383 | } | 
 | 384 |  | 
 | 385 | static inline void | 
 | 386 | MULTI_mmuext_op(struct multicall_entry *mcl, struct mmuext_op *op, int count, | 
 | 387 | 		int *success_count, domid_t domid) | 
 | 388 | { | 
 | 389 | 	mcl->op = __HYPERVISOR_mmuext_op; | 
 | 390 | 	mcl->args[0] = (unsigned long)op; | 
 | 391 | 	mcl->args[1] = count; | 
 | 392 | 	mcl->args[2] = (unsigned long)success_count; | 
 | 393 | 	mcl->args[3] = domid; | 
 | 394 | } | 
| Jeremy Fitzhardinge | 5ead97c | 2007-07-17 18:37:04 -0700 | [diff] [blame] | 395 |  | 
 | 396 | static inline void | 
 | 397 | MULTI_set_gdt(struct multicall_entry *mcl, unsigned long *frames, int entries) | 
 | 398 | { | 
 | 399 | 	mcl->op = __HYPERVISOR_set_gdt; | 
 | 400 | 	mcl->args[0] = (unsigned long)frames; | 
 | 401 | 	mcl->args[1] = entries; | 
 | 402 | } | 
 | 403 |  | 
 | 404 | static inline void | 
 | 405 | MULTI_stack_switch(struct multicall_entry *mcl, | 
 | 406 | 		   unsigned long ss, unsigned long esp) | 
 | 407 | { | 
 | 408 | 	mcl->op = __HYPERVISOR_stack_switch; | 
 | 409 | 	mcl->args[0] = ss; | 
 | 410 | 	mcl->args[1] = esp; | 
 | 411 | } | 
 | 412 |  | 
| Jeremy Fitzhardinge | a42089d | 2007-07-17 18:37:04 -0700 | [diff] [blame] | 413 | #endif /* __HYPERCALL_H__ */ |