~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/s390/kernel/cpcmd.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  *  S390 version
  4  *    Copyright IBM Corp. 1999, 2007
  5  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  6  *               Christian Borntraeger (cborntra@de.ibm.com),
  7  */
  8 
  9 #define KMSG_COMPONENT "cpcmd"
 10 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 11 
 12 #include <linux/kernel.h>
 13 #include <linux/export.h>
 14 #include <linux/slab.h>
 15 #include <linux/spinlock.h>
 16 #include <linux/stddef.h>
 17 #include <linux/string.h>
 18 #include <linux/mm.h>
 19 #include <linux/io.h>
 20 #include <asm/diag.h>
 21 #include <asm/ebcdic.h>
 22 #include <asm/cpcmd.h>
 23 
 24 static DEFINE_SPINLOCK(cpcmd_lock);
 25 static char cpcmd_buf[241];
 26 
 27 static int diag8_noresponse(int cmdlen)
 28 {
 29         asm volatile(
 30                 "       diag    %[rx],%[ry],0x8\n"
 31                 : [ry] "+&d" (cmdlen)
 32                 : [rx] "d" (__pa(cpcmd_buf))
 33                 : "cc");
 34         return cmdlen;
 35 }
 36 
 37 static int diag8_response(int cmdlen, char *response, int *rlen)
 38 {
 39         union register_pair rx, ry;
 40         int cc;
 41 
 42         rx.even = __pa(cpcmd_buf);
 43         rx.odd  = __pa(response);
 44         ry.even = cmdlen | 0x40000000L;
 45         ry.odd  = *rlen;
 46         asm volatile(
 47                 "       diag    %[rx],%[ry],0x8\n"
 48                 "       ipm     %[cc]\n"
 49                 "       srl     %[cc],28\n"
 50                 : [cc] "=&d" (cc), [ry] "+&d" (ry.pair)
 51                 : [rx] "d" (rx.pair)
 52                 : "cc");
 53         if (cc)
 54                 *rlen += ry.odd;
 55         else
 56                 *rlen = ry.odd;
 57         return ry.even;
 58 }
 59 
 60 /*
 61  * __cpcmd has some restrictions over cpcmd
 62  *  - __cpcmd is unlocked and therefore not SMP-safe
 63  */
 64 int  __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
 65 {
 66         int cmdlen;
 67         int rc;
 68         int response_len;
 69 
 70         cmdlen = strlen(cmd);
 71         BUG_ON(cmdlen > 240);
 72         memcpy(cpcmd_buf, cmd, cmdlen);
 73         ASCEBC(cpcmd_buf, cmdlen);
 74 
 75         diag_stat_inc(DIAG_STAT_X008);
 76         if (response) {
 77                 memset(response, 0, rlen);
 78                 response_len = rlen;
 79                 rc = diag8_response(cmdlen, response, &rlen);
 80                 EBCASC(response, response_len);
 81         } else {
 82                 rc = diag8_noresponse(cmdlen);
 83         }
 84         if (response_code)
 85                 *response_code = rc;
 86         return rlen;
 87 }
 88 EXPORT_SYMBOL(__cpcmd);
 89 
 90 int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
 91 {
 92         unsigned long flags;
 93         char *lowbuf;
 94         int len;
 95 
 96         if (is_vmalloc_or_module_addr(response)) {
 97                 lowbuf = kmalloc(rlen, GFP_KERNEL);
 98                 if (!lowbuf) {
 99                         pr_warn("The cpcmd kernel function failed to allocate a response buffer\n");
100                         return -ENOMEM;
101                 }
102                 spin_lock_irqsave(&cpcmd_lock, flags);
103                 len = __cpcmd(cmd, lowbuf, rlen, response_code);
104                 spin_unlock_irqrestore(&cpcmd_lock, flags);
105                 memcpy(response, lowbuf, rlen);
106                 kfree(lowbuf);
107         } else {
108                 spin_lock_irqsave(&cpcmd_lock, flags);
109                 len = __cpcmd(cmd, response, rlen, response_code);
110                 spin_unlock_irqrestore(&cpcmd_lock, flags);
111         }
112         return len;
113 }
114 EXPORT_SYMBOL(cpcmd);
115 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php