From patchwork Wed Feb 5 10:11:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juergen Gross X-Patchwork-Id: 11366009 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DBB46112B for ; Wed, 5 Feb 2020 10:13:05 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B7AC420661 for ; Wed, 5 Feb 2020 10:13:05 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B7AC420661 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1izHf9-0003OQ-87; Wed, 05 Feb 2020 10:12:03 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1izHf7-0003NZ-UO for xen-devel@lists.xenproject.org; Wed, 05 Feb 2020 10:12:01 +0000 X-Inumbo-ID: ead25fc8-47ff-11ea-8396-bc764e2007e4 Received: from mx2.suse.de (unknown [195.135.220.15]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id ead25fc8-47ff-11ea-8396-bc764e2007e4; Wed, 05 Feb 2020 10:11:47 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 5E6E0B02C; Wed, 5 Feb 2020 10:11:46 +0000 (UTC) From: Juergen Gross To: xen-devel@lists.xenproject.org Date: Wed, 5 Feb 2020 11:11:41 +0100 Message-Id: <20200205101141.24769-9-jgross@suse.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20200205101141.24769-1-jgross@suse.com> References: <20200205101141.24769-1-jgross@suse.com> Subject: [Xen-devel] [PATCH v4 8/8] xen: add runtime parameter access support to hypfs X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Juergen Gross , Kevin Tian , Stefano Stabellini , Julien Grall , Jun Nakajima , Wei Liu , Konrad Rzeszutek Wilk , George Dunlap , Andrew Cooper , Ian Jackson , Jan Beulich , Volodymyr Babchuk , =?utf-8?q?Roger_Pau_Monn?= =?utf-8?q?=C3=A9?= MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" Add support to read and modify values of hypervisor runtime parameters via the hypervisor file system. As runtime parameters can be modified via a sysctl, too, this path has to take the hypfs rw_lock as writer. For custom runtime parameters the resulting parameter value needs to be stored in a string buffer for being consumable by the file system. Signed-off-by: Juergen Gross --- V3: - complete rework - support custom parameters, too - support parameter writing --- docs/misc/hypfs-paths.pandoc | 9 ++++++ xen/arch/arm/xen.lds.S | 5 +++ xen/arch/x86/hvm/vmx/vmcs.c | 17 +++++++++- xen/arch/x86/pv/domain.c | 7 ++++- xen/arch/x86/xen.lds.S | 5 +++ xen/common/grant_table.c | 17 +++++++--- xen/common/hypfs.c | 38 +++++++++++++++++++++++ xen/common/kernel.c | 23 +++++++++++++- xen/drivers/char/console.c | 49 +++++++++++++++++++++++++---- xen/include/xen/hypfs.h | 4 +++ xen/include/xen/param.h | 74 +++++++++++++++++++++++++++++++++++++++----- 11 files changed, 226 insertions(+), 22 deletions(-) diff --git a/docs/misc/hypfs-paths.pandoc b/docs/misc/hypfs-paths.pandoc index 1faebcccbc..7d03852ccd 100644 --- a/docs/misc/hypfs-paths.pandoc +++ b/docs/misc/hypfs-paths.pandoc @@ -152,3 +152,12 @@ The major version of Xen. #### /buildinfo/version/minor = INTEGER The minor version of Xen. + +#### /params/ + +A directory of runtime parameters. + +#### /params/* + +The single parameters. The description of the different parameters can be +found in `docs/misc/xen-command-line.pandoc`. diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S index a497f6a48d..0061a8dfea 100644 --- a/xen/arch/arm/xen.lds.S +++ b/xen/arch/arm/xen.lds.S @@ -89,6 +89,11 @@ SECTIONS __start_schedulers_array = .; *(.data.schedulers) __end_schedulers_array = .; + + . = ALIGN(8); + __paramhypfs_start = .; + *(.data.paramhypfs) + __paramhypfs_end = .; *(.data.rel) *(.data.rel.*) CONSTRUCTORS diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index 65445afeb0..36ddccfb73 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -70,6 +70,17 @@ integer_param("ple_window", ple_window); static bool __read_mostly opt_ept_pml = true; static s8 __read_mostly opt_ept_ad = -1; int8_t __read_mostly opt_ept_exec_sp = -1; +static char opt_ept_setting[16] = "pml=1"; + + +static void update_ept_param(void) +{ + snprintf(opt_ept_setting, sizeof(opt_ept_setting), "pml=%d", opt_ept_pml); + if ( opt_ept_ad >= 0 ) + param_append_str(opt_ept_setting, ",ad=%d", opt_ept_ad); + if ( opt_ept_exec_sp >= 0 ) + param_append_str(opt_ept_setting, ",exec-sp=%d", opt_ept_exec_sp); +} static int __init parse_ept_param(const char *s) { @@ -93,6 +104,8 @@ static int __init parse_ept_param(const char *s) s = ss + 1; } while ( *ss ); + update_ept_param(); + return rc; } custom_param("ept", parse_ept_param); @@ -115,6 +128,8 @@ static int parse_ept_param_runtime(const char *s) opt_ept_exec_sp = val; + update_ept_param(); + rcu_read_lock(&domlist_read_lock); for_each_domain ( d ) { @@ -144,7 +159,7 @@ static int parse_ept_param_runtime(const char *s) return 0; } -custom_runtime_only_param("ept", parse_ept_param_runtime); +custom_runtime_only_param("ept", parse_ept_param_runtime, opt_ept_setting); /* Dynamic (run-time adjusted) execution control flags. */ u32 vmx_pin_based_exec_control __read_mostly; diff --git a/xen/arch/x86/pv/domain.c b/xen/arch/x86/pv/domain.c index c3473b9a47..9e0d24ce81 100644 --- a/xen/arch/x86/pv/domain.c +++ b/xen/arch/x86/pv/domain.c @@ -22,6 +22,7 @@ static __read_mostly enum { PCID_XPTI, PCID_NOXPTI } opt_pcid = PCID_XPTI; +static char opt_pcid_val[7] = "xpti"; static int parse_pcid(const char *s) { @@ -31,10 +32,12 @@ static int parse_pcid(const char *s) { case 0: opt_pcid = PCID_OFF; + snprintf(opt_pcid_val, sizeof(opt_pcid_val), "off"); break; case 1: opt_pcid = PCID_ALL; + snprintf(opt_pcid_val, sizeof(opt_pcid_val), "on"); break; default: @@ -42,10 +45,12 @@ static int parse_pcid(const char *s) { case 0: opt_pcid = PCID_NOXPTI; + snprintf(opt_pcid_val, sizeof(opt_pcid_val), "noxpti"); break; case 1: opt_pcid = PCID_XPTI; + snprintf(opt_pcid_val, sizeof(opt_pcid_val), "xpti"); break; default: @@ -57,7 +62,7 @@ static int parse_pcid(const char *s) return rc; } -custom_runtime_param("pcid", parse_pcid); +custom_runtime_param("pcid", parse_pcid, opt_pcid_val); static void noreturn continue_nonidle_domain(struct vcpu *v) { diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S index f5730ffe93..b4b12a3111 100644 --- a/xen/arch/x86/xen.lds.S +++ b/xen/arch/x86/xen.lds.S @@ -279,6 +279,11 @@ SECTIONS __start_schedulers_array = .; *(.data.schedulers) __end_schedulers_array = .; + + . = ALIGN(8); + __paramhypfs_start = .; + *(.data.paramhypfs) + __paramhypfs_end = .; } :text DECL_SECTION(.data) { diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c index 2ecf38dfbe..2de2c7e373 100644 --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -85,8 +85,10 @@ struct grant_table { struct grant_table_arch arch; }; +#define PAR_VAL_SZ 12 + static int parse_gnttab_limit(const char *param, const char *arg, - unsigned int *valp) + unsigned int *valp, char *par_val) { const char *e; unsigned long val; @@ -99,28 +101,33 @@ static int parse_gnttab_limit(const char *param, const char *arg, return -ERANGE; *valp = val; + snprintf(par_val, PAR_VAL_SZ, "%lu", val); return 0; } unsigned int __read_mostly opt_max_grant_frames = 64; +static char gnttab_max_frames_val[PAR_VAL_SZ] = "64"; static int parse_gnttab_max_frames(const char *arg) { return parse_gnttab_limit("gnttab_max_frames", arg, - &opt_max_grant_frames); + &opt_max_grant_frames, gnttab_max_frames_val); } -custom_runtime_param("gnttab_max_frames", parse_gnttab_max_frames); +custom_runtime_param("gnttab_max_frames", parse_gnttab_max_frames, + gnttab_max_frames_val); static unsigned int __read_mostly opt_max_maptrack_frames = 1024; +static char max_maptrack_frames_val[PAR_VAL_SZ] = "1024"; static int parse_gnttab_max_maptrack_frames(const char *arg) { return parse_gnttab_limit("gnttab_max_maptrack_frames", arg, - &opt_max_maptrack_frames); + &opt_max_maptrack_frames, + max_maptrack_frames_val); } custom_runtime_param("gnttab_max_maptrack_frames", - parse_gnttab_max_maptrack_frames); + parse_gnttab_max_maptrack_frames, max_maptrack_frames_val); #ifndef GNTTAB_MAX_VERSION #define GNTTAB_MAX_VERSION 2 diff --git a/xen/common/hypfs.c b/xen/common/hypfs.c index c726f89ac9..9a296674fb 100644 --- a/xen/common/hypfs.c +++ b/xen/common/hypfs.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -289,6 +290,33 @@ int hypfs_write_bool(struct hypfs_entry_leaf *leaf, return 0; } +int hypfs_write_custom(struct hypfs_entry_leaf *leaf, + XEN_GUEST_HANDLE_PARAM(void) uaddr, unsigned long ulen) +{ + struct param_hypfs *p; + char *buf; + int ret; + + buf = xzalloc_array(char, ulen); + if ( !buf ) + return -ENOMEM; + + ret = -EFAULT; + if ( copy_from_guest(buf, uaddr, ulen) ) + goto out; + + ret = -EDOM; + if ( buf[ulen - 1] ) + goto out; + + p = container_of(leaf, struct param_hypfs, hypfs); + ret = p->param->par.func(buf); + + out: + xfree(buf); + return ret; +} + static int hypfs_write(struct hypfs_entry *entry, XEN_GUEST_HANDLE_PARAM(void) uaddr, unsigned long ulen) { @@ -356,3 +384,13 @@ long do_hypfs_op(unsigned int cmd, return ret; } + +void hypfs_write_lock(void) +{ + write_lock(&hypfs_lock); +} + +void hypfs_write_unlock(void) +{ + write_unlock(&hypfs_lock); +} diff --git a/xen/common/kernel.c b/xen/common/kernel.c index 3d496bb9e6..e62a1680c7 100644 --- a/xen/common/kernel.c +++ b/xen/common/kernel.c @@ -198,7 +198,13 @@ static void __init _cmdline_parse(const char *cmdline) int runtime_parse(const char *line) { - return parse_params(line, __param_start, __param_end); + int ret; + + hypfs_write_lock(); + ret = parse_params(line, __param_start, __param_end); + hypfs_write_unlock(); + + return ret; } /** @@ -428,6 +434,21 @@ static int __init buildinfo_init(void) } __initcall(buildinfo_init); +static HYPFS_DIR_INIT(params, "params"); + +static int __init param_init(void) +{ + struct param_hypfs *param; + + hypfs_add_dir(&hypfs_root, ¶ms, true); + + for ( param = __paramhypfs_start; param < __paramhypfs_end; param++ ) + hypfs_add_leaf(¶ms, ¶m->hypfs, true); + + return 0; +} +__initcall(param_init); + # define DO(fn) long do_##fn #endif diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index 913ae1b66a..5440145549 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -78,9 +78,11 @@ enum con_timestamp_mode }; static enum con_timestamp_mode __read_mostly opt_con_timestamp_mode = TSM_NONE; +static char con_timestamp_mode_val[7] = "none"; static int parse_console_timestamps(const char *s); -custom_runtime_param("console_timestamps", parse_console_timestamps); +custom_runtime_param("console_timestamps", parse_console_timestamps, + con_timestamp_mode_val); /* conring_size: allows a large console ring than default (16kB). */ static uint32_t __initdata opt_conring_size; @@ -118,13 +120,17 @@ static DEFINE_SPINLOCK(console_lock); #ifdef NDEBUG #define XENLOG_UPPER_THRESHOLD 2 /* Do not print INFO and DEBUG */ #define XENLOG_LOWER_THRESHOLD 2 /* Always print ERR and WARNING */ +#define XENLOG_DEFAULT_VAL "warning/warning" #define XENLOG_GUEST_UPPER_THRESHOLD 2 /* Do not print INFO and DEBUG */ #define XENLOG_GUEST_LOWER_THRESHOLD 0 /* Rate-limit ERR and WARNING */ +#define XENLOG_GUEST_DEFAULT_VAL "none/warning" #else #define XENLOG_UPPER_THRESHOLD 4 /* Do not discard anything */ #define XENLOG_LOWER_THRESHOLD 4 /* Print everything */ +#define XENLOG_DEFAULT_VAL "all/all" #define XENLOG_GUEST_UPPER_THRESHOLD 4 /* Do not discard anything */ #define XENLOG_GUEST_LOWER_THRESHOLD 4 /* Print everything */ +#define XENLOG_GUEST_DEFAULT_VAL "all/all" #endif /* * The XENLOG_DEFAULT is the default given to printks that @@ -133,16 +139,20 @@ static DEFINE_SPINLOCK(console_lock); #define XENLOG_DEFAULT 1 /* XENLOG_WARNING */ #define XENLOG_GUEST_DEFAULT 1 /* XENLOG_WARNING */ +#define LOGLVL_VAL_SZ 16 static int __read_mostly xenlog_upper_thresh = XENLOG_UPPER_THRESHOLD; static int __read_mostly xenlog_lower_thresh = XENLOG_LOWER_THRESHOLD; +static char xenlog_val[LOGLVL_VAL_SZ] = XENLOG_DEFAULT_VAL; static int __read_mostly xenlog_guest_upper_thresh = XENLOG_GUEST_UPPER_THRESHOLD; static int __read_mostly xenlog_guest_lower_thresh = XENLOG_GUEST_LOWER_THRESHOLD; +static char xenlog_guest_val[LOGLVL_VAL_SZ] = XENLOG_GUEST_DEFAULT_VAL; static int parse_loglvl(const char *s); static int parse_guest_loglvl(const char *s); +static char *lvl2opt[] = { "none", "error", "warning", "info", "all" }; /* * := none|error|warning|info|debug|all * loglvl=[/] @@ -151,8 +161,8 @@ static int parse_guest_loglvl(const char *s); * Similar definitions for guest_loglvl, but applies to guest tracing. * Defaults: loglvl=warning ; guest_loglvl=none/warning */ -custom_runtime_param("loglvl", parse_loglvl); -custom_runtime_param("guest_loglvl", parse_guest_loglvl); +custom_runtime_param("loglvl", parse_loglvl, xenlog_val); +custom_runtime_param("guest_loglvl", parse_guest_loglvl, xenlog_guest_val); static atomic_t print_everything = ATOMIC_INIT(0); @@ -173,7 +183,7 @@ static int __parse_loglvl(const char *s, const char **ps) return 2; /* sane fallback */ } -static int _parse_loglvl(const char *s, int *lower, int *upper) +static int _parse_loglvl(const char *s, int *lower, int *upper, char *val) { *lower = *upper = __parse_loglvl(s, &s); if ( *s == '/' ) @@ -181,18 +191,21 @@ static int _parse_loglvl(const char *s, int *lower, int *upper) if ( *upper < *lower ) *upper = *lower; + snprintf(val, LOGLVL_VAL_SZ, "%s/%s", lvl2opt[*lower], lvl2opt[*upper]); + return *s ? -EINVAL : 0; } static int parse_loglvl(const char *s) { - return _parse_loglvl(s, &xenlog_lower_thresh, &xenlog_upper_thresh); + return _parse_loglvl(s, &xenlog_lower_thresh, &xenlog_upper_thresh, + xenlog_val); } static int parse_guest_loglvl(const char *s) { return _parse_loglvl(s, &xenlog_guest_lower_thresh, - &xenlog_guest_upper_thresh); + &xenlog_guest_upper_thresh, xenlog_guest_val); } static char *loglvl_str(int lvl) @@ -731,22 +744,46 @@ static int parse_console_timestamps(const char *s) { case 0: opt_con_timestamp_mode = TSM_NONE; + snprintf(con_timestamp_mode_val, sizeof(con_timestamp_mode_val), + "none"); return 0; case 1: opt_con_timestamp_mode = TSM_DATE; + snprintf(con_timestamp_mode_val, sizeof(con_timestamp_mode_val), + "date"); return 0; } if ( *s == '\0' || /* Compat for old booleanparam() */ !strcmp(s, "date") ) + { opt_con_timestamp_mode = TSM_DATE; + snprintf(con_timestamp_mode_val, sizeof(con_timestamp_mode_val), + "date"); + } else if ( !strcmp(s, "datems") ) + { opt_con_timestamp_mode = TSM_DATE_MS; + snprintf(con_timestamp_mode_val, sizeof(con_timestamp_mode_val), + "datems"); + } else if ( !strcmp(s, "boot") ) + { opt_con_timestamp_mode = TSM_BOOT; + snprintf(con_timestamp_mode_val, sizeof(con_timestamp_mode_val), + "boot"); + } else if ( !strcmp(s, "raw") ) + { opt_con_timestamp_mode = TSM_RAW; + snprintf(con_timestamp_mode_val, sizeof(con_timestamp_mode_val), + "raw"); + } else if ( !strcmp(s, "none") ) + { opt_con_timestamp_mode = TSM_NONE; + snprintf(con_timestamp_mode_val, sizeof(con_timestamp_mode_val), + "none"); + } else return -EINVAL; diff --git a/xen/include/xen/hypfs.h b/xen/include/xen/hypfs.h index 5b26b2e611..2b6ed8ae23 100644 --- a/xen/include/xen/hypfs.h +++ b/xen/include/xen/hypfs.h @@ -104,5 +104,9 @@ int hypfs_write_leaf(struct hypfs_entry_leaf *leaf, XEN_GUEST_HANDLE_PARAM(void) uaddr, unsigned long ulen); int hypfs_write_bool(struct hypfs_entry_leaf *leaf, XEN_GUEST_HANDLE_PARAM(void) uaddr, unsigned long ulen); +int hypfs_write_custom(struct hypfs_entry_leaf *leaf, + XEN_GUEST_HANDLE_PARAM(void) uaddr, unsigned long ulen); +void hypfs_write_lock(void); +void hypfs_write_unlock(void); #endif /* __XEN_HYPFS_H__ */ diff --git a/xen/include/xen/param.h b/xen/include/xen/param.h index 75471eb4ad..b4ef3e7a22 100644 --- a/xen/include/xen/param.h +++ b/xen/include/xen/param.h @@ -1,6 +1,7 @@ #ifndef _XEN_PARAM_H #define _XEN_PARAM_H +#include #include /* @@ -23,10 +24,17 @@ struct kernel_param { } par; }; +struct param_hypfs { + const struct kernel_param *param; + struct hypfs_entry_leaf hypfs; +}; + extern const struct kernel_param __setup_start[], __setup_end[]; extern const struct kernel_param __param_start[], __param_end[]; +extern struct param_hypfs __paramhypfs_start[], __paramhypfs_end[]; #define __dataparam __used_section(".data.param") +#define __paramhypfs __used_section(".data.paramhypfs") #define __param(att) static const att \ __attribute__((__aligned__(sizeof(void *)))) struct kernel_param @@ -76,40 +84,87 @@ extern const struct kernel_param __param_start[], __param_end[]; .type = OPT_IGNORE } #define __rtparam __param(__dataparam) +#define __paramfs static __paramhypfs \ + __attribute__((__aligned__(sizeof(void *)))) struct param_hypfs -#define custom_runtime_only_param(_name, _var) \ +#define custom_runtime_only_param(_name, _var, contvar) \ __rtparam __rtpar_##_var = \ { .name = _name, \ .type = OPT_CUSTOM, \ - .par.func = _var } + .par.func = _var }; \ + __paramfs __parfs_##_var = \ + { .param = &__rtpar_##_var, \ + .hypfs.e.type = XEN_HYPFS_TYPE_STRING, \ + .hypfs.e.encoding = XEN_HYPFS_ENC_PLAIN, \ + .hypfs.e.name = _name, \ + .hypfs.e.size = sizeof(contvar), \ + .hypfs.e.read = hypfs_read_leaf, \ + .hypfs.e.write = hypfs_write_custom, \ + .hypfs.content = &contvar } #define boolean_runtime_only_param(_name, _var) \ __rtparam __rtpar_##_var = \ { .name = _name, \ .type = OPT_BOOL, \ .len = sizeof(_var), \ - .par.var = &_var } + .par.var = &_var }; \ + __paramfs __parfs_##_var = \ + { .param = &__rtpar_##_var, \ + .hypfs.e.type = XEN_HYPFS_TYPE_UINT, \ + .hypfs.e.encoding = XEN_HYPFS_ENC_PLAIN, \ + .hypfs.e.name = _name, \ + .hypfs.e.size = sizeof(_var), \ + .hypfs.e.read = hypfs_read_leaf, \ + .hypfs.e.write = hypfs_write_bool, \ + .hypfs.content = &_var } #define integer_runtime_only_param(_name, _var) \ __rtparam __rtpar_##_var = \ { .name = _name, \ .type = OPT_UINT, \ .len = sizeof(_var), \ - .par.var = &_var } + .par.var = &_var }; \ + __paramfs __parfs_##_var = \ + { .param = &__rtpar_##_var, \ + .hypfs.e.type = XEN_HYPFS_TYPE_UINT, \ + .hypfs.e.encoding = XEN_HYPFS_ENC_PLAIN, \ + .hypfs.e.name = _name, \ + .hypfs.e.size = sizeof(_var), \ + .hypfs.e.read = hypfs_read_leaf, \ + .hypfs.e.write = hypfs_write_leaf, \ + .hypfs.content = &_var } #define size_runtime_only_param(_name, _var) \ __rtparam __rtpar_##_var = \ { .name = _name, \ .type = OPT_SIZE, \ .len = sizeof(_var), \ - .par.var = &_var } + .par.var = &_var }; \ + __paramfs __parfs_##_var = \ + { .param = &__rtpar_##_var, \ + .hypfs.e.type = XEN_HYPFS_TYPE_UINT, \ + .hypfs.e.encoding = XEN_HYPFS_ENC_PLAIN, \ + .hypfs.e.name = _name, \ + .hypfs.e.size = sizeof(_var), \ + .hypfs.e.read = hypfs_read_leaf, \ + .hypfs.e.write = hypfs_write_leaf, \ + .hypfs.content = &_var } #define string_runtime_only_param(_name, _var) \ __rtparam __rtpar_##_var = \ { .name = _name, \ .type = OPT_STR, \ .len = sizeof(_var), \ - .par.var = &_var } + .par.var = &_var }; \ + __paramfs __parfs_##_var = \ + { .param = &__rtpar_##_var, \ + .hypfs.e.type = XEN_HYPFS_TYPE_STRING, \ + .hypfs.e.encoding = XEN_HYPFS_ENC_PLAIN, \ + .hypfs.e.name = _name, \ + .hypfs.e.size = sizeof(_var), \ + .hypfs.e.read = hypfs_read_leaf, \ + .hypfs.e.write = hypfs_write_leaf, \ + .hypfs.content = &_var } -#define custom_runtime_param(_name, _var) \ +#define custom_runtime_param(_name, _var, contvar) \ custom_param(_name, _var); \ - custom_runtime_only_param(_name, _var) + custom_runtime_only_param(_name, _var, contvar) #define boolean_runtime_param(_name, _var) \ boolean_param(_name, _var); \ boolean_runtime_only_param(_name, _var) @@ -123,4 +178,7 @@ extern const struct kernel_param __param_start[], __param_end[]; string_param(_name, _var); \ string_runtime_only_param(_name, _var) +#define param_append_str(var, fmt, val) \ + snprintf(var + strlen(var), sizeof(var) - strlen(var), fmt, val) + #endif /* _XEN_PARAM_H */