Add the infrastructure for the hypervisor filesystem.
This includes the hypercall interface and the base functions for
entry creation, deletion and modification.
In order not to have to repeat the same pattern multiple times in case
adding a new node should BUG_ON() failure, the helpers for adding a
node (hypfs_add_dir() and hypfs_add_leaf()) get a nofault parameter
causing the BUG() in case of a failure.
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Julien Grall <jgrall@amazon.com>
mtrr_del mtrr_read microcode physinfo quirk writeconsole readapic
writeapic privprofile nonprivprofile kexec firmware sleep frequency
getidle debug getcpuinfo heap pm_op mca_op lockprof cpupool_op
- getscheduler setscheduler
+ getscheduler setscheduler hypfs_op
};
allow dom0_t xen_t:xen2 {
resource_op psr_cmt_op psr_alloc pmu_ctrl get_symbol
#ifdef CONFIG_ARGO
HYPERCALL(argo_op, 5),
#endif
+#ifdef CONFIG_HYPFS
+ HYPERCALL(hypfs_op, 5),
+#endif
};
#ifndef NDEBUG
#endif
HYPERCALL(xenpmu_op),
COMPAT_CALL(dm_op),
+#ifdef CONFIG_HYPFS
+ HYPERCALL(hypfs_op),
+#endif
HYPERCALL(arch_1)
};
#ifdef CONFIG_HVM
ARGS(hvm_op, 2),
ARGS(dm_op, 3),
+#endif
+#ifdef CONFIG_HYPFS
+ ARGS(hypfs_op, 5),
#endif
ARGS(mca, 1),
ARGS(arch_1, 1),
#ifdef CONFIG_HVM
HYPERCALL(hvm_op),
COMPAT_CALL(dm_op),
+#endif
+#ifdef CONFIG_HYPFS
+ HYPERCALL(hypfs_op),
#endif
HYPERCALL(mca),
HYPERCALL(arch_1),
endmenu
+config HYPFS
+ bool "Hypervisor file system support"
+ default y
+ ---help---
+ Support Xen hypervisor file system. This file system is used to
+ present various hypervisor internal data to dom0 and in some
+ cases to allow modifying settings. Disabling the support might
+ result in some features not being available.
+
+ If unsure, say Y.
+
config KEXEC
bool "kexec support"
default y
obj-$(CONFIG_GRANT_TABLE) += grant_table.o
obj-y += guestcopy.o
obj-bin-y += gunzip.init.o
+obj-$(CONFIG_HYPFS) += hypfs.o
obj-y += irq.o
obj-y += kernel.o
obj-y += keyhandler.o
--- /dev/null
+/******************************************************************************
+ *
+ * hypfs.c
+ *
+ * Simple sysfs-like file system for the hypervisor.
+ */
+
+#include <xen/err.h>
+#include <xen/guest_access.h>
+#include <xen/hypercall.h>
+#include <xen/hypfs.h>
+#include <xen/lib.h>
+#include <xen/rwlock.h>
+#include <public/hypfs.h>
+
+#ifdef CONFIG_COMPAT
+#include <compat/hypfs.h>
+CHECK_hypfs_dirlistentry;
+#endif
+
+#define DIRENTRY_NAME_OFF offsetof(struct xen_hypfs_dirlistentry, name)
+#define DIRENTRY_SIZE(name_len) \
+ (DIRENTRY_NAME_OFF + \
+ ROUNDUP((name_len) + 1, alignof(struct xen_hypfs_direntry)))
+
+static DEFINE_RWLOCK(hypfs_lock);
+enum hypfs_lock_state {
+ hypfs_unlocked,
+ hypfs_read_locked,
+ hypfs_write_locked
+};
+static DEFINE_PER_CPU(enum hypfs_lock_state, hypfs_locked);
+
+HYPFS_DIR_INIT(hypfs_root, "");
+
+static void hypfs_read_lock(void)
+{
+ ASSERT(this_cpu(hypfs_locked) != hypfs_write_locked);
+
+ read_lock(&hypfs_lock);
+ this_cpu(hypfs_locked) = hypfs_read_locked;
+}
+
+static void hypfs_write_lock(void)
+{
+ ASSERT(this_cpu(hypfs_locked) == hypfs_unlocked);
+
+ write_lock(&hypfs_lock);
+ this_cpu(hypfs_locked) = hypfs_write_locked;
+}
+
+static void hypfs_unlock(void)
+{
+ enum hypfs_lock_state locked = this_cpu(hypfs_locked);
+
+ this_cpu(hypfs_locked) = hypfs_unlocked;
+
+ switch ( locked )
+ {
+ case hypfs_read_locked:
+ read_unlock(&hypfs_lock);
+ break;
+ case hypfs_write_locked:
+ write_unlock(&hypfs_lock);
+ break;
+ default:
+ BUG();
+ }
+}
+
+static int add_entry(struct hypfs_entry_dir *parent, struct hypfs_entry *new)
+{
+ int ret = -ENOENT;
+ struct hypfs_entry *e;
+
+ hypfs_write_lock();
+
+ list_for_each_entry ( e, &parent->dirlist, list )
+ {
+ int cmp = strcmp(e->name, new->name);
+
+ if ( cmp > 0 )
+ {
+ ret = 0;
+ list_add_tail(&new->list, &e->list);
+ break;
+ }
+ if ( cmp == 0 )
+ {
+ ret = -EEXIST;
+ break;
+ }
+ }
+
+ if ( ret == -ENOENT )
+ {
+ ret = 0;
+ list_add_tail(&new->list, &parent->dirlist);
+ }
+
+ if ( !ret )
+ {
+ unsigned int sz = strlen(new->name);
+
+ parent->e.size += DIRENTRY_SIZE(sz);
+ }
+
+ hypfs_unlock();
+
+ return ret;
+}
+
+int hypfs_add_dir(struct hypfs_entry_dir *parent,
+ struct hypfs_entry_dir *dir, bool nofault)
+{
+ int ret;
+
+ ret = add_entry(parent, &dir->e);
+ BUG_ON(nofault && ret);
+
+ return ret;
+}
+
+int hypfs_add_leaf(struct hypfs_entry_dir *parent,
+ struct hypfs_entry_leaf *leaf, bool nofault)
+{
+ int ret;
+
+ if ( !leaf->content )
+ ret = -EINVAL;
+ else
+ ret = add_entry(parent, &leaf->e);
+ BUG_ON(nofault && ret);
+
+ return ret;
+}
+
+static int hypfs_get_path_user(char *buf,
+ XEN_GUEST_HANDLE_PARAM(const_char) uaddr,
+ unsigned long ulen)
+{
+ if ( ulen > XEN_HYPFS_MAX_PATHLEN )
+ return -EINVAL;
+
+ if ( copy_from_guest(buf, uaddr, ulen) )
+ return -EFAULT;
+
+ if ( memchr(buf, 0, ulen) != buf + ulen - 1 )
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct hypfs_entry *hypfs_get_entry_rel(struct hypfs_entry_dir *dir,
+ const char *path)
+{
+ const char *end;
+ struct hypfs_entry *entry;
+ unsigned int name_len;
+ bool again = true;
+
+ while ( again )
+ {
+ if ( dir->e.type != XEN_HYPFS_TYPE_DIR )
+ return NULL;
+
+ if ( !*path )
+ return &dir->e;
+
+ end = strchr(path, '/');
+ if ( !end )
+ end = strchr(path, '\0');
+ name_len = end - path;
+
+ again = false;
+
+ list_for_each_entry ( entry, &dir->dirlist, list )
+ {
+ int cmp = strncmp(path, entry->name, name_len);
+ struct hypfs_entry_dir *d = container_of(entry,
+ struct hypfs_entry_dir, e);
+
+ if ( cmp < 0 )
+ return NULL;
+ if ( !cmp && strlen(entry->name) == name_len )
+ {
+ if ( !*end )
+ return entry;
+
+ again = true;
+ dir = d;
+ path = end + 1;
+
+ break;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static struct hypfs_entry *hypfs_get_entry(const char *path)
+{
+ if ( path[0] != '/' )
+ return NULL;
+
+ return hypfs_get_entry_rel(&hypfs_root, path + 1);
+}
+
+int hypfs_read_dir(const struct hypfs_entry *entry,
+ XEN_GUEST_HANDLE_PARAM(void) uaddr)
+{
+ const struct hypfs_entry_dir *d;
+ const struct hypfs_entry *e;
+ unsigned int size = entry->size;
+
+ ASSERT(this_cpu(hypfs_locked) != hypfs_unlocked);
+
+ d = container_of(entry, const struct hypfs_entry_dir, e);
+
+ list_for_each_entry ( e, &d->dirlist, list )
+ {
+ struct xen_hypfs_dirlistentry direntry;
+ unsigned int e_namelen = strlen(e->name);
+ unsigned int e_len = DIRENTRY_SIZE(e_namelen);
+
+ direntry.e.pad = 0;
+ direntry.e.type = e->type;
+ direntry.e.encoding = e->encoding;
+ direntry.e.content_len = e->size;
+ direntry.e.max_write_len = e->max_size;
+ direntry.off_next = list_is_last(&e->list, &d->dirlist) ? 0 : e_len;
+ if ( copy_to_guest(uaddr, &direntry, 1) )
+ return -EFAULT;
+
+ if ( copy_to_guest_offset(uaddr, DIRENTRY_NAME_OFF,
+ e->name, e_namelen + 1) )
+ return -EFAULT;
+
+ guest_handle_add_offset(uaddr, e_len);
+
+ ASSERT(e_len <= size);
+ size -= e_len;
+ }
+
+ return 0;
+}
+
+int hypfs_read_leaf(const struct hypfs_entry *entry,
+ XEN_GUEST_HANDLE_PARAM(void) uaddr)
+{
+ const struct hypfs_entry_leaf *l;
+
+ ASSERT(this_cpu(hypfs_locked) != hypfs_unlocked);
+
+ l = container_of(entry, const struct hypfs_entry_leaf, e);
+
+ return copy_to_guest(uaddr, l->content, entry->size) ? -EFAULT: 0;
+}
+
+static int hypfs_read(const struct hypfs_entry *entry,
+ XEN_GUEST_HANDLE_PARAM(void) uaddr, unsigned long ulen)
+{
+ struct xen_hypfs_direntry e;
+ long ret = -EINVAL;
+
+ if ( ulen < sizeof(e) )
+ goto out;
+
+ e.pad = 0;
+ e.type = entry->type;
+ e.encoding = entry->encoding;
+ e.content_len = entry->size;
+ e.max_write_len = entry->max_size;
+
+ ret = -EFAULT;
+ if ( copy_to_guest(uaddr, &e, 1) )
+ goto out;
+
+ ret = -ENOBUFS;
+ if ( ulen < entry->size + sizeof(e) )
+ goto out;
+
+ guest_handle_add_offset(uaddr, sizeof(e));
+
+ ret = entry->read(entry, uaddr);
+
+ out:
+ return ret;
+}
+
+int hypfs_write_leaf(struct hypfs_entry_leaf *leaf,
+ XEN_GUEST_HANDLE_PARAM(void) uaddr, unsigned int ulen)
+{
+ char *buf;
+ int ret;
+
+ ASSERT(this_cpu(hypfs_locked) == hypfs_write_locked);
+ ASSERT(ulen <= leaf->e.max_size);
+
+ if ( leaf->e.type != XEN_HYPFS_TYPE_STRING &&
+ leaf->e.type != XEN_HYPFS_TYPE_BLOB && ulen != leaf->e.size )
+ return -EDOM;
+
+ buf = xmalloc_array(char, ulen);
+ if ( !buf )
+ return -ENOMEM;
+
+ ret = -EFAULT;
+ if ( copy_from_guest(buf, uaddr, ulen) )
+ goto out;
+
+ ret = -EINVAL;
+ if ( leaf->e.type == XEN_HYPFS_TYPE_STRING &&
+ leaf->e.encoding == XEN_HYPFS_ENC_PLAIN &&
+ memchr(buf, 0, ulen) != (buf + ulen - 1) )
+ goto out;
+
+ ret = 0;
+ memcpy(leaf->write_ptr, buf, ulen);
+ leaf->e.size = ulen;
+
+ out:
+ xfree(buf);
+ return ret;
+}
+
+int hypfs_write_bool(struct hypfs_entry_leaf *leaf,
+ XEN_GUEST_HANDLE_PARAM(void) uaddr, unsigned int ulen)
+{
+ bool buf;
+
+ ASSERT(this_cpu(hypfs_locked) == hypfs_write_locked);
+ ASSERT(leaf->e.type == XEN_HYPFS_TYPE_BOOL &&
+ leaf->e.size == sizeof(bool) &&
+ leaf->e.max_size == sizeof(bool) );
+
+ if ( ulen != leaf->e.max_size )
+ return -EDOM;
+
+ if ( copy_from_guest(&buf, uaddr, ulen) )
+ return -EFAULT;
+
+ *(bool *)leaf->write_ptr = buf;
+
+ return 0;
+}
+
+static int hypfs_write(struct hypfs_entry *entry,
+ XEN_GUEST_HANDLE_PARAM(void) uaddr, unsigned long ulen)
+{
+ struct hypfs_entry_leaf *l;
+
+ if ( !entry->write )
+ return -EACCES;
+
+ ASSERT(entry->max_size);
+
+ if ( ulen > entry->max_size )
+ return -ENOSPC;
+
+ l = container_of(entry, struct hypfs_entry_leaf, e);
+
+ return entry->write(l, uaddr, ulen);
+}
+
+long do_hypfs_op(unsigned int cmd,
+ XEN_GUEST_HANDLE_PARAM(const_char) arg1, unsigned long arg2,
+ XEN_GUEST_HANDLE_PARAM(void) arg3, unsigned long arg4)
+{
+ int ret;
+ struct hypfs_entry *entry;
+ static char path[XEN_HYPFS_MAX_PATHLEN];
+
+ if ( xsm_hypfs_op(XSM_PRIV) )
+ return -EPERM;
+
+ if ( cmd == XEN_HYPFS_OP_get_version )
+ {
+ if ( !guest_handle_is_null(arg1) || arg2 ||
+ !guest_handle_is_null(arg3) || arg4 )
+ return -EINVAL;
+
+ return XEN_HYPFS_VERSION;
+ }
+
+ if ( cmd == XEN_HYPFS_OP_write_contents )
+ hypfs_write_lock();
+ else
+ hypfs_read_lock();
+
+ ret = hypfs_get_path_user(path, arg1, arg2);
+ if ( ret )
+ goto out;
+
+ entry = hypfs_get_entry(path);
+ if ( !entry )
+ {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ switch ( cmd )
+ {
+ case XEN_HYPFS_OP_read:
+ ret = hypfs_read(entry, arg3, arg4);
+ break;
+
+ case XEN_HYPFS_OP_write_contents:
+ ret = hypfs_write(entry, arg3, arg4);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ out:
+ hypfs_unlock();
+
+ return ret;
+}
compat/event_channel.h \
compat/features.h \
compat/grant_table.h \
+ compat/hypfs.h \
compat/kexec.h \
compat/memory.h \
compat/nmi.h \
--- /dev/null
+/******************************************************************************
+ * Xen Hypervisor Filesystem
+ *
+ * Copyright (c) 2019, SUSE Software Solutions Germany GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __XEN_PUBLIC_HYPFS_H__
+#define __XEN_PUBLIC_HYPFS_H__
+
+#include "xen.h"
+
+/*
+ * Definitions for the __HYPERVISOR_hypfs_op hypercall.
+ */
+
+/* Highest version number of the hypfs interface currently defined. */
+#define XEN_HYPFS_VERSION 1
+
+/* Maximum length of a path in the filesystem. */
+#define XEN_HYPFS_MAX_PATHLEN 1024
+
+struct xen_hypfs_direntry {
+ uint8_t type;
+#define XEN_HYPFS_TYPE_DIR 0
+#define XEN_HYPFS_TYPE_BLOB 1
+#define XEN_HYPFS_TYPE_STRING 2
+#define XEN_HYPFS_TYPE_UINT 3
+#define XEN_HYPFS_TYPE_INT 4
+#define XEN_HYPFS_TYPE_BOOL 5
+ uint8_t encoding;
+#define XEN_HYPFS_ENC_PLAIN 0
+#define XEN_HYPFS_ENC_GZIP 1
+ uint16_t pad; /* Returned as 0. */
+ uint32_t content_len; /* Current length of data. */
+ uint32_t max_write_len; /* Max. length for writes (0 if read-only). */
+};
+
+struct xen_hypfs_dirlistentry {
+ struct xen_hypfs_direntry e;
+ /* Offset in bytes to next entry (0 == this is the last entry). */
+ uint16_t off_next;
+ /* Zero terminated entry name, possibly with some padding for alignment. */
+ char name[XEN_FLEX_ARRAY_DIM];
+};
+
+/*
+ * Hypercall operations.
+ */
+
+/*
+ * XEN_HYPFS_OP_get_version
+ *
+ * Read highest interface version supported by the hypervisor.
+ *
+ * arg1 - arg4: all 0/NULL
+ *
+ * Possible return values:
+ * >0: highest supported interface version
+ * <0: negative Xen errno value
+ */
+#define XEN_HYPFS_OP_get_version 0
+
+/*
+ * XEN_HYPFS_OP_read
+ *
+ * Read a filesystem entry.
+ *
+ * Returns the direntry and contents of an entry in the buffer supplied by the
+ * caller (struct xen_hypfs_direntry with the contents following directly
+ * after it).
+ * The data buffer must be at least the size of the direntry returned. If the
+ * data buffer was not large enough for all the data -ENOBUFS and no entry
+ * data is returned, but the direntry will contain the needed size for the
+ * returned data.
+ * The format of the contents is according to its entry type and encoding.
+ * The contents of a directory are multiple struct xen_hypfs_dirlistentry
+ * items.
+ *
+ * arg1: XEN_GUEST_HANDLE(path name)
+ * arg2: length of path name (including trailing zero byte)
+ * arg3: XEN_GUEST_HANDLE(data buffer written by hypervisor)
+ * arg4: data buffer size
+ *
+ * Possible return values:
+ * 0: success
+ * <0 : negative Xen errno value
+ */
+#define XEN_HYPFS_OP_read 1
+
+/*
+ * XEN_HYPFS_OP_write_contents
+ *
+ * Write contents of a filesystem entry.
+ *
+ * Writes an entry with the contents of a buffer supplied by the caller.
+ * The data type and encoding can't be changed. The size can be changed only
+ * for blobs and strings.
+ *
+ * arg1: XEN_GUEST_HANDLE(path name)
+ * arg2: length of path name (including trailing zero byte)
+ * arg3: XEN_GUEST_HANDLE(content buffer read by hypervisor)
+ * arg4: content buffer size
+ *
+ * Possible return values:
+ * 0: success
+ * <0 : negative Xen errno value
+ */
+#define XEN_HYPFS_OP_write_contents 2
+
+#endif /* __XEN_PUBLIC_HYPFS_H__ */
#define __HYPERVISOR_argo_op 39
#define __HYPERVISOR_xenpmu_op 40
#define __HYPERVISOR_dm_op 41
+#define __HYPERVISOR_hypfs_op 42
/* Architecture-specific hypercall definitions. */
#define __HYPERVISOR_arch_0 48
unsigned int nr_bufs,
XEN_GUEST_HANDLE_PARAM(xen_dm_op_buf_t) bufs);
+#ifdef CONFIG_HYPFS
+extern long
+do_hypfs_op(
+ unsigned int cmd,
+ XEN_GUEST_HANDLE_PARAM(const_char) arg1,
+ unsigned long arg2,
+ XEN_GUEST_HANDLE_PARAM(void) arg3,
+ unsigned long arg4);
+#endif
+
#ifdef CONFIG_COMPAT
extern int
--- /dev/null
+#ifndef __XEN_HYPFS_H__
+#define __XEN_HYPFS_H__
+
+#ifdef CONFIG_HYPFS
+#include <xen/list.h>
+#include <xen/string.h>
+#include <public/hypfs.h>
+
+struct hypfs_entry_leaf;
+
+struct hypfs_entry {
+ unsigned short type;
+ unsigned short encoding;
+ unsigned int size;
+ unsigned int max_size;
+ const char *name;
+ struct list_head list;
+ int (*read)(const struct hypfs_entry *entry,
+ XEN_GUEST_HANDLE_PARAM(void) uaddr);
+ int (*write)(struct hypfs_entry_leaf *leaf,
+ XEN_GUEST_HANDLE_PARAM(void) uaddr, unsigned int ulen);
+};
+
+struct hypfs_entry_leaf {
+ struct hypfs_entry e;
+ union {
+ const void *content;
+ void *write_ptr;
+ };
+};
+
+struct hypfs_entry_dir {
+ struct hypfs_entry e;
+ struct list_head dirlist;
+};
+
+#define HYPFS_DIR_INIT(var, nam) \
+ struct hypfs_entry_dir __read_mostly var = { \
+ .e.type = XEN_HYPFS_TYPE_DIR, \
+ .e.encoding = XEN_HYPFS_ENC_PLAIN, \
+ .e.name = (nam), \
+ .e.size = 0, \
+ .e.max_size = 0, \
+ .e.list = LIST_HEAD_INIT(var.e.list), \
+ .e.read = hypfs_read_dir, \
+ .dirlist = LIST_HEAD_INIT(var.dirlist), \
+ }
+
+#define HYPFS_VARSIZE_INIT(var, typ, nam, msz) \
+ struct hypfs_entry_leaf __read_mostly var = { \
+ .e.type = (typ), \
+ .e.encoding = XEN_HYPFS_ENC_PLAIN, \
+ .e.name = (nam), \
+ .e.max_size = (msz), \
+ .e.read = hypfs_read_leaf, \
+ }
+
+/* Content and size need to be set via hypfs_string_set_reference(). */
+#define HYPFS_STRING_INIT(var, nam) \
+ HYPFS_VARSIZE_INIT(var, XEN_HYPFS_TYPE_STRING, nam, 0)
+
+/*
+ * Set content and size of a XEN_HYPFS_TYPE_STRING node. The node will point
+ * to str, so any later modification of *str should be followed by a call
+ * to hypfs_string_set_reference() in order to update the size of the node
+ * data.
+ */
+static inline void hypfs_string_set_reference(struct hypfs_entry_leaf *leaf,
+ const char *str)
+{
+ leaf->content = str;
+ leaf->e.size = strlen(str) + 1;
+}
+
+#define HYPFS_FIXEDSIZE_INIT(var, typ, nam, contvar, wr) \
+ struct hypfs_entry_leaf __read_mostly var = { \
+ .e.type = (typ), \
+ .e.encoding = XEN_HYPFS_ENC_PLAIN, \
+ .e.name = (nam), \
+ .e.size = sizeof(contvar), \
+ .e.max_size = (wr) ? sizeof(contvar) : 0, \
+ .e.read = hypfs_read_leaf, \
+ .e.write = (wr), \
+ .content = &(contvar), \
+ }
+
+#define HYPFS_UINT_INIT(var, nam, contvar) \
+ HYPFS_FIXEDSIZE_INIT(var, XEN_HYPFS_TYPE_UINT, nam, contvar, NULL)
+#define HYPFS_UINT_INIT_WRITABLE(var, nam, contvar) \
+ HYPFS_FIXEDSIZE_INIT(var, XEN_HYPFS_TYPE_UINT, nam, contvar, \
+ hypfs_write_leaf)
+
+#define HYPFS_INT_INIT(var, nam, contvar) \
+ HYPFS_FIXEDSIZE_INIT(var, XEN_HYPFS_TYPE_INT, nam, contvar, NULL)
+#define HYPFS_INT_INIT_WRITABLE(var, nam, contvar) \
+ HYPFS_FIXEDSIZE_INIT(var, XEN_HYPFS_TYPE_INT, nam, contvar, \
+ hypfs_write_leaf)
+
+#define HYPFS_BOOL_INIT(var, nam, contvar) \
+ HYPFS_FIXEDSIZE_INIT(var, XEN_HYPFS_TYPE_BOOL, nam, contvar, NULL)
+#define HYPFS_BOOL_INIT_WRITABLE(var, nam, contvar) \
+ HYPFS_FIXEDSIZE_INIT(var, XEN_HYPFS_TYPE_BOOL, nam, contvar, \
+ hypfs_write_bool)
+
+extern struct hypfs_entry_dir hypfs_root;
+
+int hypfs_add_dir(struct hypfs_entry_dir *parent,
+ struct hypfs_entry_dir *dir, bool nofault);
+int hypfs_add_leaf(struct hypfs_entry_dir *parent,
+ struct hypfs_entry_leaf *leaf, bool nofault);
+int hypfs_read_dir(const struct hypfs_entry *entry,
+ XEN_GUEST_HANDLE_PARAM(void) uaddr);
+int hypfs_read_leaf(const struct hypfs_entry *entry,
+ XEN_GUEST_HANDLE_PARAM(void) uaddr);
+int hypfs_write_leaf(struct hypfs_entry_leaf *leaf,
+ XEN_GUEST_HANDLE_PARAM(void) uaddr, unsigned int ulen);
+int hypfs_write_bool(struct hypfs_entry_leaf *leaf,
+ XEN_GUEST_HANDLE_PARAM(void) uaddr, unsigned int ulen);
+#endif
+
+#endif /* __XEN_HYPFS_H__ */
? vcpu_hvm_context hvm/hvm_vcpu.h
? vcpu_hvm_x86_32 hvm/hvm_vcpu.h
? vcpu_hvm_x86_64 hvm/hvm_vcpu.h
+? hypfs_direntry hypfs.h
+? hypfs_dirlistentry hypfs.h
? kexec_exec kexec.h
! kexec_image kexec.h
! kexec_range kexec.h
return xsm_default_action(action, current->domain, NULL);
}
+static XSM_INLINE int xsm_hypfs_op(XSM_DEFAULT_VOID)
+{
+ XSM_ASSERT_ACTION(XSM_PRIV);
+ return xsm_default_action(action, current->domain, NULL);
+}
+
static XSM_INLINE long xsm_do_xsm_op(XEN_GUEST_HANDLE_PARAM(xsm_op_t) op)
{
return -ENOSYS;
int (*resource_setup_misc) (void);
int (*page_offline)(uint32_t cmd);
+ int (*hypfs_op)(void);
long (*do_xsm_op) (XEN_GUEST_HANDLE_PARAM(xsm_op_t) op);
#ifdef CONFIG_COMPAT
return xsm_ops->page_offline(cmd);
}
+static inline int xsm_hypfs_op(xsm_default_t def)
+{
+ return xsm_ops->hypfs_op();
+}
+
static inline long xsm_do_xsm_op (XEN_GUEST_HANDLE_PARAM(xsm_op_t) op)
{
return xsm_ops->do_xsm_op(op);
set_to_dummy_if_null(ops, resource_setup_misc);
set_to_dummy_if_null(ops, page_offline);
+ set_to_dummy_if_null(ops, hypfs_op);
set_to_dummy_if_null(ops, hvm_param);
set_to_dummy_if_null(ops, hvm_control);
set_to_dummy_if_null(ops, hvm_param_nested);
}
}
+static inline int flask_hypfs_op(void)
+{
+ return domain_has_xen(current->domain, XEN__HYPFS_OP);
+}
+
static int flask_add_to_physmap(struct domain *d1, struct domain *d2)
{
return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__PHYSMAP);
.resource_setup_misc = flask_resource_setup_misc,
.page_offline = flask_page_offline,
+ .hypfs_op = flask_hypfs_op,
.hvm_param = flask_hvm_param,
.hvm_control = flask_hvm_param,
.hvm_param_nested = flask_hvm_param_nested,
lockprof
# XEN_SYSCTL_cpupool_op
cpupool_op
+# hypfs hypercall
+ hypfs_op
# XEN_SYSCTL_scheduler_op with XEN_DOMCTL_SCHEDOP_getinfo, XEN_SYSCTL_sched_id, XEN_DOMCTL_SCHEDOP_getvcpuinfo
getscheduler
# XEN_SYSCTL_scheduler_op with XEN_DOMCTL_SCHEDOP_putinfo, XEN_DOMCTL_SCHEDOP_putvcpuinfo