Commit 415dab3c authored by Per Bilse's avatar Per Bilse Committed by Juergen Gross

drivers/xen/hypervisor: Expose Xen SIF flags to userspace

/proc/xen is a legacy pseudo filesystem which predates Xen support
getting merged into Linux.  It has largely been replaced with more
normal locations for data (/sys/hypervisor/ for info, /dev/xen/ for
user devices).  We want to compile xenfs support out of the dom0 kernel.

There is one item which only exists in /proc/xen, namely
/proc/xen/capabilities with "control_d" being the signal of "you're in
the control domain".  This ultimately comes from the SIF flags provided
at VM start.

This patch exposes all SIF flags in /sys/hypervisor/start_flags/ as
boolean files, one for each bit, returning '1' if set, '0' otherwise.
Two known flags, 'privileged' and 'initdomain', are explicitly named,
and all remaining flags can be accessed via generically named files,
as suggested by Andrew Cooper.
Signed-off-by: default avatarPer Bilse <per.bilse@citrix.com>
Reviewed-by: default avatarJuergen Gross <jgross@suse.com>
Link: https://lore.kernel.org/r/20230103130213.2129753-1-per.bilse@citrix.comSigned-off-by: default avatarJuergen Gross <jgross@suse.com>
parent ceaa837f
...@@ -120,3 +120,16 @@ Contact: xen-devel@lists.xenproject.org ...@@ -120,3 +120,16 @@ Contact: xen-devel@lists.xenproject.org
Description: If running under Xen: Description: If running under Xen:
The Xen version is in the format <major>.<minor><extra> The Xen version is in the format <major>.<minor><extra>
This is the <minor> part of it. This is the <minor> part of it.
What: /sys/hypervisor/start_flags/*
Date: March 2023
KernelVersion: 6.3.0
Contact: xen-devel@lists.xenproject.org
Description: If running under Xen:
All bits in Xen's start-flags are represented as
boolean files, returning '1' if set, '0' otherwise.
This takes the place of the defunct /proc/xen/capabilities,
which would contain "control_d" on dom0, and be empty
otherwise. This flag is now exposed as "initdomain" in
addition to the "privileged" flag; all other possible flags
are accessible as "unknownXX".
...@@ -31,7 +31,10 @@ struct hyp_sysfs_attr { ...@@ -31,7 +31,10 @@ struct hyp_sysfs_attr {
struct attribute attr; struct attribute attr;
ssize_t (*show)(struct hyp_sysfs_attr *, char *); ssize_t (*show)(struct hyp_sysfs_attr *, char *);
ssize_t (*store)(struct hyp_sysfs_attr *, const char *, size_t); ssize_t (*store)(struct hyp_sysfs_attr *, const char *, size_t);
union {
void *hyp_attr_data; void *hyp_attr_data;
unsigned long hyp_attr_value;
};
}; };
static ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer) static ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer)
...@@ -399,6 +402,60 @@ static int __init xen_sysfs_properties_init(void) ...@@ -399,6 +402,60 @@ static int __init xen_sysfs_properties_init(void)
return sysfs_create_group(hypervisor_kobj, &xen_properties_group); return sysfs_create_group(hypervisor_kobj, &xen_properties_group);
} }
#define FLAG_UNAME "unknown"
#define FLAG_UNAME_FMT FLAG_UNAME "%02u"
#define FLAG_UNAME_MAX sizeof(FLAG_UNAME "XX")
#define FLAG_COUNT (sizeof(xen_start_flags) * BITS_PER_BYTE)
static_assert(sizeof(xen_start_flags) <=
sizeof_field(struct hyp_sysfs_attr, hyp_attr_value));
static ssize_t flag_show(struct hyp_sysfs_attr *attr, char *buffer)
{
char *p = buffer;
*p++ = '0' + ((xen_start_flags & attr->hyp_attr_value) != 0);
*p++ = '\n';
return p - buffer;
}
#define FLAG_NODE(flag, node) \
[ilog2(flag)] = { \
.attr = { .name = #node, .mode = 0444 },\
.show = flag_show, \
.hyp_attr_value = flag \
}
/*
* Add new, known flags here. No other changes are required, but
* note that each known flag wastes one entry in flag_unames[].
* The code/complexity machinations to avoid this isn't worth it
* for a few entries, but keep it in mind.
*/
static struct hyp_sysfs_attr flag_attrs[FLAG_COUNT] = {
FLAG_NODE(SIF_PRIVILEGED, privileged),
FLAG_NODE(SIF_INITDOMAIN, initdomain)
};
static struct attribute_group xen_flags_group = {
.name = "start_flags",
.attrs = (struct attribute *[FLAG_COUNT + 1]){}
};
static char flag_unames[FLAG_COUNT][FLAG_UNAME_MAX];
static int __init xen_sysfs_flags_init(void)
{
for (unsigned fnum = 0; fnum != FLAG_COUNT; fnum++) {
if (likely(flag_attrs[fnum].attr.name == NULL)) {
sprintf(flag_unames[fnum], FLAG_UNAME_FMT, fnum);
flag_attrs[fnum].attr.name = flag_unames[fnum];
flag_attrs[fnum].attr.mode = 0444;
flag_attrs[fnum].show = flag_show;
flag_attrs[fnum].hyp_attr_value = 1 << fnum;
}
xen_flags_group.attrs[fnum] = &flag_attrs[fnum].attr;
}
return sysfs_create_group(hypervisor_kobj, &xen_flags_group);
}
#ifdef CONFIG_XEN_HAVE_VPMU #ifdef CONFIG_XEN_HAVE_VPMU
struct pmu_mode { struct pmu_mode {
const char *name; const char *name;
...@@ -539,18 +596,22 @@ static int __init hyper_sysfs_init(void) ...@@ -539,18 +596,22 @@ static int __init hyper_sysfs_init(void)
ret = xen_sysfs_properties_init(); ret = xen_sysfs_properties_init();
if (ret) if (ret)
goto prop_out; goto prop_out;
ret = xen_sysfs_flags_init();
if (ret)
goto flags_out;
#ifdef CONFIG_XEN_HAVE_VPMU #ifdef CONFIG_XEN_HAVE_VPMU
if (xen_initial_domain()) { if (xen_initial_domain()) {
ret = xen_sysfs_pmu_init(); ret = xen_sysfs_pmu_init();
if (ret) { if (ret) {
sysfs_remove_group(hypervisor_kobj, sysfs_remove_group(hypervisor_kobj, &xen_flags_group);
&xen_properties_group); goto flags_out;
goto prop_out;
} }
} }
#endif #endif
goto out; goto out;
flags_out:
sysfs_remove_group(hypervisor_kobj, &xen_properties_group);
prop_out: prop_out:
sysfs_remove_file(hypervisor_kobj, &uuid_attr.attr); sysfs_remove_file(hypervisor_kobj, &uuid_attr.attr);
uuid_out: uuid_out:
......
Markdown is supported
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