Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Per Bilse <per.bilse@citrix.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Link: https://lore.kernel.org/r/20230103130213.2129753-1-per.bilse@citrix.com
Signed-off-by: Juergen Gross <jgross@suse.com>

authored by

Per Bilse and committed by
Juergen Gross
415dab3c ceaa837f

+78 -4
+13
Documentation/ABI/stable/sysfs-hypervisor-xen
··· 120 120 Description: If running under Xen: 121 121 The Xen version is in the format <major>.<minor><extra> 122 122 This is the <minor> part of it. 123 + 124 + What: /sys/hypervisor/start_flags/* 125 + Date: March 2023 126 + KernelVersion: 6.3.0 127 + Contact: xen-devel@lists.xenproject.org 128 + Description: If running under Xen: 129 + All bits in Xen's start-flags are represented as 130 + boolean files, returning '1' if set, '0' otherwise. 131 + This takes the place of the defunct /proc/xen/capabilities, 132 + which would contain "control_d" on dom0, and be empty 133 + otherwise. This flag is now exposed as "initdomain" in 134 + addition to the "privileged" flag; all other possible flags 135 + are accessible as "unknownXX".
+65 -4
drivers/xen/sys-hypervisor.c
··· 31 31 struct attribute attr; 32 32 ssize_t (*show)(struct hyp_sysfs_attr *, char *); 33 33 ssize_t (*store)(struct hyp_sysfs_attr *, const char *, size_t); 34 - void *hyp_attr_data; 34 + union { 35 + void *hyp_attr_data; 36 + unsigned long hyp_attr_value; 37 + }; 35 38 }; 36 39 37 40 static ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer) ··· 402 399 return sysfs_create_group(hypervisor_kobj, &xen_properties_group); 403 400 } 404 401 402 + #define FLAG_UNAME "unknown" 403 + #define FLAG_UNAME_FMT FLAG_UNAME "%02u" 404 + #define FLAG_UNAME_MAX sizeof(FLAG_UNAME "XX") 405 + #define FLAG_COUNT (sizeof(xen_start_flags) * BITS_PER_BYTE) 406 + static_assert(sizeof(xen_start_flags) <= 407 + sizeof_field(struct hyp_sysfs_attr, hyp_attr_value)); 408 + 409 + static ssize_t flag_show(struct hyp_sysfs_attr *attr, char *buffer) 410 + { 411 + char *p = buffer; 412 + 413 + *p++ = '0' + ((xen_start_flags & attr->hyp_attr_value) != 0); 414 + *p++ = '\n'; 415 + return p - buffer; 416 + } 417 + 418 + #define FLAG_NODE(flag, node) \ 419 + [ilog2(flag)] = { \ 420 + .attr = { .name = #node, .mode = 0444 },\ 421 + .show = flag_show, \ 422 + .hyp_attr_value = flag \ 423 + } 424 + 425 + /* 426 + * Add new, known flags here. No other changes are required, but 427 + * note that each known flag wastes one entry in flag_unames[]. 428 + * The code/complexity machinations to avoid this isn't worth it 429 + * for a few entries, but keep it in mind. 430 + */ 431 + static struct hyp_sysfs_attr flag_attrs[FLAG_COUNT] = { 432 + FLAG_NODE(SIF_PRIVILEGED, privileged), 433 + FLAG_NODE(SIF_INITDOMAIN, initdomain) 434 + }; 435 + static struct attribute_group xen_flags_group = { 436 + .name = "start_flags", 437 + .attrs = (struct attribute *[FLAG_COUNT + 1]){} 438 + }; 439 + static char flag_unames[FLAG_COUNT][FLAG_UNAME_MAX]; 440 + 441 + static int __init xen_sysfs_flags_init(void) 442 + { 443 + for (unsigned fnum = 0; fnum != FLAG_COUNT; fnum++) { 444 + if (likely(flag_attrs[fnum].attr.name == NULL)) { 445 + sprintf(flag_unames[fnum], FLAG_UNAME_FMT, fnum); 446 + flag_attrs[fnum].attr.name = flag_unames[fnum]; 447 + flag_attrs[fnum].attr.mode = 0444; 448 + flag_attrs[fnum].show = flag_show; 449 + flag_attrs[fnum].hyp_attr_value = 1 << fnum; 450 + } 451 + xen_flags_group.attrs[fnum] = &flag_attrs[fnum].attr; 452 + } 453 + return sysfs_create_group(hypervisor_kobj, &xen_flags_group); 454 + } 455 + 405 456 #ifdef CONFIG_XEN_HAVE_VPMU 406 457 struct pmu_mode { 407 458 const char *name; ··· 596 539 ret = xen_sysfs_properties_init(); 597 540 if (ret) 598 541 goto prop_out; 542 + ret = xen_sysfs_flags_init(); 543 + if (ret) 544 + goto flags_out; 599 545 #ifdef CONFIG_XEN_HAVE_VPMU 600 546 if (xen_initial_domain()) { 601 547 ret = xen_sysfs_pmu_init(); 602 548 if (ret) { 603 - sysfs_remove_group(hypervisor_kobj, 604 - &xen_properties_group); 605 - goto prop_out; 549 + sysfs_remove_group(hypervisor_kobj, &xen_flags_group); 550 + goto flags_out; 606 551 } 607 552 } 608 553 #endif 609 554 goto out; 610 555 556 + flags_out: 557 + sysfs_remove_group(hypervisor_kobj, &xen_properties_group); 611 558 prop_out: 612 559 sysfs_remove_file(hypervisor_kobj, &uuid_attr.attr); 613 560 uuid_out: