kvm_host.h 16.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 * kvm_host.h: used for kvm module, and hold ia64-specific sections.
 *
 * Copyright (C) 2007, Intel Corporation.
 *
 * Xiantao Zhang <xiantao.zhang@intel.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307 USA.
 *
 */

#ifndef __ASM_KVM_HOST_H
#define __ASM_KVM_HOST_H

#define KVM_MEMORY_SLOTS 32
/* memory slots that does not exposed to userspace */
#define KVM_PRIVATE_MEM_SLOTS 4

30
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
31 32 33 34 35 36 37 38 39 40 41

/* define exit reasons from vmm to kvm*/
#define EXIT_REASON_VM_PANIC		0
#define EXIT_REASON_MMIO_INSTRUCTION	1
#define EXIT_REASON_PAL_CALL		2
#define EXIT_REASON_SAL_CALL		3
#define EXIT_REASON_SWITCH_RR6		4
#define EXIT_REASON_VM_DESTROY		5
#define EXIT_REASON_EXTERNAL_INTERRUPT	6
#define EXIT_REASON_IPI			7
#define EXIT_REASON_PTC_G		8
42
#define EXIT_REASON_DEBUG		20
43 44

/*Define vmm address space and vm data space.*/
45
#define KVM_VMM_SIZE (__IA64_UL_CONST(16)<<20)
46
#define KVM_VMM_SHIFT 24
47 48
#define KVM_VMM_BASE 0xD000000000000000
#define VMM_SIZE (__IA64_UL_CONST(8)<<20)
49 50 51

/*
 * Define vm_buffer, used by PAL Services, base address.
52
 * Note: vm_buffer is in the VMM-BLOCK, the size must be < 8M
53 54
 */
#define KVM_VM_BUFFER_BASE (KVM_VMM_BASE + VMM_SIZE)
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
#define KVM_VM_BUFFER_SIZE (__IA64_UL_CONST(8)<<20)

/*
 * kvm guest's data area looks as follow:
 *
 *            +----------------------+	-------	KVM_VM_DATA_SIZE
 *	      |	    vcpu[n]'s data   |	 |     ___________________KVM_STK_OFFSET
 *     	      |			     |	 |    /			  |
 *     	      |	       ..........    |	 |   /vcpu's struct&stack |
 *     	      |	       ..........    |	 |  /---------------------|---- 0
 *	      |	    vcpu[5]'s data   |	 | /	   vpd		  |
 *	      |	    vcpu[4]'s data   |	 |/-----------------------|
 *	      |	    vcpu[3]'s data   |	 /	   vtlb		  |
 *	      |	    vcpu[2]'s data   |	/|------------------------|
 *	      |	    vcpu[1]'s data   |/  |	   vhpt		  |
 *	      |	    vcpu[0]'s data   |____________________________|
 *            +----------------------+	 |
 *	      |	   memory dirty log  |	 |
 *            +----------------------+	 |
 *	      |	   vm's data struct  |	 |
 *            +----------------------+	 |
 *	      |			     |	 |
 *	      |			     |	 |
 *	      |			     |	 |
 *	      |			     |	 |
 *	      |			     |	 |
 *	      |			     |	 |
 *	      |			     |	 |
 *	      |	  vm's p2m table  |	 |
 *	      |			     |	 |
 *            |			     |	 |
 *	      |			     |	 |  |
 * vm's data->|			     |   |  |
 *	      +----------------------+ ------- 0
 * To support large memory, needs to increase the size of p2m.
 * To support more vcpus, needs to ensure it has enough space to
 * hold vcpus' data.
 */

#define KVM_VM_DATA_SHIFT	26
#define KVM_VM_DATA_SIZE	(__IA64_UL_CONST(1) << KVM_VM_DATA_SHIFT)
#define KVM_VM_DATA_BASE	(KVM_VMM_BASE + KVM_VM_DATA_SIZE)

#define KVM_P2M_BASE		KVM_VM_DATA_BASE
#define KVM_P2M_SIZE		(__IA64_UL_CONST(24) << 20)

#define VHPT_SHIFT		16
#define VHPT_SIZE		(__IA64_UL_CONST(1) << VHPT_SHIFT)
#define VHPT_NUM_ENTRIES	(__IA64_UL_CONST(1) << (VHPT_SHIFT-5))

#define VTLB_SHIFT		16
#define VTLB_SIZE		(__IA64_UL_CONST(1) << VTLB_SHIFT)
#define VTLB_NUM_ENTRIES	(1UL << (VHPT_SHIFT-5))

#define VPD_SHIFT		16
#define VPD_SIZE		(__IA64_UL_CONST(1) << VPD_SHIFT)

#define VCPU_STRUCT_SHIFT	16
#define VCPU_STRUCT_SIZE	(__IA64_UL_CONST(1) << VCPU_STRUCT_SHIFT)

#define KVM_STK_OFFSET		VCPU_STRUCT_SIZE

#define KVM_VM_STRUCT_SHIFT	19
#define KVM_VM_STRUCT_SIZE	(__IA64_UL_CONST(1) << KVM_VM_STRUCT_SHIFT)

#define KVM_MEM_DIRY_LOG_SHIFT	19
#define KVM_MEM_DIRTY_LOG_SIZE (__IA64_UL_CONST(1) << KVM_MEM_DIRY_LOG_SHIFT)

#ifndef __ASSEMBLY__

/*Define the max vcpus and memory for Guests.*/
#define KVM_MAX_VCPUS	(KVM_VM_DATA_SIZE - KVM_P2M_SIZE - KVM_VM_STRUCT_SIZE -\
			KVM_MEM_DIRTY_LOG_SIZE) / sizeof(struct kvm_vcpu_data)
#define KVM_MAX_MEM_SIZE (KVM_P2M_SIZE >> 3 << PAGE_SHIFT)

130 131
#define VMM_LOG_LEN 256

132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/kvm.h>
#include <linux/kvm_para.h>
#include <linux/kvm_types.h>

#include <asm/pal.h>
#include <asm/sal.h>
#include <asm/page.h>

struct kvm_vcpu_data {
	char vcpu_vhpt[VHPT_SIZE];
	char vcpu_vtlb[VTLB_SIZE];
	char vcpu_vpd[VPD_SIZE];
	char vcpu_struct[VCPU_STRUCT_SIZE];
};

struct kvm_vm_data {
	char kvm_p2m[KVM_P2M_SIZE];
	char kvm_vm_struct[KVM_VM_STRUCT_SIZE];
	char kvm_mem_dirty_log[KVM_MEM_DIRTY_LOG_SIZE];
	struct kvm_vcpu_data vcpu_data[KVM_MAX_VCPUS];
};

#define VCPU_BASE(n)	KVM_VM_DATA_BASE + \
				offsetof(struct kvm_vm_data, vcpu_data[n])
#define VM_BASE		KVM_VM_DATA_BASE + \
				offsetof(struct kvm_vm_data, kvm_vm_struct)
#define KVM_MEM_DIRTY_LOG_BASE	KVM_VM_DATA_BASE + \
				offsetof(struct kvm_vm_data, kvm_mem_dirty_log)

#define VHPT_BASE(n) (VCPU_BASE(n) + offsetof(struct kvm_vcpu_data, vcpu_vhpt))
#define VTLB_BASE(n) (VCPU_BASE(n) + offsetof(struct kvm_vcpu_data, vcpu_vtlb))
#define VPD_BASE(n)  (VCPU_BASE(n) + offsetof(struct kvm_vcpu_data, vcpu_vpd))
#define VCPU_STRUCT_BASE(n)	(VCPU_BASE(n) + \
				offsetof(struct kvm_vcpu_data, vcpu_struct))
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185

/*IO section definitions*/
#define IOREQ_READ      1
#define IOREQ_WRITE     0

#define STATE_IOREQ_NONE        0
#define STATE_IOREQ_READY       1
#define STATE_IOREQ_INPROCESS   2
#define STATE_IORESP_READY      3

/*Guest Physical address layout.*/
#define GPFN_MEM        (0UL << 60) /* Guest pfn is normal mem */
#define GPFN_FRAME_BUFFER   (1UL << 60) /* VGA framebuffer */
#define GPFN_LOW_MMIO       (2UL << 60) /* Low MMIO range */
#define GPFN_PIB        (3UL << 60) /* PIB base */
#define GPFN_IOSAPIC        (4UL << 60) /* IOSAPIC base */
#define GPFN_LEGACY_IO      (5UL << 60) /* Legacy I/O base */
#define GPFN_GFW        (6UL << 60) /* Guest Firmware */
186
#define GPFN_PHYS_MMIO      (7UL << 60) /* Directed MMIO Range */
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372

#define GPFN_IO_MASK        (7UL << 60) /* Guest pfn is I/O type */
#define GPFN_INV_MASK       (1UL << 63) /* Guest pfn is invalid */
#define INVALID_MFN       (~0UL)
#define MEM_G   (1UL << 30)
#define MEM_M   (1UL << 20)
#define MMIO_START       (3 * MEM_G)
#define MMIO_SIZE        (512 * MEM_M)
#define VGA_IO_START     0xA0000UL
#define VGA_IO_SIZE      0x20000
#define LEGACY_IO_START  (MMIO_START + MMIO_SIZE)
#define LEGACY_IO_SIZE   (64 * MEM_M)
#define IO_SAPIC_START   0xfec00000UL
#define IO_SAPIC_SIZE    0x100000
#define PIB_START 0xfee00000UL
#define PIB_SIZE 0x200000
#define GFW_START        (4 * MEM_G - 16 * MEM_M)
#define GFW_SIZE         (16 * MEM_M)

/*Deliver mode, defined for ioapic.c*/
#define dest_Fixed IOSAPIC_FIXED
#define dest_LowestPrio IOSAPIC_LOWEST_PRIORITY

#define NMI_VECTOR      		2
#define ExtINT_VECTOR       		0
#define NULL_VECTOR     		(-1)
#define IA64_SPURIOUS_INT_VECTOR    	0x0f

#define VCPU_LID(v) (((u64)(v)->vcpu_id) << 24)

/*
 *Delivery mode
 */
#define SAPIC_DELIV_SHIFT      8
#define SAPIC_FIXED            0x0
#define SAPIC_LOWEST_PRIORITY  0x1
#define SAPIC_PMI              0x2
#define SAPIC_NMI              0x4
#define SAPIC_INIT             0x5
#define SAPIC_EXTINT           0x7

/*
 * vcpu->requests bit members for arch
 */
#define KVM_REQ_PTC_G		32
#define KVM_REQ_RESUME		33

#define KVM_PAGES_PER_HPAGE	1

struct kvm;
struct kvm_vcpu;
struct kvm_guest_debug{
};

struct kvm_mmio_req {
	uint64_t addr;          /*  physical address		*/
	uint64_t size;          /*  size in bytes		*/
	uint64_t data;          /*  data (or paddr of data)     */
	uint8_t state:4;
	uint8_t dir:1;          /*  1=read, 0=write             */
};

/*Pal data struct */
struct kvm_pal_call{
	/*In area*/
	uint64_t gr28;
	uint64_t gr29;
	uint64_t gr30;
	uint64_t gr31;
	/*Out area*/
	struct ia64_pal_retval ret;
};

/* Sal data structure */
struct kvm_sal_call{
	/*In area*/
	uint64_t in0;
	uint64_t in1;
	uint64_t in2;
	uint64_t in3;
	uint64_t in4;
	uint64_t in5;
	uint64_t in6;
	uint64_t in7;
	struct sal_ret_values ret;
};

/*Guest change rr6*/
struct kvm_switch_rr6 {
	uint64_t old_rr;
	uint64_t new_rr;
};

union ia64_ipi_a{
	unsigned long val;
	struct {
		unsigned long rv  : 3;
		unsigned long ir  : 1;
		unsigned long eid : 8;
		unsigned long id  : 8;
		unsigned long ib_base : 44;
	};
};

union ia64_ipi_d {
	unsigned long val;
	struct {
		unsigned long vector : 8;
		unsigned long dm  : 3;
		unsigned long ig  : 53;
	};
};

/*ipi check exit data*/
struct kvm_ipi_data{
	union ia64_ipi_a addr;
	union ia64_ipi_d data;
};

/*global purge data*/
struct kvm_ptc_g {
	unsigned long vaddr;
	unsigned long rr;
	unsigned long ps;
	struct kvm_vcpu *vcpu;
};

/*Exit control data */
struct exit_ctl_data{
	uint32_t exit_reason;
	uint32_t vm_status;
	union {
		struct kvm_mmio_req	ioreq;
		struct kvm_pal_call	pal_data;
		struct kvm_sal_call	sal_data;
		struct kvm_switch_rr6	rr_data;
		struct kvm_ipi_data	ipi_data;
		struct kvm_ptc_g	ptc_g_data;
	} u;
};

union pte_flags {
	unsigned long val;
	struct {
		unsigned long p    :  1; /*0      */
		unsigned long      :  1; /* 1     */
		unsigned long ma   :  3; /* 2-4   */
		unsigned long a    :  1; /* 5     */
		unsigned long d    :  1; /* 6     */
		unsigned long pl   :  2; /* 7-8   */
		unsigned long ar   :  3; /* 9-11  */
		unsigned long ppn  : 38; /* 12-49 */
		unsigned long      :  2; /* 50-51 */
		unsigned long ed   :  1; /* 52    */
	};
};

union ia64_pta {
	unsigned long val;
	struct {
		unsigned long ve : 1;
		unsigned long reserved0 : 1;
		unsigned long size : 6;
		unsigned long vf : 1;
		unsigned long reserved1 : 6;
		unsigned long base : 49;
	};
};

struct thash_cb {
	/* THASH base information */
	struct thash_data	*hash; /* hash table pointer */
	union ia64_pta		pta;
	int           num;
};

struct kvm_vcpu_stat {
};

struct kvm_vcpu_arch {
	int launched;
	int last_exit;
	int last_run_cpu;
	int vmm_tr_slot;
	int vm_tr_slot;

373 374 375 376
#define KVM_MP_STATE_RUNNABLE          0
#define KVM_MP_STATE_UNINITIALIZED     1
#define KVM_MP_STATE_INIT_RECEIVED     2
#define KVM_MP_STATE_HALTED            3
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
	int mp_state;

#define MAX_PTC_G_NUM			3
	int ptc_g_count;
	struct kvm_ptc_g ptc_g_data[MAX_PTC_G_NUM];

	/*halt timer to wake up sleepy vcpus*/
	struct hrtimer hlt_timer;
	long ht_active;

	struct kvm_lapic *apic;    /* kernel irqchip context */
	struct vpd *vpd;

	/* Exit data for vmm_transition*/
	struct exit_ctl_data exit_data;

	cpumask_t cache_coherent_map;

	unsigned long vmm_rr;
	unsigned long host_rr6;
	unsigned long psbits[8];
	unsigned long cr_iipa;
	unsigned long cr_isr;
	unsigned long vsa_base;
	unsigned long dirty_log_lock_pa;
	unsigned long __gp;
	/* TR and TC.  */
	struct thash_data itrs[NITRS];
	struct thash_data dtrs[NDTRS];
	/* Bit is set if there is a tr/tc for the region.  */
	unsigned char itr_regions;
	unsigned char dtr_regions;
	unsigned char tc_regions;
	/* purge all */
	unsigned long ptce_base;
	unsigned long ptce_count[2];
	unsigned long ptce_stride[2];
	/* itc/itm */
	unsigned long last_itc;
	long itc_offset;
	unsigned long itc_check;
	unsigned long timer_check;
419 420
	unsigned int timer_pending;
	unsigned int timer_fired;
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442

	unsigned long vrr[8];
	unsigned long ibr[8];
	unsigned long dbr[8];
	unsigned long insvc[4];		/* Interrupt in service.  */
	unsigned long xtp;

	unsigned long metaphysical_rr0; /* from kvm_arch (so is pinned) */
	unsigned long metaphysical_rr4;	/* from kvm_arch (so is pinned) */
	unsigned long metaphysical_saved_rr0; /* from kvm_arch          */
	unsigned long metaphysical_saved_rr4; /* from kvm_arch          */
	unsigned long fp_psr;       /*used for lazy float register */
	unsigned long saved_gp;
	/*for phycial  emulation */
	int mode_flags;
	struct thash_cb vtlb;
	struct thash_cb vhpt;
	char irq_check;
	char irq_new_pending;

	unsigned long opcode;
	unsigned long cause;
443
	char log_buf[VMM_LOG_LEN];
444 445 446 447 448 449 450 451 452 453 454 455 456 457
	union context host;
	union context guest;
};

struct kvm_vm_stat {
	u64 remote_tlb_flush;
};

struct kvm_sal_data {
	unsigned long boot_ip;
	unsigned long boot_gp;
};

struct kvm_arch {
458 459
	spinlock_t dirty_log_lock;

460 461 462 463
	unsigned long	vm_base;
	unsigned long	metaphysical_rr0;
	unsigned long	metaphysical_rr4;
	unsigned long	vmm_init_rr;
464

465 466 467
	struct kvm_ioapic *vioapic;
	struct kvm_vm_stat stat;
	struct kvm_sal_data rdv_sal_data;
468 469 470 471

	struct list_head assigned_dev_head;
	struct dmar_domain *intel_iommu_domain;
	struct hlist_head irq_ack_notifier_list;
472 473 474

	unsigned long irq_sources_bitmap;
	unsigned long irq_states[KVM_IOAPIC_NUM_PINS];
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
};

union cpuid3_t {
	u64 value;
	struct {
		u64 number : 8;
		u64 revision : 8;
		u64 model : 8;
		u64 family : 8;
		u64 archrev : 8;
		u64 rv : 24;
	};
};

struct kvm_pt_regs {
	/* The following registers are saved by SAVE_MIN: */
	unsigned long b6;  /* scratch */
	unsigned long b7;  /* scratch */

	unsigned long ar_csd; /* used by cmp8xchg16 (scratch) */
	unsigned long ar_ssd; /* reserved for future use (scratch) */

	unsigned long r8;  /* scratch (return value register 0) */
	unsigned long r9;  /* scratch (return value register 1) */
	unsigned long r10; /* scratch (return value register 2) */
	unsigned long r11; /* scratch (return value register 3) */

	unsigned long cr_ipsr; /* interrupted task's psr */
	unsigned long cr_iip;  /* interrupted task's instruction pointer */
	unsigned long cr_ifs;  /* interrupted task's function state */

	unsigned long ar_unat; /* interrupted task's NaT register (preserved) */
	unsigned long ar_pfs;  /* prev function state  */
	unsigned long ar_rsc;  /* RSE configuration */
	/* The following two are valid only if cr_ipsr.cpl > 0: */
	unsigned long ar_rnat;  /* RSE NaT */
	unsigned long ar_bspstore; /* RSE bspstore */

	unsigned long pr;  /* 64 predicate registers (1 bit each) */
	unsigned long b0;  /* return pointer (bp) */
	unsigned long loadrs;  /* size of dirty partition << 16 */

	unsigned long r1;  /* the gp pointer */
	unsigned long r12; /* interrupted task's memory stack pointer */
	unsigned long r13; /* thread pointer */

	unsigned long ar_fpsr;  /* floating point status (preserved) */
	unsigned long r15;  /* scratch */

	/* The remaining registers are NOT saved for system calls.  */
	unsigned long r14;  /* scratch */
	unsigned long r2;  /* scratch */
	unsigned long r3;  /* scratch */
	unsigned long r16;  /* scratch */
	unsigned long r17;  /* scratch */
	unsigned long r18;  /* scratch */
	unsigned long r19;  /* scratch */
	unsigned long r20;  /* scratch */
	unsigned long r21;  /* scratch */
	unsigned long r22;  /* scratch */
	unsigned long r23;  /* scratch */
	unsigned long r24;  /* scratch */
	unsigned long r25;  /* scratch */
	unsigned long r26;  /* scratch */
	unsigned long r27;  /* scratch */
	unsigned long r28;  /* scratch */
	unsigned long r29;  /* scratch */
	unsigned long r30;  /* scratch */
	unsigned long r31;  /* scratch */
	unsigned long ar_ccv;  /* compare/exchange value (scratch) */

	/*
	 * Floating point registers that the kernel considers scratch:
	 */
	struct ia64_fpreg f6;  /* scratch */
	struct ia64_fpreg f7;  /* scratch */
	struct ia64_fpreg f8;  /* scratch */
	struct ia64_fpreg f9;  /* scratch */
	struct ia64_fpreg f10;  /* scratch */
	struct ia64_fpreg f11;  /* scratch */

	unsigned long r4;  /* preserved */
	unsigned long r5;  /* preserved */
	unsigned long r6;  /* preserved */
	unsigned long r7;  /* preserved */
	unsigned long eml_unat;    /* used for emulating instruction */
	unsigned long pad0;     /* alignment pad */
};

static inline struct kvm_pt_regs *vcpu_regs(struct kvm_vcpu *v)
{
566
	return (struct kvm_pt_regs *) ((unsigned long) v + KVM_STK_OFFSET) - 1;
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
}

typedef int kvm_vmm_entry(void);
typedef void kvm_tramp_entry(union context *host, union context *guest);

struct kvm_vmm_info{
	struct module	*module;
	kvm_vmm_entry 	*vmm_entry;
	kvm_tramp_entry *tramp_entry;
	unsigned long 	vmm_ivt;
};

int kvm_highest_pending_irq(struct kvm_vcpu *vcpu);
int kvm_emulate_halt(struct kvm_vcpu *vcpu);
int kvm_pal_emul(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run);
void kvm_sal_emul(struct kvm_vcpu *vcpu);

584
static inline void kvm_inject_nmi(struct kvm_vcpu *vcpu) {}
585
#endif /* __ASSEMBLY__*/
586

587
#endif