Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  htmdump.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (C) IBM Corporation, 2024
 */


#define pr_fmt(fmt) "htmdump: " fmt

#include <linux/debugfs.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/machdep.h>
#include <asm/plpar_wrappers.h>
#include <asm/kvm_guest.h>

static void *htm_buf;
static void *htm_status_buf;
static void *htm_info_buf;
static void *htm_caps_buf;
static u32 nodeindex;
static u32 nodalchipindex;
static u32 coreindexonchip;
static u32 htmtype;
static u32 htmconfigure;
static u32 htmstart;
static u32 htmsetup;
static u64 htmflags;

static struct dentry *htmdump_debugfs_dir;
#define HTM_ENABLE 1
#define HTM_DISABLE 0
#define HTM_NOWRAP 1
#define HTM_WRAP 0

/*
 * Check the return code for H_HTM hcall.
 * Return non-zero value (1) if either H_PARTIAL or H_SUCCESS
 * is returned. For other return codes:
 * Return zero if H_NOT_AVAILABLE.
 * Return -EBUSY if hcall return busy.
 * Return -EINVAL if any parameter or operation is not valid.
 * Return -EPERM if HTM Virtualization Engine Technology code
 * is not applied.
 * Return -EIO if the HTM state is not valid.
 */

static ssize_t htm_return_check(long rc)
{
 switch (rc) {
 case H_SUCCESS:
 /* H_PARTIAL for the case where all available data can't be
 * returned due to buffer size constraint.
 */

 case H_PARTIAL:
  break;
 /* H_NOT_AVAILABLE indicates reading from an offset outside the range,
 * i.e. past end of file.
 */

 case H_NOT_AVAILABLE:
  return 0;
 case H_BUSY:
 case H_LONG_BUSY_ORDER_1_MSEC:
 case H_LONG_BUSY_ORDER_10_MSEC:
 case H_LONG_BUSY_ORDER_100_MSEC:
 case H_LONG_BUSY_ORDER_1_SEC:
 case H_LONG_BUSY_ORDER_10_SEC:
 case H_LONG_BUSY_ORDER_100_SEC:
  return -EBUSY;
 case H_PARAMETER:
 case H_P2:
 case H_P3:
 case H_P4:
 case H_P5:
 case H_P6:
  return -EINVAL;
 case H_STATE:
  return -EIO;
 case H_AUTHORITY:
  return -EPERM;
 }

 /*
 * Return 1 for H_SUCCESS/H_PARTIAL
 */

 return 1;
}

static ssize_t htmdump_read(struct file *filp, char __user *ubuf,
        size_t count, loff_t *ppos)
{
 void *htm_buf = filp->private_data;
 unsigned long page, read_size, available;
 loff_t offset;
 long rc, ret;

 page = ALIGN_DOWN(*ppos, PAGE_SIZE);
 offset = (*ppos) % PAGE_SIZE;

 /*
 * Invoke H_HTM call with:
 * - operation as htm dump (H_HTM_OP_DUMP_DATA)
 * - last three values are address, size and offset
 */

 rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip,
       htmtype, H_HTM_OP_DUMP_DATA, virt_to_phys(htm_buf),
       PAGE_SIZE, page);

 ret = htm_return_check(rc);
 if (ret <= 0) {
  pr_debug("H_HTM hcall failed for op: H_HTM_OP_DUMP_DATA, returning %ld\n", ret);
  return ret;
 }

 available = PAGE_SIZE;
 read_size = min(count, available);
 *ppos += read_size;
 return simple_read_from_buffer(ubuf, count, &offset, htm_buf, available);
}

static const struct file_operations htmdump_fops = {
 .llseek = NULL,
 .read = htmdump_read,
 .open = simple_open,
};

static int  htmconfigure_set(void *data, u64 val)
{
 long rc, ret;
 unsigned long param1 = -1, param2 = -1;

 /*
 * value as 1 : configure HTM.
 * value as 0 : deconfigure HTM. Return -EINVAL for
 * other values.
 */

 if (val == HTM_ENABLE) {
  /*
 * Invoke H_HTM call with:
 * - operation as htm configure (H_HTM_OP_CONFIGURE)
 * - If htmflags is set, param1 and param2 will be -1
 *   which is an indicator to use default htm mode reg mask
 *   and htm mode reg value.
 * - last three values are unused, hence set to zero
 */

  if (!htmflags) {
   param1 = 0;
   param2 = 0;
  }

  rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip,
      htmtype, H_HTM_OP_CONFIGURE, param1, param2, 0);
 } else if (val == HTM_DISABLE) {
  /*
 * Invoke H_HTM call with:
 * - operation as htm deconfigure (H_HTM_OP_DECONFIGURE)
 * - last three values are unused, hence set to zero
 */

  rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip,
    htmtype, H_HTM_OP_DECONFIGURE, 0, 0, 0);
 } else
  return -EINVAL;

 ret = htm_return_check(rc);
 if (ret <= 0) {
  pr_debug("H_HTM hcall failed, returning %ld\n", ret);
  return ret;
 }

 /* Set htmconfigure if operation succeeds */
 htmconfigure = val;

 return 0;
}

static int htmconfigure_get(void *data, u64 *val)
{
 *val = htmconfigure;
 return 0;
}

static int  htmstart_set(void *data, u64 val)
{
 long rc, ret;

 /*
 * value as 1: start HTM
 * value as 0: stop HTM
 * Return -EINVAL for other values.
 */

 if (val == HTM_ENABLE) {
  /*
 * Invoke H_HTM call with:
 * - operation as htm start (H_HTM_OP_START)
 * - last three values are unused, hence set to zero
 */

  rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip,
      htmtype, H_HTM_OP_START, 0, 0, 0);

 } else if (val == HTM_DISABLE) {
  /*
 * Invoke H_HTM call with:
 * - operation as htm stop (H_HTM_OP_STOP)
 * - last three values are unused, hence set to zero
 */

  rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip,
    htmtype, H_HTM_OP_STOP, 0, 0, 0);
 } else
  return -EINVAL;

 ret = htm_return_check(rc);
 if (ret <= 0) {
  pr_debug("H_HTM hcall failed, returning %ld\n", ret);
  return ret;
 }

 /* Set htmstart if H_HTM_OP_START/H_HTM_OP_STOP operation succeeds */
 htmstart = val;

 return 0;
}

static int htmstart_get(void *data, u64 *val)
{
 *val = htmstart;
 return 0;
}

static ssize_t htmstatus_read(struct file *filp, char __user *ubuf,
        size_t count, loff_t *ppos)
{
 void *htm_status_buf = filp->private_data;
 long rc, ret;
 u64 *num_entries;
 u64 to_copy;
 int htmstatus_flag;

 /*
 * Invoke H_HTM call with:
 * - operation as htm status (H_HTM_OP_STATUS)
 * - last three values as addr, size and offset
 */

 rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip,
       htmtype, H_HTM_OP_STATUS, virt_to_phys(htm_status_buf),
       PAGE_SIZE, 0);

 ret = htm_return_check(rc);
 if (ret <= 0) {
  pr_debug("H_HTM hcall failed for op: H_HTM_OP_STATUS, returning %ld\n", ret);
  return ret;
 }

 /*
 * HTM status buffer, start of buffer + 0x10 gives the
 * number of HTM entries in the buffer. Each nest htm status
 * entry is 0x6 bytes where each core htm status entry is
 * 0x8 bytes.
 * So total count to copy is:
 * 32 bytes (for first 7 fields) + (number of HTM entries * entry size)
 */

 num_entries = htm_status_buf + 0x10;
 if (htmtype == 0x2)
  htmstatus_flag = 0x8;
 else
  htmstatus_flag = 0x6;
 to_copy = 32 + (be64_to_cpu(*num_entries) * htmstatus_flag);
 return simple_read_from_buffer(ubuf, count, ppos, htm_status_buf, to_copy);
}

static const struct file_operations htmstatus_fops = {
 .llseek = NULL,
 .read = htmstatus_read,
 .open = simple_open,
};

static ssize_t htminfo_read(struct file *filp, char __user *ubuf,
        size_t count, loff_t *ppos)
{
 void *htm_info_buf = filp->private_data;
 long rc, ret;
 u64 *num_entries;
 u64 to_copy;

 /*
 * Invoke H_HTM call with:
 * - operation as htm status (H_HTM_OP_STATUS)
 * - last three values as addr, size and offset
 */

 rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip,
       htmtype, H_HTM_OP_DUMP_SYSPROC_CONF, virt_to_phys(htm_info_buf),
       PAGE_SIZE, 0);

 ret = htm_return_check(rc);
 if (ret <= 0) {
  pr_debug("H_HTM hcall failed for op: H_HTM_OP_DUMP_SYSPROC_CONF, returning %ld\n", ret);
  return ret;
 }

 /*
 * HTM status buffer, start of buffer + 0x10 gives the
 * number of HTM entries in the buffer. Each entry of processor
 * is 16 bytes.
 *
 * So total count to copy is:
 * 32 bytes (for first 5 fields) + (number of HTM entries * entry size)
 */

 num_entries = htm_info_buf + 0x10;
 to_copy = 32 + (be64_to_cpu(*num_entries) * 16);
 return simple_read_from_buffer(ubuf, count, ppos, htm_info_buf, to_copy);
}

static ssize_t htmcaps_read(struct file *filp, char __user *ubuf,
        size_t count, loff_t *ppos)
{
 void *htm_caps_buf = filp->private_data;
 long rc, ret;

 /*
 * Invoke H_HTM call with:
 * - operation as htm capabilities (H_HTM_OP_CAPABILITIES)
 * - last three values as addr, size (0x80 for Capabilities Output Buffer
 *   and zero
 */

 rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip,
       htmtype, H_HTM_OP_CAPABILITIES, virt_to_phys(htm_caps_buf),
       0x80, 0);

 ret = htm_return_check(rc);
 if (ret <= 0) {
  pr_debug("H_HTM hcall failed for op: H_HTM_OP_CAPABILITIES, returning %ld\n", ret);
  return ret;
 }

 return simple_read_from_buffer(ubuf, count, ppos, htm_caps_buf, 0x80);
}

static const struct file_operations htminfo_fops = {
 .llseek = NULL,
 .read   = htminfo_read,
 .open   = simple_open,
};

static const struct file_operations htmcaps_fops = {
 .llseek = NULL,
 .read   = htmcaps_read,
 .open   = simple_open,
};

static int  htmsetup_set(void *data, u64 val)
{
 long rc, ret;

 /*
 * Input value: HTM buffer size in the power of 2
 * example: hex value 0x21 ( decimal: 33 ) is for
 * 8GB
 * Invoke H_HTM call with:
 * - operation as htm start (H_HTM_OP_SETUP)
 * - parameter 1 set to input value.
 * - last two values are unused, hence set to zero
 */

 rc = htm_hcall_wrapper(htmflags, nodeindex, nodalchipindex, coreindexonchip,
   htmtype, H_HTM_OP_SETUP, val, 0, 0);

 ret = htm_return_check(rc);
 if (ret <= 0) {
  pr_debug("H_HTM hcall failed for op: H_HTM_OP_SETUP, returning %ld\n", ret);
  return ret;
 }

 /* Set htmsetup if H_HTM_OP_SETUP operation succeeds */
 htmsetup = val;

 return 0;
}

static int htmsetup_get(void *data, u64 *val)
{
 *val = htmsetup;
 return 0;
}

static int  htmflags_set(void *data, u64 val)
{
 /*
 * Input value:
 * Currently supported flag value is to enable/disable
 * HTM buffer wrap. wrap is used along with "configure"
 * to prevent HTM buffer from wrapping.
 * Writing 1 will set noWrap while configuring HTM
 */

 if (val == HTM_NOWRAP)
  htmflags = H_HTM_FLAGS_NOWRAP;
 else if (val == HTM_WRAP)
  htmflags = 0;
 else
  return -EINVAL;

 return 0;
}

static int htmflags_get(void *data, u64 *val)
{
 *val = htmflags;
 return 0;
}

DEFINE_SIMPLE_ATTRIBUTE(htmconfigure_fops, htmconfigure_get, htmconfigure_set, "%llu\n");
DEFINE_SIMPLE_ATTRIBUTE(htmstart_fops, htmstart_get, htmstart_set, "%llu\n");
DEFINE_SIMPLE_ATTRIBUTE(htmsetup_fops, htmsetup_get, htmsetup_set, "%llu\n");
DEFINE_SIMPLE_ATTRIBUTE(htmflags_fops, htmflags_get, htmflags_set, "%llu\n");

static int htmdump_init_debugfs(void)
{
 htm_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 if (!htm_buf) {
  pr_err("Failed to allocate htmdump buf\n");
  return -ENOMEM;
 }

 htmdump_debugfs_dir = debugfs_create_dir("htmdump",
        arch_debugfs_dir);

 debugfs_create_u32("nodeindex", 0600,
   htmdump_debugfs_dir, &nodeindex);
 debugfs_create_u32("nodalchipindex", 0600,
   htmdump_debugfs_dir, &nodalchipindex);
 debugfs_create_u32("coreindexonchip", 0600,
   htmdump_debugfs_dir, &coreindexonchip);
 debugfs_create_u32("htmtype", 0600,
   htmdump_debugfs_dir, &htmtype);
 debugfs_create_file("trace", 0400, htmdump_debugfs_dir, htm_buf, &htmdump_fops);

 /*
 * Debugfs interface files to control HTM operations:
 */

 debugfs_create_file("htmconfigure", 0600, htmdump_debugfs_dir, NULL, &htmconfigure_fops);
 debugfs_create_file("htmstart", 0600, htmdump_debugfs_dir, NULL, &htmstart_fops);
 debugfs_create_file("htmsetup", 0600, htmdump_debugfs_dir, NULL, &htmsetup_fops);
 debugfs_create_file("htmflags", 0600, htmdump_debugfs_dir, NULL, &htmflags_fops);

 /* Debugfs interface file to present status of HTM */
 htm_status_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 if (!htm_status_buf) {
  pr_err("Failed to allocate htmstatus buf\n");
  return -ENOMEM;
 }

 /* Debugfs interface file to present System Processor Configuration */
 htm_info_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 if (!htm_info_buf) {
  pr_err("Failed to allocate htm info buf\n");
  return -ENOMEM;
 }

 /* Debugfs interface file to present HTM capabilities */
 htm_caps_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 if (!htm_caps_buf) {
  pr_err("Failed to allocate htm caps buf\n");
  return -ENOMEM;
 }

 debugfs_create_file("htmstatus", 0400, htmdump_debugfs_dir, htm_status_buf, &htmstatus_fops);
 debugfs_create_file("htminfo", 0400, htmdump_debugfs_dir, htm_info_buf, &htminfo_fops);
 debugfs_create_file("htmcaps", 0400, htmdump_debugfs_dir, htm_caps_buf, &htmcaps_fops);

 return 0;
}

static int __init htmdump_init(void)
{
 /* Disable on kvm guest */
 if (is_kvm_guest()) {
  pr_info("htmdump not supported inside KVM guest\n");
  return -EOPNOTSUPP;
 }

 if (htmdump_init_debugfs())
  return -ENOMEM;

 return 0;
}

static void __exit htmdump_exit(void)
{
 debugfs_remove_recursive(htmdump_debugfs_dir);
 kfree(htm_buf);
}

module_init(htmdump_init);
module_exit(htmdump_exit);
MODULE_DESCRIPTION("PHYP Hardware Trace Macro (HTM) data dumper");
MODULE_LICENSE("GPL");

Messung V0.5
C=95 H=96 G=95

¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge