2010-05-07 23:57:28 +00:00
|
|
|
#ifndef _ASM_X86_MSHYPER_H
|
|
|
|
#define _ASM_X86_MSHYPER_H
|
2010-05-06 19:08:41 +00:00
|
|
|
|
2010-05-07 23:57:28 +00:00
|
|
|
#include <linux/types.h>
|
2017-06-23 08:50:38 +00:00
|
|
|
#include <linux/atomic.h>
|
2010-05-07 23:57:28 +00:00
|
|
|
#include <asm/hyperv.h>
|
|
|
|
|
2017-01-19 18:51:47 +00:00
|
|
|
/*
|
|
|
|
* The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
|
|
|
|
* is set by CPUID(HVCPUID_VERSION_FEATURES).
|
|
|
|
*/
|
|
|
|
enum hv_cpuid_function {
|
|
|
|
HVCPUID_VERSION_FEATURES = 0x00000001,
|
|
|
|
HVCPUID_VENDOR_MAXFUNCTION = 0x40000000,
|
|
|
|
HVCPUID_INTERFACE = 0x40000001,
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The remaining functions depend on the value of
|
|
|
|
* HVCPUID_INTERFACE
|
|
|
|
*/
|
|
|
|
HVCPUID_VERSION = 0x40000002,
|
|
|
|
HVCPUID_FEATURES = 0x40000003,
|
|
|
|
HVCPUID_ENLIGHTENMENT_INFO = 0x40000004,
|
|
|
|
HVCPUID_IMPLEMENTATION_LIMITS = 0x40000005,
|
|
|
|
};
|
|
|
|
|
2010-05-07 23:57:28 +00:00
|
|
|
struct ms_hyperv_info {
|
|
|
|
u32 features;
|
2015-08-01 23:08:20 +00:00
|
|
|
u32 misc_features;
|
2010-05-07 23:57:28 +00:00
|
|
|
u32 hints;
|
|
|
|
};
|
|
|
|
|
|
|
|
extern struct ms_hyperv_info ms_hyperv;
|
2010-05-06 19:08:41 +00:00
|
|
|
|
2017-01-18 23:45:00 +00:00
|
|
|
/*
|
|
|
|
* Declare the MSR used to setup pages used to communicate with the hypervisor.
|
|
|
|
*/
|
|
|
|
union hv_x64_msr_hypercall_contents {
|
|
|
|
u64 as_uint64;
|
|
|
|
struct {
|
|
|
|
u64 enable:1;
|
|
|
|
u64 reserved:11;
|
|
|
|
u64 guest_physical_address:52;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2017-01-19 18:51:46 +00:00
|
|
|
/*
|
|
|
|
* TSC page layout.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct ms_hyperv_tsc_page {
|
|
|
|
volatile u32 tsc_sequence;
|
|
|
|
u32 reserved1;
|
|
|
|
volatile u64 tsc_scale;
|
|
|
|
volatile s64 tsc_offset;
|
|
|
|
u64 reserved2[509];
|
|
|
|
};
|
|
|
|
|
2017-01-18 23:45:01 +00:00
|
|
|
/*
|
|
|
|
* The guest OS needs to register the guest ID with the hypervisor.
|
|
|
|
* The guest ID is a 64 bit entity and the structure of this ID is
|
|
|
|
* specified in the Hyper-V specification:
|
|
|
|
*
|
|
|
|
* msdn.microsoft.com/en-us/library/windows/hardware/ff542653%28v=vs.85%29.aspx
|
|
|
|
*
|
|
|
|
* While the current guideline does not specify how Linux guest ID(s)
|
|
|
|
* need to be generated, our plan is to publish the guidelines for
|
|
|
|
* Linux and other guest operating systems that currently are hosted
|
|
|
|
* on Hyper-V. The implementation here conforms to this yet
|
|
|
|
* unpublished guidelines.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Bit(s)
|
|
|
|
* 63 - Indicates if the OS is Open Source or not; 1 is Open Source
|
|
|
|
* 62:56 - Os Type; Linux is 0x100
|
|
|
|
* 55:48 - Distro specific identification
|
|
|
|
* 47:16 - Linux kernel version number
|
|
|
|
* 15:0 - Distro specific identification
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2017-02-04 15:46:23 +00:00
|
|
|
#define HV_LINUX_VENDOR_ID 0x8100
|
2017-01-18 23:45:01 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Generate the guest ID based on the guideline described above.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static inline __u64 generate_guest_id(__u64 d_info1, __u64 kernel_version,
|
|
|
|
__u64 d_info2)
|
|
|
|
{
|
|
|
|
__u64 guest_id = 0;
|
|
|
|
|
2017-02-04 15:46:23 +00:00
|
|
|
guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48);
|
2017-01-18 23:45:01 +00:00
|
|
|
guest_id |= (d_info1 << 48);
|
|
|
|
guest_id |= (kernel_version << 16);
|
|
|
|
guest_id |= d_info2;
|
|
|
|
|
|
|
|
return guest_id;
|
|
|
|
}
|
|
|
|
|
2017-01-19 18:51:50 +00:00
|
|
|
|
|
|
|
/* Free the message slot and signal end-of-message if required */
|
|
|
|
static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* On crash we're reading some other CPU's message page and we need
|
|
|
|
* to be careful: this other CPU may already had cleared the header
|
|
|
|
* and the host may already had delivered some other message there.
|
|
|
|
* In case we blindly write msg->header.message_type we're going
|
|
|
|
* to lose it. We can still lose a message of the same type but
|
|
|
|
* we count on the fact that there can only be one
|
|
|
|
* CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages
|
|
|
|
* on crash.
|
|
|
|
*/
|
|
|
|
if (cmpxchg(&msg->header.message_type, old_msg_type,
|
|
|
|
HVMSG_NONE) != old_msg_type)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure the write to MessageType (ie set to
|
|
|
|
* HVMSG_NONE) happens before we read the
|
|
|
|
* MessagePending and EOMing. Otherwise, the EOMing
|
|
|
|
* will not deliver any more messages since there is
|
|
|
|
* no empty slot
|
|
|
|
*/
|
|
|
|
mb();
|
|
|
|
|
|
|
|
if (msg->header.message_flags.msg_pending) {
|
|
|
|
/*
|
|
|
|
* This will cause message queue rescan to
|
|
|
|
* possibly deliver another msg from the
|
|
|
|
* hypervisor
|
|
|
|
*/
|
|
|
|
wrmsrl(HV_X64_MSR_EOM, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-19 18:51:51 +00:00
|
|
|
#define hv_init_timer(timer, tick) wrmsrl(timer, tick)
|
|
|
|
#define hv_init_timer_config(config, val) wrmsrl(config, val)
|
|
|
|
|
2017-01-19 18:51:54 +00:00
|
|
|
#define hv_get_simp(val) rdmsrl(HV_X64_MSR_SIMP, val)
|
|
|
|
#define hv_set_simp(val) wrmsrl(HV_X64_MSR_SIMP, val)
|
|
|
|
|
2017-01-19 18:51:55 +00:00
|
|
|
#define hv_get_siefp(val) rdmsrl(HV_X64_MSR_SIEFP, val)
|
|
|
|
#define hv_set_siefp(val) wrmsrl(HV_X64_MSR_SIEFP, val)
|
|
|
|
|
2017-01-19 18:51:56 +00:00
|
|
|
#define hv_get_synic_state(val) rdmsrl(HV_X64_MSR_SCONTROL, val)
|
|
|
|
#define hv_set_synic_state(val) wrmsrl(HV_X64_MSR_SCONTROL, val)
|
|
|
|
|
2017-01-19 18:51:57 +00:00
|
|
|
#define hv_get_vp_index(index) rdmsrl(HV_X64_MSR_VP_INDEX, index)
|
|
|
|
|
2017-01-19 18:51:58 +00:00
|
|
|
#define hv_get_synint_state(int_num, val) rdmsrl(int_num, val)
|
|
|
|
#define hv_set_synint_state(int_num, val) wrmsrl(int_num, val)
|
|
|
|
|
2013-02-04 01:22:39 +00:00
|
|
|
void hyperv_callback_vector(void);
|
x86, trace: Add irq vector tracepoints
[Purpose of this patch]
As Vaibhav explained in the thread below, tracepoints for irq vectors
are useful.
http://www.spinics.net/lists/mm-commits/msg85707.html
<snip>
The current interrupt traces from irq_handler_entry and irq_handler_exit
provide when an interrupt is handled. They provide good data about when
the system has switched to kernel space and how it affects the currently
running processes.
There are some IRQ vectors which trigger the system into kernel space,
which are not handled in generic IRQ handlers. Tracing such events gives
us the information about IRQ interaction with other system events.
The trace also tells where the system is spending its time. We want to
know which cores are handling interrupts and how they are affecting other
processes in the system. Also, the trace provides information about when
the cores are idle and which interrupts are changing that state.
<snip>
On the other hand, my usecase is tracing just local timer event and
getting a value of instruction pointer.
I suggested to add an argument local timer event to get instruction pointer before.
But there is another way to get it with external module like systemtap.
So, I don't need to add any argument to irq vector tracepoints now.
[Patch Description]
Vaibhav's patch shared a trace point ,irq_vector_entry/irq_vector_exit, in all events.
But there is an above use case to trace specific irq_vector rather than tracing all events.
In this case, we are concerned about overhead due to unwanted events.
So, add following tracepoints instead of introducing irq_vector_entry/exit.
so that we can enable them independently.
- local_timer_vector
- reschedule_vector
- call_function_vector
- call_function_single_vector
- irq_work_entry_vector
- error_apic_vector
- thermal_apic_vector
- threshold_apic_vector
- spurious_apic_vector
- x86_platform_ipi_vector
Also, introduce a logic switching IDT at enabling/disabling time so that a time penalty
makes a zero when tracepoints are disabled. Detailed explanations are as follows.
- Create trace irq handlers with entering_irq()/exiting_irq().
- Create a new IDT, trace_idt_table, at boot time by adding a logic to
_set_gate(). It is just a copy of original idt table.
- Register the new handlers for tracpoints to the new IDT by introducing
macros to alloc_intr_gate() called at registering time of irq_vector handlers.
- Add checking, whether irq vector tracing is on/off, into load_current_idt().
This has to be done below debug checking for these reasons.
- Switching to debug IDT may be kicked while tracing is enabled.
- On the other hands, switching to trace IDT is kicked only when debugging
is disabled.
In addition, the new IDT is created only when CONFIG_TRACING is enabled to avoid being
used for other purposes.
Signed-off-by: Seiji Aguchi <seiji.aguchi@hds.com>
Link: http://lkml.kernel.org/r/51C323ED.5050708@hds.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
2013-06-20 15:46:53 +00:00
|
|
|
#ifdef CONFIG_TRACING
|
|
|
|
#define trace_hyperv_callback_vector hyperv_callback_vector
|
|
|
|
#endif
|
2013-02-04 01:22:39 +00:00
|
|
|
void hyperv_vector_handler(struct pt_regs *regs);
|
2014-03-05 12:42:14 +00:00
|
|
|
void hv_setup_vmbus_irq(void (*handler)(void));
|
|
|
|
void hv_remove_vmbus_irq(void);
|
2013-02-04 01:22:39 +00:00
|
|
|
|
2015-08-01 23:08:07 +00:00
|
|
|
void hv_setup_kexec_handler(void (*handler)(void));
|
|
|
|
void hv_remove_kexec_handler(void);
|
2015-08-01 23:08:09 +00:00
|
|
|
void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs));
|
|
|
|
void hv_remove_crash_handler(void);
|
2017-01-18 23:45:02 +00:00
|
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_HYPERV)
|
2017-02-04 16:57:13 +00:00
|
|
|
extern struct clocksource *hyperv_cs;
|
|
|
|
|
2017-01-18 23:45:02 +00:00
|
|
|
void hyperv_init(void);
|
2017-01-19 18:51:48 +00:00
|
|
|
void hyperv_report_panic(struct pt_regs *regs);
|
2017-01-19 18:51:49 +00:00
|
|
|
bool hv_is_hypercall_page_setup(void);
|
2017-01-28 19:37:14 +00:00
|
|
|
void hyperv_cleanup(void);
|
2017-01-18 23:45:02 +00:00
|
|
|
#endif
|
2017-03-03 13:21:40 +00:00
|
|
|
#ifdef CONFIG_HYPERV_TSCPAGE
|
|
|
|
struct ms_hyperv_tsc_page *hv_get_tsc_page(void);
|
2017-03-03 13:21:41 +00:00
|
|
|
static inline u64 hv_read_tsc_page(const struct ms_hyperv_tsc_page *tsc_pg)
|
|
|
|
{
|
|
|
|
u64 scale, offset, cur_tsc;
|
|
|
|
u32 sequence;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The protocol for reading Hyper-V TSC page is specified in Hypervisor
|
|
|
|
* Top-Level Functional Specification ver. 3.0 and above. To get the
|
|
|
|
* reference time we must do the following:
|
|
|
|
* - READ ReferenceTscSequence
|
|
|
|
* A special '0' value indicates the time source is unreliable and we
|
|
|
|
* need to use something else. The currently published specification
|
|
|
|
* versions (up to 4.0b) contain a mistake and wrongly claim '-1'
|
|
|
|
* instead of '0' as the special value, see commit c35b82ef0294.
|
|
|
|
* - ReferenceTime =
|
|
|
|
* ((RDTSC() * ReferenceTscScale) >> 64) + ReferenceTscOffset
|
|
|
|
* - READ ReferenceTscSequence again. In case its value has changed
|
|
|
|
* since our first reading we need to discard ReferenceTime and repeat
|
|
|
|
* the whole sequence as the hypervisor was updating the page in
|
|
|
|
* between.
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
sequence = READ_ONCE(tsc_pg->tsc_sequence);
|
|
|
|
if (!sequence)
|
|
|
|
return U64_MAX;
|
|
|
|
/*
|
|
|
|
* Make sure we read sequence before we read other values from
|
|
|
|
* TSC page.
|
|
|
|
*/
|
|
|
|
smp_rmb();
|
|
|
|
|
|
|
|
scale = READ_ONCE(tsc_pg->tsc_scale);
|
|
|
|
offset = READ_ONCE(tsc_pg->tsc_offset);
|
|
|
|
cur_tsc = rdtsc_ordered();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure we read sequence after we read all other values
|
|
|
|
* from TSC page.
|
|
|
|
*/
|
|
|
|
smp_rmb();
|
|
|
|
|
|
|
|
} while (READ_ONCE(tsc_pg->tsc_sequence) != sequence);
|
|
|
|
|
|
|
|
return mul_u64_u64_shr(cur_tsc, scale, 64) + offset;
|
|
|
|
}
|
|
|
|
|
2017-03-03 13:21:40 +00:00
|
|
|
#else
|
|
|
|
static inline struct ms_hyperv_tsc_page *hv_get_tsc_page(void)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
2010-05-06 19:08:41 +00:00
|
|
|
#endif
|