diff options
-rw-r--r-- | Documentation/ABI/stable/sysfs-hypervisor-xen | 13 | ||||
-rw-r--r-- | drivers/xen/sys-hypervisor.c | 69 |
2 files changed, 78 insertions, 4 deletions
diff --git a/Documentation/ABI/stable/sysfs-hypervisor-xen b/Documentation/ABI/stable/sysfs-hypervisor-xen index 748593c64568..be9ca9981bb1 100644 --- a/Documentation/ABI/stable/sysfs-hypervisor-xen +++ b/Documentation/ABI/stable/sysfs-hypervisor-xen @@ -120,3 +120,16 @@ Contact: xen-devel@lists.xenproject.org Description: If running under Xen: The Xen version is in the format <major>.<minor><extra> 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". diff --git a/drivers/xen/sys-hypervisor.c b/drivers/xen/sys-hypervisor.c index fcb0792f090e..ca092db8f498 100644 --- a/drivers/xen/sys-hypervisor.c +++ b/drivers/xen/sys-hypervisor.c @@ -31,7 +31,10 @@ struct hyp_sysfs_attr { struct attribute attr; ssize_t (*show)(struct hyp_sysfs_attr *, char *); ssize_t (*store)(struct hyp_sysfs_attr *, const char *, size_t); - void *hyp_attr_data; + union { + void *hyp_attr_data; + unsigned long hyp_attr_value; + }; }; static ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer) @@ -399,6 +402,60 @@ static int __init xen_sysfs_properties_init(void) 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 struct pmu_mode { const char *name; @@ -539,18 +596,22 @@ static int __init hyper_sysfs_init(void) ret = xen_sysfs_properties_init(); if (ret) goto prop_out; + ret = xen_sysfs_flags_init(); + if (ret) + goto flags_out; #ifdef CONFIG_XEN_HAVE_VPMU if (xen_initial_domain()) { ret = xen_sysfs_pmu_init(); if (ret) { - sysfs_remove_group(hypervisor_kobj, - &xen_properties_group); - goto prop_out; + sysfs_remove_group(hypervisor_kobj, &xen_flags_group); + goto flags_out; } } #endif goto out; +flags_out: + sysfs_remove_group(hypervisor_kobj, &xen_properties_group); prop_out: sysfs_remove_file(hypervisor_kobj, &uuid_attr.attr); uuid_out: |