Commit 92e6ecf3 authored by Christian Borntraeger's avatar Christian Borntraeger Committed by Martin Schwidefsky
Browse files

[S390] Fix hypervisor detection for KVM

Currently we use the cpuid (via STIDP instruction) to recognize LPAR,
z/VM and KVM.
The architecture states, that bit 0-7 of STIDP returns all zero, and
if STIDP is executed in a virtual machine, the VM operating system
will replace bits 0-7 with FF.

KVM should not use FE to distinguish z/VM from KVM for interested
guests. The proper way to detect the hypervisor is the STSI (Store
System Information) instruction, which return information about the
hypervisors via function code 3, selector1=2, selector2=2.

This patch changes the detection routine of Linux to use STSI instead
of STIDP. This detection is earlier than bootmem, we have to use a
static buffer. Since STSI expects a 4kb block (4kb aligned) this
patch also changes the alignment for s390. As this section
will be freed during boot, this should be no problem.

Patch is tested with LPAR, z/VM, KVM on LPAR, and KVM under z/VM.
Signed-off-by: default avatarChristian Borntraeger <>
Signed-off-by: default avatarMartin Schwidefsky <>
parent 702d9e58
......@@ -100,6 +100,7 @@ struct sysinfo_3_2_2 {
char reserved_1[24];
} vm[8];
char reserved_544[3552];
static inline int stsi(void *sysinfo, int fc, int sel1, int sel2)
......@@ -6,6 +6,7 @@
* Heiko Carstens <>
#include <linux/compiler.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/string.h>
......@@ -20,6 +21,7 @@
#include <asm/processor.h>
#include <asm/sections.h>
#include <asm/setup.h>
#include <asm/sysinfo.h>
#include <asm/cpcmd.h>
#include <asm/sclp.h>
#include "entry.h"
......@@ -173,19 +175,21 @@ static noinline __init void init_kernel_storage_key(void)
page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
static __initdata struct sysinfo_3_2_2 vmms __aligned(PAGE_SIZE);
static noinline __init void detect_machine_type(void)
struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;
/* Running under z/VM ? */
if (cpuinfo->cpu_id.version == 0xff)
machine_flags |= MACHINE_FLAG_VM;
/* No VM information? Looks like LPAR */
if (stsi(&vmms, 3, 2, 2) == -ENOSYS)
if (!vmms.count)
/* Running under KVM ? */
if (cpuinfo->cpu_id.version == 0xfe)
/* Running under KVM? If not we assume z/VM */
if (!memcmp(vmms.vm[0].cpi, "\xd2\xe5\xd4", 3))
machine_flags |= MACHINE_FLAG_KVM;
machine_flags |= MACHINE_FLAG_VM;
static __init void early_pgm_check_handler(void)
......@@ -108,6 +108,8 @@ SECTIONS
/* early.c uses stsi, which requires page aligned data. */
......@@ -286,7 +286,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
setup_timer(&vcpu->arch.ckc_timer, kvm_s390_idle_wakeup,
(unsigned long) vcpu);
vcpu->arch.cpu_id.version = 0xfe;
vcpu->arch.cpu_id.version = 0xff;
return 0;
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment