This allows user to read back hab runtime information.
Change-Id: Id266dd17b9c9d38f0e93aa600510ae1c6b12cca5
Signed-off-by: Yong Ding <yongding@codeaurora.org>
hab_mem_linux.o \
hab_pipe.o \
hab_parser.o \
- khab_test.o
+ khab_test.o \
+ hab_stat.o
ifdef CONFIG_GHS_VMM
msm_hab_hyp-objs = \
.openlock = __SPIN_LOCK_UNLOCKED(&hab_devices[__num__].openlock)\
}
-static const char hab_info_str[] = "Change: 16239527 Revision: #65";
+static const char hab_info_str[] = "Change: 16764735 Revision: #76";
/*
* The following has to match habmm definitions, order does not matter if
pr_err("vchan alloc failed\n");
ret = -ENOMEM;
goto err;
- } else
+ }
/* Send Init sequence */
hab_open_request_init(&request, HAB_PAYLOAD_TYPE_INIT, pchan,
}
} else {
pr_err("failed to find device, mmid %d\n", mmid);
+ return -ENODEV;
}
}
} else
set_dma_ops(hab_driver.dev, &hab_dma_ops);
}
+
+ hab_stat_init(&hab_driver);
+
return result;
err:
dev_t dev;
hab_hypervisor_unregister();
+ hab_stat_deinit(&hab_driver);
hab_ctx_put(hab_driver.kctx);
dev = MKDEV(MAJOR(hab_driver.major), 0);
device_destroy(hab_driver.class, dev);
#include <linux/dma-mapping.h>
#include <linux/jiffies.h>
#include <linux/reboot.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
enum hab_payload_type {
HAB_PAYLOAD_TYPE_MSG = 0x0,
int b_loopback;
void *hyp_priv; /* hypervisor plug-in storage */
+
+ void *hab_vmm_handle;
};
struct virtual_channel {
void hab_vchan_stop(struct virtual_channel *vchan);
void hab_vchans_stop(struct physical_channel *pchan);
void hab_vchan_stop_notify(struct virtual_channel *vchan);
+void hab_vchans_empty_wait(int vmid);
int hab_mem_export(struct uhab_context *ctx,
struct hab_export *param, int kernel);
int habmem_imp_hyp_mmap(struct file *flip, struct vm_area_struct *vma);
-
+int habmm_imp_hyp_map_check(void *imp_ctx, struct export_desc *exp);
void hab_msg_free(struct hab_message *message);
int hab_msg_dequeue(struct virtual_channel *vchan,
int hab_open_receive_cancel(struct physical_channel *pchan,
size_t sizebytes);
+int hab_stat_init(struct hab_driver *drv);
+int hab_stat_deinit(struct hab_driver *drv);
+int hab_stat_show_vchan(struct hab_driver *drv, char *buf, int sz);
+int hab_stat_show_ctx(struct hab_driver *drv, char *buf, int sz);
+int hab_stat_show_expimp(struct hab_driver *drv, int pid, char *buf, int sz);
+
+int hab_stat_init_sub(struct hab_driver *drv);
+int hab_stat_deinit_sub(struct hab_driver *drv);
+
/* Global singleton HAB instance */
extern struct hab_driver hab_driver;
return 0;
}
+
+int habmm_imp_hyp_map_check(void *imp_ctx, struct export_desc *exp)
+{
+ struct importer_context *priv = imp_ctx;
+ struct pages_list *pglist;
+ int found = 0;
+
+ read_lock(&priv->implist_lock);
+ list_for_each_entry(pglist, &priv->imp_list, list) {
+ if (pglist->export_id == exp->export_id &&
+ pglist->vcid == exp->vcid_remote) {
+ found = 1;
+ break;
+ }
+ }
+ read_unlock(&priv->implist_lock);
+
+ return found;
+}
exp->vchan = vchan;
exp->vcid_local = vchan->id;
exp->vcid_remote = vchan->otherend_id;
- exp->domid_local = -1; /* dom id, provided on the importer */
- exp->domid_remote = vchan->pchan->dom_id;
+ exp->domid_local = vchan->pchan->vmid_local;
+ exp->domid_remote = vchan->pchan->vmid_remote;
exp->ctx = vchan->ctx;
exp->pchan = vchan->pchan;
struct uhab_context *ctx;
if (!exp || !exp->ctx || !exp->pchan) {
- pr_err("failed to find valid info in exp %pK\n", exp);
+ pr_err("failed to find valid info in exp %pK ctx %pK pchan %pK\n",
+ exp, exp->ctx, exp->pchan);
return;
}
void *qnx_hyp_rx_dispatch(void *data);
void hab_pipe_reset(struct physical_channel *pchan);
-
+void habhyp_notify(void *commdev);
#endif /* __HAB_QNX_H */
--- /dev/null
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "hab.h"
+#include "hab_grantable.h"
+
+#define MAX_LINE_SIZE 128
+
+int hab_stat_init(struct hab_driver *driver)
+{
+ return hab_stat_init_sub(driver);
+}
+
+int hab_stat_deinit(struct hab_driver *driver)
+{
+ return hab_stat_deinit_sub(driver);
+}
+
+/*
+ * If all goes well the return value is the formated print and concatenated
+ * original dest string.
+ */
+static int hab_stat_buffer_print(char *dest,
+ int dest_size, const char *fmt, ...)
+{
+ va_list args;
+ char line[MAX_LINE_SIZE];
+ int ret;
+
+ va_start(args, fmt);
+ ret = vsnprintf(line, sizeof(line), fmt, args);
+ va_end(args);
+ if (ret > 0)
+ ret = strlcat(dest, line, dest_size);
+ return ret;
+}
+
+int hab_stat_show_vchan(struct hab_driver *driver,
+ char *buf, int size)
+{
+ int i, ret = 0;
+
+ ret = strlcpy(buf, "", size);
+ for (i = 0; i < driver->ndevices; i++) {
+ struct hab_device *dev = &driver->devp[i];
+ struct physical_channel *pchan;
+ struct virtual_channel *vc;
+
+ spin_lock_bh(&dev->pchan_lock);
+ list_for_each_entry(pchan, &dev->pchannels, node) {
+ if (!pchan->vcnt)
+ continue;
+
+ ret = hab_stat_buffer_print(buf, size,
+ "mmid %s role %d local %d remote %d vcnt %d:\n",
+ pchan->name, pchan->is_be, pchan->vmid_local,
+ pchan->vmid_remote, pchan->vcnt);
+
+ read_lock(&pchan->vchans_lock);
+ list_for_each_entry(vc, &pchan->vchannels, pnode) {
+ ret = hab_stat_buffer_print(buf, size,
+ "%08X ", vc->id);
+ }
+ ret = hab_stat_buffer_print(buf, size, "\n");
+ read_unlock(&pchan->vchans_lock);
+ }
+ spin_unlock_bh(&dev->pchan_lock);
+ }
+
+ return ret;
+}
+
+int hab_stat_show_ctx(struct hab_driver *driver,
+ char *buf, int size)
+{
+ int ret = 0;
+ struct uhab_context *ctx;
+
+ ret = strlcpy(buf, "", size);
+
+ spin_lock_bh(&hab_driver.drvlock);
+ ret = hab_stat_buffer_print(buf, size,
+ "Total contexts %d\n",
+ driver->ctx_cnt);
+ list_for_each_entry(ctx, &hab_driver.uctx_list, node) {
+ ret = hab_stat_buffer_print(buf, size,
+ "ctx %d K %d close %d vc %d exp %d imp %d open %d\n",
+ ctx->owner, ctx->kernel, ctx->closing,
+ ctx->vcnt, ctx->export_total,
+ ctx->import_total, ctx->pending_cnt);
+ }
+ spin_unlock_bh(&hab_driver.drvlock);
+
+ return ret;
+}
+
+static int get_pft_tbl_total_size(struct compressed_pfns *pfn_table)
+{
+ int i, total_size = 0;
+
+ for (i = 0; i < pfn_table->nregions; i++)
+ total_size += pfn_table->region[i].size * PAGE_SIZE;
+
+ return total_size;
+}
+
+static int print_ctx_total_expimp(struct uhab_context *ctx,
+ char *buf, int size)
+{
+ struct compressed_pfns *pfn_table;
+ int exp_total = 0, imp_total = 0;
+ int exp_cnt = 0, imp_cnt = 0;
+ struct export_desc *exp;
+
+ read_lock(&ctx->exp_lock);
+ list_for_each_entry(exp, &ctx->exp_whse, node) {
+ pfn_table = (struct compressed_pfns *)exp->payload;
+ exp_total += get_pft_tbl_total_size(pfn_table);
+ exp_cnt++;
+ }
+ read_unlock(&ctx->exp_lock);
+
+ spin_lock_bh(&ctx->imp_lock);
+ list_for_each_entry(exp, &ctx->imp_whse, node) {
+ if (habmm_imp_hyp_map_check(ctx->import_ctx, exp)) {
+ pfn_table = (struct compressed_pfns *)exp->payload;
+ imp_total += get_pft_tbl_total_size(pfn_table);
+ imp_cnt++;
+ }
+ }
+ spin_unlock_bh(&ctx->imp_lock);
+
+ if (exp_cnt || exp_total || imp_cnt || imp_total)
+ return hab_stat_buffer_print(buf, size,
+ "ctx %d exp %d size %d imp %d size %d\n",
+ ctx->owner, exp_cnt, exp_total,
+ imp_cnt, imp_total);
+ else
+ return 0;
+}
+
+int hab_stat_show_expimp(struct hab_driver *driver,
+ int pid, char *buf, int size)
+{
+ struct uhab_context *ctx;
+ int ret;
+
+ ret = strlcpy(buf, "", size);
+
+ spin_lock_bh(&hab_driver.drvlock);
+ list_for_each_entry(ctx, &hab_driver.uctx_list, node) {
+ if (pid == ctx->owner)
+ ret = print_ctx_total_expimp(ctx, buf, size);
+ }
+ spin_unlock_bh(&hab_driver.drvlock);
+
+ return ret;
+}
hab_vchan_stop(vchan);
}
+static int hab_vchans_per_pchan_empty(struct physical_channel *pchan)
+{
+ int empty;
+
+ read_lock(&pchan->vchans_lock);
+ empty = list_empty(&pchan->vchannels);
+ read_unlock(&pchan->vchans_lock);
+
+ return empty;
+}
+
+static int hab_vchans_empty(int vmid)
+{
+ int i, empty = 1;
+ struct physical_channel *pchan;
+ struct hab_device *hab_dev;
+
+ for (i = 0; i < hab_driver.ndevices; i++) {
+ hab_dev = &hab_driver.devp[i];
+
+ spin_lock_bh(&hab_dev->pchan_lock);
+ list_for_each_entry(pchan, &hab_dev->pchannels, node) {
+ if (pchan->vmid_remote == vmid) {
+ if (!hab_vchans_per_pchan_empty(pchan)) {
+ empty = 0;
+ spin_unlock_bh(&hab_dev->pchan_lock);
+ break;
+ }
+ }
+ }
+ spin_unlock_bh(&hab_dev->pchan_lock);
+ }
+
+ return empty;
+}
+
+/*
+ * block until all vchans of a given GVM are explicitly closed
+ * with habmm_socket_close() by hab clients themselves
+ */
+void hab_vchans_empty_wait(int vmid)
+{
+ pr_info("waiting for GVM%d's sockets closure\n", vmid);
+
+ while (!hab_vchans_empty(vmid))
+ schedule();
+
+ pr_info("all of GVM%d's sockets are closed\n", vmid);
+}
int hab_vchan_find_domid(struct virtual_channel *vchan)
{
*
*/
#include "hab.h"
-#include "khab_test.h"
-#include "hab_pipe.h"
-#ifdef CONFIG_MSM_GVM_QUIN
-#include "hab_qvm.h"
-#endif
+#if !defined CONFIG_GHS_VMM && defined(CONFIG_MSM_GVM_QUIN)
#include <asm/cacheflush.h>
#include <linux/list.h>
+#include "hab_pipe.h"
+#include "hab_qvm.h"
+#include "khab_test.h"
static char g_perf_test_result[256];
static int hab_shmm_throughput_test(void)
{
struct hab_device *habDev;
-#ifdef CONFIG_MSM_GVM_QUIN
struct qvm_channel *dev;
-#endif
- struct hab_shared_buf *sh_buf = NULL;
+ struct hab_shared_buf *sh_buf;
struct physical_channel *pchan;
struct timeval tv1, tv2;
int i, counter;
pchan = list_first_entry(&(habDev->pchannels),
struct physical_channel, node);
-#ifdef CONFIG_MSM_GVM_QUIN
dev = pchan->hyp_data;
if (!dev) {
ret = -EPERM;
}
sh_buf = dev->pipe_ep->tx_info.sh_buf;
-#endif
/* pChannel is of 128k, we use 64k to test */
size = 0x10000;
return strlcpy(buffer, g_perf_test_result,
strlen(g_perf_test_result)+1);
}
+#endif
+
+static struct kobject *hab_kobject;
+
+static int vchan_stat;
+static int context_stat;
+static int pid_stat;
+
+static ssize_t vchan_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return hab_stat_show_vchan(&hab_driver, buf, PAGE_SIZE);
+}
+
+static ssize_t vchan_store(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf, size_t count)
+{
+ int ret;
+
+ ret = sscanf(buf, "%du", &vchan_stat);
+ if (ret < 1) {
+ pr_err("failed to read anything from input %d", ret);
+ return 0;
+ } else
+ return vchan_stat;
+}
+
+static ssize_t ctx_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return hab_stat_show_ctx(&hab_driver, buf, PAGE_SIZE);
+}
+
+static ssize_t ctx_store(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf, size_t count)
+{
+ int ret;
+
+ ret = sscanf(buf, "%du", &context_stat);
+ if (ret < 1) {
+ pr_err("failed to read anything from input %d", ret);
+ return 0;
+ } else
+ return context_stat;
+}
+
+static ssize_t expimp_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return hab_stat_show_expimp(&hab_driver, pid_stat, buf, PAGE_SIZE);
+}
+
+static ssize_t expimp_store(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf, size_t count)
+{
+ int ret;
+
+ ret = sscanf(buf, "%du", &pid_stat);
+ if (ret < 1) {
+ pr_err("failed to read anything from input %d", ret);
+ return 0;
+ } else
+ return pid_stat;
+}
+
+static struct kobj_attribute vchan_attribute = __ATTR(vchan_stat, 0660,
+ vchan_show,
+ vchan_store);
+
+static struct kobj_attribute ctx_attribute = __ATTR(context_stat, 0660,
+ ctx_show,
+ ctx_store);
+
+static struct kobj_attribute expimp_attribute = __ATTR(pid_stat, 0660,
+ expimp_show,
+ expimp_store);
+
+int hab_stat_init_sub(struct hab_driver *driver)
+{
+ int result;
+
+ hab_kobject = kobject_create_and_add("hab", kernel_kobj);
+ if (!hab_kobject)
+ return -ENOMEM;
+
+ result = sysfs_create_file(hab_kobject, &vchan_attribute.attr);
+ if (result)
+ pr_debug("cannot add vchan in /sys/kernel/hab %d\n", result);
+
+ result = sysfs_create_file(hab_kobject, &ctx_attribute.attr);
+ if (result)
+ pr_debug("cannot add ctx in /sys/kernel/hab %d\n", result);
+
+ result = sysfs_create_file(hab_kobject, &expimp_attribute.attr);
+ if (result)
+ pr_debug("cannot add expimp in /sys/kernel/hab %d\n", result);
+
+ return result;
+}
+
+int hab_stat_deinit_sub(struct hab_driver *driver)
+{
+ sysfs_remove_file(hab_kobject, &vchan_attribute.attr);
+ sysfs_remove_file(hab_kobject, &ctx_attribute.attr);
+ sysfs_remove_file(hab_kobject, &expimp_attribute.attr);
+ kobject_put(hab_kobject);
+
+ return 0;
+}
#include "hab.h"
#include "hab_qvm.h"
-static inline void habhyp_notify(void *commdev)
+inline void habhyp_notify(void *commdev)
{
struct qvm_channel *dev = (struct qvm_channel *)commdev;
struct habmm_xing_vm_stat *pstat =
(struct habmm_xing_vm_stat *)payload;
- do_gettimeofday(&tv);
- pstat->tx_sec = tv.tv_sec;
- pstat->tx_usec = tv.tv_usec;
+ if (pstat) {
+ do_gettimeofday(&tv);
+ pstat->tx_sec = tv.tv_sec;
+ pstat->tx_usec = tv.tv_usec;
+ } else {
+ spin_unlock_bh(&dev->io_lock);
+ return -EINVAL;
+ }
}
if (sizebytes) {