Current File : //usr/share/src/uts/i86pc/sys/zvmm/zvmm_mach_hcall.h
/*
 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
 */

#ifndef _SYS_ZVMM_MACH_HCALL_H
#define	_SYS_ZVMM_MACH_HCALL_H

#include <sys/types.h>

#ifdef	__cplusplus
extern "C" {
#endif

/*
 * This is the argument used by the ZVCNTRL_START_CPU hypercall
 */
typedef struct zvg_start_cpu {
	ushort_t	zvg_which_cpu;
	ushort_t	zvg_idt_lim;
	ushort_t	zvg_gdt_lim;
	uint64_t	zvg_idt_base;
	uint64_t	zvg_gdt_base;
	uint64_t	zvg_gsbase;
	uint64_t	zvg_tss_base;
	uint64_t	zvg_stack;
	uint64_t	zvg_entry;
} zvg_start_cpu_t;


/*
 * zvmm passes initial info to the guest in this structure.
 * zvboot loader module is invoked with the following setup:
 *
 * full 64 bit paging mode, RAM (up to free_mem_start) is addressible
 * where virtual address == physical address.
 *
 * Since the Solaris kernel loads from 4Meg to just above 12Meg, the zvboot
 * loader program should avoid that address range.
 *
 * %rdi points to zv_boot_info, somewhere in mapped memory.
 * %rsp points to a large stack area, also in mapped memory.
 *
 * all memory above free_mem_start is available.
 */
typedef struct zv_boot_info {
	void		*zv_ramdisk_start;
	size_t		zv_ramdisk_size;
	void		*free_mem_start;	/* start of avail mem */
	struct boot_memlist	*zv_memlist;
	uint_t		zv_ncpu;
} zv_boot_info_t;

/*
 * Structure used to track pending interrupt numbers for zvpsm interrupts.
 *
 * On older guests we allocate and maintain this information inside the host
 * zvmm module. The guests determine which interrupt number to service at a
 * given PIL by using the ZVCNTRL_READ_PILQ hcall after taking an interrupt
 * at the given PIL's vector. The host code for that hypercall manages the
 * interrupt queues and handles any APIC end-of-interrupt processing.
 *
 * For newer guests on h/w with APIC virtualization the guest can avoid all
 * the hypercall overhead. The guest must identify memory to use for this
 * data structure (2 contiguous pages) for each VCPU with the ZVCNTRL_MAP_PILQ
 * hypercall on each VCPU before enabling interrupts on the VCPU. Then the
 * guest VCPUs can pull entries from a given VCPU PIL queue on its own. When
 * the guest VCPU empties the PIL queue it must cause APIC end-of-interrupt
 * processing. The guest does this with a wrmsr of 0 to the MSR returned
 * from the MAP_PILQ call. Note that that MSR will be the x2apic EOI MSR,
 * but no other actual configuration of the x2APIC in the guest is needed.
 *
 * Use ZVCNTRL_FEATURE to detect support for ZVCNTRL_MAP_PILQ. A given guest
 * should use only ZVCNTRL_READ_PILQ or ZVCNTRL_MAP_PILQ. As soon as one is
 * invoked the other other hcall becomes invalid within that guest.
 *
 * For correct operation, a guest *must* only ever change the ziq_next field by
 * incrementing it up to ziq_last as it consumes interrupts from the queue.
 * A value of 0xffff in ziq_q is used to mean "no interrupt". If the guest
 * finds this value it should skip to the next entry in the queue -- treating
 * it as a spurious interrupt. It is recommended that a guest write the 0xffff
 * value to each entry at ziq_next before incrementing ziq_next being careful
 * to observe write order (ie. use sfence).
 *
 * Note the structure reflects a single PIL. The 2 pages contain an array
 * of 14 of these. We only need 14, as vectors < 0x20 (which would be PIL 0 and
 * PIL 1) aren't used for interrupts on x86.
 */

/* get the pointer to a PIL's zv_int_queue_t */
#define	PIL_TO_ZIQ(base, pil)	(((zv_int_queue_t *)(base)) + (pil) - 2)

#define	ZV_NUM_PILQ	14

#define	ZIQ_EMPTY(q)		((q)->ziq_next == (q)->ziq_last)
#define	ZIQ_FULL(q)		((q)->ziq_last + 1 == (q)->ziq_next)

typedef struct zv_int_queue {
	volatile uint8_t ziq_next;	/* index of next to process */
	volatile uint8_t ziq_last;	/* index of last to process */
	uint8_t ziq_oflow;		/* flags that a new enqueue failed */
	uint8_t ziq_pad;
	uint16_t ziq_q[256];
} zv_int_queue_t;

/*
 * The array of zv_int_queue_t's must be stored across 2 pages. When it comes
 * from guest memory those pages must be contiguous and aligned so that they
 * are contiguous in host phys memory / kpm mappings.
 */
#define	ZV_INT_Q_SIZE	8192

#ifdef	__cplusplus
}
#endif

#endif	/* _SYS_ZVMM_MACH_HCALL_H */