@@ -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`.
@@ -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
@@ -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;
@@ -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)
{
@@ -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) {
@@ -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
@@ -10,6 +10,7 @@
#include <xen/hypercall.h>
#include <xen/hypfs.h>
#include <xen/lib.h>
+#include <xen/param.h>
#include <xen/rwlock.h>
#include <public/hypfs.h>
@@ -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);
+}
@@ -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
@@ -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" };
/*
* <lvl> := none|error|warning|info|debug|all
* loglvl=<lvl_print_always>[/<lvl_print_ratelimit>]
@@ -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;
@@ -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__ */
@@ -1,6 +1,7 @@
#ifndef _XEN_PARAM_H
#define _XEN_PARAM_H
+#include <xen/hypfs.h>
#include <xen/init.h>
/*
@@ -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 */
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 <jgross@suse.com> --- 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(-)