Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/* Copyright (C) 2010 - 2015 UNISYS CORPORATION
 * All rights reserved.
 *
 * 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 that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
 * NON INFRINGEMENT.  See the GNU General Public License for more
 * details.
 */

#ifndef __IOMONINTF_H__
#define __IOMONINTF_H__

/*
* This file contains all structures needed to support the VMCALLs for IO
* Virtualization.  The VMCALLs are provided by Monitor and used by IO code
* running on IO Partitions.
*/
static inline unsigned long
__unisys_vmcall_gnuc(unsigned long tuple, unsigned long reg_ebx,
		     unsigned long reg_ecx)
{
	unsigned long result = 0;
	unsigned int cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx;

	cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx);
	if (!(cpuid_ecx & 0x80000000))
		return -EPERM;

	__asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) :
		"a"(tuple), "b"(reg_ebx), "c"(reg_ecx));
	return result;
}

static inline unsigned long
__unisys_extended_vmcall_gnuc(unsigned long long tuple,
			      unsigned long long reg_ebx,
			      unsigned long long reg_ecx,
			      unsigned long long reg_edx)
{
	unsigned long result = 0;
	unsigned int cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx;

	cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx);
	if (!(cpuid_ecx & 0x80000000))
		return -EPERM;

	__asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) :
		"a"(tuple), "b"(reg_ebx), "c"(reg_ecx), "d"(reg_edx));
	return result;
}

#ifdef VMCALL_IO_CONTROLVM_ADDR
#undef VMCALL_IO_CONTROLVM_ADDR
#endif	/*  */

/* define subsystem number for AppOS, used in uislib driver  */
#define MDS_APPOS 0x4000000000000000L	/* subsystem = 62 - AppOS */
enum vmcall_monitor_interface_method_tuple { /* VMCALL identification tuples  */
	    /* Note: when a new VMCALL is added:
	     * - the 1st 2 hex digits correspond to one of the
	     *   VMCALL_MONITOR_INTERFACE types and
	     * - the next 2 hex digits are the nth relative instance of within a
	     *   type
	     * E.G. for VMCALL_VIRTPART_RECYCLE_PART,
	     * - the 0x02 identifies it as a VMCALL_VIRTPART type and
	     * - the 0x01 identifies it as the 1st instance of a VMCALL_VIRTPART
	     *   type of VMCALL
	     */
	/* used by all Guests, not just IO */
	VMCALL_IO_CONTROLVM_ADDR = 0x0501,
	/* Allow caller to query virtual time offset */
	VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET = 0x0708,
	/* LOGEVENT Post Code (RDX) with specified subsystem mask */
	/* (RCX - monitor_subsystems.h) and severity (RDX) */
	VMCALL_POST_CODE_LOGEVENT = 0x070B,
	/* Allow ULTRA_SERVICE_CAPABILITY_TIME capable guest to make VMCALL */
	VMCALL_UPDATE_PHYSICAL_TIME = 0x0a02
};

#define VMCALL_SUCCESS 0
#define VMCALL_SUCCESSFUL(result)	(result == 0)

#define unisys_vmcall(tuple, reg_ebx, reg_ecx) \
	__unisys_vmcall_gnuc(tuple, reg_ebx, reg_ecx)
#define unisys_extended_vmcall(tuple, reg_ebx, reg_ecx, reg_edx) \
	__unisys_extended_vmcall_gnuc(tuple, reg_ebx, reg_ecx, reg_edx)
#define ISSUE_IO_VMCALL(method, param, result) \
	(result = unisys_vmcall(method, (param) & 0xFFFFFFFF,	\
				(param) >> 32))

/* Structures for IO VMCALLs */

/* Parameters to VMCALL_IO_CONTROLVM_ADDR interface */
struct vmcall_io_controlvm_addr_params {
	/* The Guest-relative physical address of the ControlVm channel. */
	/* This VMCall fills this in with the appropriate address. */
	u64 address;	/* contents provided by this VMCALL (OUT) */
	/* the size of the ControlVm channel in bytes This VMCall fills this */
	/* in with the appropriate address. */
	u32 channel_bytes;	/* contents provided by this VMCALL (OUT) */
	u8 unused[4];		/* Unused Bytes in the 64-Bit Aligned Struct */
} __packed;

/******* INFO ON ISSUE_POSTCODE_LINUX() BELOW *******/
enum driver_pc {		/* POSTCODE driver identifier tuples */
	/* visorbus driver files */
	VISOR_BUS_PC = 0xF0,
	VISOR_BUS_PC_visorbus_main_c = 0xFF,
	VISOR_BUS_PC_visorchipset_c = 0xFE,
};

enum event_pc {			/* POSTCODE event identifier tuples */
	BUS_CREATE_ENTRY_PC = 0x001,
	BUS_CREATE_FAILURE_PC = 0x002,
	BUS_CREATE_EXIT_PC = 0x003,
	BUS_CONFIGURE_ENTRY_PC = 0x004,
	BUS_CONFIGURE_FAILURE_PC = 0x005,
	BUS_CONFIGURE_EXIT_PC = 0x006,
	CHIPSET_INIT_ENTRY_PC = 0x007,
	CHIPSET_INIT_SUCCESS_PC = 0x008,
	CHIPSET_INIT_FAILURE_PC = 0x009,
	CHIPSET_INIT_EXIT_PC = 0x00A,
	CONTROLVM_INIT_FAILURE_PC = 0x00B,
	DEVICE_CREATE_ENTRY_PC = 0x00C,
	DEVICE_CREATE_FAILURE_PC = 0x00D,
	DEVICE_CREATE_SUCCESS_PC = 0x00E,
	DEVICE_CREATE_EXIT_PC = 0x00F,
	DEVICE_ADD_PC = 0x010,
	DEVICE_REGISTER_FAILURE_PC = 0x011,
	DEVICE_CHANGESTATE_FAILURE_PC = 0x012,
	DRIVER_ENTRY_PC = 0x013,
	DRIVER_EXIT_PC = 0x014,
	MALLOC_FAILURE_PC = 0x015,
	CRASH_DEV_ENTRY_PC = 0x016,
	CRASH_DEV_EXIT_PC = 0x017,
	CRASH_DEV_RD_BUS_FAILURE_PC = 0x018,
	CRASH_DEV_RD_DEV_FAILURE_PC = 0x019,
	CRASH_DEV_BUS_NULL_FAILURE_PC = 0x01A,
	CRASH_DEV_DEV_NULL_FAILURE_PC = 0x01B,
	CRASH_DEV_CTRL_RD_FAILURE_PC = 0x01C,
	CRASH_DEV_COUNT_FAILURE_PC = 0x01D,
	SAVE_MSG_BUS_FAILURE_PC = 0x01E,
	SAVE_MSG_DEV_FAILURE_PC = 0x01F,
};

/* Write a 64-bit value to the hypervisor's log file
 * POSTCODE_LINUX generates a value in the form 0xAABBBCCCDDDDEEEE where
 *	A is an identifier for the file logging the postcode
 *	B is an identifier for the event logging the postcode
 *	C is the line logging the postcode
 *	D is additional information the caller wants to log
 *	E is additional information the caller wants to log
 * Please also note that the resulting postcode is in hex, so if you are
 * searching for the __LINE__ number, convert it first to decimal.  The line
 * number combined with driver and type of call, will allow you to track down
 * exactly what line an error occurred on, or where the last driver
 * entered/exited from.
 */

#define POSTCODE_LINUX(EVENT_PC, pc16bit1, pc16bit2, severity)		\
do {									\
	unsigned long long post_code_temp;				\
	post_code_temp = (((u64)CURRENT_FILE_PC) << 56) |		\
		(((u64)EVENT_PC) << 44) |				\
		((((u64)__LINE__) & 0xFFF) << 32) |			\
		((((u64)pc16bit1) & 0xFFFF) << 16) |			\
		(((u64)pc16bit2) & 0xFFFF);				\
	unisys_extended_vmcall(VMCALL_POST_CODE_LOGEVENT, severity,     \
			       MDS_APPOS, post_code_temp);              \
} while (0)

#endif /* __IOMONINTF_H__ */