[S390] virtualization aware cpu measurement

Use the SPP instruction to set a tag on entry to / exit of the virtual
machine context. This allows the cpu measurement facility to distinguish
the samples from the host and the different guests.

Signed-off-by: Carsten Otte <cotte@de.ibm.com>
This commit is contained in:
Carsten Otte 2010-05-17 10:00:04 +02:00 committed by Martin Schwidefsky
parent 6377981faf
commit cd3b70f5d4
8 changed files with 105 additions and 26 deletions

View File

@ -267,7 +267,8 @@ struct _lowcore {
__u64 vdso_per_cpu_data; /* 0x0358 */ __u64 vdso_per_cpu_data; /* 0x0358 */
__u64 machine_flags; /* 0x0360 */ __u64 machine_flags; /* 0x0360 */
__u64 ftrace_func; /* 0x0368 */ __u64 ftrace_func; /* 0x0368 */
__u8 pad_0x0370[0x0380-0x0370]; /* 0x0370 */ __u64 sie_hook; /* 0x0370 */
__u64 cmf_hpp; /* 0x0378 */
/* Interrupt response block. */ /* Interrupt response block. */
__u8 irb[64]; /* 0x0380 */ __u8 irb[64]; /* 0x0380 */

View File

@ -2,7 +2,7 @@
* include/asm-s390/setup.h * include/asm-s390/setup.h
* *
* S390 version * S390 version
* Copyright IBM Corp. 1999,2006 * Copyright IBM Corp. 1999,2010
*/ */
#ifndef _ASM_S390_SETUP_H #ifndef _ASM_S390_SETUP_H
@ -72,6 +72,7 @@ extern unsigned int user_mode;
#define MACHINE_FLAG_HPAGE (1UL << 10) #define MACHINE_FLAG_HPAGE (1UL << 10)
#define MACHINE_FLAG_PFMF (1UL << 11) #define MACHINE_FLAG_PFMF (1UL << 11)
#define MACHINE_FLAG_LPAR (1UL << 12) #define MACHINE_FLAG_LPAR (1UL << 12)
#define MACHINE_FLAG_SPP (1UL << 13)
#define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM)
#define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM) #define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM)
@ -88,6 +89,7 @@ extern unsigned int user_mode;
#define MACHINE_HAS_MVCOS (0) #define MACHINE_HAS_MVCOS (0)
#define MACHINE_HAS_HPAGE (0) #define MACHINE_HAS_HPAGE (0)
#define MACHINE_HAS_PFMF (0) #define MACHINE_HAS_PFMF (0)
#define MACHINE_HAS_SPP (0)
#else /* __s390x__ */ #else /* __s390x__ */
#define MACHINE_HAS_IEEE (1) #define MACHINE_HAS_IEEE (1)
#define MACHINE_HAS_CSP (1) #define MACHINE_HAS_CSP (1)
@ -97,6 +99,7 @@ extern unsigned int user_mode;
#define MACHINE_HAS_MVCOS (S390_lowcore.machine_flags & MACHINE_FLAG_MVCOS) #define MACHINE_HAS_MVCOS (S390_lowcore.machine_flags & MACHINE_FLAG_MVCOS)
#define MACHINE_HAS_HPAGE (S390_lowcore.machine_flags & MACHINE_FLAG_HPAGE) #define MACHINE_HAS_HPAGE (S390_lowcore.machine_flags & MACHINE_FLAG_HPAGE)
#define MACHINE_HAS_PFMF (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF) #define MACHINE_HAS_PFMF (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF)
#define MACHINE_HAS_SPP (S390_lowcore.machine_flags & MACHINE_FLAG_SPP)
#endif /* __s390x__ */ #endif /* __s390x__ */
#define ZFCPDUMP_HSA_SIZE (32UL<<20) #define ZFCPDUMP_HSA_SIZE (32UL<<20)

View File

@ -131,6 +131,8 @@ int main(void)
DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags));
DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func)); DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func));
DEFINE(__LC_SIE_HOOK, offsetof(struct _lowcore, sie_hook));
DEFINE(__LC_CMF_HPP, offsetof(struct _lowcore, cmf_hpp));
DEFINE(__LC_IRB, offsetof(struct _lowcore, irb)); DEFINE(__LC_IRB, offsetof(struct _lowcore, irb));
DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area)); DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area));
DEFINE(__LC_CLOCK_COMP_SAVE_AREA, offsetof(struct _lowcore, clock_comp_save_area)); DEFINE(__LC_CLOCK_COMP_SAVE_AREA, offsetof(struct _lowcore, clock_comp_save_area));

View File

@ -356,6 +356,7 @@ static __init void detect_machine_facilities(void)
{ {
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
unsigned int facilities; unsigned int facilities;
unsigned long long facility_bits;
facilities = stfl(); facilities = stfl();
if (facilities & (1 << 28)) if (facilities & (1 << 28))
@ -364,6 +365,9 @@ static __init void detect_machine_facilities(void)
S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF; S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF;
if (facilities & (1 << 4)) if (facilities & (1 << 4))
S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS; S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
if ((stfle(&facility_bits, 1) > 0) &&
(facility_bits & (1ULL << (63 - 40))))
S390_lowcore.machine_flags |= MACHINE_FLAG_SPP;
#endif #endif
} }

View File

@ -2,7 +2,7 @@
* arch/s390/kernel/entry64.S * arch/s390/kernel/entry64.S
* S390 low-level entry points. * S390 low-level entry points.
* *
* Copyright (C) IBM Corp. 1999,2006 * Copyright (C) IBM Corp. 1999,2010
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
* Hartmut Penner (hp@de.ibm.com), * Hartmut Penner (hp@de.ibm.com),
* Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
@ -59,6 +59,16 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
#define BASED(name) name-system_call(%r13) #define BASED(name) name-system_call(%r13)
.macro HANDLE_SIE_INTERCEPT
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
lg %r3,__LC_SIE_HOOK
ltgr %r3,%r3
jz 0f
basr %r14,%r3
0:
#endif
.endm
#ifdef CONFIG_TRACE_IRQFLAGS #ifdef CONFIG_TRACE_IRQFLAGS
.macro TRACE_IRQS_ON .macro TRACE_IRQS_ON
basr %r2,%r0 basr %r2,%r0
@ -466,6 +476,7 @@ pgm_check_handler:
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
pgm_no_vtime: pgm_no_vtime:
HANDLE_SIE_INTERCEPT
TRACE_IRQS_CHECK_OFF TRACE_IRQS_CHECK_OFF
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
mvc SP_ARGS(8,%r15),__LC_LAST_BREAK mvc SP_ARGS(8,%r15),__LC_LAST_BREAK
@ -507,6 +518,7 @@ pgm_per_std:
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
pgm_no_vtime2: pgm_no_vtime2:
HANDLE_SIE_INTERCEPT
TRACE_IRQS_CHECK_OFF TRACE_IRQS_CHECK_OFF
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
lg %r1,__TI_task(%r9) lg %r1,__TI_task(%r9)
@ -570,6 +582,7 @@ io_int_handler:
mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
io_no_vtime: io_no_vtime:
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
HANDLE_SIE_INTERCEPT
TRACE_IRQS_OFF TRACE_IRQS_OFF
la %r2,SP_PTREGS(%r15) # address of register-save area la %r2,SP_PTREGS(%r15) # address of register-save area
brasl %r14,do_IRQ # call standard irq handler brasl %r14,do_IRQ # call standard irq handler
@ -595,15 +608,6 @@ io_done:
io_work: io_work:
tm SP_PSW+1(%r15),0x01 # returning to user ? tm SP_PSW+1(%r15),0x01 # returning to user ?
jo io_work_user # yes -> do resched & signal jo io_work_user # yes -> do resched & signal
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
lg %r2,SP_PSW+8(%r15) # check if current instruction is SIE
lh %r1,0(%r2)
chi %r1,-19948 # signed 16 bit compare with 0xb214
jne 0f # no -> leave PSW alone
aghi %r2,4 # yes-> add 4 bytes to leave SIE
stg %r2,SP_PSW+8(%r15)
0:
#endif
#ifdef CONFIG_PREEMPT #ifdef CONFIG_PREEMPT
# check for preemptive scheduling # check for preemptive scheduling
icm %r0,15,__TI_precount(%r9) icm %r0,15,__TI_precount(%r9)
@ -712,6 +716,7 @@ ext_int_handler:
mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
ext_no_vtime: ext_no_vtime:
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
HANDLE_SIE_INTERCEPT
TRACE_IRQS_OFF TRACE_IRQS_OFF
la %r2,SP_PTREGS(%r15) # address of register-save area la %r2,SP_PTREGS(%r15) # address of register-save area
llgh %r3,__LC_EXT_INT_CODE # get interruption code llgh %r3,__LC_EXT_INT_CODE # get interruption code
@ -786,6 +791,7 @@ mcck_no_vtime:
stosm __SF_EMPTY(%r15),0x04 # turn dat on stosm __SF_EMPTY(%r15),0x04 # turn dat on
tm __TI_flags+7(%r9),_TIF_MCCK_PENDING tm __TI_flags+7(%r9),_TIF_MCCK_PENDING
jno mcck_return jno mcck_return
HANDLE_SIE_INTERCEPT
TRACE_IRQS_OFF TRACE_IRQS_OFF
brasl %r14,s390_handle_mcck brasl %r14,s390_handle_mcck
TRACE_IRQS_ON TRACE_IRQS_ON

View File

@ -2,7 +2,7 @@
* arch/s390/kernel/setup.c * arch/s390/kernel/setup.c
* *
* S390 version * S390 version
* Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Copyright (C) IBM Corp. 1999,2010
* Author(s): Hartmut Penner (hp@de.ibm.com), * Author(s): Hartmut Penner (hp@de.ibm.com),
* Martin Schwidefsky (schwidefsky@de.ibm.com) * Martin Schwidefsky (schwidefsky@de.ibm.com)
* *
@ -401,6 +401,7 @@ setup_lowcore(void)
lc->io_new_psw.mask = psw_kernel_bits; lc->io_new_psw.mask = psw_kernel_bits;
lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
lc->clock_comparator = -1ULL; lc->clock_comparator = -1ULL;
lc->cmf_hpp = -1ULL;
lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE; lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
lc->async_stack = (unsigned long) lc->async_stack = (unsigned long)
__alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE; __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;

View File

@ -33,6 +33,17 @@ config KVM
If unsure, say N. If unsure, say N.
config KVM_AWARE_CMF
depends on KVM
bool "KVM aware sampling"
---help---
This option enhances the sampling data from the CPU Measurement
Facility with additional information, that allows to distinguish
guest(s) and host when using the kernel based virtual machine
functionality.
If unsure, say N.
# OK, it's a little counter-intuitive to do this, but it puts it neatly under # OK, it's a little counter-intuitive to do this, but it puts it neatly under
# the virtualization menu. # the virtualization menu.
source drivers/vhost/Kconfig source drivers/vhost/Kconfig

View File

@ -1,20 +1,60 @@
/* /*
* sie64a.S - low level sie call * sie64a.S - low level sie call
* *
* Copyright IBM Corp. 2008 * Copyright IBM Corp. 2008,2010
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2 only) * it under the terms of the GNU General Public License (version 2 only)
* as published by the Free Software Foundation. * as published by the Free Software Foundation.
* *
* Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
* Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <asm/asm-offsets.h> #include <asm/asm-offsets.h>
#include <asm/setup.h>
#include <asm/asm-offsets.h>
#include <asm/ptrace.h>
#include <asm/thread_info.h>
SP_R5 = 5 * 8 # offset into stackframe _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
SP_R6 = 6 * 8
/*
* offsets into stackframe
* SP_ = offsets into stack sie64 is called with
* SPI_ = offsets into irq stack
*/
SP_GREGS = __SF_EMPTY
SP_HOOK = __SF_EMPTY+8
SP_GPP = __SF_EMPTY+16
SPI_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
.macro SPP newpp
#ifdef CONFIG_KVM_AWARE_CMF
tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_SPP
jz 0f
.insn s,0xb2800000,\newpp
0:
#endif
.endm
sie_irq_handler:
SPP __LC_CMF_HPP # set host id
larl %r2,sie_inst
clg %r2,SPI_PSW+8(0,%r15) # intercepted sie
jne 1f
xc __LC_SIE_HOOK(8),__LC_SIE_HOOK
lg %r2,__LC_THREAD_INFO # pointer thread_info struct
tm __TI_flags+7(%r2),_TIF_EXIT_SIE
jz 0f
larl %r2,sie_exit # work pending, leave sie
stg %r2,__LC_RETURN_PSW+8
br %r14
0: larl %r2,sie_reenter # re-enter with guest id
stg %r2,__LC_RETURN_PSW+8
1: br %r14
/* /*
* sie64a calling convention: * sie64a calling convention:
@ -23,23 +63,34 @@ SP_R6 = 6 * 8
*/ */
.globl sie64a .globl sie64a
sie64a: sie64a:
lgr %r5,%r3 stg %r3,SP_GREGS(%r15) # save guest register save area
stmg %r5,%r14,SP_R5(%r15) # save register on entry stmg %r6,%r14,__SF_GPRS(%r15) # save registers on entry
lgr %r14,%r2 # pointer to sie control block lgr %r14,%r2 # pointer to sie control block
larl %r5,sie_irq_handler
stg %r2,SP_GPP(%r15)
stg %r5,SP_HOOK(%r15) # save hook target
lmg %r0,%r13,0(%r3) # load guest gprs 0-13 lmg %r0,%r13,0(%r3) # load guest gprs 0-13
sie_reenter:
mvc __LC_SIE_HOOK(8),SP_HOOK(%r15)
SPP SP_GPP(%r15) # set guest id
sie_inst: sie_inst:
sie 0(%r14) sie 0(%r14)
lg %r14,SP_R5(%r15) xc __LC_SIE_HOOK(8),__LC_SIE_HOOK
SPP __LC_CMF_HPP # set host id
sie_exit:
lg %r14,SP_GREGS(%r15)
stmg %r0,%r13,0(%r14) # save guest gprs 0-13 stmg %r0,%r13,0(%r14) # save guest gprs 0-13
lghi %r2,0 lghi %r2,0
lmg %r6,%r14,SP_R6(%r15) lmg %r6,%r14,__SF_GPRS(%r15)
br %r14 br %r14
sie_err: sie_err:
lg %r14,SP_R5(%r15) xc __LC_SIE_HOOK(8),__LC_SIE_HOOK
SPP __LC_CMF_HPP # set host id
lg %r14,SP_GREGS(%r15)
stmg %r0,%r13,0(%r14) # save guest gprs 0-13 stmg %r0,%r13,0(%r14) # save guest gprs 0-13
lghi %r2,-EFAULT lghi %r2,-EFAULT
lmg %r6,%r14,SP_R6(%r15) lmg %r6,%r14,__SF_GPRS(%r15)
br %r14 br %r14
.section __ex_table,"a" .section __ex_table,"a"