Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *    Hypervisor filesystem for Linux on s390. z/VM implementation.
0004  *
0005  *    Copyright IBM Corp. 2006
0006  *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
0007  */
0008 
0009 #include <linux/types.h>
0010 #include <linux/errno.h>
0011 #include <linux/string.h>
0012 #include <linux/vmalloc.h>
0013 #include <asm/extable.h>
0014 #include <asm/diag.h>
0015 #include <asm/ebcdic.h>
0016 #include <asm/timex.h>
0017 #include "hypfs.h"
0018 
0019 #define NAME_LEN 8
0020 #define DBFS_D2FC_HDR_VERSION 0
0021 
0022 static char local_guest[] = "        ";
0023 static char all_guests[] = "*       ";
0024 static char *all_groups = all_guests;
0025 static char *guest_query;
0026 
0027 struct diag2fc_data {
0028     __u32 version;
0029     __u32 flags;
0030     __u64 used_cpu;
0031     __u64 el_time;
0032     __u64 mem_min_kb;
0033     __u64 mem_max_kb;
0034     __u64 mem_share_kb;
0035     __u64 mem_used_kb;
0036     __u32 pcpus;
0037     __u32 lcpus;
0038     __u32 vcpus;
0039     __u32 ocpus;
0040     __u32 cpu_max;
0041     __u32 cpu_shares;
0042     __u32 cpu_use_samp;
0043     __u32 cpu_delay_samp;
0044     __u32 page_wait_samp;
0045     __u32 idle_samp;
0046     __u32 other_samp;
0047     __u32 total_samp;
0048     char  guest_name[NAME_LEN];
0049 };
0050 
0051 struct diag2fc_parm_list {
0052     char userid[NAME_LEN];
0053     char aci_grp[NAME_LEN];
0054     __u64 addr;
0055     __u32 size;
0056     __u32 fmt;
0057 };
0058 
0059 static int diag2fc(int size, char* query, void *addr)
0060 {
0061     unsigned long residual_cnt;
0062     unsigned long rc;
0063     struct diag2fc_parm_list parm_list;
0064 
0065     memcpy(parm_list.userid, query, NAME_LEN);
0066     ASCEBC(parm_list.userid, NAME_LEN);
0067     memcpy(parm_list.aci_grp, all_groups, NAME_LEN);
0068     ASCEBC(parm_list.aci_grp, NAME_LEN);
0069     parm_list.addr = (unsigned long)addr;
0070     parm_list.size = size;
0071     parm_list.fmt = 0x02;
0072     rc = -1;
0073 
0074     diag_stat_inc(DIAG_STAT_X2FC);
0075     asm volatile(
0076         "   diag    %0,%1,0x2fc\n"
0077         "0: nopr    %%r7\n"
0078         EX_TABLE(0b,0b)
0079         : "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory");
0080 
0081     if ((rc != 0 ) && (rc != -2))
0082         return rc;
0083     else
0084         return -residual_cnt;
0085 }
0086 
0087 /*
0088  * Allocate buffer for "query" and store diag 2fc at "offset"
0089  */
0090 static void *diag2fc_store(char *query, unsigned int *count, int offset)
0091 {
0092     void *data;
0093     int size;
0094 
0095     do {
0096         size = diag2fc(0, query, NULL);
0097         if (size < 0)
0098             return ERR_PTR(-EACCES);
0099         data = vmalloc(size + offset);
0100         if (!data)
0101             return ERR_PTR(-ENOMEM);
0102         if (diag2fc(size, query, data + offset) == 0)
0103             break;
0104         vfree(data);
0105     } while (1);
0106     *count = (size / sizeof(struct diag2fc_data));
0107 
0108     return data;
0109 }
0110 
0111 static void diag2fc_free(const void *data)
0112 {
0113     vfree(data);
0114 }
0115 
0116 #define ATTRIBUTE(dir, name, member) \
0117 do { \
0118     void *rc; \
0119     rc = hypfs_create_u64(dir, name, member); \
0120     if (IS_ERR(rc)) \
0121         return PTR_ERR(rc); \
0122 } while(0)
0123 
0124 static int hypfs_vm_create_guest(struct dentry *systems_dir,
0125                  struct diag2fc_data *data)
0126 {
0127     char guest_name[NAME_LEN + 1] = {};
0128     struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir;
0129     int dedicated_flag, capped_value;
0130 
0131     capped_value = (data->flags & 0x00000006) >> 1;
0132     dedicated_flag = (data->flags & 0x00000008) >> 3;
0133 
0134     /* guest dir */
0135     memcpy(guest_name, data->guest_name, NAME_LEN);
0136     EBCASC(guest_name, NAME_LEN);
0137     strim(guest_name);
0138     guest_dir = hypfs_mkdir(systems_dir, guest_name);
0139     if (IS_ERR(guest_dir))
0140         return PTR_ERR(guest_dir);
0141     ATTRIBUTE(guest_dir, "onlinetime_us", data->el_time);
0142 
0143     /* logical cpu information */
0144     cpus_dir = hypfs_mkdir(guest_dir, "cpus");
0145     if (IS_ERR(cpus_dir))
0146         return PTR_ERR(cpus_dir);
0147     ATTRIBUTE(cpus_dir, "cputime_us", data->used_cpu);
0148     ATTRIBUTE(cpus_dir, "capped", capped_value);
0149     ATTRIBUTE(cpus_dir, "dedicated", dedicated_flag);
0150     ATTRIBUTE(cpus_dir, "count", data->vcpus);
0151     /*
0152      * Note: The "weight_min" attribute got the wrong name.
0153      * The value represents the number of non-stopped (operating)
0154      * CPUS.
0155      */
0156     ATTRIBUTE(cpus_dir, "weight_min", data->ocpus);
0157     ATTRIBUTE(cpus_dir, "weight_max", data->cpu_max);
0158     ATTRIBUTE(cpus_dir, "weight_cur", data->cpu_shares);
0159 
0160     /* memory information */
0161     mem_dir = hypfs_mkdir(guest_dir, "mem");
0162     if (IS_ERR(mem_dir))
0163         return PTR_ERR(mem_dir);
0164     ATTRIBUTE(mem_dir, "min_KiB", data->mem_min_kb);
0165     ATTRIBUTE(mem_dir, "max_KiB", data->mem_max_kb);
0166     ATTRIBUTE(mem_dir, "used_KiB", data->mem_used_kb);
0167     ATTRIBUTE(mem_dir, "share_KiB", data->mem_share_kb);
0168 
0169     /* samples */
0170     samples_dir = hypfs_mkdir(guest_dir, "samples");
0171     if (IS_ERR(samples_dir))
0172         return PTR_ERR(samples_dir);
0173     ATTRIBUTE(samples_dir, "cpu_using", data->cpu_use_samp);
0174     ATTRIBUTE(samples_dir, "cpu_delay", data->cpu_delay_samp);
0175     ATTRIBUTE(samples_dir, "mem_delay", data->page_wait_samp);
0176     ATTRIBUTE(samples_dir, "idle", data->idle_samp);
0177     ATTRIBUTE(samples_dir, "other", data->other_samp);
0178     ATTRIBUTE(samples_dir, "total", data->total_samp);
0179     return 0;
0180 }
0181 
0182 int hypfs_vm_create_files(struct dentry *root)
0183 {
0184     struct dentry *dir, *file;
0185     struct diag2fc_data *data;
0186     unsigned int count = 0;
0187     int rc, i;
0188 
0189     data = diag2fc_store(guest_query, &count, 0);
0190     if (IS_ERR(data))
0191         return PTR_ERR(data);
0192 
0193     /* Hypervisor Info */
0194     dir = hypfs_mkdir(root, "hyp");
0195     if (IS_ERR(dir)) {
0196         rc = PTR_ERR(dir);
0197         goto failed;
0198     }
0199     file = hypfs_create_str(dir, "type", "z/VM Hypervisor");
0200     if (IS_ERR(file)) {
0201         rc = PTR_ERR(file);
0202         goto failed;
0203     }
0204 
0205     /* physical cpus */
0206     dir = hypfs_mkdir(root, "cpus");
0207     if (IS_ERR(dir)) {
0208         rc = PTR_ERR(dir);
0209         goto failed;
0210     }
0211     file = hypfs_create_u64(dir, "count", data->lcpus);
0212     if (IS_ERR(file)) {
0213         rc = PTR_ERR(file);
0214         goto failed;
0215     }
0216 
0217     /* guests */
0218     dir = hypfs_mkdir(root, "systems");
0219     if (IS_ERR(dir)) {
0220         rc = PTR_ERR(dir);
0221         goto failed;
0222     }
0223 
0224     for (i = 0; i < count; i++) {
0225         rc = hypfs_vm_create_guest(dir, &(data[i]));
0226         if (rc)
0227             goto failed;
0228     }
0229     diag2fc_free(data);
0230     return 0;
0231 
0232 failed:
0233     diag2fc_free(data);
0234     return rc;
0235 }
0236 
0237 struct dbfs_d2fc_hdr {
0238     u64 len;        /* Length of d2fc buffer without header */
0239     u16 version;    /* Version of header */
0240     union tod_clock tod_ext; /* TOD clock for d2fc */
0241     u64 count;      /* Number of VM guests in d2fc buffer */
0242     char    reserved[30];
0243 } __attribute__ ((packed));
0244 
0245 struct dbfs_d2fc {
0246     struct dbfs_d2fc_hdr    hdr;    /* 64 byte header */
0247     char            buf[];  /* d2fc buffer */
0248 } __attribute__ ((packed));
0249 
0250 static int dbfs_diag2fc_create(void **data, void **data_free_ptr, size_t *size)
0251 {
0252     struct dbfs_d2fc *d2fc;
0253     unsigned int count;
0254 
0255     d2fc = diag2fc_store(guest_query, &count, sizeof(d2fc->hdr));
0256     if (IS_ERR(d2fc))
0257         return PTR_ERR(d2fc);
0258     store_tod_clock_ext(&d2fc->hdr.tod_ext);
0259     d2fc->hdr.len = count * sizeof(struct diag2fc_data);
0260     d2fc->hdr.version = DBFS_D2FC_HDR_VERSION;
0261     d2fc->hdr.count = count;
0262     memset(&d2fc->hdr.reserved, 0, sizeof(d2fc->hdr.reserved));
0263     *data = d2fc;
0264     *data_free_ptr = d2fc;
0265     *size = d2fc->hdr.len + sizeof(struct dbfs_d2fc_hdr);
0266     return 0;
0267 }
0268 
0269 static struct hypfs_dbfs_file dbfs_file_2fc = {
0270     .name       = "diag_2fc",
0271     .data_create    = dbfs_diag2fc_create,
0272     .data_free  = diag2fc_free,
0273 };
0274 
0275 int hypfs_vm_init(void)
0276 {
0277     if (!MACHINE_IS_VM)
0278         return 0;
0279     if (diag2fc(0, all_guests, NULL) > 0)
0280         guest_query = all_guests;
0281     else if (diag2fc(0, local_guest, NULL) > 0)
0282         guest_query = local_guest;
0283     else
0284         return -EACCES;
0285     hypfs_dbfs_create_file(&dbfs_file_2fc);
0286     return 0;
0287 }
0288 
0289 void hypfs_vm_exit(void)
0290 {
0291     if (!MACHINE_IS_VM)
0292         return;
0293     hypfs_dbfs_remove_file(&dbfs_file_2fc);
0294 }