Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
generated-y += dis-defs.h
generated-y += facility-defs.h
generated-y += syscall_table.h
generated-y += unistd_nr.h
generic-y += asm-offsets.h
generic-y += mcs_spinlock.h
generic-y += mmzone.h
generic-y += ring_buffer.h
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_ABS_LOWCORE_H
#define _ASM_S390_ABS_LOWCORE_H
#include <linux/smp.h>
#include <asm/lowcore.h>
#define ABS_LOWCORE_MAP_SIZE (NR_CPUS * sizeof(struct lowcore))
extern unsigned long __abs_lowcore;
int abs_lowcore_map(int cpu, struct lowcore *lc, bool alloc);
void abs_lowcore_unmap(int cpu);
static inline struct lowcore *get_abs_lowcore(void)
{
int cpu;
cpu = get_cpu();
return ((struct lowcore *)__abs_lowcore) + cpu;
}
static inline void put_abs_lowcore(struct lowcore *lc)
{
put_cpu();
}
#endif /* _ASM_S390_ABS_LOWCORE_H */
@@ -0,0 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 1999, 2024
*/
#ifndef __ASM_S390_ACCESS_REGS_H
#define __ASM_S390_ACCESS_REGS_H
#include <linux/instrumented.h>
#include <asm/sigcontext.h>
struct access_regs {
unsigned int regs[NUM_ACRS];
};
static inline void save_access_regs(unsigned int *acrs)
{
struct access_regs *regs = (struct access_regs *)acrs;
instrument_write(regs, sizeof(*regs));
asm volatile("stamy 0,15,%[regs]"
: [regs] "=QS" (*regs)
:
: "memory");
}
static inline void restore_access_regs(unsigned int *acrs)
{
struct access_regs *regs = (struct access_regs *)acrs;
instrument_read(regs, sizeof(*regs));
asm volatile("lamy 0,15,%[regs]"
:
: [regs] "QS" (*regs)
: "memory");
}
#endif /* __ASM_S390_ACCESS_REGS_H */
+110
View File
@@ -0,0 +1,110 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 2002, 2007
* Author(s): Ingo Adlung <adlung@de.ibm.com>
* Cornelia Huck <cornelia.huck@de.ibm.com>
* Arnd Bergmann <arndb@de.ibm.com>
* Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
*/
#ifndef _ASM_S390_AIRQ_H
#define _ASM_S390_AIRQ_H
#include <linux/bit_spinlock.h>
#include <linux/dma-mapping.h>
#include <asm/tpi.h>
struct airq_struct {
struct hlist_node list; /* Handler queueing. */
void (*handler)(struct airq_struct *airq, struct tpi_info *tpi_info);
u8 *lsi_ptr; /* Local-Summary-Indicator pointer */
u8 isc; /* Interrupt-subclass */
u8 flags;
};
#define AIRQ_PTR_ALLOCATED 0x01
int register_adapter_interrupt(struct airq_struct *airq);
void unregister_adapter_interrupt(struct airq_struct *airq);
/* Adapter interrupt bit vector */
struct airq_iv {
unsigned long *vector; /* Adapter interrupt bit vector */
dma_addr_t vector_dma; /* Adapter interrupt bit vector dma */
unsigned long *avail; /* Allocation bit mask for the bit vector */
unsigned long *bitlock; /* Lock bit mask for the bit vector */
unsigned long *ptr; /* Pointer associated with each bit */
unsigned int *data; /* 32 bit value associated with each bit */
unsigned long bits; /* Number of bits in the vector */
unsigned long end; /* Number of highest allocated bit + 1 */
unsigned long flags; /* Allocation flags */
spinlock_t lock; /* Lock to protect alloc & free */
};
#define AIRQ_IV_ALLOC 1 /* Use an allocation bit mask */
#define AIRQ_IV_BITLOCK 2 /* Allocate the lock bit mask */
#define AIRQ_IV_PTR 4 /* Allocate the ptr array */
#define AIRQ_IV_DATA 8 /* Allocate the data array */
#define AIRQ_IV_CACHELINE 16 /* Cacheline alignment for the vector */
#define AIRQ_IV_GUESTVEC 32 /* Vector is a pinned guest page */
struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags,
unsigned long *vec);
void airq_iv_release(struct airq_iv *iv);
unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num);
void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num);
unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start,
unsigned long end);
static inline unsigned long airq_iv_alloc_bit(struct airq_iv *iv)
{
return airq_iv_alloc(iv, 1);
}
static inline void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit)
{
airq_iv_free(iv, bit, 1);
}
static inline unsigned long airq_iv_end(struct airq_iv *iv)
{
return iv->end;
}
static inline void airq_iv_lock(struct airq_iv *iv, unsigned long bit)
{
const unsigned long be_to_le = BITS_PER_LONG - 1;
bit_spin_lock(bit ^ be_to_le, iv->bitlock);
}
static inline void airq_iv_unlock(struct airq_iv *iv, unsigned long bit)
{
const unsigned long be_to_le = BITS_PER_LONG - 1;
bit_spin_unlock(bit ^ be_to_le, iv->bitlock);
}
static inline void airq_iv_set_data(struct airq_iv *iv, unsigned long bit,
unsigned int data)
{
iv->data[bit] = data;
}
static inline unsigned int airq_iv_get_data(struct airq_iv *iv,
unsigned long bit)
{
return iv->data[bit];
}
static inline void airq_iv_set_ptr(struct airq_iv *iv, unsigned long bit,
unsigned long ptr)
{
iv->ptr[bit] = ptr;
}
static inline unsigned long airq_iv_get_ptr(struct airq_iv *iv,
unsigned long bit)
{
return iv->ptr[bit];
}
#endif /* _ASM_S390_AIRQ_H */
@@ -0,0 +1,238 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_ALTERNATIVE_H
#define _ASM_S390_ALTERNATIVE_H
/*
* Each alternative comes with a 32 bit feature field:
* union {
* u32 feature;
* struct {
* u32 ctx : 4;
* u32 type : 8;
* u32 data : 20;
* };
* }
*
* @ctx is a bitfield, where only one bit must be set. Each bit defines
* in which context an alternative is supposed to be applied to the
* kernel image:
*
* - from the decompressor before the kernel itself is executed
* - from early kernel code from within the kernel
*
* @type is a number which defines the type and with that the type
* specific alternative patching.
*
* @data is additional type specific information which defines if an
* alternative should be applied.
*/
#define ALT_CTX_EARLY 1
#define ALT_CTX_LATE 2
#define ALT_CTX_ALL (ALT_CTX_EARLY | ALT_CTX_LATE)
#define ALT_TYPE_FACILITY 0
#define ALT_TYPE_FEATURE 1
#define ALT_TYPE_SPEC 2
#define ALT_DATA_SHIFT 0
#define ALT_TYPE_SHIFT 20
#define ALT_CTX_SHIFT 28
#define ALT_FACILITY(facility) (ALT_CTX_EARLY << ALT_CTX_SHIFT | \
ALT_TYPE_FACILITY << ALT_TYPE_SHIFT | \
(facility) << ALT_DATA_SHIFT)
#define ALT_FEATURE(feature) (ALT_CTX_EARLY << ALT_CTX_SHIFT | \
ALT_TYPE_FEATURE << ALT_TYPE_SHIFT | \
(feature) << ALT_DATA_SHIFT)
#define ALT_SPEC(facility) (ALT_CTX_LATE << ALT_CTX_SHIFT | \
ALT_TYPE_SPEC << ALT_TYPE_SHIFT | \
(facility) << ALT_DATA_SHIFT)
#ifndef __ASSEMBLER__
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/stringify.h>
struct alt_instr {
s32 instr_offset; /* original instruction */
s32 repl_offset; /* offset to replacement instruction */
union {
u32 feature; /* feature required for replacement */
struct {
u32 ctx : 4; /* context */
u32 type : 8; /* type of alternative */
u32 data : 20; /* patching information */
};
};
u8 instrlen; /* length of original instruction */
} __packed;
extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
void __apply_alternatives(struct alt_instr *start, struct alt_instr *end, unsigned int ctx);
static inline void apply_alternative_instructions(void)
{
__apply_alternatives(__alt_instructions, __alt_instructions_end, ALT_CTX_LATE);
}
static inline void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
{
__apply_alternatives(start, end, ALT_CTX_ALL);
}
/*
* +---------------------------------+
* |661: |662:
* | oldinstr |
* +---------------------------------+
*
* .altinstr_replacement section
* +---------------------------------+
* |6641: |6651:
* | alternative instr 1 |
* +---------------------------------+
* |6642: |6652:
* | alternative instr 2 |
* +---------------------------------+
*
* .altinstructions section
* +---------------------------------+
* | alt_instr entries for each |
* | alternative instr |
* +---------------------------------+
*/
#define b_altinstr(num) "664"#num
#define e_altinstr(num) "665"#num
#define oldinstr_len "662b-661b"
#define altinstr_len(num) e_altinstr(num)"b-"b_altinstr(num)"b"
#define OLDINSTR(oldinstr) \
"661:\n\t" oldinstr "\n662:\n"
#define ALTINSTR_ENTRY(feature, num) \
"\t.long 661b - .\n" /* old instruction */ \
"\t.long " b_altinstr(num)"b - .\n" /* alt instruction */ \
"\t.long " __stringify(feature) "\n" /* feature */ \
"\t.byte " oldinstr_len "\n" /* instruction len */ \
"\t.org . - (" oldinstr_len ") & 1\n" \
"\t.org . - (" oldinstr_len ") + (" altinstr_len(num) ")\n" \
"\t.org . - (" altinstr_len(num) ") + (" oldinstr_len ")\n"
#define ALTINSTR_REPLACEMENT(altinstr, num) /* replacement */ \
b_altinstr(num)":\n\t" altinstr "\n" e_altinstr(num) ":\n"
/* alternative assembly primitive: */
#define ALTERNATIVE(oldinstr, altinstr, feature) \
".pushsection .altinstr_replacement, \"ax\"\n" \
ALTINSTR_REPLACEMENT(altinstr, 1) \
".popsection\n" \
OLDINSTR(oldinstr) \
".pushsection .altinstructions,\"a\"\n" \
ALTINSTR_ENTRY(feature, 1) \
".popsection\n"
#define ALTERNATIVE_2(oldinstr, altinstr1, feature1, altinstr2, feature2)\
".pushsection .altinstr_replacement, \"ax\"\n" \
ALTINSTR_REPLACEMENT(altinstr1, 1) \
ALTINSTR_REPLACEMENT(altinstr2, 2) \
".popsection\n" \
OLDINSTR(oldinstr) \
".pushsection .altinstructions,\"a\"\n" \
ALTINSTR_ENTRY(feature1, 1) \
ALTINSTR_ENTRY(feature2, 2) \
".popsection\n"
/*
* Alternative instructions for different CPU types or capabilities.
*
* This allows to use optimized instructions even on generic binary
* kernels.
*
* oldinstr is padded with jump and nops at compile time if altinstr is
* longer. altinstr is padded with jump and nops at run-time during patching.
*
* For non barrier like inlines please define new variants
* without volatile and memory clobber.
*/
#define alternative(oldinstr, altinstr, feature) \
asm_inline volatile(ALTERNATIVE(oldinstr, altinstr, feature) : : : "memory")
#define alternative_2(oldinstr, altinstr1, feature1, altinstr2, feature2) \
asm_inline volatile(ALTERNATIVE_2(oldinstr, altinstr1, feature1, \
altinstr2, feature2) ::: "memory")
/* Alternative inline assembly with input. */
#define alternative_input(oldinstr, newinstr, feature, input...) \
asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, feature) \
: : input)
/* Like alternative_input, but with a single output argument */
#define alternative_io(oldinstr, altinstr, feature, output, input...) \
asm_inline volatile(ALTERNATIVE(oldinstr, altinstr, feature) \
: output : input)
/* Use this macro if more than one output parameter is needed. */
#define ASM_OUTPUT2(a...) a
/* Use this macro if clobbers are needed without inputs. */
#define ASM_NO_INPUT_CLOBBER(clobber...) : clobber
#else /* __ASSEMBLER__ */
/*
* Issue one struct alt_instr descriptor entry (need to put it into
* the section .altinstructions, see below). This entry contains
* enough information for the alternatives patching code to patch an
* instruction. See apply_alternatives().
*/
.macro alt_entry orig_start, orig_end, alt_start, alt_end, feature
.long \orig_start - .
.long \alt_start - .
.long \feature
.byte \orig_end - \orig_start
.org . - ( \orig_end - \orig_start ) & 1
.org . - ( \orig_end - \orig_start ) + ( \alt_end - \alt_start )
.org . - ( \alt_end - \alt_start ) + ( \orig_end - \orig_start )
.endm
/*
* Define an alternative between two instructions. If @feature is
* present, early code in apply_alternatives() replaces @oldinstr with
* @newinstr.
*/
.macro ALTERNATIVE oldinstr, newinstr, feature
.pushsection .altinstr_replacement,"ax"
770: \newinstr
771: .popsection
772: \oldinstr
773: .pushsection .altinstructions,"a"
alt_entry 772b, 773b, 770b, 771b, \feature
.popsection
.endm
/*
* Define an alternative between two instructions. If @feature is
* present, early code in apply_alternatives() replaces @oldinstr with
* @newinstr.
*/
.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2
.pushsection .altinstr_replacement,"ax"
770: \newinstr1
771: \newinstr2
772: .popsection
773: \oldinstr
774: .pushsection .altinstructions,"a"
alt_entry 773b, 774b, 770b, 771b,\feature1
alt_entry 773b, 774b, 771b, 772b,\feature2
.popsection
.endm
#endif /* __ASSEMBLER__ */
#endif /* _ASM_S390_ALTERNATIVE_H */
+566
View File
@@ -0,0 +1,566 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Adjunct processor (AP) interfaces
*
* Copyright IBM Corp. 2017
*
* Author(s): Tony Krowiak <akrowia@linux.vnet.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
* Harald Freudenberger <freude@de.ibm.com>
*/
#ifndef _ASM_S390_AP_H_
#define _ASM_S390_AP_H_
#include <linux/io.h>
#include <asm/asm-extable.h>
/**
* The ap_qid_t identifier of an ap queue.
* If the AP facilities test (APFT) facility is available,
* card and queue index are 8 bit values, otherwise
* card index is 6 bit and queue index a 4 bit value.
*/
typedef unsigned int ap_qid_t;
#define AP_MKQID(_card, _queue) (((_card) & 0xff) << 8 | ((_queue) & 0xff))
#define AP_QID_CARD(_qid) (((_qid) >> 8) & 0xff)
#define AP_QID_QUEUE(_qid) ((_qid) & 0xff)
/**
* struct ap_queue_status - Holds the AP queue status.
* @queue_empty: Shows if queue is empty
* @replies_waiting: Waiting replies
* @queue_full: Is 1 if the queue is full
* @irq_enabled: Shows if interrupts are enabled for the AP
* @response_code: Holds the 8 bit response code
*
* The ap queue status word is returned by all three AP functions
* (PQAP, NQAP and DQAP). There's a set of flags in the first
* byte, followed by a 1 byte response code.
*
* For convenience the 'value' field is a 32 bit access of the
* whole status and the 'status_bits' and 'rc' fields comprise
* the leftmost 8 status bits and the response_code.
*/
struct ap_queue_status {
union {
unsigned int value : 32;
struct {
unsigned int status_bits : 8;
unsigned int rc : 8;
unsigned int : 16;
};
struct {
unsigned int queue_empty : 1;
unsigned int replies_waiting : 1;
unsigned int queue_full : 1;
unsigned int : 3;
unsigned int async : 1;
unsigned int irq_enabled : 1;
unsigned int response_code : 8;
unsigned int : 16;
};
};
};
/*
* AP queue status reg union to access the reg1
* register with the lower 32 bits comprising the
* ap queue status.
*/
union ap_queue_status_reg {
unsigned long value;
struct {
u32 _pad;
struct ap_queue_status status;
};
};
/**
* ap_instructions_available() - Test if AP instructions are available.
*
* Returns true if the AP instructions are installed, otherwise false.
*/
static inline bool ap_instructions_available(void)
{
unsigned long reg0 = AP_MKQID(0, 0);
unsigned long reg1 = 0;
asm volatile(
" lgr 0,%[reg0]\n" /* qid into gr0 */
" lghi 1,0\n" /* 0 into gr1 */
" lghi 2,0\n" /* 0 into gr2 */
" .insn rre,0xb2af0000,0,0\n" /* PQAP(TAPQ) */
"0: la %[reg1],1\n" /* 1 into reg1 */
"1:\n"
EX_TABLE(0b, 1b)
: [reg1] "+&d" (reg1)
: [reg0] "d" (reg0)
: "cc", "0", "1", "2");
return reg1 != 0;
}
/* TAPQ register GR2 response struct */
struct ap_tapq_hwinfo {
union {
unsigned long value;
struct {
unsigned int fac : 32; /* facility bits */
unsigned int apinfo : 32; /* ap type, ... */
};
struct {
unsigned int apsc : 1; /* APSC */
unsigned int mex4k : 1; /* AP4KM */
unsigned int crt4k : 1; /* AP4KC */
unsigned int cca : 1; /* D */
unsigned int accel : 1; /* A */
unsigned int ep11 : 1; /* X */
unsigned int apxa : 1; /* APXA */
unsigned int slcf : 1; /* Cmd filtering avail. */
unsigned int class : 8;
unsigned int bs : 2; /* SE bind/assoc */
unsigned int : 14;
unsigned int at : 8; /* ap type */
unsigned int nd : 8; /* nr of domains */
unsigned int : 4;
unsigned int ml : 4; /* apxl ml */
unsigned int : 4;
unsigned int qd : 4; /* queue depth */
};
};
};
/*
* Convenience defines to be used with the bs field from struct ap_tapq_gr2
*/
#define AP_BS_Q_USABLE 0
#define AP_BS_Q_USABLE_NO_SECURE_KEY 1
#define AP_BS_Q_AVAIL_FOR_BINDING 2
#define AP_BS_Q_UNUSABLE 3
/**
* ap_tapq(): Test adjunct processor queue.
* @qid: The AP queue number
* @info: Pointer to tapq hwinfo struct
*
* Returns AP queue status structure.
*/
static inline struct ap_queue_status ap_tapq(ap_qid_t qid,
struct ap_tapq_hwinfo *info)
{
union ap_queue_status_reg reg1;
unsigned long reg2;
asm volatile(
" lgr 0,%[qid]\n" /* qid into gr0 */
" lghi 2,0\n" /* 0 into gr2 */
" .insn rre,0xb2af0000,0,0\n" /* PQAP(TAPQ) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
" lgr %[reg2],2" /* gr2 into reg2 */
: [reg1] "=&d" (reg1.value), [reg2] "=&d" (reg2)
: [qid] "d" (qid)
: "cc", "0", "1", "2");
if (info)
info->value = reg2;
return reg1.status;
}
/**
* ap_test_queue(): Test adjunct processor queue.
* @qid: The AP queue number
* @tbit: Test facilities bit
* @info: Ptr to tapq gr2 struct
*
* Returns AP queue status structure.
*/
static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, int tbit,
struct ap_tapq_hwinfo *info)
{
if (tbit)
qid |= 1UL << 23; /* set T bit*/
return ap_tapq(qid, info);
}
/**
* ap_pqap_rapq(): Reset adjunct processor queue.
* @qid: The AP queue number
* @fbit: if != 0 set F bit
*
* Returns AP queue status structure.
*/
static inline struct ap_queue_status ap_rapq(ap_qid_t qid, int fbit)
{
unsigned long reg0 = qid | (1UL << 24); /* fc 1UL is RAPQ */
union ap_queue_status_reg reg1;
if (fbit)
reg0 |= 1UL << 22;
asm volatile(
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
" .insn rre,0xb2af0000,0,0\n" /* PQAP(RAPQ) */
" lgr %[reg1],1" /* gr1 (status) into reg1 */
: [reg1] "=&d" (reg1.value)
: [reg0] "d" (reg0)
: "cc", "0", "1");
return reg1.status;
}
/**
* ap_pqap_zapq(): Reset and zeroize adjunct processor queue.
* @qid: The AP queue number
* @fbit: if != 0 set F bit
*
* Returns AP queue status structure.
*/
static inline struct ap_queue_status ap_zapq(ap_qid_t qid, int fbit)
{
unsigned long reg0 = qid | (2UL << 24); /* fc 2UL is ZAPQ */
union ap_queue_status_reg reg1;
if (fbit)
reg0 |= 1UL << 22;
asm volatile(
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
" .insn rre,0xb2af0000,0,0\n" /* PQAP(ZAPQ) */
" lgr %[reg1],1" /* gr1 (status) into reg1 */
: [reg1] "=&d" (reg1.value)
: [reg0] "d" (reg0)
: "cc", "0", "1");
return reg1.status;
}
/**
* struct ap_config_info - convenience struct for AP crypto
* config info as returned by the ap_qci() function.
*/
struct ap_config_info {
union {
unsigned int flags;
struct {
unsigned int apsc : 1; /* S bit */
unsigned int apxa : 1; /* N bit */
unsigned int qact : 1; /* C bit */
unsigned int rc8a : 1; /* R bit */
unsigned int : 4;
unsigned int apsb : 1; /* B bit */
unsigned int : 23;
};
};
unsigned char na; /* max # of APs - 1 */
unsigned char nd; /* max # of Domains - 1 */
unsigned char _reserved0[10];
unsigned int apm[8]; /* AP ID mask */
unsigned int aqm[8]; /* AP (usage) queue mask */
unsigned int adm[8]; /* AP (control) domain mask */
unsigned char _reserved1[16];
} __aligned(8);
/**
* ap_qci(): Get AP configuration data
*
* Returns 0 on success, or -EOPNOTSUPP.
*/
static inline int ap_qci(struct ap_config_info *config)
{
unsigned long reg0 = 4UL << 24; /* fc 4UL is QCI */
unsigned long reg1 = -EOPNOTSUPP;
struct ap_config_info *reg2 = config;
asm volatile(
" lgr 0,%[reg0]\n" /* QCI fc into gr0 */
" lgr 2,%[reg2]\n" /* ptr to config into gr2 */
" .insn rre,0xb2af0000,0,0\n" /* PQAP(QCI) */
"0: la %[reg1],0\n" /* good case, QCI fc available */
"1:\n"
EX_TABLE(0b, 1b)
: [reg1] "+&d" (reg1)
: [reg0] "d" (reg0), [reg2] "d" (reg2)
: "cc", "memory", "0", "2");
return reg1;
}
/*
* struct ap_qirq_ctrl - convenient struct for easy invocation
* of the ap_aqic() function. This struct is passed as GR1
* parameter to the PQAP(AQIC) instruction. For details please
* see the AR documentation.
*/
union ap_qirq_ctrl {
unsigned long value;
struct {
unsigned int : 8;
unsigned int zone : 8; /* zone info */
unsigned int ir : 1; /* ir flag: enable (1) or disable (0) irq */
unsigned int : 4;
unsigned int gisc : 3; /* guest isc field */
unsigned int : 6;
unsigned int gf : 2; /* gisa format */
unsigned int : 1;
unsigned int gisa : 27; /* gisa origin */
unsigned int : 1;
unsigned int isc : 3; /* irq sub class */
};
};
/**
* ap_aqic(): Control interruption for a specific AP.
* @qid: The AP queue number
* @qirqctrl: struct ap_qirq_ctrl (64 bit value)
* @pa_ind: Physical address of the notification indicator byte
*
* Returns AP queue status.
*/
static inline struct ap_queue_status ap_aqic(ap_qid_t qid,
union ap_qirq_ctrl qirqctrl,
phys_addr_t pa_ind)
{
unsigned long reg0 = qid | (3UL << 24); /* fc 3UL is AQIC */
union ap_queue_status_reg reg1;
unsigned long reg2 = pa_ind;
reg1.value = qirqctrl.value;
asm volatile(
" lgr 0,%[reg0]\n" /* qid param into gr0 */
" lgr 1,%[reg1]\n" /* irq ctrl into gr1 */
" lgr 2,%[reg2]\n" /* ni addr into gr2 */
" .insn rre,0xb2af0000,0,0\n" /* PQAP(AQIC) */
" lgr %[reg1],1" /* gr1 (status) into reg1 */
: [reg1] "+&d" (reg1.value)
: [reg0] "d" (reg0), [reg2] "d" (reg2)
: "cc", "memory", "0", "1", "2");
return reg1.status;
}
/*
* union ap_qact_ap_info - used together with the
* ap_aqic() function to provide a convenient way
* to handle the ap info needed by the qact function.
*/
union ap_qact_ap_info {
unsigned long val;
struct {
unsigned int : 3;
unsigned int mode : 3;
unsigned int : 26;
unsigned int cat : 8;
unsigned int : 8;
unsigned char ver[2];
};
};
/**
* ap_qact(): Query AP compatibility type.
* @qid: The AP queue number
* @apinfo: On input the info about the AP queue. On output the
* alternate AP queue info provided by the qact function
* in GR2 is stored in.
*
* Returns AP queue status. Check response_code field for failures.
*/
static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit,
union ap_qact_ap_info *apinfo)
{
unsigned long reg0 = qid | (5UL << 24) | ((ifbit & 0x01) << 22);
union ap_queue_status_reg reg1;
unsigned long reg2;
reg1.value = apinfo->val;
asm volatile(
" lgr 0,%[reg0]\n" /* qid param into gr0 */
" lgr 1,%[reg1]\n" /* qact in info into gr1 */
" .insn rre,0xb2af0000,0,0\n" /* PQAP(QACT) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
" lgr %[reg2],2" /* qact out info into reg2 */
: [reg1] "+&d" (reg1.value), [reg2] "=&d" (reg2)
: [reg0] "d" (reg0)
: "cc", "0", "1", "2");
apinfo->val = reg2;
return reg1.status;
}
/*
* ap_bapq(): SE bind AP queue.
* @qid: The AP queue number
*
* Returns AP queue status structure.
*
* Invoking this function in a non-SE environment
* may case a specification exception.
*/
static inline struct ap_queue_status ap_bapq(ap_qid_t qid)
{
unsigned long reg0 = qid | (7UL << 24); /* fc 7 is BAPQ */
union ap_queue_status_reg reg1;
asm volatile(
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
" .insn rre,0xb2af0000,0,0\n" /* PQAP(BAPQ) */
" lgr %[reg1],1" /* gr1 (status) into reg1 */
: [reg1] "=&d" (reg1.value)
: [reg0] "d" (reg0)
: "cc", "0", "1");
return reg1.status;
}
/*
* ap_aapq(): SE associate AP queue.
* @qid: The AP queue number
* @sec_idx: The secret index
*
* Returns AP queue status structure.
*
* Invoking this function in a non-SE environment
* may case a specification exception.
*/
static inline struct ap_queue_status ap_aapq(ap_qid_t qid, unsigned int sec_idx)
{
unsigned long reg0 = qid | (8UL << 24); /* fc 8 is AAPQ */
unsigned long reg2 = sec_idx;
union ap_queue_status_reg reg1;
asm volatile(
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
" lgr 2,%[reg2]\n" /* secret index into gr2 */
" .insn rre,0xb2af0000,0,0\n" /* PQAP(AAPQ) */
" lgr %[reg1],1" /* gr1 (status) into reg1 */
: [reg1] "=&d" (reg1.value)
: [reg0] "d" (reg0), [reg2] "d" (reg2)
: "cc", "0", "1", "2");
return reg1.status;
}
/**
* ap_nqap(): Send message to adjunct processor queue.
* @qid: The AP queue number
* @psmid: The program supplied message identifier
* @msg: The message text
* @length: The message length
*
* Returns AP queue status structure.
* Condition code 1 on NQAP can't happen because the L bit is 1.
* Condition code 2 on NQAP also means the send is incomplete,
* because a segment boundary was reached. The NQAP is repeated.
*/
static inline struct ap_queue_status ap_nqap(ap_qid_t qid,
unsigned long long psmid,
void *msg, size_t length)
{
unsigned long reg0 = qid | 0x40000000UL; /* 0x4... is last msg part */
union register_pair nqap_r1, nqap_r2;
union ap_queue_status_reg reg1;
nqap_r1.even = (unsigned int)(psmid >> 32);
nqap_r1.odd = psmid & 0xffffffff;
nqap_r2.even = (unsigned long)msg;
nqap_r2.odd = (unsigned long)length;
asm volatile (
" lgr 0,%[reg0]\n" /* qid param in gr0 */
"0: .insn rre,0xb2ad0000,%[nqap_r1],%[nqap_r2]\n"
" brc 2,0b\n" /* handle partial completion */
" lgr %[reg1],1" /* gr1 (status) into reg1 */
: [reg0] "+&d" (reg0), [reg1] "=&d" (reg1.value),
[nqap_r2] "+&d" (nqap_r2.pair)
: [nqap_r1] "d" (nqap_r1.pair)
: "cc", "memory", "0", "1");
return reg1.status;
}
/**
* ap_dqap(): Receive message from adjunct processor queue.
* @qid: The AP queue number
* @psmid: Pointer to program supplied message identifier
* @msg: Pointer to message buffer
* @msglen: Message buffer size
* @length: Pointer to length of actually written bytes
* @reslength: Residual length on return
* @resgr0: input: gr0 value (only used if != 0), output: residual gr0 content
*
* Returns AP queue status structure.
* Condition code 1 on DQAP means the receive has taken place
* but only partially. The response is incomplete, hence the
* DQAP is repeated.
* Condition code 2 on DQAP also means the receive is incomplete,
* this time because a segment boundary was reached. Again, the
* DQAP is repeated.
* Note that gpr2 is used by the DQAP instruction to keep track of
* any 'residual' length, in case the instruction gets interrupted.
* Hence it gets zeroed before the instruction.
* If the message does not fit into the buffer, this function will
* return with a truncated message and the reply in the firmware queue
* is not removed. This is indicated to the caller with an
* ap_queue_status response_code value of all bits on (0xFF) and (if
* the reslength ptr is given) the remaining length is stored in
* *reslength and (if the resgr0 ptr is given) the updated gr0 value
* for further processing of this msg entry is stored in *resgr0. The
* caller needs to detect this situation and should invoke ap_dqap
* with a valid resgr0 ptr and a value in there != 0 to indicate that
* *resgr0 is to be used instead of qid to further process this entry.
*/
static inline struct ap_queue_status ap_dqap(ap_qid_t qid,
unsigned long *psmid,
void *msg, size_t msglen,
size_t *length,
size_t *reslength,
unsigned long *resgr0)
{
unsigned long reg0 = resgr0 && *resgr0 ? *resgr0 : qid | 0x80000000UL;
union ap_queue_status_reg reg1;
unsigned long reg2;
union register_pair rp1, rp2;
rp1.even = 0UL;
rp1.odd = 0UL;
rp2.even = (unsigned long)msg;
rp2.odd = (unsigned long)msglen;
asm volatile(
" lgr 0,%[reg0]\n" /* qid param into gr0 */
" lghi 2,0\n" /* 0 into gr2 (res length) */
"0: ltgr %N[rp2],%N[rp2]\n" /* check buf len */
" jz 2f\n" /* go out if buf len is 0 */
"1: .insn rre,0xb2ae0000,%[rp1],%[rp2]\n"
" brc 6,0b\n" /* handle partial complete */
"2: lgr %[reg0],0\n" /* gr0 (qid + info) into reg0 */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
" lgr %[reg2],2" /* gr2 (res length) into reg2 */
: [reg0] "+&d" (reg0), [reg1] "=&d" (reg1.value),
[reg2] "=&d" (reg2), [rp1] "+&d" (rp1.pair),
[rp2] "+&d" (rp2.pair)
:
: "cc", "memory", "0", "1", "2");
if (reslength)
*reslength = reg2;
if (reg2 != 0 && rp2.odd == 0) {
/*
* Partially complete, status in gr1 is not set.
* Signal the caller that this dqap is only partially received
* with a special status response code 0xFF and *resgr0 updated
*/
reg1.status.response_code = 0xFF;
if (resgr0)
*resgr0 = reg0;
} else {
*psmid = (rp1.even << 32) + rp1.odd;
if (resgr0)
*resgr0 = 0;
}
/* update *length with the nr of bytes stored into the msg buffer */
if (length)
*length = msglen - rp2.odd;
return reg1.status;
}
#endif /* _ASM_S390_AP_H_ */
@@ -0,0 +1,69 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 2006
*
* Author(s): Melissa Howland <melissah@us.ibm.com>
*/
#ifndef _ASM_S390_APPLDATA_H
#define _ASM_S390_APPLDATA_H
#include <linux/io.h>
#include <asm/machine.h>
#include <asm/diag.h>
#define APPLDATA_START_INTERVAL_REC 0x80
#define APPLDATA_STOP_REC 0x81
#define APPLDATA_GEN_EVENT_REC 0x82
#define APPLDATA_START_CONFIG_REC 0x83
/*
* Parameter list for DIAGNOSE X'DC'
*/
struct appldata_parameter_list {
u16 diag;
u8 function;
u8 parlist_length;
u32 unused01;
u16 reserved;
u16 buffer_length;
u32 unused02;
u64 product_id_addr;
u64 buffer_addr;
} __attribute__ ((packed));
struct appldata_product_id {
char prod_nr[7]; /* product number */
u16 prod_fn; /* product function */
u8 record_nr; /* record number */
u16 version_nr; /* version */
u16 release_nr; /* release */
u16 mod_lvl; /* modification level */
} __attribute__ ((packed));
static inline int appldata_asm(struct appldata_parameter_list *parm_list,
struct appldata_product_id *id,
unsigned short fn, void *buffer,
unsigned short length)
{
int ry;
if (!machine_is_vm())
return -EOPNOTSUPP;
parm_list->diag = 0xdc;
parm_list->function = fn;
parm_list->parlist_length = sizeof(*parm_list);
parm_list->buffer_length = length;
parm_list->product_id_addr = virt_to_phys(id);
parm_list->buffer_addr = virt_to_phys(buffer);
diag_stat_inc(DIAG_STAT_X0DC);
asm volatile(
" diag %1,%0,0xdc"
: "=d" (ry)
: "d" (virt_to_phys(parm_list)), "m" (*parm_list), "m" (*id)
: "cc");
return ry;
}
#endif /* _ASM_S390_APPLDATA_H */
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_ARCH_STACKPROTECTOR_H
#define _ASM_S390_ARCH_STACKPROTECTOR_H
extern unsigned long __stack_chk_guard;
extern int stack_protector_debug;
void __stack_protector_apply_early(unsigned long kernel_start);
int __stack_protector_apply(unsigned long *start, unsigned long *end, unsigned long kernel_start);
static inline void stack_protector_apply_early(unsigned long kernel_start)
{
if (IS_ENABLED(CONFIG_STACKPROTECTOR))
__stack_protector_apply_early(kernel_start);
}
static inline int stack_protector_apply(unsigned long *start, unsigned long *end)
{
if (IS_ENABLED(CONFIG_STACKPROTECTOR))
return __stack_protector_apply(start, end, 0);
return 0;
}
#endif /* _ASM_S390_ARCH_STACKPROTECTOR_H */
@@ -0,0 +1,77 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_ARCH_HWEIGHT_H
#define _ASM_S390_ARCH_HWEIGHT_H
#include <linux/types.h>
#include <asm/march.h>
static __always_inline unsigned long popcnt_z196(unsigned long w)
{
unsigned long cnt;
asm volatile(".insn rrf,0xb9e10000,%[cnt],%[w],0,0"
: [cnt] "=d" (cnt)
: [w] "d" (w)
: "cc");
return cnt;
}
static __always_inline unsigned long popcnt_z15(unsigned long w)
{
unsigned long cnt;
asm volatile(".insn rrf,0xb9e10000,%[cnt],%[w],8,0"
: [cnt] "=d" (cnt)
: [w] "d" (w)
: "cc");
return cnt;
}
static __always_inline unsigned long __arch_hweight64(__u64 w)
{
if (__is_defined(MARCH_HAS_Z15_FEATURES))
return popcnt_z15(w);
if (__is_defined(MARCH_HAS_Z196_FEATURES)) {
w = popcnt_z196(w);
w += w >> 32;
w += w >> 16;
w += w >> 8;
return w & 0xff;
}
return __sw_hweight64(w);
}
static __always_inline unsigned int __arch_hweight32(unsigned int w)
{
if (__is_defined(MARCH_HAS_Z15_FEATURES))
return popcnt_z15(w);
if (__is_defined(MARCH_HAS_Z196_FEATURES)) {
w = popcnt_z196(w);
w += w >> 16;
w += w >> 8;
return w & 0xff;
}
return __sw_hweight32(w);
}
static __always_inline unsigned int __arch_hweight16(unsigned int w)
{
if (__is_defined(MARCH_HAS_Z15_FEATURES))
return popcnt_z15((unsigned short)w);
if (__is_defined(MARCH_HAS_Z196_FEATURES)) {
w = popcnt_z196(w);
w += w >> 8;
return w & 0xff;
}
return __sw_hweight16(w);
}
static __always_inline unsigned int __arch_hweight8(unsigned int w)
{
if (__is_defined(MARCH_HAS_Z196_FEATURES))
return popcnt_z196((unsigned char)w);
return __sw_hweight8(w);
}
#endif /* _ASM_S390_ARCH_HWEIGHT_H */
@@ -0,0 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Kernel interface for the s390 arch_random_* functions
*
* Copyright IBM Corp. 2017, 2022
*
* Author: Harald Freudenberger <freude@de.ibm.com>
*
*/
#ifndef _ASM_S390_ARCHRANDOM_H
#define _ASM_S390_ARCHRANDOM_H
#include <linux/static_key.h>
#include <linux/preempt.h>
#include <linux/atomic.h>
#include <asm/cpacf.h>
DECLARE_STATIC_KEY_FALSE(s390_arch_random_available);
extern atomic64_t s390_arch_random_counter;
static inline size_t __must_check arch_get_random_longs(unsigned long *v, size_t max_longs)
{
return 0;
}
static inline size_t __must_check arch_get_random_seed_longs(unsigned long *v, size_t max_longs)
{
if (static_branch_likely(&s390_arch_random_available) &&
in_task()) {
cpacf_trng(NULL, 0, (u8 *)v, max_longs * sizeof(*v));
atomic64_add(max_longs * sizeof(*v), &s390_arch_random_counter);
return max_longs;
}
return 0;
}
#endif /* _ASM_S390_ARCHRANDOM_H */
+36
View File
@@ -0,0 +1,36 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_ASCE_H
#define _ASM_S390_ASCE_H
#include <linux/thread_info.h>
#include <linux/irqflags.h>
#include <asm/lowcore.h>
#include <asm/ctlreg.h>
static inline bool enable_sacf_uaccess(void)
{
unsigned long flags;
if (test_thread_flag(TIF_ASCE_PRIMARY))
return true;
local_irq_save(flags);
local_ctl_load(1, &get_lowcore()->kernel_asce);
set_thread_flag(TIF_ASCE_PRIMARY);
local_irq_restore(flags);
return false;
}
static inline void disable_sacf_uaccess(bool previous)
{
unsigned long flags;
if (previous)
return;
local_irq_save(flags);
local_ctl_load(1, &get_lowcore()->user_asce);
clear_thread_flag(TIF_ASCE_PRIMARY);
local_irq_restore(flags);
}
#endif /* _ASM_S390_ASCE_H */
@@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_ASM_CONST_H
#define _ASM_S390_ASM_CONST_H
#ifdef __ASSEMBLER__
# define stringify_in_c(...) __VA_ARGS__
#else
/* This version of stringify will deal with commas... */
# define __stringify_in_c(...) #__VA_ARGS__
# define stringify_in_c(...) __stringify_in_c(__VA_ARGS__) " "
#endif
#endif /* _ASM_S390_ASM_CONST_H */
@@ -0,0 +1,91 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_EXTABLE_H
#define __ASM_EXTABLE_H
#include <linux/stringify.h>
#include <linux/bits.h>
#include <asm/asm-const.h>
#define EX_TYPE_NONE 0
#define EX_TYPE_FIXUP 1
#define EX_TYPE_BPF 2
#define EX_TYPE_UA_FAULT 3
#define EX_TYPE_UA_LOAD_REG 5
#define EX_TYPE_UA_LOAD_REGPAIR 6
#define EX_TYPE_FPC 8
#define EX_TYPE_UA_MVCOS_TO 9
#define EX_TYPE_UA_MVCOS_FROM 10
#define EX_DATA_REG_ERR_SHIFT 0
#define EX_DATA_REG_ERR GENMASK(3, 0)
#define EX_DATA_REG_ADDR_SHIFT 4
#define EX_DATA_REG_ADDR GENMASK(7, 4)
#define EX_DATA_LEN_SHIFT 8
#define EX_DATA_LEN GENMASK(11, 8)
#define __EX_TABLE(_section, _fault, _target, _type, _regerr, _regaddr, _len) \
stringify_in_c(.section _section,"a";) \
stringify_in_c(.balign 4;) \
stringify_in_c(.long (_fault) - .;) \
stringify_in_c(.long (_target) - .;) \
stringify_in_c(.short (_type);) \
stringify_in_c(.macro extable_reg regerr, regaddr;) \
stringify_in_c(.set .Lfound, 0;) \
stringify_in_c(.set .Lcurr, 0;) \
stringify_in_c(.irp rs,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15;) \
stringify_in_c( .ifc "\regerr", "%%r\rs";) \
stringify_in_c( .set .Lfound, 1;) \
stringify_in_c( .set .Lregerr, .Lcurr;) \
stringify_in_c( .endif;) \
stringify_in_c( .set .Lcurr, .Lcurr+1;) \
stringify_in_c(.endr;) \
stringify_in_c(.ifne (.Lfound != 1);) \
stringify_in_c( .error "extable_reg: bad register argument1";) \
stringify_in_c(.endif;) \
stringify_in_c(.set .Lfound, 0;) \
stringify_in_c(.set .Lcurr, 0;) \
stringify_in_c(.irp rs,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15;) \
stringify_in_c( .ifc "\regaddr", "%%r\rs";) \
stringify_in_c( .set .Lfound, 1;) \
stringify_in_c( .set .Lregaddr, .Lcurr;) \
stringify_in_c( .endif;) \
stringify_in_c( .set .Lcurr, .Lcurr+1;) \
stringify_in_c(.endr;) \
stringify_in_c(.ifne (.Lfound != 1);) \
stringify_in_c( .error "extable_reg: bad register argument2";) \
stringify_in_c(.endif;) \
stringify_in_c(.short .Lregerr << EX_DATA_REG_ERR_SHIFT | \
.Lregaddr << EX_DATA_REG_ADDR_SHIFT | \
_len << EX_DATA_LEN_SHIFT;) \
stringify_in_c(.endm;) \
stringify_in_c(extable_reg _regerr,_regaddr;) \
stringify_in_c(.purgem extable_reg;) \
stringify_in_c(.previous)
#define EX_TABLE(_fault, _target) \
__EX_TABLE(__ex_table, _fault, _target, EX_TYPE_FIXUP, __stringify(%%r0), __stringify(%%r0), 0)
#define EX_TABLE_AMODE31(_fault, _target) \
__EX_TABLE(.amode31.ex_table, _fault, _target, EX_TYPE_FIXUP, __stringify(%%r0), __stringify(%%r0), 0)
#define EX_TABLE_UA_FAULT(_fault, _target, _regerr) \
__EX_TABLE(__ex_table, _fault, _target, EX_TYPE_UA_FAULT, _regerr, _regerr, 0)
#define EX_TABLE_UA_LOAD_REG(_fault, _target, _regerr, _regzero) \
__EX_TABLE(__ex_table, _fault, _target, EX_TYPE_UA_LOAD_REG, _regerr, _regzero, 0)
#define EX_TABLE_UA_LOAD_REGPAIR(_fault, _target, _regerr, _regzero) \
__EX_TABLE(__ex_table, _fault, _target, EX_TYPE_UA_LOAD_REGPAIR, _regerr, _regzero, 0)
#define EX_TABLE_FPC(_fault, _target) \
__EX_TABLE(__ex_table, _fault, _target, EX_TYPE_FPC, __stringify(%%r0), __stringify(%%r0), 0)
#define EX_TABLE_UA_MVCOS_TO(_fault, _target) \
__EX_TABLE(__ex_table, _fault, _target, EX_TYPE_UA_MVCOS_TO, __stringify(%%r0), __stringify(%%r0), 0)
#define EX_TABLE_UA_MVCOS_FROM(_fault, _target) \
__EX_TABLE(__ex_table, _fault, _target, EX_TYPE_UA_MVCOS_FROM, __stringify(%%r0), __stringify(%%r0), 0)
#endif /* __ASM_EXTABLE_H */
@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_PROTOTYPES_H
#include <linux/kvm_host.h>
#include <linux/ftrace.h>
#include <asm/bug.h>
#include <asm/fpu.h>
#include <asm/nospec-branch.h>
#include <asm-generic/asm-prototypes.h>
#endif /* _ASM_S390_PROTOTYPES_H */
+51
View File
@@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_ASM_H
#define _ASM_S390_ASM_H
#include <linux/stringify.h>
/*
* Helper macros to be used for flag output operand handling.
* Inline assemblies must use four of the five supplied macros:
*
* Use CC_IPM(sym) at the end of the inline assembly; this extracts the
* condition code and program mask with the ipm instruction and writes it to
* the variable with symbolic name [sym] if the compiler has no support for
* flag output operands. If the compiler has support for flag output operands
* this generates no code.
*
* Use CC_OUT(sym, var) at the output operand list of an inline assembly. This
* defines an output operand with symbolic name [sym] for the variable
* [var]. [var] must be an int variable and [sym] must be identical with [sym]
* used with CC_IPM().
*
* Use either CC_CLOBBER or CC_CLOBBER_LIST() for the clobber list. Use
* CC_CLOBBER if the clobber list contains only "cc", otherwise use
* CC_CLOBBER_LIST() and add all clobbers as argument to the macro.
*
* Use CC_TRANSFORM() to convert the variable [var] which contains the
* extracted condition code. If the condition code is extracted with ipm, the
* [var] also contains the program mask. CC_TRANSFORM() moves the condition
* code to the two least significant bits and sets all other bits to zero.
*/
#if defined(__GCC_ASM_FLAG_OUTPUTS__) && !(IS_ENABLED(CONFIG_CC_ASM_FLAG_OUTPUT_BROKEN))
#define __HAVE_ASM_FLAG_OUTPUTS__ 1
#define CC_IPM(sym)
#define CC_OUT(sym, var) "=@cc" (var)
#define CC_TRANSFORM(cc) ({ cc; })
#define CC_CLOBBER
#define CC_CLOBBER_LIST(...) __VA_ARGS__
#else
#define CC_IPM(sym) " ipm %[" __stringify(sym) "]\n"
#define CC_OUT(sym, var) [sym] "=d" (var)
#define CC_TRANSFORM(cc) ({ (cc) >> 28; })
#define CC_CLOBBER "cc"
#define CC_CLOBBER_LIST(...) "cc", __VA_ARGS__
#endif
#endif /* _ASM_S390_ASM_H */
+230
View File
@@ -0,0 +1,230 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 1999, 2016
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
* Denis Joseph Barrow,
* Arnd Bergmann,
*/
#ifndef __ARCH_S390_ATOMIC__
#define __ARCH_S390_ATOMIC__
#include <linux/compiler.h>
#include <linux/types.h>
#include <asm/atomic_ops.h>
#include <asm/barrier.h>
#include <asm/cmpxchg.h>
static __always_inline int arch_atomic_read(const atomic_t *v)
{
return __atomic_read(&v->counter);
}
#define arch_atomic_read arch_atomic_read
static __always_inline void arch_atomic_set(atomic_t *v, int i)
{
__atomic_set(&v->counter, i);
}
#define arch_atomic_set arch_atomic_set
static __always_inline int arch_atomic_add_return(int i, atomic_t *v)
{
return __atomic_add_barrier(i, &v->counter) + i;
}
#define arch_atomic_add_return arch_atomic_add_return
static __always_inline int arch_atomic_fetch_add(int i, atomic_t *v)
{
return __atomic_add_barrier(i, &v->counter);
}
#define arch_atomic_fetch_add arch_atomic_fetch_add
static __always_inline void arch_atomic_add(int i, atomic_t *v)
{
__atomic_add(i, &v->counter);
}
#define arch_atomic_add arch_atomic_add
static __always_inline void arch_atomic_inc(atomic_t *v)
{
__atomic_add_const(1, &v->counter);
}
#define arch_atomic_inc arch_atomic_inc
static __always_inline void arch_atomic_dec(atomic_t *v)
{
__atomic_add_const(-1, &v->counter);
}
#define arch_atomic_dec arch_atomic_dec
static __always_inline bool arch_atomic_sub_and_test(int i, atomic_t *v)
{
return __atomic_add_and_test_barrier(-i, &v->counter);
}
#define arch_atomic_sub_and_test arch_atomic_sub_and_test
static __always_inline bool arch_atomic_dec_and_test(atomic_t *v)
{
return __atomic_add_const_and_test_barrier(-1, &v->counter);
}
#define arch_atomic_dec_and_test arch_atomic_dec_and_test
static __always_inline bool arch_atomic_inc_and_test(atomic_t *v)
{
return __atomic_add_const_and_test_barrier(1, &v->counter);
}
#define arch_atomic_inc_and_test arch_atomic_inc_and_test
#define arch_atomic_sub(_i, _v) arch_atomic_add(-(int)(_i), _v)
#define arch_atomic_sub_return(_i, _v) arch_atomic_add_return(-(int)(_i), _v)
#define arch_atomic_fetch_sub(_i, _v) arch_atomic_fetch_add(-(int)(_i), _v)
#define ATOMIC_OPS(op) \
static __always_inline void arch_atomic_##op(int i, atomic_t *v) \
{ \
__atomic_##op(i, &v->counter); \
} \
static __always_inline int arch_atomic_fetch_##op(int i, atomic_t *v) \
{ \
return __atomic_##op##_barrier(i, &v->counter); \
}
ATOMIC_OPS(and)
ATOMIC_OPS(or)
ATOMIC_OPS(xor)
#undef ATOMIC_OPS
#define arch_atomic_and arch_atomic_and
#define arch_atomic_or arch_atomic_or
#define arch_atomic_xor arch_atomic_xor
#define arch_atomic_fetch_and arch_atomic_fetch_and
#define arch_atomic_fetch_or arch_atomic_fetch_or
#define arch_atomic_fetch_xor arch_atomic_fetch_xor
static __always_inline int arch_atomic_xchg(atomic_t *v, int new)
{
return arch_xchg(&v->counter, new);
}
#define arch_atomic_xchg arch_atomic_xchg
static __always_inline int arch_atomic_cmpxchg(atomic_t *v, int old, int new)
{
return arch_cmpxchg(&v->counter, old, new);
}
#define arch_atomic_cmpxchg arch_atomic_cmpxchg
static __always_inline bool arch_atomic_try_cmpxchg(atomic_t *v, int *old, int new)
{
return arch_try_cmpxchg(&v->counter, old, new);
}
#define arch_atomic_try_cmpxchg arch_atomic_try_cmpxchg
#define ATOMIC64_INIT(i) { (i) }
static __always_inline s64 arch_atomic64_read(const atomic64_t *v)
{
return __atomic64_read((long *)&v->counter);
}
#define arch_atomic64_read arch_atomic64_read
static __always_inline void arch_atomic64_set(atomic64_t *v, s64 i)
{
__atomic64_set((long *)&v->counter, i);
}
#define arch_atomic64_set arch_atomic64_set
static __always_inline s64 arch_atomic64_add_return(s64 i, atomic64_t *v)
{
return __atomic64_add_barrier(i, (long *)&v->counter) + i;
}
#define arch_atomic64_add_return arch_atomic64_add_return
static __always_inline s64 arch_atomic64_fetch_add(s64 i, atomic64_t *v)
{
return __atomic64_add_barrier(i, (long *)&v->counter);
}
#define arch_atomic64_fetch_add arch_atomic64_fetch_add
static __always_inline void arch_atomic64_add(s64 i, atomic64_t *v)
{
__atomic64_add(i, (long *)&v->counter);
}
#define arch_atomic64_add arch_atomic64_add
static __always_inline void arch_atomic64_inc(atomic64_t *v)
{
__atomic64_add_const(1, (long *)&v->counter);
}
#define arch_atomic64_inc arch_atomic64_inc
static __always_inline void arch_atomic64_dec(atomic64_t *v)
{
__atomic64_add_const(-1, (long *)&v->counter);
}
#define arch_atomic64_dec arch_atomic64_dec
static __always_inline bool arch_atomic64_sub_and_test(s64 i, atomic64_t *v)
{
return __atomic64_add_and_test_barrier(-i, (long *)&v->counter);
}
#define arch_atomic64_sub_and_test arch_atomic64_sub_and_test
static __always_inline bool arch_atomic64_dec_and_test(atomic64_t *v)
{
return __atomic64_add_const_and_test_barrier(-1, (long *)&v->counter);
}
#define arch_atomic64_dec_and_test arch_atomic64_dec_and_test
static __always_inline bool arch_atomic64_inc_and_test(atomic64_t *v)
{
return __atomic64_add_const_and_test_barrier(1, (long *)&v->counter);
}
#define arch_atomic64_inc_and_test arch_atomic64_inc_and_test
static __always_inline s64 arch_atomic64_xchg(atomic64_t *v, s64 new)
{
return arch_xchg(&v->counter, new);
}
#define arch_atomic64_xchg arch_atomic64_xchg
static __always_inline s64 arch_atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)
{
return arch_cmpxchg(&v->counter, old, new);
}
#define arch_atomic64_cmpxchg arch_atomic64_cmpxchg
static __always_inline bool arch_atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new)
{
return arch_try_cmpxchg(&v->counter, old, new);
}
#define arch_atomic64_try_cmpxchg arch_atomic64_try_cmpxchg
#define ATOMIC64_OPS(op) \
static __always_inline void arch_atomic64_##op(s64 i, atomic64_t *v) \
{ \
__atomic64_##op(i, (long *)&v->counter); \
} \
static __always_inline long arch_atomic64_fetch_##op(s64 i, atomic64_t *v) \
{ \
return __atomic64_##op##_barrier(i, (long *)&v->counter); \
}
ATOMIC64_OPS(and)
ATOMIC64_OPS(or)
ATOMIC64_OPS(xor)
#undef ATOMIC64_OPS
#define arch_atomic64_and arch_atomic64_and
#define arch_atomic64_or arch_atomic64_or
#define arch_atomic64_xor arch_atomic64_xor
#define arch_atomic64_fetch_and arch_atomic64_fetch_and
#define arch_atomic64_fetch_or arch_atomic64_fetch_or
#define arch_atomic64_fetch_xor arch_atomic64_fetch_xor
#define arch_atomic64_sub_return(_i, _v) arch_atomic64_add_return(-(s64)(_i), _v)
#define arch_atomic64_fetch_sub(_i, _v) arch_atomic64_fetch_add(-(s64)(_i), _v)
#define arch_atomic64_sub(_i, _v) arch_atomic64_add(-(s64)(_i), _v)
#endif /* __ARCH_S390_ATOMIC__ */
@@ -0,0 +1,245 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Low level function for atomic operations
*
* Copyright IBM Corp. 1999, 2016
*/
#ifndef __ARCH_S390_ATOMIC_OPS__
#define __ARCH_S390_ATOMIC_OPS__
#include <linux/limits.h>
#include <asm/march.h>
#include <asm/asm.h>
static __always_inline int __atomic_read(const int *ptr)
{
int val;
asm volatile(
" l %[val],%[ptr]"
: [val] "=d" (val) : [ptr] "R" (*ptr));
return val;
}
static __always_inline void __atomic_set(int *ptr, int val)
{
if (__builtin_constant_p(val) && val >= S16_MIN && val <= S16_MAX) {
asm volatile(
" mvhi %[ptr],%[val]"
: [ptr] "=Q" (*ptr) : [val] "K" (val));
} else {
asm volatile(
" st %[val],%[ptr]"
: [ptr] "=R" (*ptr) : [val] "d" (val));
}
}
static __always_inline long __atomic64_read(const long *ptr)
{
long val;
asm volatile(
" lg %[val],%[ptr]"
: [val] "=d" (val) : [ptr] "RT" (*ptr));
return val;
}
static __always_inline void __atomic64_set(long *ptr, long val)
{
if (__builtin_constant_p(val) && val >= S16_MIN && val <= S16_MAX) {
asm volatile(
" mvghi %[ptr],%[val]"
: [ptr] "=Q" (*ptr) : [val] "K" (val));
} else {
asm volatile(
" stg %[val],%[ptr]"
: [ptr] "=RT" (*ptr) : [val] "d" (val));
}
}
#ifdef MARCH_HAS_Z196_FEATURES
#define __ATOMIC_OP(op_name, op_type, op_string, op_barrier) \
static __always_inline op_type op_name(op_type val, op_type *ptr) \
{ \
op_type old; \
\
asm volatile( \
op_string " %[old],%[val],%[ptr]" \
op_barrier \
: [old] "=d" (old), [ptr] "+QS" (*ptr) \
: [val] "d" (val) : "cc", "memory"); \
return old; \
} \
#define __ATOMIC_OPS(op_name, op_type, op_string) \
__ATOMIC_OP(op_name, op_type, op_string, "") \
__ATOMIC_OP(op_name##_barrier, op_type, op_string, "\nbcr 14,0")
__ATOMIC_OPS(__atomic_add, int, "laa")
__ATOMIC_OPS(__atomic_and, int, "lan")
__ATOMIC_OPS(__atomic_or, int, "lao")
__ATOMIC_OPS(__atomic_xor, int, "lax")
__ATOMIC_OPS(__atomic64_add, long, "laag")
__ATOMIC_OPS(__atomic64_and, long, "lang")
__ATOMIC_OPS(__atomic64_or, long, "laog")
__ATOMIC_OPS(__atomic64_xor, long, "laxg")
#undef __ATOMIC_OPS
#undef __ATOMIC_OP
#define __ATOMIC_CONST_OP(op_name, op_type, op_string, op_barrier) \
static __always_inline void op_name(op_type val, op_type *ptr) \
{ \
asm volatile( \
op_string " %[ptr],%[val]" \
op_barrier \
: [ptr] "+QS" (*ptr) : [val] "i" (val) : "cc", "memory");\
}
#define __ATOMIC_CONST_OPS(op_name, op_type, op_string) \
__ATOMIC_CONST_OP(op_name, op_type, op_string, "") \
__ATOMIC_CONST_OP(op_name##_barrier, op_type, op_string, "\nbcr 14,0")
__ATOMIC_CONST_OPS(__atomic_add_const, int, "asi")
__ATOMIC_CONST_OPS(__atomic64_add_const, long, "agsi")
#undef __ATOMIC_CONST_OPS
#undef __ATOMIC_CONST_OP
#else /* MARCH_HAS_Z196_FEATURES */
#define __ATOMIC_OP(op_name, op_string) \
static __always_inline int op_name(int val, int *ptr) \
{ \
int old, new; \
\
asm volatile( \
"0: lr %[new],%[old]\n" \
op_string " %[new],%[val]\n" \
" cs %[old],%[new],%[ptr]\n" \
" jl 0b" \
: [old] "=d" (old), [new] "=&d" (new), [ptr] "+Q" (*ptr)\
: [val] "d" (val), "0" (*ptr) : "cc", "memory"); \
return old; \
}
#define __ATOMIC_OPS(op_name, op_string) \
__ATOMIC_OP(op_name, op_string) \
__ATOMIC_OP(op_name##_barrier, op_string)
__ATOMIC_OPS(__atomic_add, "ar")
__ATOMIC_OPS(__atomic_and, "nr")
__ATOMIC_OPS(__atomic_or, "or")
__ATOMIC_OPS(__atomic_xor, "xr")
#undef __ATOMIC_OPS
#define __ATOMIC64_OP(op_name, op_string) \
static __always_inline long op_name(long val, long *ptr) \
{ \
long old, new; \
\
asm volatile( \
"0: lgr %[new],%[old]\n" \
op_string " %[new],%[val]\n" \
" csg %[old],%[new],%[ptr]\n" \
" jl 0b" \
: [old] "=d" (old), [new] "=&d" (new), [ptr] "+QS" (*ptr)\
: [val] "d" (val), "0" (*ptr) : "cc", "memory"); \
return old; \
}
#define __ATOMIC64_OPS(op_name, op_string) \
__ATOMIC64_OP(op_name, op_string) \
__ATOMIC64_OP(op_name##_barrier, op_string)
__ATOMIC64_OPS(__atomic64_add, "agr")
__ATOMIC64_OPS(__atomic64_and, "ngr")
__ATOMIC64_OPS(__atomic64_or, "ogr")
__ATOMIC64_OPS(__atomic64_xor, "xgr")
#undef __ATOMIC64_OPS
#define __atomic_add_const(val, ptr) ((void)__atomic_add(val, ptr))
#define __atomic_add_const_barrier(val, ptr) ((void)__atomic_add(val, ptr))
#define __atomic64_add_const(val, ptr) ((void)__atomic64_add(val, ptr))
#define __atomic64_add_const_barrier(val, ptr) ((void)__atomic64_add(val, ptr))
#endif /* MARCH_HAS_Z196_FEATURES */
#if defined(MARCH_HAS_Z196_FEATURES) && defined(__HAVE_ASM_FLAG_OUTPUTS__)
#define __ATOMIC_TEST_OP(op_name, op_type, op_string, op_barrier) \
static __always_inline bool op_name(op_type val, op_type *ptr) \
{ \
op_type tmp; \
int cc; \
\
asm volatile( \
op_string " %[tmp],%[val],%[ptr]" \
op_barrier \
: "=@cc" (cc), [tmp] "=d" (tmp), [ptr] "+QS" (*ptr) \
: [val] "d" (val) \
: "memory"); \
return (cc == 0) || (cc == 2); \
} \
#define __ATOMIC_TEST_OPS(op_name, op_type, op_string) \
__ATOMIC_TEST_OP(op_name, op_type, op_string, "") \
__ATOMIC_TEST_OP(op_name##_barrier, op_type, op_string, "\nbcr 14,0")
__ATOMIC_TEST_OPS(__atomic_add_and_test, int, "laal")
__ATOMIC_TEST_OPS(__atomic64_add_and_test, long, "laalg")
#undef __ATOMIC_TEST_OPS
#undef __ATOMIC_TEST_OP
#define __ATOMIC_CONST_TEST_OP(op_name, op_type, op_string, op_barrier) \
static __always_inline bool op_name(op_type val, op_type *ptr) \
{ \
int cc; \
\
asm volatile( \
op_string " %[ptr],%[val]" \
op_barrier \
: "=@cc" (cc), [ptr] "+QS" (*ptr) \
: [val] "i" (val) \
: "memory"); \
return (cc == 0) || (cc == 2); \
}
#define __ATOMIC_CONST_TEST_OPS(op_name, op_type, op_string) \
__ATOMIC_CONST_TEST_OP(op_name, op_type, op_string, "") \
__ATOMIC_CONST_TEST_OP(op_name##_barrier, op_type, op_string, "\nbcr 14,0")
__ATOMIC_CONST_TEST_OPS(__atomic_add_const_and_test, int, "alsi")
__ATOMIC_CONST_TEST_OPS(__atomic64_add_const_and_test, long, "algsi")
#undef __ATOMIC_CONST_TEST_OPS
#undef __ATOMIC_CONST_TEST_OP
#else /* defined(MARCH_HAS_Z196_FEATURES) && defined(__HAVE_ASM_FLAG_OUTPUTS__) */
#define __ATOMIC_TEST_OP(op_name, op_func, op_type) \
static __always_inline bool op_name(op_type val, op_type *ptr) \
{ \
return op_func(val, ptr) == -val; \
}
__ATOMIC_TEST_OP(__atomic_add_and_test, __atomic_add, int)
__ATOMIC_TEST_OP(__atomic_add_and_test_barrier, __atomic_add_barrier, int)
__ATOMIC_TEST_OP(__atomic_add_const_and_test, __atomic_add, int)
__ATOMIC_TEST_OP(__atomic_add_const_and_test_barrier, __atomic_add_barrier, int)
__ATOMIC_TEST_OP(__atomic64_add_and_test, __atomic64_add, long)
__ATOMIC_TEST_OP(__atomic64_add_and_test_barrier, __atomic64_add_barrier, long)
__ATOMIC_TEST_OP(__atomic64_add_const_and_test, __atomic64_add, long)
__ATOMIC_TEST_OP(__atomic64_add_const_and_test_barrier, __atomic64_add_barrier, long)
#undef __ATOMIC_TEST_OP
#endif /* defined(MARCH_HAS_Z196_FEATURES) && defined(__HAVE_ASM_FLAG_OUTPUTS__) */
#endif /* __ARCH_S390_ATOMIC_OPS__ */
@@ -0,0 +1,80 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 1999, 2009
*
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
#ifndef __ASM_BARRIER_H
#define __ASM_BARRIER_H
#include <asm/alternative.h>
#include <asm/march.h>
/*
* Force strict CPU ordering.
* And yes, this is required on UP too when we're talking
* to devices.
*/
static __always_inline void bcr_serialize(void)
{
asm_inline volatile(
ALTERNATIVE("bcr 15,0", "bcr 14,0", ALT_FACILITY(45))
: : : "memory");
}
#define __mb() bcr_serialize()
#define __rmb() barrier()
#define __wmb() barrier()
#define __dma_rmb() __mb()
#define __dma_wmb() __mb()
#define __smp_mb() __mb()
#define __smp_rmb() __rmb()
#define __smp_wmb() __wmb()
#define __smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
barrier(); \
WRITE_ONCE(*p, v); \
} while (0)
#define __smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = READ_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
barrier(); \
___p1; \
})
#define __smp_mb__before_atomic() barrier()
#define __smp_mb__after_atomic() barrier()
/**
* array_index_mask_nospec - generate a mask for array_idx() that is
* ~0UL when the bounds check succeeds and 0 otherwise
* @index: array element index
* @size: number of elements in array
*/
#define array_index_mask_nospec array_index_mask_nospec
static __always_inline unsigned long array_index_mask_nospec(unsigned long index,
unsigned long size)
{
unsigned long mask;
if (__builtin_constant_p(size) && size > 0) {
asm(" clgr %2,%1\n"
" slbgr %0,%0"
:"=d" (mask) : "d" (size-1), "d" (index) :"cc");
return mask;
}
asm(" clgr %1,%2\n"
" slbgr %0,%0"
:"=d" (mask) : "d" (size), "d" (index) :"cc");
return ~mask;
}
#include <asm-generic/barrier.h>
#endif /* __ASM_BARRIER_H */
+216
View File
@@ -0,0 +1,216 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 1999,2013
*
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
*
* The description below was taken in large parts from the powerpc
* bitops header file:
* Within a word, bits are numbered LSB first. Lot's of places make
* this assumption by directly testing bits with (val & (1<<nr)).
* This can cause confusion for large (> 1 word) bitmaps on a
* big-endian system because, unlike little endian, the number of each
* bit depends on the word size.
*
* The bitop functions are defined to work on unsigned longs, so the bits
* end up numbered:
* |63..............0|127............64|191...........128|255...........192|
*
* We also have special functions which work with an MSB0 encoding.
* The bits are numbered:
* |0..............63|64............127|128...........191|192...........255|
*
* The main difference is that bit 0-63 in the bit number field needs to be
* reversed compared to the LSB0 encoded bit fields. This can be achieved by
* XOR with 0x3f.
*
*/
#ifndef _S390_BITOPS_H
#define _S390_BITOPS_H
#ifndef _LINUX_BITOPS_H
#error only <linux/bitops.h> can be included directly
#endif
#include <linux/typecheck.h>
#include <linux/compiler.h>
#include <linux/types.h>
#include <asm/asm.h>
#define arch___set_bit generic___set_bit
#define arch___clear_bit generic___clear_bit
#define arch___change_bit generic___change_bit
#define arch___test_and_set_bit generic___test_and_set_bit
#define arch___test_and_clear_bit generic___test_and_clear_bit
#define arch___test_and_change_bit generic___test_and_change_bit
#define arch_test_bit_acquire generic_test_bit_acquire
static __always_inline bool arch_test_bit(unsigned long nr, const volatile unsigned long *ptr)
{
#ifdef __HAVE_ASM_FLAG_OUTPUTS__
const volatile unsigned char *addr;
unsigned long mask;
int cc;
/*
* With CONFIG_PROFILE_ALL_BRANCHES enabled gcc fails to
* handle __builtin_constant_p() in some cases.
*/
if (!IS_ENABLED(CONFIG_PROFILE_ALL_BRANCHES) && __builtin_constant_p(nr)) {
addr = (const volatile unsigned char *)ptr;
addr += (nr ^ (BITS_PER_LONG - BITS_PER_BYTE)) / BITS_PER_BYTE;
mask = 1UL << (nr & (BITS_PER_BYTE - 1));
asm volatile(
" tm %[addr],%[mask]"
: "=@cc" (cc)
: [addr] "Q" (*addr), [mask] "I" (mask)
);
return cc == 3;
}
#endif
return generic_test_bit(nr, ptr);
}
#include <asm-generic/bitops/atomic.h>
#include <asm-generic/bitops/non-instrumented-non-atomic.h>
#include <asm-generic/bitops/lock.h>
/*
* Functions which use MSB0 bit numbering.
* The bits are numbered:
* |0..............63|64............127|128...........191|192...........255|
*/
unsigned long find_first_bit_inv(const unsigned long *addr, unsigned long size);
unsigned long find_next_bit_inv(const unsigned long *addr, unsigned long size,
unsigned long offset);
#define for_each_set_bit_inv(bit, addr, size) \
for ((bit) = find_first_bit_inv((addr), (size)); \
(bit) < (size); \
(bit) = find_next_bit_inv((addr), (size), (bit) + 1))
static inline void set_bit_inv(unsigned long nr, volatile unsigned long *ptr)
{
return set_bit(nr ^ (BITS_PER_LONG - 1), ptr);
}
static inline void clear_bit_inv(unsigned long nr, volatile unsigned long *ptr)
{
return clear_bit(nr ^ (BITS_PER_LONG - 1), ptr);
}
static inline bool test_and_clear_bit_inv(unsigned long nr,
volatile unsigned long *ptr)
{
return test_and_clear_bit(nr ^ (BITS_PER_LONG - 1), ptr);
}
static inline void __set_bit_inv(unsigned long nr, volatile unsigned long *ptr)
{
return __set_bit(nr ^ (BITS_PER_LONG - 1), ptr);
}
static inline void __clear_bit_inv(unsigned long nr, volatile unsigned long *ptr)
{
return __clear_bit(nr ^ (BITS_PER_LONG - 1), ptr);
}
static inline bool test_bit_inv(unsigned long nr,
const volatile unsigned long *ptr)
{
return test_bit(nr ^ (BITS_PER_LONG - 1), ptr);
}
#ifndef CONFIG_CC_HAS_BUILTIN_FFS
/**
* __flogr - find leftmost one
* @word - The word to search
*
* Returns the bit number of the most significant bit set,
* where the most significant bit has bit number 0.
* If no bit is set this function returns 64.
*/
static __always_inline __attribute_const__ unsigned long __flogr(unsigned long word)
{
unsigned long bit;
if (__builtin_constant_p(word)) {
bit = 0;
if (!word)
return 64;
if (!(word & 0xffffffff00000000UL)) {
word <<= 32;
bit += 32;
}
if (!(word & 0xffff000000000000UL)) {
word <<= 16;
bit += 16;
}
if (!(word & 0xff00000000000000UL)) {
word <<= 8;
bit += 8;
}
if (!(word & 0xf000000000000000UL)) {
word <<= 4;
bit += 4;
}
if (!(word & 0xc000000000000000UL)) {
word <<= 2;
bit += 2;
}
if (!(word & 0x8000000000000000UL)) {
word <<= 1;
bit += 1;
}
return bit;
} else {
union register_pair rp __uninitialized;
rp.even = word;
asm("flogr %[rp],%[rp]"
: [rp] "+d" (rp.pair) : : "cc");
bit = rp.even;
/*
* The result of the flogr instruction is a value in the range
* of 0..64. Let the compiler know that the AND operation can
* be optimized away.
*/
__assume(bit <= 64);
return bit & 127;
}
}
/**
* ffs - find first bit set
* @word: the word to search
*
* This is defined the same way as the libc and
* compiler builtin ffs routines (man ffs).
*/
static __always_inline __flatten __attribute_const__ int ffs(int word)
{
unsigned int val = (unsigned int)word;
return BITS_PER_LONG - __flogr(-val & val);
}
#else /* CONFIG_CC_HAS_BUILTIN_FFS */
#include <asm-generic/bitops/builtin-ffs.h>
#endif /* CONFIG_CC_HAS_BUILTIN_FFS */
#include <asm-generic/bitops/builtin-__ffs.h>
#include <asm-generic/bitops/ffz.h>
#include <asm-generic/bitops/builtin-__fls.h>
#include <asm-generic/bitops/builtin-fls.h>
#include <asm-generic/bitops/fls64.h>
#include <asm/arch_hweight.h>
#include <asm-generic/bitops/const_hweight.h>
#include <asm-generic/bitops/sched.h>
#include <asm-generic/bitops/le.h>
#include <asm-generic/bitops/ext2-atomic-setbit.h>
#endif /* _S390_BITOPS_H */
@@ -0,0 +1,69 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_BOOT_DATA_H
#include <linux/string.h>
#include <asm/setup.h>
#include <asm/ipl.h>
extern char early_command_line[COMMAND_LINE_SIZE];
extern struct ipl_parameter_block ipl_block;
extern int ipl_block_valid;
extern int ipl_secure_flag;
extern unsigned long ipl_cert_list_addr;
extern unsigned long ipl_cert_list_size;
extern unsigned long early_ipl_comp_list_addr;
extern unsigned long early_ipl_comp_list_size;
extern char boot_rb[PAGE_SIZE * 2];
extern bool boot_earlyprintk;
extern size_t boot_rb_off;
extern char bootdebug_filter[128];
extern bool bootdebug;
#define boot_rb_foreach(cb) \
do { \
size_t off = boot_rb_off + strlen(boot_rb + boot_rb_off) + 1; \
size_t len; \
for (; off < sizeof(boot_rb) && (len = strlen(boot_rb + off)); off += len + 1) \
cb(boot_rb + off); \
for (off = 0; off < boot_rb_off && (len = strlen(boot_rb + off)); off += len + 1) \
cb(boot_rb + off); \
} while (0)
/*
* bootdebug_filter is a comma separated list of strings,
* where each string can be a prefix of the message.
*/
static inline bool bootdebug_filter_match(const char *buf)
{
char *p = bootdebug_filter, *s;
char *end;
if (!*p)
return true;
end = p + strlen(p);
while (p < end) {
p = skip_spaces(p);
s = memscan(p, ',', end - p);
if (!strncmp(p, buf, s - p))
return true;
p = s + 1;
}
return false;
}
static inline const char *skip_timestamp(const char *buf)
{
#ifdef CONFIG_PRINTK_TIME
const char *p = memchr(buf, ']', strlen(buf));
if (p && p[1] == ' ')
return p + 2;
#endif
return buf;
}
#endif /* _ASM_S390_BOOT_DATA_H */
+141
View File
@@ -0,0 +1,141 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_BUG_H
#define _ASM_S390_BUG_H
#include <linux/compiler.h>
#include <linux/const.h>
#include <linux/stringify.h>
#define MONCODE_BUG _AC(0, U)
#define MONCODE_BUG_ARG _AC(1, U)
#ifndef __ASSEMBLER__
#if defined(CONFIG_BUG) && defined(CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS)
#ifdef CONFIG_DEBUG_BUGVERBOSE
#define __BUG_ENTRY_VERBOSE(file, line) \
" .long " file " - . # bug_entry::file\n" \
" .short " line " # bug_entry::line\n"
#else
#define __BUG_ENTRY_VERBOSE(file, line)
#endif
#ifdef CONFIG_DEBUG_BUGVERBOSE_DETAILED
#define WARN_CONDITION_STR(cond_str) cond_str
#else
#define WARN_CONDITION_STR(cond_str) ""
#endif
#define __BUG_ENTRY(format, file, line, flags, size) \
" .section __bug_table,\"aw\"\n" \
"1: .long 0b - . # bug_entry::bug_addr\n"\
" .long " format " - . # bug_entry::format\n" \
__BUG_ENTRY_VERBOSE(file, line) \
" .short "flags" # bug_entry::flags\n" \
" .org 1b+"size"\n" \
" .previous"
#define __BUG_ASM(cond_str, flags) \
do { \
asm_inline volatile("\n" \
"0: mc %[monc](%%r0),0\n" \
__BUG_ENTRY("%[frmt]", "%[file]", "%[line]", \
"%[flgs]", "%[size]") \
: \
: [monc] "i" (MONCODE_BUG), \
[frmt] "i" (WARN_CONDITION_STR(cond_str)), \
[file] "i" (__FILE__), \
[line] "i" (__LINE__), \
[flgs] "i" (flags), \
[size] "i" (sizeof(struct bug_entry))); \
} while (0)
#define BUG() \
do { \
__BUG_ASM("", 0); \
unreachable(); \
} while (0)
#define __WARN_FLAGS(cond_str, flags) \
do { \
__BUG_ASM(cond_str, BUGFLAG_WARNING | (flags)); \
} while (0)
#define __WARN_bug_entry(flags, format) \
({ \
struct bug_entry *bug; \
\
asm_inline volatile("\n" \
"0: larl %[bug],1f\n" \
__BUG_ENTRY("%[frmt]", "%[file]", "%[line]", \
"%[flgs]", "%[size]") \
: [bug] "=d" (bug) \
: [frmt] "i" (format), \
[file] "i" (__FILE__), \
[line] "i" (__LINE__), \
[flgs] "i" (flags), \
[size] "i" (sizeof(struct bug_entry))); \
bug; \
})
/*
* Variable Argument List (va_list) as defined in ELF Application
* Binary Interface s390x Supplement documentation.
*/
struct arch_va_list {
long __gpr;
long __fpr;
void *__overflow_arg_area;
void *__reg_save_area;
};
struct bug_entry;
struct pt_regs;
void *__warn_args(struct arch_va_list *args, struct pt_regs *regs);
void __WARN_trap(struct bug_entry *bug, ...);
#define __WARN_print_arg(flags, format, arg...) \
do { \
int __flags = (flags) | BUGFLAG_WARNING | BUGFLAG_ARGS; \
\
__WARN_trap(__WARN_bug_entry(__flags, format), ## arg); \
/* prevent tail-call optimization */ \
asm(""); \
} while (0)
#define __WARN_printf(taint, fmt, arg...) \
__WARN_print_arg(BUGFLAG_TAINT(taint), fmt, ## arg)
#define WARN_ONCE(cond, format, arg...) \
({ \
int __ret_warn_on = !!(cond); \
\
if (unlikely(__ret_warn_on)) { \
__WARN_print_arg(BUGFLAG_ONCE|BUGFLAG_TAINT(TAINT_WARN),\
format, ## arg); \
} \
__ret_warn_on; \
})
#define HAVE_ARCH_BUG
#define HAVE_ARCH_BUG_FORMAT
#define HAVE_ARCH_BUG_FORMAT_ARGS
#define ARCH_WARN_ASM(file, line, flags, size) \
".section .rodata.str,\"aMS\",@progbits,1\n" \
"9:\n" \
".asciz \"\"\n" /* Empty string for compatibility */ \
".previous\n" \
"0:\n" \
__stringify(mc 0(%r0),0) "\n" \
__BUG_ENTRY("9b", file, line, flags, size)
#define ARCH_WARN_REACHABLE
#endif /* CONFIG_BUG && CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS */
#endif /* __ASSEMBLER__ */
#include <asm-generic/bug.h>
#endif /* _ASM_S390_BUG_H */
+19
View File
@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* S390 version
* Copyright IBM Corp. 1999
*
* Derived from "include/asm-i386/cache.h"
* Copyright (C) 1992, Linus Torvalds
*/
#ifndef __ARCH_S390_CACHE_H
#define __ARCH_S390_CACHE_H
#define L1_CACHE_BYTES 256
#define L1_CACHE_SHIFT 8
#define NET_SKB_PAD 32
#define __read_mostly __section(".data..read_mostly")
#endif
+238
View File
@@ -0,0 +1,238 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 2002, 2009
*
* Author(s): Arnd Bergmann <arndb@de.ibm.com>
*
* Interface for CCW device drivers
*/
#ifndef _S390_CCWDEV_H_
#define _S390_CCWDEV_H_
#include <linux/device.h>
#include <linux/device-id/ccw.h>
#include <asm/chsc.h>
#include <asm/fcx.h>
#include <asm/irq.h>
#include <asm/schid.h>
#include <linux/mutex.h>
/* structs from asm/cio.h */
struct irb;
struct ccw1;
struct ccw_dev_id;
/* simplified initializers for struct ccw_device:
* CCW_DEVICE and CCW_DEVICE_DEVTYPE initialize one
* entry in your MODULE_DEVICE_TABLE and set the match_flag correctly */
#define CCW_DEVICE(cu, cum) \
.cu_type=(cu), .cu_model=(cum), \
.match_flags=(CCW_DEVICE_ID_MATCH_CU_TYPE \
| (cum ? CCW_DEVICE_ID_MATCH_CU_MODEL : 0))
#define CCW_DEVICE_DEVTYPE(cu, cum, dev, devm) \
.cu_type=(cu), .cu_model=(cum), .dev_type=(dev), .dev_model=(devm),\
.match_flags=CCW_DEVICE_ID_MATCH_CU_TYPE \
| ((cum) ? CCW_DEVICE_ID_MATCH_CU_MODEL : 0) \
| CCW_DEVICE_ID_MATCH_DEVICE_TYPE \
| ((devm) ? CCW_DEVICE_ID_MATCH_DEVICE_MODEL : 0)
/* scan through an array of device ids and return the first
* entry that matches the device.
*
* the array must end with an entry containing zero match_flags
*/
static inline const struct ccw_device_id *
ccw_device_id_match(const struct ccw_device_id *array,
const struct ccw_device_id *match)
{
const struct ccw_device_id *id = array;
for (id = array; id->match_flags; id++) {
if ((id->match_flags & CCW_DEVICE_ID_MATCH_CU_TYPE)
&& (id->cu_type != match->cu_type))
continue;
if ((id->match_flags & CCW_DEVICE_ID_MATCH_CU_MODEL)
&& (id->cu_model != match->cu_model))
continue;
if ((id->match_flags & CCW_DEVICE_ID_MATCH_DEVICE_TYPE)
&& (id->dev_type != match->dev_type))
continue;
if ((id->match_flags & CCW_DEVICE_ID_MATCH_DEVICE_MODEL)
&& (id->dev_model != match->dev_model))
continue;
return id;
}
return NULL;
}
/**
* struct ccw_device - channel attached device
* @ccwlock: pointer to device lock
* @id: id of this device
* @drv: ccw driver for this device
* @dev: embedded device structure
* @online: online status of device
* @handler: interrupt handler
*
* @handler is a member of the device rather than the driver since a driver
* can have different interrupt handlers for different ccw devices
* (multi-subchannel drivers).
*/
struct ccw_device {
spinlock_t *ccwlock;
/* private: */
struct ccw_device_private *private; /* cio private information */
struct mutex reg_mutex;
/* public: */
struct ccw_device_id id;
struct ccw_driver *drv;
struct device dev;
int online;
void (*handler) (struct ccw_device *, unsigned long, struct irb *);
};
/*
* Possible events used by the path_event notifier.
*/
#define PE_NONE 0x0
#define PE_PATH_GONE 0x1 /* A path is no longer available. */
#define PE_PATH_AVAILABLE 0x2 /* A path has become available and
was successfully verified. */
#define PE_PATHGROUP_ESTABLISHED 0x4 /* A pathgroup was reset and had
to be established again. */
#define PE_PATH_FCES_EVENT 0x8 /* The FCES Status of a path has
* changed. */
/*
* Possible CIO actions triggered by the unit check handler.
*/
enum uc_todo {
UC_TODO_RETRY,
UC_TODO_RETRY_ON_NEW_PATH,
UC_TODO_STOP
};
/**
* struct ccw_driver - device driver for channel attached devices
* @ids: ids supported by this driver
* @probe: function called on probe
* @remove: function called on remove
* @set_online: called when setting device online
* @set_offline: called when setting device offline
* @notify: notify driver of device state changes
* @path_event: notify driver of channel path events
* @shutdown: called at device shutdown
* @uc_handler: callback for unit check handler
* @driver: embedded device driver structure
* @int_class: interruption class to use for accounting interrupts
*/
struct ccw_driver {
struct ccw_device_id *ids;
int (*probe) (struct ccw_device *);
void (*remove) (struct ccw_device *);
int (*set_online) (struct ccw_device *);
int (*set_offline) (struct ccw_device *);
int (*notify) (struct ccw_device *, int);
void (*path_event) (struct ccw_device *, int *);
void (*shutdown) (struct ccw_device *);
enum uc_todo (*uc_handler) (struct ccw_device *, struct irb *);
struct device_driver driver;
enum interruption_class int_class;
};
extern struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv,
const char *bus_id);
/* devices drivers call these during module load and unload.
* When a driver is registered, its probe method is called
* when new devices for its type pop up */
extern int ccw_driver_register (struct ccw_driver *driver);
extern void ccw_driver_unregister (struct ccw_driver *driver);
extern int ccw_device_set_options_mask(struct ccw_device *, unsigned long);
extern int ccw_device_set_options(struct ccw_device *, unsigned long);
extern void ccw_device_clear_options(struct ccw_device *, unsigned long);
int ccw_device_is_pathgroup(struct ccw_device *cdev);
int ccw_device_is_multipath(struct ccw_device *cdev);
/* Allow for i/o completion notification after primary interrupt status. */
#define CCWDEV_EARLY_NOTIFICATION 0x0001
/* Report all interrupt conditions. */
#define CCWDEV_REPORT_ALL 0x0002
/* Try to perform path grouping. */
#define CCWDEV_DO_PATHGROUP 0x0004
/* Allow forced onlining of boxed devices. */
#define CCWDEV_ALLOW_FORCE 0x0008
/* Try to use multipath mode. */
#define CCWDEV_DO_MULTIPATH 0x0010
extern int ccw_device_start(struct ccw_device *, struct ccw1 *,
unsigned long, __u8, unsigned long);
extern int ccw_device_start_timeout(struct ccw_device *, struct ccw1 *,
unsigned long, __u8, unsigned long, int);
extern int ccw_device_start_key(struct ccw_device *, struct ccw1 *,
unsigned long, __u8, __u8, unsigned long);
extern int ccw_device_start_timeout_key(struct ccw_device *, struct ccw1 *,
unsigned long, __u8, __u8,
unsigned long, int);
extern int ccw_device_resume(struct ccw_device *);
extern int ccw_device_halt(struct ccw_device *, unsigned long);
extern int ccw_device_clear(struct ccw_device *, unsigned long);
int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw,
unsigned long intparm, u8 lpm, u8 key);
int ccw_device_tm_start_key(struct ccw_device *, struct tcw *,
unsigned long, u8, u8);
int ccw_device_tm_start_timeout_key(struct ccw_device *, struct tcw *,
unsigned long, u8, u8, int);
int ccw_device_tm_start(struct ccw_device *, struct tcw *,
unsigned long, u8);
int ccw_device_tm_start_timeout(struct ccw_device *, struct tcw *,
unsigned long, u8, int);
int ccw_device_tm_intrg(struct ccw_device *cdev);
int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask);
extern int ccw_device_set_online(struct ccw_device *cdev);
extern int ccw_device_set_offline(struct ccw_device *cdev);
extern struct ciw *ccw_device_get_ciw(struct ccw_device *, __u32 cmd);
extern __u8 ccw_device_get_path_mask(struct ccw_device *);
extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *);
#define get_ccwdev_lock(x) (x)->ccwlock
#define to_ccwdev(n) container_of(n, struct ccw_device, dev)
#define to_ccwdrv(n) container_of_const(n, struct ccw_driver, driver)
extern struct ccw_device *ccw_device_create_console(struct ccw_driver *);
extern void ccw_device_destroy_console(struct ccw_device *);
extern int ccw_device_enable_console(struct ccw_device *);
extern void ccw_device_wait_idle(struct ccw_device *);
extern void *ccw_device_dma_zalloc(struct ccw_device *cdev, size_t size,
dma32_t *dma_handle);
extern void ccw_device_dma_free(struct ccw_device *cdev,
void *cpu_addr, size_t size);
int ccw_device_siosl(struct ccw_device *);
extern void ccw_device_get_schid(struct ccw_device *, struct subchannel_id *);
struct channel_path_desc_fmt0 *ccw_device_get_chp_desc(struct ccw_device *, int);
u8 *ccw_device_get_util_str(struct ccw_device *cdev, int chp_idx);
int ccw_device_pnso(struct ccw_device *cdev,
struct chsc_pnso_area *pnso_area, u8 oc,
struct chsc_pnso_resume_token resume_token, int cnc);
int ccw_device_get_cssid(struct ccw_device *cdev, u8 *cssid);
int ccw_device_get_iid(struct ccw_device *cdev, u8 *iid);
int ccw_device_get_chpid(struct ccw_device *cdev, int chp_idx, u8 *chpid);
int ccw_device_get_chid(struct ccw_device *cdev, int chp_idx, u16 *chid);
#endif /* _S390_CCWDEV_H_ */
@@ -0,0 +1,75 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef S390_CCWGROUP_H
#define S390_CCWGROUP_H
struct ccw_device;
struct ccw_driver;
/**
* struct ccwgroup_device - ccw group device
* @state: online/offline state
* @count: number of attached slave devices
* @dev: embedded device structure
* @cdev: variable number of slave devices, allocated as needed
* @ungroup_work: used to ungroup the ccwgroup device
*/
struct ccwgroup_device {
enum {
CCWGROUP_OFFLINE,
CCWGROUP_ONLINE,
} state;
/* private: */
atomic_t onoff;
struct mutex reg_mutex;
/* public: */
unsigned int count;
struct device dev;
struct work_struct ungroup_work;
struct ccw_device *cdev[];
};
/**
* struct ccwgroup_driver - driver for ccw group devices
* @setup: function called during device creation to setup the device
* @remove: function called on remove
* @set_online: function called when device is set online
* @set_offline: function called when device is set offline
* @shutdown: function called when device is shut down
* @driver: embedded driver structure
* @ccw_driver: supported ccw_driver (optional)
*/
struct ccwgroup_driver {
int (*setup) (struct ccwgroup_device *);
void (*remove) (struct ccwgroup_device *);
int (*set_online) (struct ccwgroup_device *);
int (*set_offline) (struct ccwgroup_device *);
void (*shutdown)(struct ccwgroup_device *);
struct device_driver driver;
struct ccw_driver *ccw_driver;
};
extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver);
extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver);
int ccwgroup_create_dev(struct device *root, struct ccwgroup_driver *gdrv,
int num_devices, const char *buf);
extern int ccwgroup_set_online(struct ccwgroup_device *gdev);
int ccwgroup_set_offline(struct ccwgroup_device *gdev, bool call_gdrv);
extern int ccwgroup_probe_ccwdev(struct ccw_device *cdev);
extern void ccwgroup_remove_ccwdev(struct ccw_device *cdev);
#define to_ccwgroupdev(x) container_of((x), struct ccwgroup_device, dev)
#define to_ccwgroupdrv(x) container_of((x), struct ccwgroup_driver, driver)
#if IS_ENABLED(CONFIG_CCWGROUP)
bool dev_is_ccwgroup(struct device *dev);
#else /* CONFIG_CCWGROUP */
static inline bool dev_is_ccwgroup(struct device *dev)
{
return false;
}
#endif /* CONFIG_CCWGROUP */
#endif
@@ -0,0 +1,128 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* S390 fast network checksum routines
*
* S390 version
* Copyright IBM Corp. 1999
* Author(s): Ulrich Hild (first version)
* Martin Schwidefsky (heavily optimized CKSM version)
* D.J. Barrow (third attempt)
*/
#ifndef _S390_CHECKSUM_H
#define _S390_CHECKSUM_H
#include <linux/instrumented.h>
#include <linux/kmsan-checks.h>
#include <linux/in6.h>
static inline __wsum cksm(const void *buff, int len, __wsum sum)
{
union register_pair rp = {
.even = (unsigned long)buff,
.odd = (unsigned long)len,
};
instrument_read(buff, len);
kmsan_check_memory(buff, len);
asm volatile(
"0: cksm %[sum],%[rp]\n"
" jo 0b"
: [sum] "+&d" (sum), [rp] "+&d" (rp.pair) : : "cc", "memory");
return sum;
}
__wsum csum_partial(const void *buff, int len, __wsum sum);
#define _HAVE_ARCH_CSUM_AND_COPY
__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len);
/*
* Fold a partial checksum without adding pseudo headers.
*/
static inline __sum16 csum_fold(__wsum sum)
{
u32 csum = (__force u32) sum;
csum += (csum >> 16) | (csum << 16);
csum >>= 16;
return (__force __sum16) ~csum;
}
/*
* This is a version of ip_compute_csum() optimized for IP headers,
* which always checksums on 4 octet boundaries.
*/
static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
{
__u64 csum = 0;
__u32 *ptr = (u32 *)iph;
csum += *ptr++;
csum += *ptr++;
csum += *ptr++;
csum += *ptr++;
ihl -= 4;
while (ihl--)
csum += *ptr++;
csum += (csum >> 32) | (csum << 32);
return csum_fold((__force __wsum)(csum >> 32));
}
/*
* Computes the checksum of the TCP/UDP pseudo-header.
* Returns a 32-bit checksum.
*/
static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
{
__u64 csum = (__force __u64)sum;
csum += (__force __u32)saddr;
csum += (__force __u32)daddr;
csum += len;
csum += proto;
csum += (csum >> 32) | (csum << 32);
return (__force __wsum)(csum >> 32);
}
/*
* Computes the checksum of the TCP/UDP pseudo-header.
* Returns a 16-bit checksum, already complemented.
*/
static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
{
return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
}
/*
* Used for miscellaneous IP-like checksums, mainly icmp.
*/
static inline __sum16 ip_compute_csum(const void *buff, int len)
{
return csum_fold(csum_partial(buff, len, 0));
}
#define _HAVE_ARCH_IPV6_CSUM
static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
const struct in6_addr *daddr,
__u32 len, __u8 proto, __wsum csum)
{
__u64 sum = (__force __u64)csum;
sum += (__force __u32)saddr->s6_addr32[0];
sum += (__force __u32)saddr->s6_addr32[1];
sum += (__force __u32)saddr->s6_addr32[2];
sum += (__force __u32)saddr->s6_addr32[3];
sum += (__force __u32)daddr->s6_addr32[0];
sum += (__force __u32)daddr->s6_addr32[1];
sum += (__force __u32)daddr->s6_addr32[2];
sum += (__force __u32)daddr->s6_addr32[3];
sum += len;
sum += proto;
sum += (sum >> 32) | (sum << 32);
return csum_fold((__force __wsum)(sum >> 32));
}
#endif /* _S390_CHECKSUM_H */
+51
View File
@@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 2007, 2012
* Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
*/
#ifndef _ASM_S390_CHPID_H
#define _ASM_S390_CHPID_H
#include <uapi/asm/chpid.h>
#include <asm/cio.h>
struct channel_path_desc_fmt0 {
u8 flags;
u8 lsn;
u8 desc;
u8 chpid;
u8 swla;
u8 zeroes;
u8 chla;
u8 chpp;
} __packed;
static inline void chp_id_init(struct chp_id *chpid)
{
memset(chpid, 0, sizeof(struct chp_id));
}
static inline int chp_id_is_equal(struct chp_id *a, struct chp_id *b)
{
return (a->id == b->id) && (a->cssid == b->cssid);
}
static inline void chp_id_next(struct chp_id *chpid)
{
if (chpid->id < __MAX_CHPID)
chpid->id++;
else {
chpid->id = 0;
chpid->cssid++;
}
}
static inline int chp_id_is_valid(struct chp_id *chpid)
{
return (chpid->cssid <= __MAX_CSSID);
}
#define chp_id_for_each(c) \
for (chp_id_init(c); chp_id_is_valid(c); chp_id_next(c))
#endif /* _ASM_S390_CHPID_H */
+84
View File
@@ -0,0 +1,84 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 2020
*
* Author(s): Alexandra Winter <wintera@linux.ibm.com>
*
* Interface for Channel Subsystem Call
*/
#ifndef _ASM_S390_CHSC_H
#define _ASM_S390_CHSC_H
#include <uapi/asm/chsc.h>
/* struct from linux/notifier.h */
struct notifier_block;
/**
* Operation codes for CHSC PNSO:
* PNSO_OC_NET_BRIDGE_INFO - only addresses that are visible to a bridgeport
* PNSO_OC_NET_ADDR_INFO - all addresses
*/
#define PNSO_OC_NET_BRIDGE_INFO 0
#define PNSO_OC_NET_ADDR_INFO 3
/**
* struct chsc_pnso_naid_l2 - network address information descriptor
* @nit: Network interface token
* @addr_lnid: network address and logical network id (VLAN ID)
*/
struct chsc_pnso_naid_l2 {
u64 nit;
struct { u8 mac[6]; u16 lnid; } addr_lnid;
} __packed;
struct chsc_pnso_resume_token {
u64 t1;
u64 t2;
} __packed;
struct chsc_pnso_naihdr {
struct chsc_pnso_resume_token resume_token;
u32:32;
u32 instance;
u32:24;
u8 naids;
u32 reserved[3];
} __packed;
struct chsc_pnso_area {
struct chsc_header request;
u8:2;
u8 m:1;
u8:5;
u8:2;
u8 ssid:2;
u8 fmt:4;
u16 sch;
u8:8;
u8 cssid;
u16:16;
u8 oc;
u32:24;
struct chsc_pnso_resume_token resume_token;
u32 n:1;
u32:31;
u32 reserved[3];
struct chsc_header response;
u32:32;
struct chsc_pnso_naihdr naihdr;
struct chsc_pnso_naid_l2 entries[];
} __packed __aligned(PAGE_SIZE);
/*
* notifier interface - registered notifiers gets called on
* the following events:
* - ap config changed (CHSC_NOTIFY_AP_CFG)
*/
enum chsc_notify_type {
CHSC_NOTIFY_AP_CFG = 3,
};
int chsc_notifier_register(struct notifier_block *nb);
int chsc_notifier_unregister(struct notifier_block *nb);
#endif /* _ASM_S390_CHSC_H */
+383
View File
@@ -0,0 +1,383 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Common interface for I/O on S/390
*/
#ifndef _ASM_S390_CIO_H_
#define _ASM_S390_CIO_H_
#include <linux/bitops.h>
#include <linux/genalloc.h>
#include <asm/dma-types.h>
#include <asm/types.h>
#include <asm/tpi.h>
#define LPM_ANYPATH 0xff
#define __MAX_CSSID 0
#define __MAX_SUBCHANNEL 65535
#define __MAX_SSID 3
#include <asm/scsw.h>
#define CCW_MAX_BYTE_COUNT 65535
/**
* struct ccw1 - channel command word
* @cmd_code: command code
* @flags: flags, like IDA addressing, etc.
* @count: byte count
* @cda: data address
*
* The ccw is the basic structure to build channel programs that perform
* operations with the device or the control unit. Only Format-1 channel
* command words are supported.
*/
struct ccw1 {
__u8 cmd_code;
__u8 flags;
__u16 count;
dma32_t cda;
} __attribute__ ((packed,aligned(8)));
/**
* struct ccw0 - channel command word
* @cmd_code: command code
* @cda: data address
* @flags: flags, like IDA addressing, etc.
* @reserved: will be ignored
* @count: byte count
*
* The format-0 ccw structure.
*/
struct ccw0 {
__u8 cmd_code;
__u32 cda : 24;
__u8 flags;
__u8 reserved;
__u16 count;
} __packed __aligned(8);
#define CCW_FLAG_DC 0x80
#define CCW_FLAG_CC 0x40
#define CCW_FLAG_SLI 0x20
#define CCW_FLAG_SKIP 0x10
#define CCW_FLAG_PCI 0x08
#define CCW_FLAG_IDA 0x04
#define CCW_FLAG_SUSPEND 0x02
#define CCW_CMD_READ_IPL 0x02
#define CCW_CMD_NOOP 0x03
#define CCW_CMD_BASIC_SENSE 0x04
#define CCW_CMD_TIC 0x08
#define CCW_CMD_STLCK 0x14
#define CCW_CMD_SENSE_PGID 0x34
#define CCW_CMD_SUSPEND_RECONN 0x5B
#define CCW_CMD_RDC 0x64
#define CCW_CMD_RELEASE 0x94
#define CCW_CMD_SET_PGID 0xAF
#define CCW_CMD_SENSE_ID 0xE4
#define CCW_CMD_DCTL 0xF3
#define SENSE_MAX_COUNT 0x20
/**
* struct erw - extended report word
* @res0: reserved
* @auth: authorization check
* @pvrf: path-verification-required flag
* @cpt: channel-path timeout
* @fsavf: failing storage address validity flag
* @cons: concurrent sense
* @scavf: secondary ccw address validity flag
* @fsaf: failing storage address format
* @scnt: sense count, if @cons == %1
* @res16: reserved
*/
struct erw {
__u32 res0 : 3;
__u32 auth : 1;
__u32 pvrf : 1;
__u32 cpt : 1;
__u32 fsavf : 1;
__u32 cons : 1;
__u32 scavf : 1;
__u32 fsaf : 1;
__u32 scnt : 6;
__u32 res16 : 16;
} __attribute__ ((packed));
/**
* struct erw_eadm - EADM Subchannel extended report word
* @b: aob error
* @r: arsb error
*/
struct erw_eadm {
__u32 : 16;
__u32 b : 1;
__u32 r : 1;
__u32 : 14;
} __packed;
/**
* struct sublog - subchannel logout area
* @res0: reserved
* @esf: extended status flags
* @lpum: last path used mask
* @arep: ancillary report
* @fvf: field-validity flags
* @sacc: storage access code
* @termc: termination code
* @devsc: device-status check
* @serr: secondary error
* @ioerr: i/o-error alert
* @seqc: sequence code
*/
struct sublog {
__u32 res0 : 1;
__u32 esf : 7;
__u32 lpum : 8;
__u32 arep : 1;
__u32 fvf : 5;
__u32 sacc : 2;
__u32 termc : 2;
__u32 devsc : 1;
__u32 serr : 1;
__u32 ioerr : 1;
__u32 seqc : 3;
} __attribute__ ((packed));
/**
* struct esw0 - Format 0 Extended Status Word (ESW)
* @sublog: subchannel logout
* @erw: extended report word
* @faddr: failing storage address
* @saddr: secondary ccw address
*/
struct esw0 {
struct sublog sublog;
struct erw erw;
dma32_t faddr[2];
dma32_t saddr;
} __attribute__ ((packed));
/**
* struct esw1 - Format 1 Extended Status Word (ESW)
* @zero0: reserved zeros
* @lpum: last path used mask
* @zero16: reserved zeros
* @erw: extended report word
* @zeros: three fullwords of zeros
*/
struct esw1 {
__u8 zero0;
__u8 lpum;
__u16 zero16;
struct erw erw;
__u32 zeros[3];
} __attribute__ ((packed));
/**
* struct esw2 - Format 2 Extended Status Word (ESW)
* @zero0: reserved zeros
* @lpum: last path used mask
* @dcti: device-connect-time interval
* @erw: extended report word
* @zeros: three fullwords of zeros
*/
struct esw2 {
__u8 zero0;
__u8 lpum;
__u16 dcti;
struct erw erw;
__u32 zeros[3];
} __attribute__ ((packed));
/**
* struct esw3 - Format 3 Extended Status Word (ESW)
* @zero0: reserved zeros
* @lpum: last path used mask
* @res: reserved
* @erw: extended report word
* @zeros: three fullwords of zeros
*/
struct esw3 {
__u8 zero0;
__u8 lpum;
__u16 res;
struct erw erw;
__u32 zeros[3];
} __attribute__ ((packed));
/**
* struct esw_eadm - EADM Subchannel Extended Status Word (ESW)
* @sublog: subchannel logout
* @erw: extended report word
*/
struct esw_eadm {
__u32 sublog;
struct erw_eadm erw;
__u32 : 32;
__u32 : 32;
__u32 : 32;
} __packed;
/**
* struct irb - interruption response block
* @scsw: subchannel status word
* @esw: extended status word
* @ecw: extended control word
*
* The irb that is handed to the device driver when an interrupt occurs. For
* solicited interrupts, the common I/O layer already performs checks whether
* a field is valid; a field not being valid is always passed as %0.
* If a unit check occurred, @ecw may contain sense data; this is retrieved
* by the common I/O layer itself if the device doesn't support concurrent
* sense (so that the device driver never needs to perform basic sense itself).
* For unsolicited interrupts, the irb is passed as-is (expect for sense data,
* if applicable).
*/
struct irb {
union scsw scsw;
union {
struct esw0 esw0;
struct esw1 esw1;
struct esw2 esw2;
struct esw3 esw3;
struct esw_eadm eadm;
} esw;
__u8 ecw[32];
} __attribute__ ((packed,aligned(4)));
/**
* struct ciw - command information word (CIW) layout
* @et: entry type
* @reserved: reserved bits
* @ct: command type
* @cmd: command code
* @count: command count
*/
struct ciw {
__u32 et : 2;
__u32 reserved : 2;
__u32 ct : 4;
__u32 cmd : 8;
__u32 count : 16;
} __attribute__ ((packed));
#define CIW_TYPE_RCD 0x0 /* read configuration data */
#define CIW_TYPE_SII 0x1 /* set interface identifier */
#define CIW_TYPE_RNI 0x2 /* read node identifier */
/*
* Node Descriptor as defined in SA22-7204, "Common I/O-Device Commands"
*/
#define ND_VALIDITY_VALID 0
#define ND_VALIDITY_OUTDATED 1
#define ND_VALIDITY_INVALID 2
struct node_descriptor {
/* Flags. */
union {
struct {
u32 validity:3;
u32 reserved:5;
} __packed;
u8 byte0;
} __packed;
/* Node parameters. */
u32 params:24;
/* Node ID. */
char type[6];
char model[3];
char manufacturer[3];
char plant[2];
char seq[12];
u16 tag;
} __packed;
/*
* Flags used as input parameters for do_IO()
*/
#define DOIO_ALLOW_SUSPEND 0x0001 /* allow for channel prog. suspend */
#define DOIO_DENY_PREFETCH 0x0002 /* don't allow for CCW prefetch */
#define DOIO_SUPPRESS_INTER 0x0004 /* suppress intermediate inter. */
/* ... for suspended CCWs */
/* Device or subchannel gone. */
#define CIO_GONE 0x0001
/* No path to device. */
#define CIO_NO_PATH 0x0002
/* Device has appeared. */
#define CIO_OPER 0x0004
/* Sick revalidation of device. */
#define CIO_REVALIDATE 0x0008
/* Device did not respond in time. */
#define CIO_BOXED 0x0010
/**
* struct ccw_dev_id - unique identifier for ccw devices
* @ssid: subchannel set id
* @devno: device number
*
* This structure is not directly based on any hardware structure. The
* hardware identifies a device by its device number and its subchannel,
* which is in turn identified by its id. In order to get a unique identifier
* for ccw devices across subchannel sets, @struct ccw_dev_id has been
* introduced.
*/
struct ccw_dev_id {
u8 ssid;
u16 devno;
};
/**
* ccw_dev_id_is_equal() - compare two ccw_dev_ids
* @dev_id1: a ccw_dev_id
* @dev_id2: another ccw_dev_id
* Returns:
* %1 if the two structures are equal field-by-field,
* %0 if not.
* Context:
* any
*/
static inline int ccw_dev_id_is_equal(struct ccw_dev_id *dev_id1,
struct ccw_dev_id *dev_id2)
{
if ((dev_id1->ssid == dev_id2->ssid) &&
(dev_id1->devno == dev_id2->devno))
return 1;
return 0;
}
/**
* pathmask_to_pos() - find the position of the left-most bit in a pathmask
* @mask: pathmask with at least one bit set
*/
static inline u8 pathmask_to_pos(u8 mask)
{
return 8 - ffs(mask);
}
extern void css_schedule_reprobe(void);
extern void *cio_dma_zalloc(size_t size);
extern void cio_dma_free(void *cpu_addr, size_t size);
extern struct device *cio_get_dma_css_dev(void);
void *cio_gp_dma_zalloc(struct gen_pool *gp_dma, struct device *dma_dev,
size_t size);
void *__cio_gp_dma_zalloc(struct gen_pool *gp_dma, struct device *dma_dev,
size_t size, dma32_t *dma_handle);
void cio_gp_dma_free(struct gen_pool *gp_dma, void *cpu_addr, size_t size);
void cio_gp_dma_destroy(struct gen_pool *gp_dma, struct device *dma_dev);
struct gen_pool *cio_gp_dma_create(struct device *dma_dev, int nr_pages);
/* Function from drivers/s390/cio/chsc.c */
int chsc_sstpc(void *page, unsigned int op, u16 ctrl, long *clock_delta);
int chsc_sstpi(void *page, void *result, size_t size);
int chsc_stzi(void *page, void *result, size_t size);
int chsc_sgib(u32 origin);
int chsc_scud(u16 cu, u64 *esm, u8 *esm_valid);
#endif
@@ -0,0 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* s390-specific clocksource additions */
#ifndef _ASM_S390_CLOCKSOURCE_H
#define _ASM_S390_CLOCKSOURCE_H
#endif /* _ASM_S390_CLOCKSOURCE_H */
+59
View File
@@ -0,0 +1,59 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_CLP_H
#define _ASM_S390_CLP_H
/* CLP common request & response block size */
#define CLP_BLK_SIZE PAGE_SIZE
/* Call Logical Processor - Command Code */
#define CLP_SLPC 0x0001
#define CLP_LPS_BASE 0
#define CLP_LPS_PCI 2
struct clp_req_hdr {
u16 len;
u16 cmd;
u32 fmt : 4;
u32 reserved1 : 28;
u64 reserved2;
} __packed;
struct clp_rsp_hdr {
u16 len;
u16 rsp;
u32 fmt : 4;
u32 reserved1 : 28;
u64 reserved2;
} __packed;
/* CLP Response Codes */
#define CLP_RC_OK 0x0010 /* Command request successfully */
#define CLP_RC_CMD 0x0020 /* Command code not recognized */
#define CLP_RC_PERM 0x0030 /* Command not authorized */
#define CLP_RC_FMT 0x0040 /* Invalid command request format */
#define CLP_RC_LEN 0x0050 /* Invalid command request length */
#define CLP_RC_8K 0x0060 /* Command requires 8K LPCB */
#define CLP_RC_RESNOT0 0x0070 /* Reserved field not zero */
#define CLP_RC_NODATA 0x0080 /* No data available */
#define CLP_RC_FC_UNKNOWN 0x0100 /* Function code not recognized */
/* Store logical-processor characteristics request */
struct clp_req_slpc {
struct clp_req_hdr hdr;
} __packed;
struct clp_rsp_slpc {
struct clp_rsp_hdr hdr;
u32 reserved2[4];
u32 lpif[8];
u32 reserved3[8];
u32 lpic[8];
} __packed;
struct clp_req_rsp_slpc {
struct clp_req_slpc request;
struct clp_rsp_slpc response;
} __packed;
#endif
+14
View File
@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef S390_CMB_H
#define S390_CMB_H
#include <uapi/asm/cmb.h>
struct ccw_device;
extern int enable_cmf(struct ccw_device *cdev);
extern int disable_cmf(struct ccw_device *cdev);
extern int __disable_cmf(struct ccw_device *cdev);
extern u64 cmf_read(struct ccw_device *cdev, int index);
extern int cmf_readall(struct ccw_device *cdev, struct cmbdata *data);
#endif /* S390_CMB_H */
+273
View File
@@ -0,0 +1,273 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 1999, 2011
*
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
*/
#ifndef __ASM_CMPXCHG_H
#define __ASM_CMPXCHG_H
#include <linux/mmdebug.h>
#include <linux/types.h>
#include <linux/bug.h>
#include <asm/asm.h>
void __cmpxchg_called_with_bad_pointer(void);
static __always_inline u32 __cs_asm(u64 ptr, u32 old, u32 new)
{
asm volatile(
" cs %[old],%[new],%[ptr]"
: [old] "+d" (old), [ptr] "+Q" (*(u32 *)ptr)
: [new] "d" (new)
: "memory", "cc");
return old;
}
static __always_inline u64 __csg_asm(u64 ptr, u64 old, u64 new)
{
asm volatile(
" csg %[old],%[new],%[ptr]"
: [old] "+d" (old), [ptr] "+QS" (*(u64 *)ptr)
: [new] "d" (new)
: "memory", "cc");
return old;
}
static __no_sanitize_or_inline u8 __arch_cmpxchg1(u64 ptr, u8 old, u8 new)
{
union {
u8 b[4];
u32 w;
} old32, new32;
u32 prev;
int i;
i = ptr & 3;
ptr &= ~0x3;
prev = READ_ONCE(*(u32 *)ptr);
do {
old32.w = prev;
if (old32.b[i] != old)
return old32.b[i];
new32.w = old32.w;
new32.b[i] = new;
prev = __cs_asm(ptr, old32.w, new32.w);
} while (prev != old32.w);
return old;
}
static __no_sanitize_or_inline u16 __arch_cmpxchg2(u64 ptr, u16 old, u16 new)
{
union {
u16 b[2];
u32 w;
} old32, new32;
u32 prev;
int i;
i = (ptr & 3) >> 1;
ptr &= ~0x3;
prev = READ_ONCE(*(u32 *)ptr);
do {
old32.w = prev;
if (old32.b[i] != old)
return old32.b[i];
new32.w = old32.w;
new32.b[i] = new;
prev = __cs_asm(ptr, old32.w, new32.w);
} while (prev != old32.w);
return old;
}
static __always_inline u64 __arch_cmpxchg(u64 ptr, u64 old, u64 new, int size)
{
switch (size) {
case 1: return __arch_cmpxchg1(ptr, old & 0xff, new & 0xff);
case 2: return __arch_cmpxchg2(ptr, old & 0xffff, new & 0xffff);
case 4: return __cs_asm(ptr, old & 0xffffffff, new & 0xffffffff);
case 8: return __csg_asm(ptr, old, new);
default: __cmpxchg_called_with_bad_pointer();
}
return old;
}
#define arch_cmpxchg(ptr, o, n) \
({ \
(__typeof__(*(ptr)))__arch_cmpxchg((unsigned long)(ptr), \
(unsigned long)(o), \
(unsigned long)(n), \
sizeof(*(ptr))); \
})
#define arch_cmpxchg64 arch_cmpxchg
#define arch_cmpxchg_local arch_cmpxchg
#define arch_cmpxchg64_local arch_cmpxchg
#ifdef __HAVE_ASM_FLAG_OUTPUTS__
#define arch_try_cmpxchg(ptr, oldp, new) \
({ \
__typeof__(ptr) __oldp = (__typeof__(ptr))(oldp); \
__typeof__(*(ptr)) __old = *__oldp; \
__typeof__(*(ptr)) __new = (new); \
__typeof__(*(ptr)) __prev; \
int __cc; \
\
switch (sizeof(*(ptr))) { \
case 1: \
case 2: { \
__prev = arch_cmpxchg((ptr), (__old), (__new)); \
__cc = (__prev != __old); \
if (unlikely(__cc)) \
*__oldp = __prev; \
break; \
} \
case 4: { \
asm volatile( \
" cs %[__old],%[__new],%[__ptr]" \
: [__old] "+d" (*__oldp), \
[__ptr] "+Q" (*(ptr)), \
"=@cc" (__cc) \
: [__new] "d" (__new) \
: "memory"); \
break; \
} \
case 8: { \
asm volatile( \
" csg %[__old],%[__new],%[__ptr]" \
: [__old] "+d" (*__oldp), \
[__ptr] "+QS" (*(ptr)), \
"=@cc" (__cc) \
: [__new] "d" (__new) \
: "memory"); \
break; \
} \
default: \
__cmpxchg_called_with_bad_pointer(); \
} \
likely(__cc == 0); \
})
#else /* __HAVE_ASM_FLAG_OUTPUTS__ */
#define arch_try_cmpxchg(ptr, oldp, new) \
({ \
__typeof__((ptr)) __oldp = (__typeof__(ptr))(oldp); \
__typeof__(*(ptr)) __old = *__oldp; \
__typeof__(*(ptr)) __new = (new); \
__typeof__(*(ptr)) __prev; \
\
__prev = arch_cmpxchg((ptr), (__old), (__new)); \
if (unlikely(__prev != __old)) \
*__oldp = __prev; \
likely(__prev == __old); \
})
#endif /* __HAVE_ASM_FLAG_OUTPUTS__ */
#define arch_try_cmpxchg64 arch_try_cmpxchg
#define arch_try_cmpxchg_local arch_try_cmpxchg
#define arch_try_cmpxchg64_local arch_try_cmpxchg
void __xchg_called_with_bad_pointer(void);
static __no_sanitize_or_inline u8 __arch_xchg1(u64 ptr, u8 x)
{
int shift = (3 ^ (ptr & 3)) << 3;
u32 mask, old, new;
ptr &= ~0x3;
mask = ~(0xff << shift);
old = READ_ONCE(*(u32 *)ptr);
do {
new = old & mask;
new |= x << shift;
} while (!arch_try_cmpxchg((u32 *)ptr, &old, new));
return old >> shift;
}
static __no_sanitize_or_inline u16 __arch_xchg2(u64 ptr, u16 x)
{
int shift = (2 ^ (ptr & 2)) << 3;
u32 mask, old, new;
ptr &= ~0x3;
mask = ~(0xffff << shift);
old = READ_ONCE(*(u32 *)ptr);
do {
new = old & mask;
new |= x << shift;
} while (!arch_try_cmpxchg((u32 *)ptr, &old, new));
return old >> shift;
}
static __always_inline u64 __arch_xchg(u64 ptr, u64 x, int size)
{
switch (size) {
case 1:
return __arch_xchg1(ptr, x & 0xff);
case 2:
return __arch_xchg2(ptr, x & 0xffff);
case 4: {
u32 old = READ_ONCE(*(u32 *)ptr);
do {
} while (!arch_try_cmpxchg((u32 *)ptr, &old, x & 0xffffffff));
return old;
}
case 8: {
u64 old = READ_ONCE(*(u64 *)ptr);
do {
} while (!arch_try_cmpxchg((u64 *)ptr, &old, x));
return old;
}
}
__xchg_called_with_bad_pointer();
return x;
}
#define arch_xchg(ptr, x) \
({ \
(__typeof__(*(ptr)))__arch_xchg((unsigned long)(ptr), \
(unsigned long)(x), \
sizeof(*(ptr))); \
})
#define system_has_cmpxchg128() 1
static __always_inline u128 arch_cmpxchg128(volatile u128 *ptr, u128 old, u128 new)
{
asm volatile(
" cdsg %[old],%[new],%[ptr]"
: [old] "+d" (old), [ptr] "+QS" (*ptr)
: [new] "d" (new)
: "memory", "cc");
return old;
}
#define arch_cmpxchg128 arch_cmpxchg128
#define arch_cmpxchg128_local arch_cmpxchg128
#ifdef __HAVE_ASM_FLAG_OUTPUTS__
static __always_inline bool arch_try_cmpxchg128(volatile u128 *ptr, u128 *oldp, u128 new)
{
int cc;
asm volatile(
" cdsg %[old],%[new],%[ptr]"
: [old] "+d" (*oldp), [ptr] "+QS" (*ptr), "=@cc" (cc)
: [new] "d" (new)
: "memory");
return likely(cc == 0);
}
#define arch_try_cmpxchg128 arch_try_cmpxchg128
#define arch_try_cmpxchg128_local arch_try_cmpxchg128
#endif /* __HAVE_ASM_FLAG_OUTPUTS__ */
#endif /* __ASM_CMPXCHG_H */
+736
View File
@@ -0,0 +1,736 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* CP Assist for Cryptographic Functions (CPACF)
*
* Copyright IBM Corp. 2003, 2023
* Author(s): Thomas Spatzier
* Jan Glauber
* Harald Freudenberger (freude@de.ibm.com)
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
#ifndef _ASM_S390_CPACF_H
#define _ASM_S390_CPACF_H
#include <asm/facility.h>
#include <linux/kmsan-checks.h>
/*
* Instruction opcodes for the CPACF instructions
*/
#define CPACF_KMAC 0xb91e /* MSA */
#define CPACF_KM 0xb92e /* MSA */
#define CPACF_KMC 0xb92f /* MSA */
#define CPACF_KIMD 0xb93e /* MSA */
#define CPACF_KLMD 0xb93f /* MSA */
#define CPACF_PCKMO 0xb928 /* MSA3 */
#define CPACF_KMF 0xb92a /* MSA4 */
#define CPACF_KMO 0xb92b /* MSA4 */
#define CPACF_PCC 0xb92c /* MSA4 */
#define CPACF_KMCTR 0xb92d /* MSA4 */
#define CPACF_PRNO 0xb93c /* MSA5 */
#define CPACF_KMA 0xb929 /* MSA8 */
#define CPACF_KDSA 0xb93a /* MSA9 */
/*
* En/decryption modifier bits
*/
#define CPACF_ENCRYPT 0x00
#define CPACF_DECRYPT 0x80
/*
* Function codes for the KM (CIPHER MESSAGE) instruction
*/
#define CPACF_KM_QUERY 0x00
#define CPACF_KM_DEA 0x01
#define CPACF_KM_TDEA_128 0x02
#define CPACF_KM_TDEA_192 0x03
#define CPACF_KM_AES_128 0x12
#define CPACF_KM_AES_192 0x13
#define CPACF_KM_AES_256 0x14
#define CPACF_KM_PAES_128 0x1a
#define CPACF_KM_PAES_192 0x1b
#define CPACF_KM_PAES_256 0x1c
#define CPACF_KM_XTS_128 0x32
#define CPACF_KM_XTS_256 0x34
#define CPACF_KM_PXTS_128 0x3a
#define CPACF_KM_PXTS_256 0x3c
#define CPACF_KM_XTS_128_FULL 0x52
#define CPACF_KM_XTS_256_FULL 0x54
#define CPACF_KM_PXTS_128_FULL 0x5a
#define CPACF_KM_PXTS_256_FULL 0x5c
/*
* Function codes for the KMC (CIPHER MESSAGE WITH CHAINING)
* instruction
*/
#define CPACF_KMC_QUERY 0x00
#define CPACF_KMC_DEA 0x01
#define CPACF_KMC_TDEA_128 0x02
#define CPACF_KMC_TDEA_192 0x03
#define CPACF_KMC_AES_128 0x12
#define CPACF_KMC_AES_192 0x13
#define CPACF_KMC_AES_256 0x14
#define CPACF_KMC_PAES_128 0x1a
#define CPACF_KMC_PAES_192 0x1b
#define CPACF_KMC_PAES_256 0x1c
#define CPACF_KMC_PRNG 0x43
/*
* Function codes for the KMCTR (CIPHER MESSAGE WITH COUNTER)
* instruction
*/
#define CPACF_KMCTR_QUERY 0x00
#define CPACF_KMCTR_DEA 0x01
#define CPACF_KMCTR_TDEA_128 0x02
#define CPACF_KMCTR_TDEA_192 0x03
#define CPACF_KMCTR_AES_128 0x12
#define CPACF_KMCTR_AES_192 0x13
#define CPACF_KMCTR_AES_256 0x14
#define CPACF_KMCTR_PAES_128 0x1a
#define CPACF_KMCTR_PAES_192 0x1b
#define CPACF_KMCTR_PAES_256 0x1c
/*
* Function codes for the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
* instruction
*/
#define CPACF_KIMD_QUERY 0x00
#define CPACF_KIMD_SHA_1 0x01
#define CPACF_KIMD_SHA_256 0x02
#define CPACF_KIMD_SHA_512 0x03
#define CPACF_KIMD_SHA3_224 0x20
#define CPACF_KIMD_SHA3_256 0x21
#define CPACF_KIMD_SHA3_384 0x22
#define CPACF_KIMD_SHA3_512 0x23
#define CPACF_KIMD_GHASH 0x41
/*
* Function codes for the KLMD (COMPUTE LAST MESSAGE DIGEST)
* instruction
*/
#define CPACF_KLMD_QUERY 0x00
#define CPACF_KLMD_SHA_1 0x01
#define CPACF_KLMD_SHA_256 0x02
#define CPACF_KLMD_SHA_512 0x03
#define CPACF_KLMD_SHA3_224 0x20
#define CPACF_KLMD_SHA3_256 0x21
#define CPACF_KLMD_SHA3_384 0x22
#define CPACF_KLMD_SHA3_512 0x23
/*
* function codes for the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
* instruction
*/
#define CPACF_KMAC_QUERY 0x00
#define CPACF_KMAC_DEA 0x01
#define CPACF_KMAC_TDEA_128 0x02
#define CPACF_KMAC_TDEA_192 0x03
#define CPACF_KMAC_HMAC_SHA_224 0x70
#define CPACF_KMAC_HMAC_SHA_256 0x71
#define CPACF_KMAC_HMAC_SHA_384 0x72
#define CPACF_KMAC_HMAC_SHA_512 0x73
#define CPACF_KMAC_PHMAC_SHA_224 0x78
#define CPACF_KMAC_PHMAC_SHA_256 0x79
#define CPACF_KMAC_PHMAC_SHA_384 0x7a
#define CPACF_KMAC_PHMAC_SHA_512 0x7b
/*
* Function codes for the PCKMO (PERFORM CRYPTOGRAPHIC KEY MANAGEMENT)
* instruction
*/
#define CPACF_PCKMO_QUERY 0x00
#define CPACF_PCKMO_ENC_DES_KEY 0x01
#define CPACF_PCKMO_ENC_TDES_128_KEY 0x02
#define CPACF_PCKMO_ENC_TDES_192_KEY 0x03
#define CPACF_PCKMO_ENC_AES_128_KEY 0x12
#define CPACF_PCKMO_ENC_AES_192_KEY 0x13
#define CPACF_PCKMO_ENC_AES_256_KEY 0x14
#define CPACF_PCKMO_ENC_AES_XTS_128_DOUBLE_KEY 0x15
#define CPACF_PCKMO_ENC_AES_XTS_256_DOUBLE_KEY 0x16
#define CPACF_PCKMO_ENC_ECC_P256_KEY 0x20
#define CPACF_PCKMO_ENC_ECC_P384_KEY 0x21
#define CPACF_PCKMO_ENC_ECC_P521_KEY 0x22
#define CPACF_PCKMO_ENC_ECC_ED25519_KEY 0x28
#define CPACF_PCKMO_ENC_ECC_ED448_KEY 0x29
#define CPACF_PCKMO_ENC_HMAC_512_KEY 0x76
#define CPACF_PCKMO_ENC_HMAC_1024_KEY 0x7a
/*
* Function codes for the PRNO (PERFORM RANDOM NUMBER OPERATION)
* instruction
*/
#define CPACF_PRNO_QUERY 0x00
#define CPACF_PRNO_SHA512_DRNG_GEN 0x03
#define CPACF_PRNO_SHA512_DRNG_SEED 0x83
#define CPACF_PRNO_TRNG_Q_R2C_RATIO 0x70
#define CPACF_PRNO_TRNG 0x72
/*
* Function codes for the KMA (CIPHER MESSAGE WITH AUTHENTICATION)
* instruction
*/
#define CPACF_KMA_QUERY 0x00
#define CPACF_KMA_GCM_AES_128 0x12
#define CPACF_KMA_GCM_AES_192 0x13
#define CPACF_KMA_GCM_AES_256 0x14
/*
* Flags for the KMA (CIPHER MESSAGE WITH AUTHENTICATION) instruction
*/
#define CPACF_KMA_LPC 0x100 /* Last-Plaintext/Ciphertext */
#define CPACF_KMA_LAAD 0x200 /* Last-AAD */
#define CPACF_KMA_HS 0x400 /* Hash-subkey Supplied */
/*
* Flags for the KIMD/KLMD (COMPUTE INTERMEDIATE/LAST MESSAGE DIGEST)
* instructions
*/
#define CPACF_KIMD_NIP 0x8000
#define CPACF_KLMD_DUFOP 0x4000
#define CPACF_KLMD_NIP 0x8000
/*
* Function codes for KDSA (COMPUTE DIGITAL SIGNATURE AUTHENTICATION)
* instruction
*/
#define CPACF_KDSA_QUERY 0x00
#define CPACF_KDSA_ECDSA_VERIFY_P256 0x01
#define CPACF_KDSA_ECDSA_VERIFY_P384 0x02
#define CPACF_KDSA_ECDSA_VERIFY_P521 0x03
#define CPACF_KDSA_ECDSA_SIGN_P256 0x09
#define CPACF_KDSA_ECDSA_SIGN_P384 0x0a
#define CPACF_KDSA_ECDSA_SIGN_P521 0x0b
#define CPACF_KDSA_ENC_ECDSA_SIGN_P256 0x11
#define CPACF_KDSA_ENC_ECDSA_SIGN_P384 0x12
#define CPACF_KDSA_ENC_ECDSA_SIGN_P521 0x13
#define CPACF_KDSA_EDDSA_VERIFY_ED25519 0x20
#define CPACF_KDSA_EDDSA_VERIFY_ED448 0x24
#define CPACF_KDSA_EDDSA_SIGN_ED25519 0x28
#define CPACF_KDSA_EDDSA_SIGN_ED448 0x2c
#define CPACF_KDSA_ENC_EDDSA_SIGN_ED25519 0x30
#define CPACF_KDSA_ENC_EDDSA_SIGN_ED448 0x34
#define CPACF_FC_QUERY 0x00
#define CPACF_FC_QUERY_AUTH_INFO 0x7F
typedef struct { unsigned char bytes[16]; } cpacf_mask_t;
typedef struct { unsigned char bytes[256]; } cpacf_qai_t;
/*
* Prototype for a not existing function to produce a link
* error if __cpacf_query() or __cpacf_check_opcode() is used
* with an invalid compile time const opcode.
*/
void __cpacf_bad_opcode(void);
static __always_inline void __cpacf_query_rre(u32 opc, u8 r1, u8 r2,
u8 *pb, u8 fc)
{
asm volatile(
" la %%r1,%[pb]\n"
" lghi %%r0,%[fc]\n"
" .insn rre,%[opc] << 16,%[r1],%[r2]"
: [pb] "=R" (*pb)
: [opc] "i" (opc), [fc] "i" (fc),
[r1] "i" (r1), [r2] "i" (r2)
: "cc", "memory", "r0", "r1");
}
static __always_inline void __cpacf_query_rrf(u32 opc, u8 r1, u8 r2, u8 r3,
u8 m4, u8 *pb, u8 fc)
{
asm volatile(
" la %%r1,%[pb]\n"
" lghi %%r0,%[fc]\n"
" .insn rrf,%[opc] << 16,%[r1],%[r2],%[r3],%[m4]"
: [pb] "=R" (*pb)
: [opc] "i" (opc), [fc] "i" (fc), [r1] "i" (r1),
[r2] "i" (r2), [r3] "i" (r3), [m4] "i" (m4)
: "cc", "memory", "r0", "r1");
}
static __always_inline void __cpacf_query_insn(unsigned int opcode, void *pb,
u8 fc)
{
switch (opcode) {
case CPACF_KDSA:
__cpacf_query_rre(CPACF_KDSA, 0, 2, pb, fc);
break;
case CPACF_KIMD:
__cpacf_query_rre(CPACF_KIMD, 0, 2, pb, fc);
break;
case CPACF_KLMD:
__cpacf_query_rre(CPACF_KLMD, 0, 2, pb, fc);
break;
case CPACF_KM:
__cpacf_query_rre(CPACF_KM, 2, 4, pb, fc);
break;
case CPACF_KMA:
__cpacf_query_rrf(CPACF_KMA, 2, 4, 6, 0, pb, fc);
break;
case CPACF_KMAC:
__cpacf_query_rre(CPACF_KMAC, 0, 2, pb, fc);
break;
case CPACF_KMC:
__cpacf_query_rre(CPACF_KMC, 2, 4, pb, fc);
break;
case CPACF_KMCTR:
__cpacf_query_rrf(CPACF_KMCTR, 2, 4, 6, 0, pb, fc);
break;
case CPACF_KMF:
__cpacf_query_rre(CPACF_KMF, 2, 4, pb, fc);
break;
case CPACF_KMO:
__cpacf_query_rre(CPACF_KMO, 2, 4, pb, fc);
break;
case CPACF_PCC:
__cpacf_query_rre(CPACF_PCC, 0, 0, pb, fc);
break;
case CPACF_PCKMO:
__cpacf_query_rre(CPACF_PCKMO, 0, 0, pb, fc);
break;
case CPACF_PRNO:
__cpacf_query_rre(CPACF_PRNO, 2, 4, pb, fc);
break;
default:
__cpacf_bad_opcode();
}
}
static __always_inline void __cpacf_query(unsigned int opcode,
cpacf_mask_t *mask)
{
__cpacf_query_insn(opcode, mask, CPACF_FC_QUERY);
}
static __always_inline int __cpacf_check_opcode(unsigned int opcode)
{
switch (opcode) {
case CPACF_KMAC:
case CPACF_KM:
case CPACF_KMC:
case CPACF_KIMD:
case CPACF_KLMD:
return test_facility(17); /* check for MSA */
case CPACF_PCKMO:
return test_facility(76); /* check for MSA3 */
case CPACF_KMF:
case CPACF_KMO:
case CPACF_PCC:
case CPACF_KMCTR:
return test_facility(77); /* check for MSA4 */
case CPACF_PRNO:
return test_facility(57); /* check for MSA5 */
case CPACF_KMA:
return test_facility(146); /* check for MSA8 */
case CPACF_KDSA:
return test_facility(155); /* check for MSA9 */
default:
__cpacf_bad_opcode();
return 0;
}
}
/**
* cpacf_query() - Query the function code mask for this CPACF opcode
* @opcode: the opcode of the crypto instruction
* @mask: ptr to struct cpacf_mask_t
*
* Executes the query function for the given crypto instruction @opcode
* and checks if @func is available
*
* On success 1 is returned and the mask is filled with the function
* code mask for this CPACF opcode, otherwise 0 is returned.
*/
static __always_inline int cpacf_query(unsigned int opcode, cpacf_mask_t *mask)
{
if (__cpacf_check_opcode(opcode)) {
__cpacf_query(opcode, mask);
return 1;
}
memset(mask, 0, sizeof(*mask));
return 0;
}
static inline int cpacf_test_func(cpacf_mask_t *mask, unsigned int func)
{
return (mask->bytes[func >> 3] & (0x80 >> (func & 7))) != 0;
}
static __always_inline int cpacf_query_func(unsigned int opcode,
unsigned int func)
{
cpacf_mask_t mask;
if (cpacf_query(opcode, &mask))
return cpacf_test_func(&mask, func);
return 0;
}
static __always_inline void __cpacf_qai(unsigned int opcode, cpacf_qai_t *qai)
{
__cpacf_query_insn(opcode, qai, CPACF_FC_QUERY_AUTH_INFO);
}
/**
* cpacf_qai() - Get the query authentication information for a CPACF opcode
* @opcode: the opcode of the crypto instruction
* @mask: ptr to struct cpacf_qai_t
*
* Executes the query authentication information function for the given crypto
* instruction @opcode and checks if @func is available
*
* On success 1 is returned and the mask is filled with the query authentication
* information for this CPACF opcode, otherwise 0 is returned.
*/
static __always_inline int cpacf_qai(unsigned int opcode, cpacf_qai_t *qai)
{
if (cpacf_query_func(opcode, CPACF_FC_QUERY_AUTH_INFO)) {
__cpacf_qai(opcode, qai);
return 1;
}
memset(qai, 0, sizeof(*qai));
return 0;
}
/**
* cpacf_km() - executes the KM (CIPHER MESSAGE) instruction
* @func: the function code passed to KM; see CPACF_KM_xxx defines
* @param: address of parameter block; see POP for details on each func
* @dest: address of destination memory area
* @src: address of source memory area
* @src_len: length of src operand in bytes
*
* Returns 0 for the query func, number of processed bytes for
* encryption/decryption funcs
*/
static inline int cpacf_km(unsigned long func, void *param,
u8 *dest, const u8 *src, long src_len)
{
union register_pair d, s;
d.even = (unsigned long)dest;
s.even = (unsigned long)src;
s.odd = (unsigned long)src_len;
asm volatile(
" lgr 0,%[fc]\n"
" lgr 1,%[pba]\n"
"0: .insn rre,%[opc] << 16,%[dst],%[src]\n"
" brc 1,0b" /* handle partial completion */
: [src] "+&d" (s.pair), [dst] "+&d" (d.pair)
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
[opc] "i" (CPACF_KM)
: "cc", "memory", "0", "1");
return src_len - s.odd;
}
/**
* cpacf_kmc() - executes the KMC (CIPHER MESSAGE WITH CHAINING) instruction
* @func: the function code passed to KM; see CPACF_KMC_xxx defines
* @param: address of parameter block; see POP for details on each func
* @dest: address of destination memory area
* @src: address of source memory area
* @src_len: length of src operand in bytes
*
* Returns 0 for the query func, number of processed bytes for
* encryption/decryption funcs
*/
static inline int cpacf_kmc(unsigned long func, void *param,
u8 *dest, const u8 *src, long src_len)
{
union register_pair d, s;
d.even = (unsigned long)dest;
s.even = (unsigned long)src;
s.odd = (unsigned long)src_len;
asm volatile(
" lgr 0,%[fc]\n"
" lgr 1,%[pba]\n"
"0: .insn rre,%[opc] << 16,%[dst],%[src]\n"
" brc 1,0b" /* handle partial completion */
: [src] "+&d" (s.pair), [dst] "+&d" (d.pair)
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
[opc] "i" (CPACF_KMC)
: "cc", "memory", "0", "1");
return src_len - s.odd;
}
/**
* cpacf_kimd() - executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
* instruction
* @func: the function code passed to KM; see CPACF_KIMD_xxx defines
* @param: address of parameter block; see POP for details on each func
* @src: address of source memory area
* @src_len: length of src operand in bytes
*/
static inline void cpacf_kimd(unsigned long func, void *param,
const u8 *src, long src_len)
{
union register_pair s;
s.even = (unsigned long)src;
s.odd = (unsigned long)src_len;
asm volatile(
" lgr 0,%[fc]\n"
" lgr 1,%[pba]\n"
"0: .insn rrf,%[opc] << 16,0,%[src],8,0\n"
" brc 1,0b" /* handle partial completion */
: [src] "+&d" (s.pair)
: [fc] "d" (func), [pba] "d" ((unsigned long)(param)),
[opc] "i" (CPACF_KIMD)
: "cc", "memory", "0", "1");
}
/**
* cpacf_klmd() - executes the KLMD (COMPUTE LAST MESSAGE DIGEST) instruction
* @func: the function code passed to KM; see CPACF_KLMD_xxx defines
* @param: address of parameter block; see POP for details on each func
* @src: address of source memory area
* @src_len: length of src operand in bytes
*/
static inline void cpacf_klmd(unsigned long func, void *param,
const u8 *src, long src_len)
{
union register_pair s;
s.even = (unsigned long)src;
s.odd = (unsigned long)src_len;
asm volatile(
" lgr 0,%[fc]\n"
" lgr 1,%[pba]\n"
"0: .insn rrf,%[opc] << 16,0,%[src],8,0\n"
" brc 1,0b" /* handle partial completion */
: [src] "+&d" (s.pair)
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
[opc] "i" (CPACF_KLMD)
: "cc", "memory", "0", "1");
}
/**
* _cpacf_kmac() - executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
* instruction and updates flags in gr0
* @gr0: pointer to gr0 (fc and flags) passed to KMAC; see CPACF_KMAC_xxx defines
* @param: address of parameter block; see POP for details on each func
* @src: address of source memory area
* @src_len: length of src operand in bytes
*
* Returns 0 for the query func, number of processed bytes for digest funcs
*/
static inline int _cpacf_kmac(unsigned long *gr0, void *param,
const u8 *src, long src_len)
{
union register_pair s;
s.even = (unsigned long)src;
s.odd = (unsigned long)src_len;
asm volatile(
" lgr 0,%[r0]\n"
" lgr 1,%[pba]\n"
"0: .insn rre,%[opc] << 16,0,%[src]\n"
" brc 1,0b\n" /* handle partial completion */
" lgr %[r0],0"
: [r0] "+d" (*gr0), [src] "+&d" (s.pair)
: [pba] "d" ((unsigned long)param),
[opc] "i" (CPACF_KMAC)
: "cc", "memory", "0", "1");
return src_len - s.odd;
}
/**
* cpacf_kmac() - executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
* instruction
* @func: function code passed to KMAC; see CPACF_KMAC_xxx defines
* @param: address of parameter block; see POP for details on each func
* @src: address of source memory area
* @src_len: length of src operand in bytes
*
* Returns 0 for the query func, number of processed bytes for digest funcs
*/
static inline int cpacf_kmac(unsigned long func, void *param,
const u8 *src, long src_len)
{
return _cpacf_kmac(&func, param, src, src_len);
}
/**
* cpacf_kmctr() - executes the KMCTR (CIPHER MESSAGE WITH COUNTER) instruction
* @func: the function code passed to KMCTR; see CPACF_KMCTR_xxx defines
* @param: address of parameter block; see POP for details on each func
* @dest: address of destination memory area
* @src: address of source memory area
* @src_len: length of src operand in bytes
* @counter: address of counter value
*
* Returns 0 for the query func, number of processed bytes for
* encryption/decryption funcs
*/
static inline int cpacf_kmctr(unsigned long func, void *param, u8 *dest,
const u8 *src, long src_len, u8 *counter)
{
union register_pair d, s, c;
d.even = (unsigned long)dest;
s.even = (unsigned long)src;
s.odd = (unsigned long)src_len;
c.even = (unsigned long)counter;
asm volatile(
" lgr 0,%[fc]\n"
" lgr 1,%[pba]\n"
"0: .insn rrf,%[opc] << 16,%[dst],%[src],%[ctr],0\n"
" brc 1,0b" /* handle partial completion */
: [src] "+&d" (s.pair), [dst] "+&d" (d.pair),
[ctr] "+&d" (c.pair)
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
[opc] "i" (CPACF_KMCTR)
: "cc", "memory", "0", "1");
return src_len - s.odd;
}
/**
* cpacf_prno() - executes the PRNO (PERFORM RANDOM NUMBER OPERATION)
* instruction
* @func: the function code passed to PRNO; see CPACF_PRNO_xxx defines
* @param: address of parameter block; see POP for details on each func
* @dest: address of destination memory area
* @dest_len: size of destination memory area in bytes
* @seed: address of seed data
* @seed_len: size of seed data in bytes
*/
static inline void cpacf_prno(unsigned long func, void *param,
u8 *dest, unsigned long dest_len,
const u8 *seed, unsigned long seed_len)
{
union register_pair d, s;
d.even = (unsigned long)dest;
d.odd = (unsigned long)dest_len;
s.even = (unsigned long)seed;
s.odd = (unsigned long)seed_len;
asm volatile (
" lgr 0,%[fc]\n"
" lgr 1,%[pba]\n"
"0: .insn rre,%[opc] << 16,%[dst],%[seed]\n"
" brc 1,0b" /* handle partial completion */
: [dst] "+&d" (d.pair)
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
[seed] "d" (s.pair), [opc] "i" (CPACF_PRNO)
: "cc", "memory", "0", "1");
}
/**
* cpacf_trng() - executes the TRNG subfunction of the PRNO instruction
* @ucbuf: buffer for unconditioned data
* @ucbuf_len: amount of unconditioned data to fetch in bytes
* @cbuf: buffer for conditioned data
* @cbuf_len: amount of conditioned data to fetch in bytes
*/
static inline void cpacf_trng(u8 *ucbuf, unsigned long ucbuf_len,
u8 *cbuf, unsigned long cbuf_len)
{
union register_pair u, c;
u.even = (unsigned long)ucbuf;
u.odd = (unsigned long)ucbuf_len;
c.even = (unsigned long)cbuf;
c.odd = (unsigned long)cbuf_len;
asm volatile (
" lghi 0,%[fc]\n"
"0: .insn rre,%[opc] << 16,%[ucbuf],%[cbuf]\n"
" brc 1,0b" /* handle partial completion */
: [ucbuf] "+&d" (u.pair), [cbuf] "+&d" (c.pair)
: [fc] "K" (CPACF_PRNO_TRNG), [opc] "i" (CPACF_PRNO)
: "cc", "memory", "0");
kmsan_unpoison_memory(ucbuf, ucbuf_len);
kmsan_unpoison_memory(cbuf, cbuf_len);
}
/**
* cpacf_pcc() - executes the PCC (PERFORM CRYPTOGRAPHIC COMPUTATION)
* instruction
* @func: the function code passed to PCC; see CPACF_KM_xxx defines
* @param: address of parameter block; see POP for details on each func
*
* Returns the condition code, this is
* 0 - cc code 0 (normal completion)
* 1 - cc code 1 (protected key wkvp mismatch or src operand out of range)
* 2 - cc code 2 (something invalid, scalar multiply infinity, ...)
* Condition code 3 (partial completion) is handled within the asm code
* and never returned.
*/
static inline int cpacf_pcc(unsigned long func, void *param)
{
int cc;
asm volatile(
" lgr 0,%[fc]\n"
" lgr 1,%[pba]\n"
"0: .insn rre,%[opc] << 16,0,0\n" /* PCC opcode */
" brc 1,0b\n" /* handle partial completion */
CC_IPM(cc)
: CC_OUT(cc, cc)
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
[opc] "i" (CPACF_PCC)
: CC_CLOBBER_LIST("memory", "0", "1"));
return CC_TRANSFORM(cc);
}
/**
* cpacf_pckmo() - executes the PCKMO (PERFORM CRYPTOGRAPHIC KEY
* MANAGEMENT) instruction
* @func: the function code passed to PCKMO; see CPACF_PCKMO_xxx defines
* @param: address of parameter block; see POP for details on each func
*
* Returns 0.
*/
static inline void cpacf_pckmo(long func, void *param)
{
asm volatile(
" lgr 0,%[fc]\n"
" lgr 1,%[pba]\n"
" .insn rre,%[opc] << 16,0,0" /* PCKMO opcode */
:
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
[opc] "i" (CPACF_PCKMO)
: "cc", "memory", "0", "1");
}
/**
* cpacf_kma() - executes the KMA (CIPHER MESSAGE WITH AUTHENTICATION)
* instruction
* @func: the function code passed to KMA; see CPACF_KMA_xxx defines
* @param: address of parameter block; see POP for details on each func
* @dest: address of destination memory area
* @src: address of source memory area
* @src_len: length of src operand in bytes
* @aad: address of additional authenticated data memory area
* @aad_len: length of aad operand in bytes
*/
static inline void cpacf_kma(unsigned long func, void *param, u8 *dest,
const u8 *src, unsigned long src_len,
const u8 *aad, unsigned long aad_len)
{
union register_pair d, s, a;
d.even = (unsigned long)dest;
s.even = (unsigned long)src;
s.odd = (unsigned long)src_len;
a.even = (unsigned long)aad;
a.odd = (unsigned long)aad_len;
asm volatile(
" lgr 0,%[fc]\n"
" lgr 1,%[pba]\n"
"0: .insn rrf,%[opc] << 16,%[dst],%[src],%[aad],0\n"
" brc 1,0b" /* handle partial completion */
: [dst] "+&d" (d.pair), [src] "+&d" (s.pair),
[aad] "+&d" (a.pair)
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
[opc] "i" (CPACF_KMA)
: "cc", "memory", "0", "1");
}
#endif /* _ASM_S390_CPACF_H */
+32
View File
@@ -0,0 +1,32 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* S390 version
* Copyright IBM Corp. 1999
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
* Christian Borntraeger (cborntra@de.ibm.com),
*/
#ifndef _ASM_S390_CPCMD_H
#define _ASM_S390_CPCMD_H
/*
* the lowlevel function for cpcmd
*/
int __cpcmd(const char *cmd, char *response, int rlen, int *response_code);
/*
* cpcmd is the in-kernel interface for issuing CP commands
*
* cmd: null-terminated command string, max 240 characters
* response: response buffer for VM's textual response
* rlen: size of the response buffer, cpcmd will not exceed this size
* but will cap the output, if its too large. Everything that
* did not fit into the buffer will be silently dropped
* response_code: return pointer for VM's error code
* return value: the size of the response. The caller can check if the buffer
* was large enough by comparing the return value and rlen
* NOTE: If the response buffer is not in real storage, cpcmd can sleep
*/
int cpcmd(const char *cmd, char *response, int rlen, int *response_code);
#endif /* _ASM_S390_CPCMD_H */
+28
View File
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 2000, 2009
* Author(s): Hartmut Penner <hp@de.ibm.com>,
* Martin Schwidefsky <schwidefsky@de.ibm.com>,
* Christian Ehrhardt <ehrhardt@de.ibm.com>,
*/
#ifndef _ASM_S390_CPU_H
#define _ASM_S390_CPU_H
#ifndef __ASSEMBLER__
#include <linux/types.h>
#include <linux/jump_label.h>
struct cpuid
{
unsigned int version : 8;
unsigned int ident : 24;
unsigned int machine : 16;
unsigned int unused : 16;
} __attribute__ ((packed, aligned(8)));
DECLARE_STATIC_KEY_FALSE(cpu_has_bear);
#endif /* __ASSEMBLER__ */
#endif /* _ASM_S390_CPU_H */
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Support for CPU-MF instructions
*
* Copyright IBM Corp. 2019
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
*/
#ifndef _ASM_S390_CPU_MF_INSN_H
#define _ASM_S390_CPU_MF_INSN_H
#ifdef __ASSEMBLER__
/* Macro to generate the STCCTM instruction with a customized
* M3 field designating the counter set.
*/
.macro STCCTM r1 m3 db2
.insn rsy,0xeb0000000017,\r1,\m3 & 0xf,\db2
.endm
#endif /* __ASSEMBLER__ */
#endif
+286
View File
@@ -0,0 +1,286 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* CPU-measurement facilities
*
* Copyright IBM Corp. 2012, 2018
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
* Jan Glauber <jang@linux.vnet.ibm.com>
*/
#ifndef _ASM_S390_CPU_MF_H
#define _ASM_S390_CPU_MF_H
#include <linux/errno.h>
#include <linux/kmsan-checks.h>
#include <asm/asm-extable.h>
#include <asm/facility.h>
#include <asm/asm.h>
asm(".include \"asm/cpu_mf-insn.h\"\n");
#define CPU_MF_INT_SF_IAE (1 << 31) /* invalid entry address */
#define CPU_MF_INT_SF_ISE (1 << 30) /* incorrect SDBT entry */
#define CPU_MF_INT_SF_PRA (1 << 29) /* program request alert */
#define CPU_MF_INT_SF_SACA (1 << 23) /* sampler auth. change alert */
#define CPU_MF_INT_SF_LSDA (1 << 22) /* loss of sample data alert */
#define CPU_MF_INT_CF_MTDA (1 << 15) /* loss of MT ctr. data alert */
#define CPU_MF_INT_CF_CACA (1 << 7) /* counter auth. change alert */
#define CPU_MF_INT_CF_LCDA (1 << 6) /* loss of counter data alert */
#define CPU_MF_INT_CF_MASK (CPU_MF_INT_CF_MTDA|CPU_MF_INT_CF_CACA| \
CPU_MF_INT_CF_LCDA)
#define CPU_MF_INT_SF_MASK (CPU_MF_INT_SF_IAE|CPU_MF_INT_SF_ISE| \
CPU_MF_INT_SF_PRA|CPU_MF_INT_SF_SACA| \
CPU_MF_INT_SF_LSDA)
#define CPU_MF_SF_RIBM_NOTAV 0x1 /* Sampling unavailable */
/* CPU measurement facility support */
static inline int cpum_cf_avail(void)
{
return test_facility(40) && test_facility(67);
}
static inline int cpum_sf_avail(void)
{
return test_facility(40) && test_facility(68);
}
struct cpumf_ctr_info {
u16 cfvn;
u16 auth_ctl;
u16 enable_ctl;
u16 act_ctl;
u16 max_cpu;
u16 csvn;
u16 max_cg;
u16 reserved1;
u32 reserved2[12];
} __packed;
/* QUERY SAMPLING INFORMATION block */
struct hws_qsi_info_block { /* Bit(s) */
unsigned int b0_13:14; /* 0-13: zeros */
unsigned int as:1; /* 14: basic-sampling authorization */
unsigned int ad:1; /* 15: diag-sampling authorization */
unsigned int b16_21:6; /* 16-21: zeros */
unsigned int es:1; /* 22: basic-sampling enable control */
unsigned int ed:1; /* 23: diag-sampling enable control */
unsigned int b24_29:6; /* 24-29: zeros */
unsigned int cs:1; /* 30: basic-sampling activation control */
unsigned int cd:1; /* 31: diag-sampling activation control */
unsigned int bsdes:16; /* 4-5: size of basic sampling entry */
unsigned int dsdes:16; /* 6-7: size of diagnostic sampling entry */
unsigned long min_sampl_rate; /* 8-15: minimum sampling interval */
unsigned long max_sampl_rate; /* 16-23: maximum sampling interval*/
unsigned long tear; /* 24-31: TEAR contents */
unsigned long dear; /* 32-39: DEAR contents */
unsigned int rsvrd0:24; /* 40-42: reserved */
unsigned int ribm:8; /* 43: Reserved by IBM */
unsigned int cpu_speed; /* 44-47: CPU speed */
unsigned long long rsvrd1; /* 48-55: reserved */
unsigned long long rsvrd2; /* 56-63: reserved */
} __packed;
/* SET SAMPLING CONTROLS request block */
struct hws_lsctl_request_block {
unsigned int s:1; /* 0: maximum buffer indicator */
unsigned int h:1; /* 1: part. level reserved for VM use*/
unsigned long long b2_53:52;/* 2-53: zeros */
unsigned int es:1; /* 54: basic-sampling enable control */
unsigned int ed:1; /* 55: diag-sampling enable control */
unsigned int b56_61:6; /* 56-61: - zeros */
unsigned int cs:1; /* 62: basic-sampling activation control */
unsigned int cd:1; /* 63: diag-sampling activation control */
unsigned long interval; /* 8-15: sampling interval */
unsigned long tear; /* 16-23: TEAR contents */
unsigned long dear; /* 24-31: DEAR contents */
/* 32-63: */
unsigned long rsvrd1; /* reserved */
unsigned long rsvrd2; /* reserved */
unsigned long rsvrd3; /* reserved */
unsigned long rsvrd4; /* reserved */
} __packed;
struct hws_basic_entry {
unsigned int def:16; /* 0-15 Data Entry Format */
unsigned int R:4; /* 16-19 reserved */
unsigned int U:4; /* 20-23 Number of unique instruct. */
unsigned int z:2; /* zeros */
unsigned int T:1; /* 26 PSW DAT mode */
unsigned int W:1; /* 27 PSW wait state */
unsigned int P:1; /* 28 PSW Problem state */
unsigned int AS:2; /* 29-30 PSW address-space control */
unsigned int I:1; /* 31 entry valid or invalid */
unsigned int CL:2; /* 32-33 Configuration Level */
unsigned int H:1; /* 34 Host Indicator */
unsigned int LS:1; /* 35 Limited Sampling */
unsigned int:12;
unsigned int prim_asn:16; /* primary ASN */
unsigned long long ia; /* Instruction Address */
unsigned long long gpp; /* Guest Program Parameter */
unsigned long long hpp; /* Host Program Parameter */
} __packed;
struct hws_diag_entry {
unsigned int def:16; /* 0-15 Data Entry Format */
unsigned int R:15; /* 16-19 and 20-30 reserved */
unsigned int I:1; /* 31 entry valid or invalid */
u8 data[]; /* Machine-dependent sample data */
} __packed;
struct hws_combined_entry {
struct hws_basic_entry basic; /* Basic-sampling data entry */
struct hws_diag_entry diag; /* Diagnostic-sampling data entry */
} __packed;
union hws_trailer_header {
struct {
unsigned int f:1; /* 0 - Block Full Indicator */
unsigned int a:1; /* 1 - Alert request control */
unsigned int t:1; /* 2 - Timestamp format */
unsigned int :29; /* 3 - 31: Reserved */
unsigned int bsdes:16; /* 32-47: size of basic SDE */
unsigned int dsdes:16; /* 48-63: size of diagnostic SDE */
unsigned long long overflow; /* 64 - Overflow Count */
};
u128 val;
};
struct hws_trailer_entry {
union hws_trailer_header header; /* 0 - 15 Flags + Overflow Count */
unsigned char timestamp[16]; /* 16 - 31 timestamp */
unsigned long long reserved1; /* 32 -Reserved */
unsigned long long reserved2; /* */
union { /* 48 - reserved for programming use */
struct {
unsigned int clock_base:1; /* in progusage2 */
unsigned long long progusage1:63;
unsigned long long progusage2;
};
unsigned long long progusage[2];
};
} __packed;
/* Load program parameter */
static inline void lpp(void *pp)
{
asm volatile("lpp 0(%0)\n" :: "a" (pp) : "memory");
}
/* Query counter information */
static inline int qctri(struct cpumf_ctr_info *info)
{
int rc = -EINVAL;
asm_inline volatile (
"0: qctri %1\n"
"1: lhi %0,0\n"
"2:\n"
EX_TABLE(1b, 2b)
: "+d" (rc), "=Q" (*info));
return rc;
}
/* Load CPU-counter-set controls */
static inline int lcctl(u64 ctl)
{
int cc;
asm_inline volatile (
" lcctl %[ctl]\n"
CC_IPM(cc)
: CC_OUT(cc, cc)
: [ctl] "Q" (ctl)
: CC_CLOBBER);
return CC_TRANSFORM(cc);
}
/* Extract CPU counter */
static inline int __ecctr(u64 ctr, u64 *content)
{
u64 _content;
int cc;
asm_inline volatile (
" ecctr %[_content],%[ctr]\n"
CC_IPM(cc)
: CC_OUT(cc, cc), [_content] "=d" (_content)
: [ctr] "d" (ctr)
: CC_CLOBBER);
*content = _content;
return CC_TRANSFORM(cc);
}
/* Extract CPU counter */
static inline int ecctr(u64 ctr, u64 *val)
{
u64 content;
int cc;
cc = __ecctr(ctr, &content);
if (!cc)
*val = content;
return cc;
}
/* Store CPU counter multiple for a particular counter set */
enum stcctm_ctr_set {
EXTENDED = 0,
BASIC = 1,
PROBLEM_STATE = 2,
CRYPTO_ACTIVITY = 3,
MT_DIAG = 5,
MT_DIAG_CLEARING = 9, /* clears loss-of-MT-ctr-data alert */
};
static __always_inline int stcctm(enum stcctm_ctr_set set, u64 range, u64 *dest)
{
int cc;
asm volatile (
" STCCTM %[range],%[set],%[dest]\n"
CC_IPM(cc)
: CC_OUT(cc, cc)
: [dest] "Q" (*dest), [range] "d" (range), [set] "i" (set)
: CC_CLOBBER_LIST("memory"));
/*
* If cc == 2, less than RANGE counters are stored, but it's not easy
* to tell how many. Always unpoison the whole range for simplicity.
*/
kmsan_unpoison_memory(dest, range * sizeof(u64));
return CC_TRANSFORM(cc);
}
/* Query sampling information */
static inline int qsi(struct hws_qsi_info_block *info)
{
int cc = 1;
asm volatile(
"0: qsi %1\n"
"1: lhi %0,0\n"
"2:\n"
EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "+d" (cc), "+Q" (*info));
return cc ? -EINVAL : 0;
}
/* Load sampling controls */
static inline int lsctl(struct hws_lsctl_request_block *req)
{
int cc, exception;
exception = 1;
asm volatile(
"0: lsctl %[req]\n"
"1: lhi %[exc],0\n"
"2:\n"
CC_IPM(cc)
EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: CC_OUT(cc, cc), [exc] "+d" (exception)
: [req] "Q" (*req)
: CC_CLOBBER);
if (exception || CC_TRANSFORM(cc))
return -EINVAL;
return 0;
}
#endif /* _ASM_S390_CPU_MF_H */
@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Module interface for CPU features
*
* Copyright IBM Corp. 2015, 2022
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
*/
#ifndef __ASM_S390_CPUFEATURE_H
#define __ASM_S390_CPUFEATURE_H
#include <asm/facility.h>
enum {
S390_CPU_FEATURE_MSA,
S390_CPU_FEATURE_VXRS,
S390_CPU_FEATURE_UV,
S390_CPU_FEATURE_D288,
MAX_CPU_FEATURES
};
#define cpu_feature(feature) (feature)
int cpu_have_feature(unsigned int nr);
#define cpu_has_bear() test_facility(193)
#define cpu_has_edat1() test_facility(8)
#define cpu_has_edat2() test_facility(78)
#define cpu_has_gs() test_facility(133)
#define cpu_has_nx() test_facility(130)
#define cpu_has_rdp() test_facility(194)
#define cpu_has_seq_insn() test_facility(85)
#define cpu_has_tlb_lc() test_facility(51)
#define cpu_has_topology() test_facility(11)
#define cpu_has_vx() test_facility(129)
#endif /* __ASM_S390_CPUFEATURE_H */
@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 2004
*
* Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
#ifndef _S390_CPUTIME_H
#define _S390_CPUTIME_H
#include <linux/types.h>
#include <asm/timex.h>
/*
* Convert cputime to nanoseconds.
*/
#define cputime_to_nsecs(cputime) tod_to_ns(cputime)
void account_idle_time_irq(void);
#endif /* _S390_CPUTIME_H */
+55
View File
@@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Data definitions for channel report processing
* Copyright IBM Corp. 2000, 2009
* Author(s): Ingo Adlung <adlung@de.ibm.com>,
* Martin Schwidefsky <schwidefsky@de.ibm.com>,
* Cornelia Huck <cornelia.huck@de.ibm.com>,
*/
#ifndef _ASM_S390_CRW_H
#define _ASM_S390_CRW_H
#include <linux/types.h>
/*
* Channel Report Word
*/
struct crw {
__u32 res1 : 1; /* reserved zero */
__u32 slct : 1; /* solicited */
__u32 oflw : 1; /* overflow */
__u32 chn : 1; /* chained */
__u32 rsc : 4; /* reporting source code */
__u32 anc : 1; /* ancillary report */
__u32 res2 : 1; /* reserved zero */
__u32 erc : 6; /* error-recovery code */
__u32 rsid : 16; /* reporting-source ID */
} __attribute__ ((packed));
typedef void (*crw_handler_t)(struct crw *, struct crw *, int);
extern int crw_register_handler(int rsc, crw_handler_t handler);
extern void crw_unregister_handler(int rsc);
extern void crw_handle_channel_report(void);
void crw_wait_for_channel_report(void);
#define NR_RSCS 16
#define CRW_RSC_MONITOR 0x2 /* monitoring facility */
#define CRW_RSC_SCH 0x3 /* subchannel */
#define CRW_RSC_CPATH 0x4 /* channel path */
#define CRW_RSC_CONFIG 0x9 /* configuration-alert facility */
#define CRW_RSC_CSS 0xB /* channel subsystem */
#define CRW_ERC_EVENT 0x00 /* event information pending */
#define CRW_ERC_AVAIL 0x01 /* available */
#define CRW_ERC_INIT 0x02 /* initialized */
#define CRW_ERC_TERROR 0x03 /* temporary error */
#define CRW_ERC_IPARM 0x04 /* installed parm initialized */
#define CRW_ERC_TERM 0x05 /* terminal */
#define CRW_ERC_PERRN 0x06 /* perm. error, fac. not init */
#define CRW_ERC_PERRI 0x07 /* perm. error, facility init */
#define CRW_ERC_PMOD 0x08 /* installed parameters modified */
#endif /* _ASM_S390_CRW_H */
@@ -0,0 +1,47 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_CSS_CHARS_H
#define _ASM_CSS_CHARS_H
#include <linux/types.h>
struct css_general_char {
u64 : 12;
u64 dynio : 1; /* bit 12 */
u64 : 4;
u64 eadm : 1; /* bit 17 */
u64 : 23;
u64 aif : 1; /* bit 41 */
u64 : 3;
u64 mcss : 1; /* bit 45 */
u64 fcs : 1; /* bit 46 */
u64 : 1;
u64 ext_mb : 1; /* bit 48 */
u64 : 7;
u64 aif_tdd : 1; /* bit 56 */
u64 : 1;
u64 qebsm : 1; /* bit 58 */
u64 : 2;
u64 aiv : 1; /* bit 61 */
u64 : 2;
u64 : 3;
u64 aif_qdio : 1;/* bit 67 */
u64 : 12;
u64 eadm_rf : 1; /* bit 80 */
u64 : 1;
u64 cib : 1; /* bit 82 */
u64 : 5;
u64 fcx : 1; /* bit 88 */
u64 : 19;
u64 alt_ssi : 1; /* bit 108 */
u64 : 1;
u64 narf : 1; /* bit 110 */
u64 : 5;
u64 enarf: 1; /* bit 116 */
u64 : 6;
u64 util_str : 1;/* bit 123 */
} __packed;
extern struct css_general_char css_general_characteristics;
#endif
+256
View File
@@ -0,0 +1,256 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 1999, 2009
*
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
#ifndef __ASM_S390_CTLREG_H
#define __ASM_S390_CTLREG_H
#include <linux/bits.h>
#define CR0_TRANSACTIONAL_EXECUTION_BIT (63 - 8)
#define CR0_CLOCK_COMPARATOR_SIGN_BIT (63 - 10)
#define CR0_CRYPTOGRAPHY_COUNTER_BIT (63 - 13)
#define CR0_PAI_EXTENSION_BIT (63 - 14)
#define CR0_CPUMF_EXTRACTION_AUTH_BIT (63 - 15)
#define CR0_WARNING_TRACK_BIT (63 - 30)
#define CR0_LOW_ADDRESS_PROTECTION_BIT (63 - 35)
#define CR0_FETCH_PROTECTION_OVERRIDE_BIT (63 - 38)
#define CR0_STORAGE_PROTECTION_OVERRIDE_BIT (63 - 39)
#define CR0_EDAT_BIT (63 - 40)
#define CR0_INSTRUCTION_EXEC_PROTECTION_BIT (63 - 43)
#define CR0_VECTOR_BIT (63 - 46)
#define CR0_MALFUNCTION_ALERT_SUBMASK_BIT (63 - 48)
#define CR0_EMERGENCY_SIGNAL_SUBMASK_BIT (63 - 49)
#define CR0_EXTERNAL_CALL_SUBMASK_BIT (63 - 50)
#define CR0_CLOCK_COMPARATOR_SUBMASK_BIT (63 - 52)
#define CR0_CPU_TIMER_SUBMASK_BIT (63 - 53)
#define CR0_SERVICE_SIGNAL_SUBMASK_BIT (63 - 54)
#define CR0_UNUSED_56_BIT (63 - 56)
#define CR0_INTERRUPT_KEY_SUBMASK_BIT (63 - 57)
#define CR0_MEASUREMENT_ALERT_SUBMASK_BIT (63 - 58)
#define CR0_ETR_SUBMASK_BIT (63 - 59)
#define CR0_IUCV_BIT (63 - 62)
#define CR0_TRANSACTIONAL_EXECUTION BIT(CR0_TRANSACTIONAL_EXECUTION_BIT)
#define CR0_CLOCK_COMPARATOR_SIGN BIT(CR0_CLOCK_COMPARATOR_SIGN_BIT)
#define CR0_CRYPTOGRAPHY_COUNTER BIT(CR0_CRYPTOGRAPHY_COUNTER_BIT)
#define CR0_PAI_EXTENSION BIT(CR0_PAI_EXTENSION_BIT)
#define CR0_CPUMF_EXTRACTION_AUTH BIT(CR0_CPUMF_EXTRACTION_AUTH_BIT)
#define CR0_WARNING_TRACK BIT(CR0_WARNING_TRACK_BIT)
#define CR0_LOW_ADDRESS_PROTECTION BIT(CR0_LOW_ADDRESS_PROTECTION_BIT)
#define CR0_FETCH_PROTECTION_OVERRIDE BIT(CR0_FETCH_PROTECTION_OVERRIDE_BIT)
#define CR0_STORAGE_PROTECTION_OVERRIDE BIT(CR0_STORAGE_PROTECTION_OVERRIDE_BIT)
#define CR0_EDAT BIT(CR0_EDAT_BIT)
#define CR0_INSTRUCTION_EXEC_PROTECTION BIT(CR0_INSTRUCTION_EXEC_PROTECTION_BIT)
#define CR0_VECTOR BIT(CR0_VECTOR_BIT)
#define CR0_MALFUNCTION_ALERT_SUBMASK BIT(CR0_MALFUNCTION_ALERT_SUBMASK_BIT)
#define CR0_EMERGENCY_SIGNAL_SUBMASK BIT(CR0_EMERGENCY_SIGNAL_SUBMASK_BIT)
#define CR0_EXTERNAL_CALL_SUBMASK BIT(CR0_EXTERNAL_CALL_SUBMASK_BIT)
#define CR0_CLOCK_COMPARATOR_SUBMASK BIT(CR0_CLOCK_COMPARATOR_SUBMASK_BIT)
#define CR0_CPU_TIMER_SUBMASK BIT(CR0_CPU_TIMER_SUBMASK_BIT)
#define CR0_SERVICE_SIGNAL_SUBMASK BIT(CR0_SERVICE_SIGNAL_SUBMASK_BIT)
#define CR0_UNUSED_56 BIT(CR0_UNUSED_56_BIT)
#define CR0_INTERRUPT_KEY_SUBMASK BIT(CR0_INTERRUPT_KEY_SUBMASK_BIT)
#define CR0_MEASUREMENT_ALERT_SUBMASK BIT(CR0_MEASUREMENT_ALERT_SUBMASK_BIT)
#define CR0_ETR_SUBMASK BIT(CR0_ETR_SUBMASK_BIT)
#define CR0_IUCV BIT(CR0_IUCV_BIT)
#define CR2_MIO_ADDRESSING_BIT (63 - 58)
#define CR2_GUARDED_STORAGE_BIT (63 - 59)
#define CR2_MIO_ADDRESSING BIT(CR2_MIO_ADDRESSING_BIT)
#define CR2_GUARDED_STORAGE BIT(CR2_GUARDED_STORAGE_BIT)
#define CR14_UNUSED_32_BIT (63 - 32)
#define CR14_UNUSED_33_BIT (63 - 33)
#define CR14_CHANNEL_REPORT_SUBMASK_BIT (63 - 35)
#define CR14_RECOVERY_SUBMASK_BIT (63 - 36)
#define CR14_DEGRADATION_SUBMASK_BIT (63 - 37)
#define CR14_EXTERNAL_DAMAGE_SUBMASK_BIT (63 - 38)
#define CR14_WARNING_SUBMASK_BIT (63 - 39)
#define CR14_UNUSED_32 BIT(CR14_UNUSED_32_BIT)
#define CR14_UNUSED_33 BIT(CR14_UNUSED_33_BIT)
#define CR14_CHANNEL_REPORT_SUBMASK BIT(CR14_CHANNEL_REPORT_SUBMASK_BIT)
#define CR14_RECOVERY_SUBMASK BIT(CR14_RECOVERY_SUBMASK_BIT)
#define CR14_DEGRADATION_SUBMASK BIT(CR14_DEGRADATION_SUBMASK_BIT)
#define CR14_EXTERNAL_DAMAGE_SUBMASK BIT(CR14_EXTERNAL_DAMAGE_SUBMASK_BIT)
#define CR14_WARNING_SUBMASK BIT(CR14_WARNING_SUBMASK_BIT)
#ifndef __ASSEMBLER__
#include <linux/bug.h>
struct ctlreg {
unsigned long val;
};
#define __local_ctl_load(low, high, array) do { \
struct addrtype { \
char _[sizeof(array)]; \
}; \
int _high = high; \
int _low = low; \
int _esize; \
\
_esize = (_high - _low + 1) * sizeof(struct ctlreg); \
BUILD_BUG_ON(sizeof(struct addrtype) != _esize); \
typecheck(struct ctlreg, array[0]); \
asm volatile( \
" lctlg %[_low],%[_high],%[_arr]" \
: \
: [_arr] "Q" (*(struct addrtype *)(&array)), \
[_low] "i" (low), [_high] "i" (high) \
: "memory"); \
} while (0)
#define __local_ctl_store(low, high, array) do { \
struct addrtype { \
char _[sizeof(array)]; \
}; \
int _high = high; \
int _low = low; \
int _esize; \
\
_esize = (_high - _low + 1) * sizeof(struct ctlreg); \
BUILD_BUG_ON(sizeof(struct addrtype) != _esize); \
typecheck(struct ctlreg, array[0]); \
asm volatile( \
" stctg %[_low],%[_high],%[_arr]" \
: [_arr] "=Q" (*(struct addrtype *)(&array)) \
: [_low] "i" (low), [_high] "i" (high)); \
} while (0)
static __always_inline void local_ctl_load(unsigned int cr, struct ctlreg *reg)
{
asm volatile(
" lctlg %[cr],%[cr],%[reg]"
:
: [reg] "Q" (*reg), [cr] "i" (cr)
: "memory");
}
static __always_inline void local_ctl_store(unsigned int cr, struct ctlreg *reg)
{
asm volatile(
" stctg %[cr],%[cr],%[reg]"
: [reg] "=Q" (*reg)
: [cr] "i" (cr));
}
static __always_inline struct ctlreg local_ctl_set_bit(unsigned int cr, unsigned int bit)
{
struct ctlreg new, old;
local_ctl_store(cr, &old);
new = old;
new.val |= 1UL << bit;
local_ctl_load(cr, &new);
return old;
}
static __always_inline struct ctlreg local_ctl_clear_bit(unsigned int cr, unsigned int bit)
{
struct ctlreg new, old;
local_ctl_store(cr, &old);
new = old;
new.val &= ~(1UL << bit);
local_ctl_load(cr, &new);
return old;
}
struct lowcore;
void system_ctlreg_lock(void);
void system_ctlreg_unlock(void);
void system_ctlreg_init_save_area(struct lowcore *lc);
void system_ctlreg_modify(unsigned int cr, unsigned long data, int request);
enum {
CTLREG_SET_BIT,
CTLREG_CLEAR_BIT,
CTLREG_LOAD,
};
static inline void system_ctl_set_bit(unsigned int cr, unsigned int bit)
{
system_ctlreg_modify(cr, bit, CTLREG_SET_BIT);
}
static inline void system_ctl_clear_bit(unsigned int cr, unsigned int bit)
{
system_ctlreg_modify(cr, bit, CTLREG_CLEAR_BIT);
}
static inline void system_ctl_load(unsigned int cr, struct ctlreg *reg)
{
system_ctlreg_modify(cr, reg->val, CTLREG_LOAD);
}
union ctlreg0 {
unsigned long val;
struct ctlreg reg;
struct {
unsigned long : 8;
unsigned long tcx : 1; /* Transactional-Execution control */
unsigned long pifo : 1; /* Transactional-Execution Program-
Interruption-Filtering Override */
unsigned long : 3;
unsigned long ccc : 1; /* Cryptography counter control */
unsigned long pec : 1; /* PAI extension control */
unsigned long : 15;
unsigned long wti : 1; /* Warning-track */
unsigned long : 4;
unsigned long lap : 1; /* Low-address-protection control */
unsigned long : 4;
unsigned long edat : 1; /* Enhanced-DAT-enablement control */
unsigned long : 2;
unsigned long iep : 1; /* Instruction-Execution-Protection */
unsigned long : 1;
unsigned long afp : 1; /* AFP-register control */
unsigned long vx : 1; /* Vector enablement control */
unsigned long : 7;
unsigned long sssm : 1; /* Service signal subclass mask */
unsigned long : 9;
};
};
union ctlreg2 {
unsigned long val;
struct ctlreg reg;
struct {
unsigned long : 33;
unsigned long ducto : 25;
unsigned long : 1;
unsigned long gse : 1;
unsigned long : 1;
unsigned long tds : 1;
unsigned long tdc : 2;
};
};
union ctlreg5 {
unsigned long val;
struct ctlreg reg;
struct {
unsigned long : 33;
unsigned long pasteo: 25;
unsigned long : 6;
};
};
union ctlreg15 {
unsigned long val;
struct ctlreg reg;
struct {
unsigned long lsea : 61;
unsigned long : 3;
};
};
#endif /* __ASSEMBLER__ */
#endif /* __ASM_S390_CTLREG_H */
@@ -0,0 +1,35 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* S390 version
* Copyright IBM Corp. 1999
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
*
* Derived from "include/asm-i386/current.h"
*/
#ifndef _S390_CURRENT_H
#define _S390_CURRENT_H
#include <asm/lowcore.h>
#include <asm/machine.h>
struct task_struct;
static __always_inline struct task_struct *get_current(void)
{
unsigned long ptr, lc_current;
lc_current = offsetof(struct lowcore, current_task);
asm_inline(
ALTERNATIVE(" lg %[ptr],%[offzero](%%r0)\n",
" lg %[ptr],%[offalt](%%r0)\n",
ALT_FEATURE(MFEATURE_LOWCORE))
: [ptr] "=d" (ptr)
: [offzero] "i" (lc_current),
[offalt] "i" (lc_current + LOWCORE_ALT_ADDRESS));
return (struct task_struct *)ptr;
}
#define current get_current()
#endif /* !(_S390_CURRENT_H) */
@@ -0,0 +1,198 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* DAT table and related structures
*
* Copyright IBM Corp. 2024
*
*/
#ifndef _S390_DAT_BITS_H
#define _S390_DAT_BITS_H
/*
* vaddress union in order to easily decode a virtual address into its
* region first index, region second index etc. parts.
*/
union vaddress {
unsigned long addr;
struct {
unsigned long rfx : 11;
unsigned long rsx : 11;
unsigned long rtx : 11;
unsigned long sx : 11;
unsigned long px : 8;
unsigned long bx : 12;
};
struct {
unsigned long rfx01 : 2;
unsigned long : 9;
unsigned long rsx01 : 2;
unsigned long : 9;
unsigned long rtx01 : 2;
unsigned long : 9;
unsigned long sx01 : 2;
unsigned long : 29;
};
};
union asce {
unsigned long val;
struct {
unsigned long rsto: 52;/* Region- or Segment-Table Origin */
unsigned long : 2;
unsigned long g : 1; /* Subspace Group control */
unsigned long p : 1; /* Private Space control */
unsigned long s : 1; /* Storage-Alteration-Event control */
unsigned long x : 1; /* Space-Switch-Event control */
unsigned long r : 1; /* Real-Space control */
unsigned long : 1;
unsigned long dt : 2; /* Designation-Type control */
unsigned long tl : 2; /* Region- or Segment-Table Length */
};
};
enum {
ASCE_TYPE_SEGMENT = 0,
ASCE_TYPE_REGION3 = 1,
ASCE_TYPE_REGION2 = 2,
ASCE_TYPE_REGION1 = 3
};
union region1_table_entry {
unsigned long val;
struct {
unsigned long rto: 52;/* Region-Table Origin */
unsigned long : 2;
unsigned long p : 1; /* DAT-Protection Bit */
unsigned long : 1;
unsigned long tf : 2; /* Region-Second-Table Offset */
unsigned long i : 1; /* Region-Invalid Bit */
unsigned long : 1;
unsigned long tt : 2; /* Table-Type Bits */
unsigned long tl : 2; /* Region-Second-Table Length */
};
};
union region2_table_entry {
unsigned long val;
struct {
unsigned long rto: 52;/* Region-Table Origin */
unsigned long : 2;
unsigned long p : 1; /* DAT-Protection Bit */
unsigned long : 1;
unsigned long tf : 2; /* Region-Third-Table Offset */
unsigned long i : 1; /* Region-Invalid Bit */
unsigned long : 1;
unsigned long tt : 2; /* Table-Type Bits */
unsigned long tl : 2; /* Region-Third-Table Length */
};
};
struct region3_table_entry_fc0 {
unsigned long sto: 52;/* Segment-Table Origin */
unsigned long : 1;
unsigned long fc : 1; /* Format-Control */
unsigned long p : 1; /* DAT-Protection Bit */
unsigned long : 1;
unsigned long tf : 2; /* Segment-Table Offset */
unsigned long i : 1; /* Region-Invalid Bit */
unsigned long cr : 1; /* Common-Region Bit */
unsigned long tt : 2; /* Table-Type Bits */
unsigned long tl : 2; /* Segment-Table Length */
};
struct region3_table_entry_fc1 {
unsigned long rfaa: 33;/* Region-Frame Absolute Address */
unsigned long : 14;
unsigned long av : 1; /* ACCF-Validity Control */
unsigned long acc : 4; /* Access-Control Bits */
unsigned long f : 1; /* Fetch-Protection Bit */
unsigned long fc : 1; /* Format-Control */
unsigned long p : 1; /* DAT-Protection Bit */
unsigned long iep : 1; /* Instruction-Execution-Protection */
unsigned long : 2;
unsigned long i : 1; /* Region-Invalid Bit */
unsigned long cr : 1; /* Common-Region Bit */
unsigned long tt : 2; /* Table-Type Bits */
unsigned long : 2;
};
union region3_table_entry {
unsigned long val;
struct region3_table_entry_fc0 fc0;
struct region3_table_entry_fc1 fc1;
struct {
unsigned long : 53;
unsigned long fc: 1; /* Format-Control */
unsigned long p : 1; /* DAT-Protection Bit */
unsigned long : 3;
unsigned long i : 1; /* Region-Invalid Bit */
unsigned long cr: 1; /* Common-Region Bit */
unsigned long tt: 2; /* Table-Type Bits */
unsigned long : 2;
};
};
struct segment_table_entry_fc0 {
unsigned long pto: 53;/* Page-Table Origin */
unsigned long fc : 1; /* Format-Control */
unsigned long p : 1; /* DAT-Protection Bit */
unsigned long : 3;
unsigned long i : 1; /* Segment-Invalid Bit */
unsigned long cs : 1; /* Common-Segment Bit */
unsigned long tt : 2; /* Table-Type Bits */
unsigned long : 2;
};
struct segment_table_entry_fc1 {
unsigned long sfaa: 44;/* Segment-Frame Absolute Address */
unsigned long : 3;
unsigned long av : 1; /* ACCF-Validity Control */
unsigned long acc : 4; /* Access-Control Bits */
unsigned long f : 1; /* Fetch-Protection Bit */
unsigned long fc : 1; /* Format-Control */
unsigned long p : 1; /* DAT-Protection Bit */
unsigned long iep : 1; /* Instruction-Execution-Protection */
unsigned long : 2;
unsigned long i : 1; /* Segment-Invalid Bit */
unsigned long cs : 1; /* Common-Segment Bit */
unsigned long tt : 2; /* Table-Type Bits */
unsigned long : 2;
};
union segment_table_entry {
unsigned long val;
struct segment_table_entry_fc0 fc0;
struct segment_table_entry_fc1 fc1;
struct {
unsigned long : 53;
unsigned long fc: 1; /* Format-Control */
unsigned long p : 1; /* DAT-Protection Bit */
unsigned long : 3;
unsigned long i : 1; /* Segment-Invalid Bit */
unsigned long cs: 1; /* Common-Segment Bit */
unsigned long tt: 2; /* Table-Type Bits */
unsigned long : 2;
};
};
union page_table_entry {
unsigned long val;
struct {
unsigned long pfra: 52;/* Page-Frame Real Address */
unsigned long z : 1; /* Zero Bit */
unsigned long i : 1; /* Page-Invalid Bit */
unsigned long p : 1; /* DAT-Protection Bit */
unsigned long iep : 1; /* Instruction-Execution-Protection */
unsigned long : 8;
};
};
enum {
TABLE_TYPE_SEGMENT = 0,
TABLE_TYPE_REGION3 = 1,
TABLE_TYPE_REGION2 = 2,
TABLE_TYPE_REGION1 = 3
};
#endif /* _S390_DAT_BITS_H */
+500
View File
@@ -0,0 +1,500 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* S/390 debug facility
*
* Copyright IBM Corp. 1999, 2020
*/
#ifndef _ASM_S390_DEBUG_H
#define _ASM_S390_DEBUG_H
#include <linux/string.h>
#include <linux/spinlock.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/refcount.h>
#include <linux/fs.h>
#include <linux/init.h>
#define DEBUG_MAX_LEVEL 6 /* debug levels range from 0 to 6 */
#define DEBUG_OFF_LEVEL -1 /* level where debug is switched off */
#define DEBUG_FLUSH_ALL -1 /* parameter to flush all areas */
#define DEBUG_MAX_VIEWS 10 /* max number of views in proc fs */
#define DEBUG_MAX_NAME_LEN 64 /* max length for a debugfs file name */
#define DEBUG_DEFAULT_LEVEL 3 /* initial debug level */
#define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */
#define DEBUG_DATA(entry) (char *)(entry + 1) /* data is stored behind */
/* the entry information */
#define __DEBUG_FEATURE_VERSION 3 /* version of debug feature */
struct __debug_entry {
unsigned long clock : 60;
unsigned long exception : 1;
unsigned long level : 3;
void *caller;
unsigned short cpu;
} __packed;
typedef struct __debug_entry debug_entry_t;
struct debug_view;
typedef struct debug_info {
struct debug_info *next;
struct debug_info *prev;
refcount_t ref_count;
raw_spinlock_t lock;
int level;
int nr_areas;
int pages_per_area;
int buf_size;
int entry_size;
debug_entry_t ***areas;
int active_area;
int *active_pages;
int *active_entries;
struct dentry *debugfs_root_entry;
struct dentry *debugfs_entries[DEBUG_MAX_VIEWS];
struct debug_view *views[DEBUG_MAX_VIEWS];
char name[DEBUG_MAX_NAME_LEN];
umode_t mode;
} debug_info_t;
typedef int (debug_header_proc_t) (debug_info_t *id,
struct debug_view *view,
int area,
debug_entry_t *entry,
char *out_buf, size_t out_buf_size);
typedef int (debug_format_proc_t) (debug_info_t *id,
struct debug_view *view, char *out_buf,
size_t out_buf_size,
const char *in_buf);
typedef int (debug_prolog_proc_t) (debug_info_t *id,
struct debug_view *view,
char *out_buf, size_t out_buf_size);
typedef int (debug_input_proc_t) (debug_info_t *id,
struct debug_view *view,
struct file *file,
const char __user *user_buf,
size_t in_buf_size, loff_t *offset);
int debug_dflt_header_fn(debug_info_t *id, struct debug_view *view,
int area, debug_entry_t *entry,
char *out_buf, size_t out_buf_size);
#define DEBUG_SPRINTF_MAX_ARGS 10
int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view,
char *out_buf, size_t out_buf_size,
const char *inbuf);
struct debug_view {
char name[DEBUG_MAX_NAME_LEN];
debug_prolog_proc_t *prolog_proc;
debug_header_proc_t *header_proc;
debug_format_proc_t *format_proc;
debug_input_proc_t *input_proc;
void *private_data;
};
extern struct debug_view debug_hex_ascii_view;
extern struct debug_view debug_sprintf_view;
/* do NOT use the _common functions */
debug_entry_t *debug_event_common(debug_info_t *id, int level,
const void *data, int length);
debug_entry_t *debug_exception_common(debug_info_t *id, int level,
const void *data, int length);
/* Debug Feature API: */
debug_info_t *debug_register(const char *name, int pages, int nr_areas,
int buf_size);
debug_info_t *debug_register_mode(const char *name, int pages, int nr_areas,
int buf_size, umode_t mode, uid_t uid,
gid_t gid);
ssize_t debug_dump(debug_info_t *id, struct debug_view *view,
char *buf, size_t buf_size, bool reverse);
void debug_unregister(debug_info_t *id);
void debug_set_level(debug_info_t *id, int new_level);
void debug_set_critical(void);
void debug_stop_all(void);
/**
* debug_level_enabled() - Returns true if debug events for the specified
* level would be logged. Otherwise returns false.
*
* @id: handle for debug log
* @level: debug level
*
* Return:
* - %true if level is less or equal to the current debug level.
*/
static inline bool debug_level_enabled(debug_info_t *id, int level)
{
return level <= id->level;
}
/**
* debug_event() - writes binary debug entry to active debug area
* (if level <= actual debug level)
*
* @id: handle for debug log
* @level: debug level
* @data: pointer to data for debug entry
* @length: length of data in bytes
*
* Return:
* - Address of written debug entry
* - %NULL if error
*/
static inline debug_entry_t *debug_event(debug_info_t *id, int level,
void *data, int length)
{
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
return NULL;
return debug_event_common(id, level, data, length);
}
/**
* debug_int_event() - writes unsigned integer debug entry to active debug area
* (if level <= actual debug level)
*
* @id: handle for debug log
* @level: debug level
* @tag: integer value for debug entry
*
* Return:
* - Address of written debug entry
* - %NULL if error
*/
static inline debug_entry_t *debug_int_event(debug_info_t *id, int level,
unsigned int tag)
{
unsigned int t = tag;
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
return NULL;
return debug_event_common(id, level, &t, sizeof(unsigned int));
}
/**
* debug_long_event() - writes unsigned long debug entry to active debug area
* (if level <= actual debug level)
*
* @id: handle for debug log
* @level: debug level
* @tag: long integer value for debug entry
*
* Return:
* - Address of written debug entry
* - %NULL if error
*/
static inline debug_entry_t *debug_long_event(debug_info_t *id, int level,
unsigned long tag)
{
unsigned long t = tag;
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
return NULL;
return debug_event_common(id, level, &t, sizeof(unsigned long));
}
/**
* debug_text_event() - writes string debug entry in ascii format to active
* debug area (if level <= actual debug level)
*
* @id: handle for debug log
* @level: debug level
* @txt: string for debug entry
*
* Return:
* - Address of written debug entry
* - %NULL if error
*/
static inline debug_entry_t *debug_text_event(debug_info_t *id, int level,
const char *txt)
{
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
return NULL;
return debug_event_common(id, level, txt, strlen(txt));
}
/*
* IMPORTANT: Use "%s" in sprintf format strings with care! Only pointers are
* stored in the s390dbf. See Documentation/arch/s390/s390dbf.rst for more details!
*/
extern debug_entry_t *
__debug_sprintf_event(debug_info_t *id, int level, char *string, ...)
__attribute__ ((format(printf, 3, 4)));
/**
* debug_sprintf_event() - writes debug entry with format string
* and varargs (longs) to active debug area
* (if level $<=$ actual debug level).
*
* @_id: handle for debug log
* @_level: debug level
* @_fmt: format string for debug entry
* @...: varargs used as in sprintf()
*
* Return:
* - Address of written debug entry
* - %NULL if error
*
* floats and long long datatypes cannot be used as varargs.
*/
#define debug_sprintf_event(_id, _level, _fmt, ...) \
({ \
debug_entry_t *__ret; \
debug_info_t *__id = _id; \
int __level = _level; \
\
if ((!__id) || (__level > __id->level)) \
__ret = NULL; \
else \
__ret = __debug_sprintf_event(__id, __level, \
_fmt, ## __VA_ARGS__); \
__ret; \
})
/**
* debug_exception() - writes binary debug entry to active debug area
* (if level <= actual debug level)
* and switches to next debug area
*
* @id: handle for debug log
* @level: debug level
* @data: pointer to data for debug entry
* @length: length of data in bytes
*
* Return:
* - Address of written debug entry
* - %NULL if error
*/
static inline debug_entry_t *debug_exception(debug_info_t *id, int level,
void *data, int length)
{
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
return NULL;
return debug_exception_common(id, level, data, length);
}
/**
* debug_int_exception() - writes unsigned int debug entry to active debug area
* (if level <= actual debug level)
* and switches to next debug area
*
* @id: handle for debug log
* @level: debug level
* @tag: integer value for debug entry
*
* Return:
* - Address of written debug entry
* - %NULL if error
*/
static inline debug_entry_t *debug_int_exception(debug_info_t *id, int level,
unsigned int tag)
{
unsigned int t = tag;
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
return NULL;
return debug_exception_common(id, level, &t, sizeof(unsigned int));
}
/**
* debug_long_exception() - writes long debug entry to active debug area
* (if level <= actual debug level)
* and switches to next debug area
*
* @id: handle for debug log
* @level: debug level
* @tag: long integer value for debug entry
*
* Return:
* - Address of written debug entry
* - %NULL if error
*/
static inline debug_entry_t *debug_long_exception (debug_info_t *id, int level,
unsigned long tag)
{
unsigned long t = tag;
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
return NULL;
return debug_exception_common(id, level, &t, sizeof(unsigned long));
}
/**
* debug_text_exception() - writes string debug entry in ascii format to active
* debug area (if level <= actual debug level)
* and switches to next debug area
* area
*
* @id: handle for debug log
* @level: debug level
* @txt: string for debug entry
*
* Return:
* - Address of written debug entry
* - %NULL if error
*/
static inline debug_entry_t *debug_text_exception(debug_info_t *id, int level,
const char *txt)
{
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
return NULL;
return debug_exception_common(id, level, txt, strlen(txt));
}
/*
* IMPORTANT: Use "%s" in sprintf format strings with care! Only pointers are
* stored in the s390dbf. See Documentation/arch/s390/s390dbf.rst for more details!
*/
extern debug_entry_t *
__debug_sprintf_exception(debug_info_t *id, int level, char *string, ...)
__attribute__ ((format(printf, 3, 4)));
/**
* debug_sprintf_exception() - writes debug entry with format string and
* varargs (longs) to active debug area
* (if level <= actual debug level)
* and switches to next debug area.
*
* @_id: handle for debug log
* @_level: debug level
* @_fmt: format string for debug entry
* @...: varargs used as in sprintf()
*
* Return:
* - Address of written debug entry
* - %NULL if error
*
* floats and long long datatypes cannot be used as varargs.
*/
#define debug_sprintf_exception(_id, _level, _fmt, ...) \
({ \
debug_entry_t *__ret; \
debug_info_t *__id = _id; \
int __level = _level; \
\
if ((!__id) || (__level > __id->level)) \
__ret = NULL; \
else \
__ret = __debug_sprintf_exception(__id, __level, \
_fmt, ## __VA_ARGS__);\
__ret; \
})
int debug_register_view(debug_info_t *id, struct debug_view *view);
int debug_unregister_view(debug_info_t *id, struct debug_view *view);
#ifndef MODULE
/*
* Note: Initial page and area numbers must be fixed to allow static
* initialization. This enables very early tracing. Changes to these values
* must be reflected in __DEFINE_STATIC_AREA.
*/
#define EARLY_PAGES 8
#define EARLY_AREAS 1
#define VNAME(var, suffix) __##var##_##suffix
/*
* Define static areas for early trace data. During boot debug_register_static()
* will replace these with dynamically allocated areas to allow custom page and
* area sizes, and dynamic resizing.
*/
#define __DEFINE_STATIC_AREA(var) \
static char VNAME(var, data)[EARLY_PAGES][PAGE_SIZE] __initdata; \
static debug_entry_t *VNAME(var, pages)[EARLY_PAGES] __initdata = { \
(debug_entry_t *)VNAME(var, data)[0], \
(debug_entry_t *)VNAME(var, data)[1], \
(debug_entry_t *)VNAME(var, data)[2], \
(debug_entry_t *)VNAME(var, data)[3], \
(debug_entry_t *)VNAME(var, data)[4], \
(debug_entry_t *)VNAME(var, data)[5], \
(debug_entry_t *)VNAME(var, data)[6], \
(debug_entry_t *)VNAME(var, data)[7], \
}; \
static debug_entry_t **VNAME(var, areas)[EARLY_AREAS] __initdata = { \
(debug_entry_t **)VNAME(var, pages), \
}; \
static int VNAME(var, active_pages)[EARLY_AREAS] __initdata; \
static int VNAME(var, active_entries)[EARLY_AREAS] __initdata
#define __DEBUG_INFO_INIT(var, _name, _buf_size) { \
.next = NULL, \
.prev = NULL, \
.ref_count = REFCOUNT_INIT(1), \
.lock = __RAW_SPIN_LOCK_UNLOCKED(var.lock), \
.level = DEBUG_DEFAULT_LEVEL, \
.nr_areas = EARLY_AREAS, \
.pages_per_area = EARLY_PAGES, \
.buf_size = (_buf_size), \
.entry_size = sizeof(debug_entry_t) + (_buf_size), \
.areas = VNAME(var, areas), \
.active_area = 0, \
.active_pages = VNAME(var, active_pages), \
.active_entries = VNAME(var, active_entries), \
.debugfs_root_entry = NULL, \
.debugfs_entries = { NULL }, \
.views = { NULL }, \
.name = (_name), \
.mode = 0600, \
}
#define __REGISTER_STATIC_DEBUG_INFO(var, name, pages, areas, view) \
static int __init VNAME(var, reg)(void) \
{ \
debug_register_static(&var, (pages), (areas)); \
debug_register_view(&var, (view)); \
return 0; \
} \
arch_initcall(VNAME(var, reg))
/**
* DEFINE_STATIC_DEBUG_INFO - Define static debug_info_t
*
* @var: Name of debug_info_t variable
* @name: Name of debug log (e.g. used for debugfs entry)
* @pages: Number of pages per area
* @nr_areas: Number of debug areas
* @buf_size: Size of data area in each debug entry
* @view: Pointer to debug view struct
*
* Define a static debug_info_t for early tracing. The associated debugfs log
* is automatically registered with the specified debug view.
*
* Important: Users of this macro must not call any of the
* debug_register/_unregister() functions for this debug_info_t!
*
* Note: Tracing will start with a fixed number of initial pages and areas.
* The debug area will be changed to use the specified numbers during
* arch_initcall.
*/
#define DEFINE_STATIC_DEBUG_INFO(var, name, pages, nr_areas, buf_size, view) \
__DEFINE_STATIC_AREA(var); \
static debug_info_t __refdata var = \
__DEBUG_INFO_INIT(var, (name), (buf_size)); \
static debug_info_t __used __section(".s390dbf_info") *VNAME(var, info) = &var; \
__REGISTER_STATIC_DEBUG_INFO(var, name, pages, nr_areas, view)
void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas);
#endif /* MODULE */
#endif /* _ASM_S390_DEBUG_H */
+24
View File
@@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* S390 version
* Copyright IBM Corp. 1999
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
*
* Derived from "include/asm-i386/delay.h"
* Copyright (C) 1993 Linus Torvalds
*
* Delay routines calling functions in arch/s390/lib/delay.c
*/
#ifndef _S390_DELAY_H
#define _S390_DELAY_H
void __ndelay(unsigned long nsecs);
void __udelay(unsigned long usecs);
void __delay(unsigned long loops);
#define ndelay(n) __ndelay((unsigned long)(n))
#define udelay(n) __udelay((unsigned long)(n))
#define mdelay(n) __udelay((unsigned long)(n) * 1000)
#endif /* defined(_S390_DELAY_H) */
+377
View File
@@ -0,0 +1,377 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* s390 diagnose functions
*
* Copyright IBM Corp. 2007
* Author(s): Michael Holzheu <holzheu@de.ibm.com>
*/
#ifndef _ASM_S390_DIAG_H
#define _ASM_S390_DIAG_H
#include <linux/if_ether.h>
#include <linux/percpu.h>
#include <asm/asm-extable.h>
#include <asm/sclp.h>
#include <asm/cio.h>
enum diag_stat_enum {
DIAG_STAT_X008,
DIAG_STAT_X00C,
DIAG_STAT_X010,
DIAG_STAT_X014,
DIAG_STAT_X044,
DIAG_STAT_X064,
DIAG_STAT_X08C,
DIAG_STAT_X09C,
DIAG_STAT_X0DC,
DIAG_STAT_X204,
DIAG_STAT_X210,
DIAG_STAT_X224,
DIAG_STAT_X250,
DIAG_STAT_X258,
DIAG_STAT_X26C,
DIAG_STAT_X288,
DIAG_STAT_X2C4,
DIAG_STAT_X2FC,
DIAG_STAT_X304,
DIAG_STAT_X308,
DIAG_STAT_X310,
DIAG_STAT_X318,
DIAG_STAT_X320,
DIAG_STAT_X324,
DIAG_STAT_X49C,
DIAG_STAT_X500,
NR_DIAG_STAT
};
void diag_stat_inc(enum diag_stat_enum nr);
void diag_stat_inc_norecursion(enum diag_stat_enum nr);
struct hypfs_diag0c_entry;
/*
* Diagnose 0c: Pseudo Timer
*/
void diag0c(struct hypfs_diag0c_entry *data);
/*
* Diagnose 10: Release page range
*/
static inline void diag10_range(unsigned long start_pfn, unsigned long num_pfn)
{
unsigned long start_addr, end_addr;
start_addr = pfn_to_phys(start_pfn);
end_addr = pfn_to_phys(start_pfn + num_pfn - 1);
diag_stat_inc(DIAG_STAT_X010);
asm_inline volatile(
"0: diag %0,%1,0x10\n"
"1: nopr %%r7\n"
EX_TABLE(0b, 1b)
EX_TABLE(1b, 1b)
: : "a" (start_addr), "a" (end_addr));
}
/*
* Diagnose 14: Input spool file manipulation
*/
extern int diag14(unsigned long rx, unsigned long ry1, unsigned long subcode);
/*
* Diagnose 210: Get information about a virtual device
*/
struct diag210 {
u16 vrdcdvno; /* device number (input) */
u16 vrdclen; /* data block length (input) */
u8 vrdcvcla; /* virtual device class (output) */
u8 vrdcvtyp; /* virtual device type (output) */
u8 vrdcvsta; /* virtual device status (output) */
u8 vrdcvfla; /* virtual device flags (output) */
u8 vrdcrccl; /* real device class (output) */
u8 vrdccrty; /* real device type (output) */
u8 vrdccrmd; /* real device model (output) */
u8 vrdccrft; /* real device feature (output) */
} __packed __aligned(4);
extern int diag210(struct diag210 *addr);
struct diag8c {
u8 flags;
u8 num_partitions;
u16 width;
u16 height;
u8 data[];
} __packed __aligned(4);
extern int diag8c(struct diag8c *out, struct ccw_dev_id *devno);
/* bit is set in flags, when physical cpu info is included in diag 204 data */
#define DIAG204_LPAR_PHYS_FLG 0x80
#define DIAG204_LPAR_NAME_LEN 8 /* lpar name len in diag 204 data */
#define DIAG204_CPU_NAME_LEN 16 /* type name len of cpus in diag224 name table */
/* diag 204 subcodes */
enum diag204_sc {
DIAG204_SUBC_STIB4 = 4,
DIAG204_SUBC_RSI = 5,
DIAG204_SUBC_STIB6 = 6,
DIAG204_SUBC_STIB7 = 7
};
#define DIAG204_SUBCODE_MASK 0xffff
#define DIAG204_BIF_BIT 0x80000000
#define DIAG204_BUSY_WAIT (HZ / 10)
/* The two available diag 204 data formats */
enum diag204_format {
DIAG204_INFO_SIMPLE = 0,
DIAG204_INFO_EXT = 0x00010000
};
enum diag204_cpu_flags {
DIAG204_CPU_ONLINE = 0x20,
DIAG204_CPU_CAPPED = 0x40,
};
struct diag204_info_blk_hdr {
__u8 npar;
__u8 flags;
__u16 tslice;
__u16 phys_cpus;
__u16 this_part;
__u64 curtod;
} __packed;
struct diag204_x_info_blk_hdr {
__u8 npar;
__u8 flags;
__u16 tslice;
__u16 phys_cpus;
__u16 this_part;
__u64 curtod1;
__u64 curtod2;
char reserved[40];
} __packed;
struct diag204_part_hdr {
__u8 pn;
__u8 cpus;
char reserved[6];
char part_name[DIAG204_LPAR_NAME_LEN];
} __packed;
struct diag204_x_part_hdr {
__u8 pn;
__u8 cpus;
__u8 rcpus;
__u8 pflag;
__u32 mlu;
char part_name[DIAG204_LPAR_NAME_LEN];
char lpc_name[8];
char os_name[8];
__u64 online_cs;
__u64 online_es;
__u8 upid;
__u8 reserved:3;
__u8 mtid:5;
char reserved1[2];
__u32 group_mlu;
char group_name[8];
char hardware_group_name[8];
char reserved2[24];
} __packed;
struct diag204_cpu_info {
__u16 cpu_addr;
char reserved1[2];
__u8 ctidx;
__u8 cflag;
__u16 weight;
__u64 acc_time;
__u64 lp_time;
} __packed;
struct diag204_x_cpu_info {
__u16 cpu_addr;
char reserved1[2];
__u8 ctidx;
__u8 cflag;
__u16 weight;
__u64 acc_time;
__u64 lp_time;
__u16 min_weight;
__u16 cur_weight;
__u16 max_weight;
char reseved2[2];
__u64 online_time;
__u64 wait_time;
__u32 pma_weight;
__u32 polar_weight;
__u32 cpu_type_cap;
__u32 group_cpu_type_cap;
char reserved3[32];
} __packed;
struct diag204_phys_hdr {
char reserved1[1];
__u8 cpus;
char reserved2[6];
char mgm_name[8];
} __packed;
struct diag204_x_phys_hdr {
char reserved1[1];
__u8 cpus;
char reserved2[6];
char mgm_name[8];
char reserved3[80];
} __packed;
struct diag204_phys_cpu {
__u16 cpu_addr;
char reserved1[2];
__u8 ctidx;
char reserved2[3];
__u64 mgm_time;
char reserved3[8];
} __packed;
struct diag204_x_phys_cpu {
__u16 cpu_addr;
char reserved1[2];
__u8 ctidx;
char reserved2[1];
__u16 weight;
__u64 mgm_time;
char reserved3[80];
} __packed;
struct diag204_x_part_block {
struct diag204_x_part_hdr hdr;
struct diag204_x_cpu_info cpus[];
} __packed;
struct diag204_x_phys_block {
struct diag204_x_phys_hdr hdr;
struct diag204_x_phys_cpu cpus[];
} __packed;
enum diag26c_sc {
DIAG26C_PORT_VNIC = 0x00000024,
DIAG26C_MAC_SERVICES = 0x00000030
};
enum diag26c_version {
DIAG26C_VERSION2 = 0x00000002, /* z/VM 5.4.0 */
DIAG26C_VERSION6_VM65918 = 0x00020006 /* z/VM 6.4.0 + VM65918 */
};
#define DIAG26C_VNIC_INFO 0x0002
struct diag26c_vnic_req {
u32 resp_buf_len;
u32 resp_version;
u16 req_format;
u16 vlan_id;
u64 sys_name;
u8 res[2];
u16 devno;
} __packed __aligned(8);
#define VNIC_INFO_PROT_L3 1
#define VNIC_INFO_PROT_L2 2
/* Note: this is the bare minimum, use it for uninitialized VNICs only. */
struct diag26c_vnic_resp {
u32 version;
u32 entry_cnt;
/* VNIC info: */
u32 next_entry;
u64 owner;
u16 devno;
u8 status;
u8 type;
u64 lan_owner;
u64 lan_name;
u64 port_name;
u8 port_type;
u8 ext_status:6;
u8 protocol:2;
u16 base_devno;
u32 port_num;
u32 ifindex;
u32 maxinfo;
u32 dev_count;
/* 3x device info: */
u8 dev_info1[28];
u8 dev_info2[28];
u8 dev_info3[28];
} __packed __aligned(8);
#define DIAG26C_GET_MAC 0x0000
struct diag26c_mac_req {
u32 resp_buf_len;
u32 resp_version;
u16 op_code;
u16 devno;
u8 res[4];
};
struct diag26c_mac_resp {
u32 version;
u8 mac[ETH_ALEN];
u8 res[2];
} __aligned(8);
#define CPNC_LINUX 0x4
union diag318_info {
unsigned long val;
struct {
unsigned long cpnc : 8;
unsigned long cpvc : 56;
};
};
static inline bool diag204_has_bif(void)
{
return sclp.has_diag204_bif;
}
int diag204(unsigned long subcode, unsigned long size, void *addr);
int diag224(void *ptr);
int diag26c(void *req, void *resp, enum diag26c_sc subcode);
struct hypfs_diag0c_entry;
/*
* This structure must contain only pointers/references into
* the AMODE31 text section.
*/
struct diag_ops {
int (*diag210)(struct diag210 *addr);
int (*diag26c)(unsigned long rx, unsigned long rx1, enum diag26c_sc subcode);
int (*diag14)(unsigned long rx, unsigned long ry1, unsigned long subcode);
int (*diag8c)(struct diag8c *addr, struct ccw_dev_id *devno, size_t len);
void (*diag0c)(unsigned long rx);
void (*diag308_reset)(void);
};
extern struct diag_ops diag_amode31_ops;
extern struct diag210 *__diag210_tmp_amode31;
int _diag210_amode31(struct diag210 *addr);
int _diag26c_amode31(unsigned long rx, unsigned long rx1, enum diag26c_sc subcode);
int _diag14_amode31(unsigned long rx, unsigned long ry1, unsigned long subcode);
void _diag0c_amode31(unsigned long rx);
void _diag308_reset_amode31(void);
int _diag8c_amode31(struct diag8c *addr, struct ccw_dev_id *devno, size_t len);
/* diag 49c subcodes */
enum diag49c_sc {
DIAG49C_SUBC_ACK = 0,
DIAG49C_SUBC_REG = 1
};
int diag49c(unsigned long subcode);
#endif /* _ASM_S390_DIAG_H */
@@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_DIAG288_H
#define _ASM_S390_DIAG288_H
#include <asm/asm-extable.h>
#include <asm/types.h>
#define MIN_INTERVAL 15 /* Minimal time supported by diag288 */
#define MAX_INTERVAL 3600 /* One hour should be enough - pure estimation */
#define WDT_DEFAULT_TIMEOUT 30
/* Function codes - init, change, cancel */
#define WDT_FUNC_INIT 0
#define WDT_FUNC_CHANGE 1
#define WDT_FUNC_CANCEL 2
#define WDT_FUNC_CONCEAL 0x80000000
/* Action codes for LPAR watchdog */
#define LPARWDT_RESTART 0
static inline int __diag288(unsigned int func, unsigned int timeout,
unsigned long action, unsigned int len)
{
union register_pair r1 = { .even = func, .odd = timeout, };
union register_pair r3 = { .even = action, .odd = len, };
int rc = -EINVAL;
asm volatile(
" diag %[r1],%[r3],0x288\n"
"0: lhi %[rc],0\n"
"1:"
EX_TABLE(0b, 1b)
: [rc] "+d" (rc)
: [r1] "d" (r1.pair), [r3] "d" (r3.pair)
: "cc", "memory");
return rc;
}
#endif /* _ASM_S390_DIAG288_H */
+30
View File
@@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Disassemble s390 instructions.
*
* Copyright IBM Corp. 2007
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
*/
#ifndef __ASM_S390_DIS_H__
#define __ASM_S390_DIS_H__
#include <asm/dis-defs.h>
static inline int insn_length(unsigned char code)
{
return ((((int) code + 64) >> 7) + 1) << 1;
}
struct pt_regs;
void show_code(struct pt_regs *regs);
void print_fn_code(unsigned char *code, unsigned long len);
struct s390_insn *find_insn(unsigned char *code);
static inline int is_known_insn(unsigned char *code)
{
return !!find_insn(code);
}
#endif /* __ASM_S390_DIS_H__ */
@@ -0,0 +1,103 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_DMA_TYPES_H_
#define _ASM_S390_DMA_TYPES_H_
#include <linux/types.h>
#include <linux/io.h>
/*
* typedef dma32_t
* Contains a 31 bit absolute address to a DMA capable piece of storage.
*
* For CIO, DMA addresses are always absolute addresses. These addresses tend
* to be used in architectured memory blocks (like ORB, IDAW, MIDAW). Under
* certain circumstances 31 bit wide addresses must be used because the
* address must fit in 31 bits.
*
* This type is to be used when such fields can be modelled as 32 bit wide.
*/
typedef u32 __bitwise dma32_t;
/*
* typedef dma64_t
* Contains a 64 bit absolute address to a DMA capable piece of storage.
*
* For CIO, DMA addresses are always absolute addresses. These addresses tend
* to be used in architectured memory blocks (like ORB, IDAW, MIDAW).
*
* This type is to be used to model such 64 bit wide fields.
*/
typedef u64 __bitwise dma64_t;
/*
* Although DMA addresses should be obtained using the DMA API, in cases when
* it is known that the first argument holds a virtual address that points to
* DMA-able 31 bit addressable storage, then this function can be safely used.
*/
static inline dma32_t virt_to_dma32(void *ptr)
{
return (__force dma32_t)__pa32(ptr);
}
static inline void *dma32_to_virt(dma32_t addr)
{
return __va((__force unsigned long)addr);
}
static inline dma32_t u32_to_dma32(u32 addr)
{
return (__force dma32_t)addr;
}
static inline u32 dma32_to_u32(dma32_t addr)
{
return (__force u32)addr;
}
static inline dma32_t dma32_add(dma32_t a, u32 b)
{
return (__force dma32_t)((__force u32)a + b);
}
static inline dma32_t dma32_and(dma32_t a, u32 b)
{
return (__force dma32_t)((__force u32)a & b);
}
/*
* Although DMA addresses should be obtained using the DMA API, in cases when
* it is known that the first argument holds a virtual address that points to
* DMA-able storage, then this function can be safely used.
*/
static inline dma64_t virt_to_dma64(void *ptr)
{
return (__force dma64_t)__pa(ptr);
}
static inline void *dma64_to_virt(dma64_t addr)
{
return __va((__force unsigned long)addr);
}
static inline dma64_t u64_to_dma64(u64 addr)
{
return (__force dma64_t)addr;
}
static inline u64 dma64_to_u64(dma64_t addr)
{
return (__force u64)addr;
}
static inline dma64_t dma64_add(dma64_t a, u64 b)
{
return (__force dma64_t)((__force u64)a + b);
}
static inline dma64_t dma64_and(dma64_t a, u64 b)
{
return (__force dma64_t)((__force u64)a & b);
}
#endif /* _ASM_S390_DMA_TYPES_H_ */
+14
View File
@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_DMA_H
#define _ASM_S390_DMA_H
#include <linux/io.h>
/*
* MAX_DMA_ADDRESS is ambiguous because on s390 its completely unrelated
* to DMA. It _is_ used for the s390 memory zone split at 2GB caused
* by the 31 bit heritage.
*/
#define MAX_DMA_ADDRESS __va(0x80000000)
#endif /* _ASM_S390_DMA_H */
+38
View File
@@ -0,0 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_DWARF_H
#define _ASM_S390_DWARF_H
#ifdef __ASSEMBLER__
#define CFI_STARTPROC .cfi_startproc
#define CFI_ENDPROC .cfi_endproc
#define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset
#define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset
#define CFI_RESTORE .cfi_restore
#define CFI_REL_OFFSET .cfi_rel_offset
#ifdef CONFIG_AS_CFI_VAL_OFFSET
#define CFI_VAL_OFFSET .cfi_val_offset
#else
#define CFI_VAL_OFFSET #
#endif
#ifndef BUILD_VDSO
/*
* Emit CFI data in .debug_frame sections and not in .eh_frame
* sections. The .eh_frame CFI is used for runtime unwind
* information that is not being used. Hence, vmlinux.lds.S
* can discard the .eh_frame sections.
*/
.cfi_sections .debug_frame
#else
/*
* For vDSO, emit CFI data in both, .eh_frame and .debug_frame
* sections.
*/
.cfi_sections .eh_frame, .debug_frame
#endif
#endif /* __ASSEMBLER__ */
#endif /* _ASM_S390_DWARF_H */
+121
View File
@@ -0,0 +1,121 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_EADM_H
#define _ASM_S390_EADM_H
#include <linux/types.h>
#include <linux/device.h>
#include <linux/blk_types.h>
#include <asm/dma-types.h>
struct arqb {
u64 data;
u16 fmt:4;
u16:12;
u16 cmd_code;
u16:16;
u16 msb_count;
u32 reserved[12];
} __packed;
#define ARQB_CMD_MOVE 1
struct arsb {
u16 fmt:4;
u32:28;
u8 ef;
u8:8;
u8 ecbi;
u8:8;
u8 fvf;
u16:16;
u8 eqc;
u32:32;
u64 fail_msb;
u64 fail_aidaw;
u64 fail_ms;
u64 fail_scm;
u32 reserved[4];
} __packed;
#define EQC_WR_PROHIBIT 22
struct msb {
u8 fmt:4;
u8 oc:4;
u8 flags;
u16:12;
u16 bs:4;
u32 blk_count;
dma64_t data_addr;
u64 scm_addr;
u64:64;
} __packed;
struct aidaw {
u8 flags;
u32 :24;
u32 :32;
dma64_t data_addr;
} __packed;
#define MSB_OC_CLEAR 0
#define MSB_OC_READ 1
#define MSB_OC_WRITE 2
#define MSB_OC_RELEASE 3
#define MSB_FLAG_BNM 0x80
#define MSB_FLAG_IDA 0x40
#define MSB_BS_4K 0
#define MSB_BS_1M 1
#define AOB_NR_MSB 124
struct aob {
struct arqb request;
struct arsb response;
struct msb msb[AOB_NR_MSB];
} __packed __aligned(PAGE_SIZE);
struct aob_rq_header {
struct scm_device *scmdev;
char data[];
};
struct scm_device {
u64 address;
u64 size;
unsigned int nr_max_block;
struct device dev;
struct {
unsigned int persistence:4;
unsigned int oper_state:4;
unsigned int data_state:4;
unsigned int rank:4;
unsigned int release:1;
unsigned int res_id:8;
} __packed attrs;
};
#define OP_STATE_GOOD 1
#define OP_STATE_TEMP_ERR 2
#define OP_STATE_PERM_ERR 3
enum scm_event {SCM_CHANGE, SCM_AVAIL};
struct scm_driver {
struct device_driver drv;
int (*probe) (struct scm_device *scmdev);
void (*remove) (struct scm_device *scmdev);
void (*notify) (struct scm_device *scmdev, enum scm_event event);
void (*handler) (struct scm_device *scmdev, void *data,
blk_status_t error);
};
int scm_driver_register(struct scm_driver *scmdrv);
void scm_driver_unregister(struct scm_driver *scmdrv);
int eadm_start_aob(struct aob *aob);
void scm_irq_handler(struct aob *aob, blk_status_t error);
#endif /* _ASM_S390_EADM_H */
@@ -0,0 +1,47 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* EBCDIC -> ASCII, ASCII -> EBCDIC conversion routines.
*
* S390 version
* Copyright IBM Corp. 1999
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
#ifndef _EBCDIC_H
#define _EBCDIC_H
#include <linux/types.h>
extern __u8 _ascebc_500[256]; /* ASCII -> EBCDIC 500 conversion table */
extern __u8 _ebcasc_500[256]; /* EBCDIC 500 -> ASCII conversion table */
extern __u8 _ascebc[256]; /* ASCII -> EBCDIC conversion table */
extern __u8 _ebcasc[256]; /* EBCDIC -> ASCII conversion table */
extern __u8 _ebc_tolower[256]; /* EBCDIC -> lowercase */
extern __u8 _ebc_toupper[256]; /* EBCDIC -> uppercase */
static inline void
codepage_convert(const __u8 *codepage, volatile char *addr, unsigned long nr)
{
if (!nr--)
return;
asm volatile(
" j 2f\n"
"0: tr 0(1,%0),0(%2)\n"
"1: tr 0(256,%0),0(%2)\n"
" la %0,256(%0)\n"
"2: aghi %1,-256\n"
" jnm 1b\n"
" exrl %1,0b"
: "+&a" (addr), "+&a" (nr)
: "a" (codepage) : "cc", "memory");
}
#define ASCEBC(addr,nr) codepage_convert(_ascebc, addr, nr)
#define EBCASC(addr,nr) codepage_convert(_ebcasc, addr, nr)
#define ASCEBC_500(addr,nr) codepage_convert(_ascebc_500, addr, nr)
#define EBCASC_500(addr,nr) codepage_convert(_ebcasc_500, addr, nr)
#define EBC_TOLOWER(addr,nr) codepage_convert(_ebc_tolower, addr, nr)
#define EBC_TOUPPER(addr,nr) codepage_convert(_ebc_toupper, addr, nr)
#endif
+245
View File
@@ -0,0 +1,245 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* S390 version
*
* Derived from "include/asm-i386/elf.h"
*/
#ifndef __ASMS390_ELF_H
#define __ASMS390_ELF_H
/* s390 relocations defined by the ABIs */
#define R_390_NONE 0 /* No reloc. */
#define R_390_8 1 /* Direct 8 bit. */
#define R_390_12 2 /* Direct 12 bit. */
#define R_390_16 3 /* Direct 16 bit. */
#define R_390_32 4 /* Direct 32 bit. */
#define R_390_PC32 5 /* PC relative 32 bit. */
#define R_390_GOT12 6 /* 12 bit GOT offset. */
#define R_390_GOT32 7 /* 32 bit GOT offset. */
#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */
#define R_390_COPY 9 /* Copy symbol at runtime. */
#define R_390_GLOB_DAT 10 /* Create GOT entry. */
#define R_390_JMP_SLOT 11 /* Create PLT entry. */
#define R_390_RELATIVE 12 /* Adjust by program base. */
#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */
#define R_390_GOTPC 14 /* 32 bit PC rel. offset to GOT. */
#define R_390_GOT16 15 /* 16 bit GOT offset. */
#define R_390_PC16 16 /* PC relative 16 bit. */
#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */
#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */
#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */
#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */
#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */
#define R_390_64 22 /* Direct 64 bit. */
#define R_390_PC64 23 /* PC relative 64 bit. */
#define R_390_GOT64 24 /* 64 bit GOT offset. */
#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */
#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */
#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */
#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */
#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */
#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */
#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */
#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */
#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */
#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */
#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */
#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */
#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */
#define R_390_TLS_GDCALL 38 /* Tag for function call in general
dynamic TLS code. */
#define R_390_TLS_LDCALL 39 /* Tag for function call in local
dynamic TLS code. */
#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic
thread local data. */
#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic
thread local data. */
#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS
block offset. */
#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS
block offset. */
#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS
block offset. */
#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic
thread local data in LD code. */
#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic
thread local data in LD code. */
#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for
negated static TLS block offset. */
#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for
negated static TLS block offset. */
#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for
negated static TLS block offset. */
#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to
static TLS block. */
#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to
static TLS block. */
#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS
block. */
#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS
block. */
#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */
#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */
#define R_390_TLS_TPOFF 56 /* Negate offset in static TLS
block. */
#define R_390_20 57 /* Direct 20 bit. */
#define R_390_GOT20 58 /* 20 bit GOT offset. */
#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */
#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS
block offset. */
/* Keep this the last entry. */
#define R_390_NUM 61
/*
* HWCAP flags - for AT_HWCAP
*
* Bits 32-63 are reserved for use by libc.
* Bit 31 is reserved and will be used by libc to determine if a second
* argument is passed to IFUNC resolvers. This will be implemented when
* there is a need for AT_HWCAP2.
*/
enum {
HWCAP_NR_ESAN3 = 0,
HWCAP_NR_ZARCH = 1,
HWCAP_NR_STFLE = 2,
HWCAP_NR_MSA = 3,
HWCAP_NR_LDISP = 4,
HWCAP_NR_EIMM = 5,
HWCAP_NR_DFP = 6,
HWCAP_NR_HPAGE = 7,
HWCAP_NR_ETF3EH = 8,
HWCAP_NR_HIGH_GPRS = 9,
HWCAP_NR_TE = 10,
HWCAP_NR_VXRS = 11,
HWCAP_NR_VXRS_BCD = 12,
HWCAP_NR_VXRS_EXT = 13,
HWCAP_NR_GS = 14,
HWCAP_NR_VXRS_EXT2 = 15,
HWCAP_NR_VXRS_PDE = 16,
HWCAP_NR_SORT = 17,
HWCAP_NR_DFLT = 18,
HWCAP_NR_VXRS_PDE2 = 19,
HWCAP_NR_NNPA = 20,
HWCAP_NR_PCI_MIO = 21,
HWCAP_NR_SIE = 22,
HWCAP_NR_MAX
};
/* Bits present in AT_HWCAP. */
#define HWCAP_ESAN3 BIT(HWCAP_NR_ESAN3)
#define HWCAP_ZARCH BIT(HWCAP_NR_ZARCH)
#define HWCAP_STFLE BIT(HWCAP_NR_STFLE)
#define HWCAP_MSA BIT(HWCAP_NR_MSA)
#define HWCAP_LDISP BIT(HWCAP_NR_LDISP)
#define HWCAP_EIMM BIT(HWCAP_NR_EIMM)
#define HWCAP_DFP BIT(HWCAP_NR_DFP)
#define HWCAP_HPAGE BIT(HWCAP_NR_HPAGE)
#define HWCAP_ETF3EH BIT(HWCAP_NR_ETF3EH)
#define HWCAP_HIGH_GPRS BIT(HWCAP_NR_HIGH_GPRS)
#define HWCAP_TE BIT(HWCAP_NR_TE)
#define HWCAP_VXRS BIT(HWCAP_NR_VXRS)
#define HWCAP_VXRS_BCD BIT(HWCAP_NR_VXRS_BCD)
#define HWCAP_VXRS_EXT BIT(HWCAP_NR_VXRS_EXT)
#define HWCAP_GS BIT(HWCAP_NR_GS)
#define HWCAP_VXRS_EXT2 BIT(HWCAP_NR_VXRS_EXT2)
#define HWCAP_VXRS_PDE BIT(HWCAP_NR_VXRS_PDE)
#define HWCAP_SORT BIT(HWCAP_NR_SORT)
#define HWCAP_DFLT BIT(HWCAP_NR_DFLT)
#define HWCAP_VXRS_PDE2 BIT(HWCAP_NR_VXRS_PDE2)
#define HWCAP_NNPA BIT(HWCAP_NR_NNPA)
#define HWCAP_PCI_MIO BIT(HWCAP_NR_PCI_MIO)
#define HWCAP_SIE BIT(HWCAP_NR_SIE)
/*
* These are used to set parameters in the core dumps.
*/
#define ELF_CLASS ELFCLASS64
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_S390
/*
* ELF register definitions..
*/
#include <asm/ptrace.h>
#include <asm/syscall.h>
#include <asm/user.h>
typedef s390_fp_regs elf_fpregset_t;
typedef s390_regs elf_gregset_t;
#include <linux/sched/mm.h> /* for task_struct */
#include <asm/mmu_context.h>
/*
* This is used to ensure we don't load something for the wrong architecture.
*/
#define elf_check_arch(x) \
(((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \
&& (x)->e_ident[EI_CLASS] == ELF_CLASS)
/* For SVR4/S390 the function pointer to be registered with `atexit` is
passed in R14. */
#define ELF_PLAT_INIT(_r, load_addr) \
do { \
_r->gprs[14] = 0; \
} while (0)
#define CORE_DUMP_USE_REGSET
#define ELF_EXEC_PAGESIZE PAGE_SIZE
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
use of this is to invoke "./ld.so someprog" to test out a new version of
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. 64-bit
tasks are aligned to 4GB. */
#define ELF_ET_DYN_BASE ((STACK_TOP / 3 * 2) & ~((1UL << 32) - 1))
/* This yields a mask that user programs can use to figure out what
instruction set this CPU supports. */
extern unsigned long elf_hwcap;
#define ELF_HWCAP (elf_hwcap)
/* This yields a string that ld.so will use to load implementation
specific libraries for optimization. This is more specific in
intent than poking at uname or /proc/cpuinfo.
For the moment, we have only optimizations for the Intel generations,
but that could change... */
#define ELF_PLATFORM_SIZE 8
extern char elf_platform[];
#define ELF_PLATFORM (elf_platform)
#define SET_PERSONALITY(ex) \
do { \
set_personality(PER_LINUX | \
(current->personality & (~PER_MASK))); \
} while (0)
/*
* Cache aliasing on the latest machines calls for a mapping granularity
* of 512KB for the anonymous mapping base. Use a 512KB alignment and a
* randomization of up to 1GB.
* For the additional randomization of the program break use 32MB.
*/
#define BRK_RND_MASK (0x1fffUL)
#define MMAP_RND_MASK (0x3ff80UL)
#define MMAP_ALIGN_MASK (0x7fUL)
#define STACK_RND_MASK MMAP_RND_MASK
/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
#define ARCH_DLINFO \
do { \
NEW_AUX_ENT(AT_SYSINFO_EHDR, \
(unsigned long)current->mm->context.vdso_base); \
} while (0)
struct linux_binprm;
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
int arch_setup_additional_pages(struct linux_binprm *, int);
#endif
@@ -0,0 +1,64 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef ARCH_S390_ENTRY_COMMON_H
#define ARCH_S390_ENTRY_COMMON_H
#include <linux/sched.h>
#include <linux/audit.h>
#include <linux/randomize_kstack.h>
#include <linux/processor.h>
#include <linux/uaccess.h>
#include <asm/timex.h>
#include <asm/fpu.h>
#include <asm/pai.h>
#define ARCH_EXIT_TO_USER_MODE_WORK (_TIF_GUARDED_STORAGE | _TIF_PER_TRAP)
void do_per_trap(struct pt_regs *regs);
static __always_inline void arch_enter_from_user_mode(struct pt_regs *regs)
{
if (IS_ENABLED(CONFIG_DEBUG_ENTRY))
debug_user_asce(0);
pai_kernel_enter(regs);
}
#define arch_enter_from_user_mode arch_enter_from_user_mode
static __always_inline void arch_exit_to_user_mode_work(struct pt_regs *regs,
unsigned long ti_work)
{
if (ti_work & _TIF_PER_TRAP) {
clear_thread_flag(TIF_PER_TRAP);
do_per_trap(regs);
}
if (ti_work & _TIF_GUARDED_STORAGE)
gs_load_bc_cb(regs);
}
#define arch_exit_to_user_mode_work arch_exit_to_user_mode_work
static __always_inline void arch_exit_to_user_mode(void)
{
load_user_fpu_regs();
if (IS_ENABLED(CONFIG_DEBUG_ENTRY))
debug_user_asce(1);
pai_kernel_exit(current_pt_regs());
}
#define arch_exit_to_user_mode arch_exit_to_user_mode
static __always_inline bool arch_in_rcu_eqs(void)
{
if (IS_ENABLED(CONFIG_KVM))
return current->flags & PF_VCPU;
return false;
}
#define arch_in_rcu_eqs arch_in_rcu_eqs
#endif
@@ -0,0 +1,80 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef ARCH_S390_ENTRY_PERCPU_H
#define ARCH_S390_ENTRY_PERCPU_H
#include <linux/kprobes.h>
#include <linux/percpu.h>
#include <asm/lowcore.h>
#include <asm/ptrace.h>
#include <asm/asm-offsets.h>
static __always_inline void percpu_entry(struct pt_regs *regs)
{
struct lowcore *lc = get_lowcore();
if (user_mode(regs))
return;
regs->cpu = lc->cpu_nr;
regs->percpu_register = lc->percpu_register;
lc->percpu_register = 0;
}
static __always_inline bool percpu_code_check(struct pt_regs *regs)
{
unsigned int insn, disp;
struct kprobe *p;
if (likely(user_mode(regs) || !regs->percpu_register))
return false;
/*
* Within a percpu code section - check if the percpu base register
* needs to be updated. This is the case if the PSW does not point to
* the ADD instruction within the section.
* - AG %rx,percpu_offset_in_lowcore(%r0,%r0)
* which adds the percpu offset to the percpu base register.
*/
lockdep_assert_preemption_disabled();
again:
insn = READ_ONCE(*(u16 *)psw_bits(regs->psw).ia);
if (unlikely(insn == BREAKPOINT_INSTRUCTION)) {
p = get_kprobe((void *)psw_bits(regs->psw).ia);
/*
* If the kprobe is concurrently removed on a different CPU
* it might not be found anymore. However text must have
* been restored - try again.
*/
if (!p)
goto again;
insn = p->opcode;
}
if ((insn & 0xff0f) != 0xe300)
return true;
disp = offsetof(struct lowcore, percpu_offset);
if (machine_has_relocated_lowcore())
disp += LOWCORE_ALT_ADDRESS;
insn = (disp & 0xff000) >> 4 | (disp & 0x00fff) << 16 | 0x8;
if (*(u32 *)(psw_bits(regs->psw).ia + 2) != insn)
return true;
return false;
}
static __always_inline void percpu_exit(struct pt_regs *regs, bool needs_fixup)
{
struct lowcore *lc = get_lowcore();
unsigned char reg;
if (user_mode(regs))
return;
reg = regs->percpu_register;
lc->percpu_register = reg;
if (likely(!needs_fixup))
return;
/* Check if process has been migrated to a different CPU. */
if (regs->cpu == lc->cpu_nr)
return;
/* Fixup percpu base register */
regs->gprs[reg] -= __per_cpu_offset[regs->cpu];
regs->gprs[reg] += lc->percpu_offset;
}
#endif
+13
View File
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 1999, 2009
*
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
#ifndef __ASM_EXEC_H
#define __ASM_EXEC_H
extern unsigned long arch_align_stack(unsigned long sp);
#endif /* __ASM_EXEC_H */
@@ -0,0 +1,72 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __S390_EXTABLE_H
#define __S390_EXTABLE_H
#include <asm/ptrace.h>
#include <linux/compiler.h>
/*
* The exception table consists of three addresses:
*
* - Address of an instruction that is allowed to fault.
* - Address at which the program should continue.
* - Optional address of handler that takes pt_regs * argument and runs in
* interrupt context.
*
* No registers are modified, so it is entirely up to the continuation code
* to figure out what to do.
*
* All the routines below use bits of fixup code that are out of line
* with the main instruction path. This means when everything is well,
* we don't even have to jump over them. Further, they do not intrude
* on our cache or tlb entries.
*/
struct exception_table_entry
{
int insn, fixup;
short type, data;
};
extern struct exception_table_entry *__start_amode31_ex_table;
extern struct exception_table_entry *__stop_amode31_ex_table;
const struct exception_table_entry *s390_search_extables(unsigned long addr);
static inline unsigned long extable_fixup(const struct exception_table_entry *x)
{
return (unsigned long)&x->fixup + x->fixup;
}
#define ARCH_HAS_RELATIVE_EXTABLE
static inline void swap_ex_entry_fixup(struct exception_table_entry *a,
struct exception_table_entry *b,
struct exception_table_entry tmp,
int delta)
{
a->fixup = b->fixup + delta;
b->fixup = tmp.fixup - delta;
a->type = b->type;
b->type = tmp.type;
a->data = b->data;
b->data = tmp.data;
}
#define swap_ex_entry_fixup swap_ex_entry_fixup
#ifdef CONFIG_BPF_JIT
bool ex_handler_bpf(const struct exception_table_entry *ex, struct pt_regs *regs);
#else /* !CONFIG_BPF_JIT */
static inline bool ex_handler_bpf(const struct exception_table_entry *ex, struct pt_regs *regs)
{
return false;
}
#endif /* CONFIG_BPF_JIT */
bool fixup_exception(struct pt_regs *regs);
#endif
@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* definitions for external memory segment support
* Copyright IBM Corp. 2003
*/
#ifndef _ASM_S390X_DCSS_H
#define _ASM_S390X_DCSS_H
#ifndef __ASSEMBLER__
/*
* DCSS segment is defined as a contiguous range of pages using DEFSEG command.
* The range start and end is a page number with a value less than or equal to
* 0x7ffffff (see CP Commands and Utilities Reference).
*/
#define MAX_DCSS_ADDR (512UL * SZ_1G)
/* possible values for segment type as returned by segment_info */
#define SEG_TYPE_SW 0
#define SEG_TYPE_EW 1
#define SEG_TYPE_SR 2
#define SEG_TYPE_ER 3
#define SEG_TYPE_SN 4
#define SEG_TYPE_EN 5
#define SEG_TYPE_SC 6
#define SEG_TYPE_EWEN 7
#define SEGMENT_SHARED 0
#define SEGMENT_EXCLUSIVE 1
int segment_load (char *name, int segtype, unsigned long *addr, unsigned long *length);
void segment_unload(char *name);
void segment_save(char *name);
int segment_type (char* name);
int segment_modify_shared (char *name, int do_nonshared);
void segment_warning(int rc, char *seg_name);
#endif
#endif
@@ -0,0 +1,142 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 1999, 2009
*
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
#ifndef __ASM_FACILITY_H
#define __ASM_FACILITY_H
#include <asm/facility-defs.h>
#include <linux/minmax.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/preempt.h>
#include <asm/alternative.h>
#include <asm/lowcore.h>
#define MAX_FACILITY_BIT (sizeof(stfle_fac_list) * 8)
extern u64 stfle_fac_list[16];
static inline void __set_facility(unsigned long nr, void *facilities)
{
unsigned char *ptr = (unsigned char *) facilities;
if (nr >= MAX_FACILITY_BIT)
return;
ptr[nr >> 3] |= 0x80 >> (nr & 7);
}
static inline void __clear_facility(unsigned long nr, void *facilities)
{
unsigned char *ptr = (unsigned char *) facilities;
if (nr >= MAX_FACILITY_BIT)
return;
ptr[nr >> 3] &= ~(0x80 >> (nr & 7));
}
static __always_inline bool __test_facility(unsigned long nr, void *facilities)
{
unsigned char *ptr;
if (nr >= MAX_FACILITY_BIT)
return false;
ptr = (unsigned char *) facilities + (nr >> 3);
return (*ptr & (0x80 >> (nr & 7))) != 0;
}
/*
* __test_facility_constant() generates a single instruction branch. If the
* tested facility is available (likely) the branch is patched into a nop.
*
* Do not use this function unless you know what you are doing. All users are
* supposed to use test_facility() which will do the right thing.
*/
static __always_inline bool __test_facility_constant(unsigned long nr)
{
asm goto(
ALTERNATIVE("brcl 15,%l[l_no]", "brcl 0,0", ALT_FACILITY(%[nr]))
:
: [nr] "i" (nr)
:
: l_no);
return true;
l_no:
return false;
}
/*
* The test_facility function uses the bit ordering where the MSB is bit 0.
* That makes it easier to query facility bits with the bit number as
* documented in the Principles of Operation.
*/
static __always_inline bool test_facility(unsigned long nr)
{
unsigned long facilities_als[] = { FACILITIES_ALS };
if (!__is_defined(__DECOMPRESSOR) && __builtin_constant_p(nr)) {
if (nr < sizeof(facilities_als) * 8) {
if (__test_facility(nr, &facilities_als))
return true;
}
return __test_facility_constant(nr);
}
return __test_facility(nr, &stfle_fac_list);
}
static inline unsigned long __stfle_asm(u64 *fac_list, int size)
{
unsigned long reg0 = size - 1;
asm volatile(
" lgr 0,%[reg0]\n"
" .insn s,0xb2b00000,%[list]\n" /* stfle */
" lgr %[reg0],0\n"
: [reg0] "+&d" (reg0), [list] "+Q" (*fac_list)
:
: "memory", "cc", "0");
return reg0;
}
/**
* stfle - Store facility list extended
* @fac_list: array where facility list can be stored
* @size: size of passed in array in double words
*/
static inline void __stfle(u64 *fac_list, int size)
{
unsigned long nr;
u32 stfl_fac_list;
asm volatile(
" stfl 0(0)\n"
: "=m" (get_lowcore()->stfl_fac_list));
stfl_fac_list = get_lowcore()->stfl_fac_list;
memcpy(fac_list, &stfl_fac_list, 4);
nr = 4; /* bytes stored by stfl */
if (stfl_fac_list & 0x01000000) {
/* More facility bits available with stfle */
nr = __stfle_asm(fac_list, size);
nr = min_t(unsigned long, (nr + 1) * 8, size * 8);
}
memset((char *)fac_list + nr, 0, size * 8 - nr);
}
static inline void stfle(u64 *fac_list, int size)
{
preempt_disable();
__stfle(fac_list, size);
preempt_enable();
}
/**
* stfle_size - Actual size of the facility list as specified by stfle
* (number of double words)
*/
unsigned int stfle_size(void);
#endif /* __ASM_FACILITY_H */
+28
View File
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 1999, 2023
*/
#ifndef _ASM_S390_FAULT_H
#define _ASM_S390_FAULT_H
union teid {
unsigned long val;
struct {
unsigned long addr : 52; /* Translation-exception Address */
unsigned long fsi : 2; /* Access Exception Fetch/Store Indication */
unsigned long : 2;
unsigned long b56 : 1;
unsigned long : 3;
unsigned long b60 : 1;
unsigned long b61 : 1;
unsigned long as : 2; /* ASCE Identifier */
};
};
enum {
TEID_FSI_UNKNOWN = 0, /* Unknown whether fetch or store */
TEID_FSI_STORE = 1, /* Exception was due to store operation */
TEID_FSI_FETCH = 2 /* Exception was due to fetch operation */
};
#endif /* _ASM_S390_FAULT_H */
+313
View File
@@ -0,0 +1,313 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Functions for assembling fcx enabled I/O control blocks.
*
* Copyright IBM Corp. 2008
* Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
*/
#ifndef _ASM_S390_FCX_H
#define _ASM_S390_FCX_H
#include <linux/types.h>
#include <asm/dma-types.h>
#define TCW_FORMAT_DEFAULT 0
#define TCW_TIDAW_FORMAT_DEFAULT 0
#define TCW_FLAGS_INPUT_TIDA (1 << (23 - 5))
#define TCW_FLAGS_TCCB_TIDA (1 << (23 - 6))
#define TCW_FLAGS_OUTPUT_TIDA (1 << (23 - 7))
#define TCW_FLAGS_TIDAW_FORMAT(x) ((x) & 3) << (23 - 9)
#define TCW_FLAGS_GET_TIDAW_FORMAT(x) (((x) >> (23 - 9)) & 3)
/**
* struct tcw - Transport Control Word (TCW)
* @format: TCW format
* @flags: TCW flags
* @tccbl: Transport-Command-Control-Block Length
* @r: Read Operations
* @w: Write Operations
* @output: Output-Data Address
* @input: Input-Data Address
* @tsb: Transport-Status-Block Address
* @tccb: Transport-Command-Control-Block Address
* @output_count: Output Count
* @input_count: Input Count
* @intrg: Interrogate TCW Address
*/
struct tcw {
u32 format:2;
u32 :6;
u32 flags:24;
u32 :8;
u32 tccbl:6;
u32 r:1;
u32 w:1;
u32 :16;
dma64_t output;
dma64_t input;
dma64_t tsb;
dma64_t tccb;
u32 output_count;
u32 input_count;
u32 :32;
u32 :32;
u32 :32;
dma32_t intrg;
} __attribute__ ((packed, aligned(64)));
#define TIDAW_FLAGS_LAST (1 << (7 - 0))
#define TIDAW_FLAGS_SKIP (1 << (7 - 1))
#define TIDAW_FLAGS_DATA_INT (1 << (7 - 2))
#define TIDAW_FLAGS_TTIC (1 << (7 - 3))
#define TIDAW_FLAGS_INSERT_CBC (1 << (7 - 4))
/**
* struct tidaw - Transport-Indirect-Addressing Word (TIDAW)
* @flags: TIDAW flags. Can be an arithmetic OR of the following constants:
* %TIDAW_FLAGS_LAST, %TIDAW_FLAGS_SKIP, %TIDAW_FLAGS_DATA_INT,
* %TIDAW_FLAGS_TTIC, %TIDAW_FLAGS_INSERT_CBC
* @count: Count
* @addr: Address
*/
struct tidaw {
u32 flags:8;
u32 :24;
u32 count;
dma64_t addr;
} __attribute__ ((packed, aligned(16)));
/**
* struct tsa_iostat - I/O-Status Transport-Status Area (IO-Stat TSA)
* @dev_time: Device Time
* @def_time: Defer Time
* @queue_time: Queue Time
* @dev_busy_time: Device-Busy Time
* @dev_act_time: Device-Active-Only Time
* @sense: Sense Data (if present)
*/
struct tsa_iostat {
u32 dev_time;
u32 def_time;
u32 queue_time;
u32 dev_busy_time;
u32 dev_act_time;
u8 sense[32];
} __attribute__ ((packed));
/**
* struct tsa_ddpcs - Device-Detected-Program-Check Transport-Status Area (DDPC TSA)
* @rc: Reason Code
* @rcq: Reason Code Qualifier
* @sense: Sense Data (if present)
*/
struct tsa_ddpc {
u32 :24;
u32 rc:8;
u8 rcq[16];
u8 sense[32];
} __attribute__ ((packed));
#define TSA_INTRG_FLAGS_CU_STATE_VALID (1 << (7 - 0))
#define TSA_INTRG_FLAGS_DEV_STATE_VALID (1 << (7 - 1))
#define TSA_INTRG_FLAGS_OP_STATE_VALID (1 << (7 - 2))
/**
* struct tsa_intrg - Interrogate Transport-Status Area (Intrg. TSA)
* @format: Format
* @flags: Flags. Can be an arithmetic OR of the following constants:
* %TSA_INTRG_FLAGS_CU_STATE_VALID, %TSA_INTRG_FLAGS_DEV_STATE_VALID,
* %TSA_INTRG_FLAGS_OP_STATE_VALID
* @cu_state: Controle-Unit State
* @dev_state: Device State
* @op_state: Operation State
* @sd_info: State-Dependent Information
* @dl_id: Device-Level Identifier
* @dd_data: Device-Dependent Data
*/
struct tsa_intrg {
u32 format:8;
u32 flags:8;
u32 cu_state:8;
u32 dev_state:8;
u32 op_state:8;
u32 :24;
u8 sd_info[12];
u32 dl_id;
u8 dd_data[28];
} __attribute__ ((packed));
#define TSB_FORMAT_NONE 0
#define TSB_FORMAT_IOSTAT 1
#define TSB_FORMAT_DDPC 2
#define TSB_FORMAT_INTRG 3
#define TSB_FLAGS_DCW_OFFSET_VALID (1 << (7 - 0))
#define TSB_FLAGS_COUNT_VALID (1 << (7 - 1))
#define TSB_FLAGS_CACHE_MISS (1 << (7 - 2))
#define TSB_FLAGS_TIME_VALID (1 << (7 - 3))
#define TSB_FLAGS_FORMAT(x) ((x) & 7)
#define TSB_FORMAT(t) ((t)->flags & 7)
/**
* struct tsb - Transport-Status Block (TSB)
* @length: Length
* @flags: Flags. Can be an arithmetic OR of the following constants:
* %TSB_FLAGS_DCW_OFFSET_VALID, %TSB_FLAGS_COUNT_VALID, %TSB_FLAGS_CACHE_MISS,
* %TSB_FLAGS_TIME_VALID
* @dcw_offset: DCW Offset
* @count: Count
* @tsa: Transport-Status-Area
*/
struct tsb {
u32 length:8;
u32 flags:8;
u32 dcw_offset:16;
u32 count;
u32 :32;
union {
struct tsa_iostat iostat;
struct tsa_ddpc ddpc;
struct tsa_intrg intrg;
} __attribute__ ((packed)) tsa;
} __attribute__ ((packed, aligned(8)));
#define DCW_INTRG_FORMAT_DEFAULT 0
#define DCW_INTRG_RC_UNSPECIFIED 0
#define DCW_INTRG_RC_TIMEOUT 1
#define DCW_INTRG_RCQ_UNSPECIFIED 0
#define DCW_INTRG_RCQ_PRIMARY 1
#define DCW_INTRG_RCQ_SECONDARY 2
#define DCW_INTRG_FLAGS_MPM (1 << (7 - 0))
#define DCW_INTRG_FLAGS_PPR (1 << (7 - 1))
#define DCW_INTRG_FLAGS_CRIT (1 << (7 - 2))
/**
* struct dcw_intrg_data - Interrogate DCW data
* @format: Format. Should be %DCW_INTRG_FORMAT_DEFAULT
* @rc: Reason Code. Can be one of %DCW_INTRG_RC_UNSPECIFIED,
* %DCW_INTRG_RC_TIMEOUT
* @rcq: Reason Code Qualifier: Can be one of %DCW_INTRG_RCQ_UNSPECIFIED,
* %DCW_INTRG_RCQ_PRIMARY, %DCW_INTRG_RCQ_SECONDARY
* @lpm: Logical-Path Mask
* @pam: Path-Available Mask
* @pim: Path-Installed Mask
* @timeout: Timeout
* @flags: Flags. Can be an arithmetic OR of %DCW_INTRG_FLAGS_MPM,
* %DCW_INTRG_FLAGS_PPR, %DCW_INTRG_FLAGS_CRIT
* @time: Time
* @prog_id: Program Identifier
* @prog_data: Program-Dependent Data
*/
struct dcw_intrg_data {
u32 format:8;
u32 rc:8;
u32 rcq:8;
u32 lpm:8;
u32 pam:8;
u32 pim:8;
u32 timeout:16;
u32 flags:8;
u32 :24;
u32 :32;
u64 time;
u64 prog_id;
u8 prog_data[];
} __attribute__ ((packed));
#define DCW_FLAGS_CC (1 << (7 - 1))
#define DCW_CMD_WRITE 0x01
#define DCW_CMD_READ 0x02
#define DCW_CMD_CONTROL 0x03
#define DCW_CMD_SENSE 0x04
#define DCW_CMD_SENSE_ID 0xe4
#define DCW_CMD_INTRG 0x40
/**
* struct dcw - Device-Command Word (DCW)
* @cmd: Command Code. Can be one of %DCW_CMD_WRITE, %DCW_CMD_READ,
* %DCW_CMD_CONTROL, %DCW_CMD_SENSE, %DCW_CMD_SENSE_ID, %DCW_CMD_INTRG
* @flags: Flags. Can be an arithmetic OR of %DCW_FLAGS_CC
* @cd_count: Control-Data Count
* @count: Count
* @cd: Control Data
*/
struct dcw {
u32 cmd:8;
u32 flags:8;
u32 :8;
u32 cd_count:8;
u32 count;
u8 cd[];
} __attribute__ ((packed));
#define TCCB_FORMAT_DEFAULT 0x7f
#define TCCB_MAX_DCW 30
#define TCCB_MAX_SIZE (sizeof(struct tccb_tcah) + \
TCCB_MAX_DCW * sizeof(struct dcw) + \
sizeof(struct tccb_tcat))
#define TCCB_SAC_DEFAULT 0x1ffe
#define TCCB_SAC_INTRG 0x1fff
/**
* struct tccb_tcah - Transport-Command-Area Header (TCAH)
* @format: Format. Should be %TCCB_FORMAT_DEFAULT
* @tcal: Transport-Command-Area Length
* @sac: Service-Action Code. Can be one of %TCCB_SAC_DEFAULT, %TCCB_SAC_INTRG
* @prio: Priority
*/
struct tccb_tcah {
u32 format:8;
u32 :24;
u32 :24;
u32 tcal:8;
u32 sac:16;
u32 :8;
u32 prio:8;
u32 :32;
} __attribute__ ((packed));
/**
* struct tccb_tcat - Transport-Command-Area Trailer (TCAT)
* @count: Transport Count
*/
struct tccb_tcat {
u32 :32;
u32 count;
} __attribute__ ((packed));
/**
* struct tccb - (partial) Transport-Command-Control Block (TCCB)
* @tcah: TCAH
* @tca: Transport-Command Area
*/
struct tccb {
struct tccb_tcah tcah;
u8 tca[];
} __attribute__ ((packed, aligned(8)));
struct tcw *tcw_get_intrg(struct tcw *tcw);
void *tcw_get_data(struct tcw *tcw);
struct tccb *tcw_get_tccb(struct tcw *tcw);
struct tsb *tcw_get_tsb(struct tcw *tcw);
void tcw_init(struct tcw *tcw, int r, int w);
void tcw_finalize(struct tcw *tcw, int num_tidaws);
void tcw_set_intrg(struct tcw *tcw, struct tcw *intrg_tcw);
void tcw_set_data(struct tcw *tcw, void *data, int use_tidal);
void tcw_set_tccb(struct tcw *tcw, struct tccb *tccb);
void tcw_set_tsb(struct tcw *tcw, struct tsb *tsb);
void tccb_init(struct tccb *tccb, size_t tccb_size, u32 sac);
void tsb_init(struct tsb *tsb);
struct dcw *tccb_add_dcw(struct tccb *tccb, size_t tccb_size, u8 cmd, u8 flags,
void *cd, u8 cd_count, u32 count);
struct tidaw *tcw_add_tidaw(struct tcw *tcw, int num_tidaws, u8 flags,
void *addr, u32 count);
#endif /* _ASM_S390_FCX_H */
@@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_FPROBE_H
#define _ASM_S390_FPROBE_H
#include <asm-generic/fprobe.h>
#undef FPROBE_HEADER_MSB_PATTERN
#define FPROBE_HEADER_MSB_PATTERN 0
#endif /* _ASM_S390_FPROBE_H */
@@ -0,0 +1,582 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Support for Vector Instructions
*
* Assembler macros to generate .byte/.word code for particular
* vector instructions that are supported by recent binutils (>= 2.26) only.
*
* Copyright IBM Corp. 2015
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
*/
#ifndef __ASM_S390_FPU_INSN_ASM_H
#define __ASM_S390_FPU_INSN_ASM_H
#ifndef __ASM_S390_FPU_INSN_H
#error only <asm/fpu-insn.h> can be included directly
#endif
#include <asm/insn-common-asm.h>
#ifdef __ASSEMBLER__
/* RXB - Compute most significant bit used vector registers
*
* @rxb: Operand to store computed RXB value
* @v1: Vector register designated operand whose MSB is stored in
* RXB bit 0 (instruction bit 36) and whose remaining bits
* are stored in instruction bits 8-11.
* @v2: Vector register designated operand whose MSB is stored in
* RXB bit 1 (instruction bit 37) and whose remaining bits
* are stored in instruction bits 12-15.
* @v3: Vector register designated operand whose MSB is stored in
* RXB bit 2 (instruction bit 38) and whose remaining bits
* are stored in instruction bits 16-19.
* @v4: Vector register designated operand whose MSB is stored in
* RXB bit 3 (instruction bit 39) and whose remaining bits
* are stored in instruction bits 32-35.
*
* Note: In most vector instruction formats [1] V1, V2, V3, and V4 directly
* correspond to @v1, @v2, @v3, and @v4. But there are exceptions, such as but
* not limited to the vector instruction formats VRR-g, VRR-h, VRS-a, VRS-d,
* and VSI.
*
* [1] IBM z/Architecture Principles of Operation, chapter "Program
* Execution, section "Instructions", subsection "Instruction Formats".
*/
.macro RXB rxb v1 v2=0 v3=0 v4=0
\rxb = 0
.if \v1 & 0x10
\rxb = \rxb | 0x08
.endif
.if \v2 & 0x10
\rxb = \rxb | 0x04
.endif
.if \v3 & 0x10
\rxb = \rxb | 0x02
.endif
.if \v4 & 0x10
\rxb = \rxb | 0x01
.endif
.endm
/* MRXB - Generate Element Size Control and RXB value
*
* @m: Element size control
* @v1: First vector register designated operand (for RXB)
* @v2: Second vector register designated operand (for RXB)
* @v3: Third vector register designated operand (for RXB)
* @v4: Fourth vector register designated operand (for RXB)
*
* Note: For @v1, @v2, @v3, and @v4 also refer to the RXB macro
* description for further details.
*/
.macro MRXB m v1 v2=0 v3=0 v4=0
rxb = 0
RXB rxb, \v1, \v2, \v3, \v4
.byte (\m << 4) | rxb
.endm
/* MRXBOPC - Generate Element Size Control, RXB, and final Opcode fields
*
* @m: Element size control
* @opc: Opcode
* @v1: First vector register designated operand (for RXB)
* @v2: Second vector register designated operand (for RXB)
* @v3: Third vector register designated operand (for RXB)
* @v4: Fourth vector register designated operand (for RXB)
*
* Note: For @v1, @v2, @v3, and @v4 also refer to the RXB macro
* description for further details.
*/
.macro MRXBOPC m opc v1 v2=0 v3=0 v4=0
MRXB \m, \v1, \v2, \v3, \v4
.byte \opc
.endm
/* Vector support instructions */
/* VECTOR GENERATE BYTE MASK */
.macro VGBM vr imm2
VX_NUM v1, \vr
.word (0xE700 | ((v1&15) << 4))
.word \imm2
MRXBOPC 0, 0x44, v1
.endm
.macro VZERO vxr
VGBM \vxr, 0
.endm
.macro VONE vxr
VGBM \vxr, 0xFFFF
.endm
/* VECTOR LOAD VR ELEMENT FROM GR */
.macro VLVG v, gr, disp, m
VX_NUM v1, \v
GR_NUM b2, "%r0"
GR_NUM r3, \gr
.word 0xE700 | ((v1&15) << 4) | r3
.word (b2 << 12) | (\disp)
MRXBOPC \m, 0x22, v1
.endm
.macro VLVGB v, gr, index, base
VLVG \v, \gr, \index, \base, 0
.endm
.macro VLVGH v, gr, index
VLVG \v, \gr, \index, 1
.endm
.macro VLVGF v, gr, index
VLVG \v, \gr, \index, 2
.endm
.macro VLVGG v, gr, index
VLVG \v, \gr, \index, 3
.endm
/* VECTOR LOAD REGISTER */
.macro VLR v1, v2
VX_NUM v1, \v1
VX_NUM v2, \v2
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word 0
MRXBOPC 0, 0x56, v1, v2
.endm
/* VECTOR LOAD */
.macro VL v, disp, index="%r0", base
VX_NUM v1, \v
GR_NUM x2, \index
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | x2
.word (b2 << 12) | (\disp)
MRXBOPC 0, 0x06, v1
.endm
/* VECTOR LOAD ELEMENT */
.macro VLEx vr1, disp, index="%r0", base, m3, opc
VX_NUM v1, \vr1
GR_NUM x2, \index
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | x2
.word (b2 << 12) | (\disp)
MRXBOPC \m3, \opc, v1
.endm
.macro VLEB vr1, disp, index="%r0", base, m3
VLEx \vr1, \disp, \index, \base, \m3, 0x00
.endm
.macro VLEH vr1, disp, index="%r0", base, m3
VLEx \vr1, \disp, \index, \base, \m3, 0x01
.endm
.macro VLEF vr1, disp, index="%r0", base, m3
VLEx \vr1, \disp, \index, \base, \m3, 0x03
.endm
.macro VLEG vr1, disp, index="%r0", base, m3
VLEx \vr1, \disp, \index, \base, \m3, 0x02
.endm
/* VECTOR LOAD ELEMENT IMMEDIATE */
.macro VLEIx vr1, imm2, m3, opc
VX_NUM v1, \vr1
.word 0xE700 | ((v1&15) << 4)
.word \imm2
MRXBOPC \m3, \opc, v1
.endm
.macro VLEIB vr1, imm2, index
VLEIx \vr1, \imm2, \index, 0x40
.endm
.macro VLEIH vr1, imm2, index
VLEIx \vr1, \imm2, \index, 0x41
.endm
.macro VLEIF vr1, imm2, index
VLEIx \vr1, \imm2, \index, 0x43
.endm
.macro VLEIG vr1, imm2, index
VLEIx \vr1, \imm2, \index, 0x42
.endm
/* VECTOR LOAD GR FROM VR ELEMENT */
.macro VLGV gr, vr, disp, base="%r0", m
GR_NUM r1, \gr
GR_NUM b2, \base
VX_NUM v3, \vr
.word 0xE700 | (r1 << 4) | (v3&15)
.word (b2 << 12) | (\disp)
MRXBOPC \m, 0x21, 0, v3
.endm
.macro VLGVB gr, vr, disp, base="%r0"
VLGV \gr, \vr, \disp, \base, 0
.endm
.macro VLGVH gr, vr, disp, base="%r0"
VLGV \gr, \vr, \disp, \base, 1
.endm
.macro VLGVF gr, vr, disp, base="%r0"
VLGV \gr, \vr, \disp, \base, 2
.endm
.macro VLGVG gr, vr, disp, base="%r0"
VLGV \gr, \vr, \disp, \base, 3
.endm
/* VECTOR LOAD MULTIPLE */
.macro VLM vfrom, vto, disp, base, hint=3
VX_NUM v1, \vfrom
VX_NUM v3, \vto
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | (v3&15)
.word (b2 << 12) | (\disp)
MRXBOPC \hint, 0x36, v1, v3
.endm
/* VECTOR STORE */
.macro VST vr1, disp, index="%r0", base
VX_NUM v1, \vr1
GR_NUM x2, \index
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | (x2&15)
.word (b2 << 12) | (\disp)
MRXBOPC 0, 0x0E, v1
.endm
/* VECTOR STORE BYTE REVERSED ELEMENTS */
.macro VSTBR vr1, disp, index="%r0", base, m
VX_NUM v1, \vr1
GR_NUM x2, \index
GR_NUM b2, \base
.word 0xE600 | ((v1&15) << 4) | (x2&15)
.word (b2 << 12) | (\disp)
MRXBOPC \m, 0x0E, v1
.endm
.macro VSTBRH vr1, disp, index="%r0", base
VSTBR \vr1, \disp, \index, \base, 1
.endm
.macro VSTBRF vr1, disp, index="%r0", base
VSTBR \vr1, \disp, \index, \base, 2
.endm
.macro VSTBRG vr1, disp, index="%r0", base
VSTBR \vr1, \disp, \index, \base, 3
.endm
.macro VSTBRQ vr1, disp, index="%r0", base
VSTBR \vr1, \disp, \index, \base, 4
.endm
/* VECTOR STORE MULTIPLE */
.macro VSTM vfrom, vto, disp, base, hint=3
VX_NUM v1, \vfrom
VX_NUM v3, \vto
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | (v3&15)
.word (b2 << 12) | (\disp)
MRXBOPC \hint, 0x3E, v1, v3
.endm
/* VECTOR PERMUTE */
.macro VPERM vr1, vr2, vr3, vr4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
VX_NUM v4, \vr4
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC (v4&15), 0x8C, v1, v2, v3, v4
.endm
/* VECTOR UNPACK LOGICAL LOW */
.macro VUPLL vr1, vr2, m3
VX_NUM v1, \vr1
VX_NUM v2, \vr2
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word 0x0000
MRXBOPC \m3, 0xD4, v1, v2
.endm
.macro VUPLLB vr1, vr2
VUPLL \vr1, \vr2, 0
.endm
.macro VUPLLH vr1, vr2
VUPLL \vr1, \vr2, 1
.endm
.macro VUPLLF vr1, vr2
VUPLL \vr1, \vr2, 2
.endm
/* VECTOR PERMUTE DOUBLEWORD IMMEDIATE */
.macro VPDI vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0x84, v1, v2, v3
.endm
/* VECTOR REPLICATE */
.macro VREP vr1, vr3, imm2, m4
VX_NUM v1, \vr1
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v3&15)
.word \imm2
MRXBOPC \m4, 0x4D, v1, v3
.endm
.macro VREPB vr1, vr3, imm2
VREP \vr1, \vr3, \imm2, 0
.endm
.macro VREPH vr1, vr3, imm2
VREP \vr1, \vr3, \imm2, 1
.endm
.macro VREPF vr1, vr3, imm2
VREP \vr1, \vr3, \imm2, 2
.endm
.macro VREPG vr1, vr3, imm2
VREP \vr1, \vr3, \imm2, 3
.endm
/* VECTOR MERGE HIGH */
.macro VMRH vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0x61, v1, v2, v3
.endm
.macro VMRHB vr1, vr2, vr3
VMRH \vr1, \vr2, \vr3, 0
.endm
.macro VMRHH vr1, vr2, vr3
VMRH \vr1, \vr2, \vr3, 1
.endm
.macro VMRHF vr1, vr2, vr3
VMRH \vr1, \vr2, \vr3, 2
.endm
.macro VMRHG vr1, vr2, vr3
VMRH \vr1, \vr2, \vr3, 3
.endm
/* VECTOR MERGE LOW */
.macro VMRL vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0x60, v1, v2, v3
.endm
.macro VMRLB vr1, vr2, vr3
VMRL \vr1, \vr2, \vr3, 0
.endm
.macro VMRLH vr1, vr2, vr3
VMRL \vr1, \vr2, \vr3, 1
.endm
.macro VMRLF vr1, vr2, vr3
VMRL \vr1, \vr2, \vr3, 2
.endm
.macro VMRLG vr1, vr2, vr3
VMRL \vr1, \vr2, \vr3, 3
.endm
/* VECTOR LOAD WITH LENGTH */
.macro VLL v, gr, disp, base
VX_NUM v1, \v
GR_NUM b2, \base
GR_NUM r3, \gr
.word 0xE700 | ((v1&15) << 4) | r3
.word (b2 << 12) | (\disp)
MRXBOPC 0, 0x37, v1
.endm
/* VECTOR STORE WITH LENGTH */
.macro VSTL v, gr, disp, base
VX_NUM v1, \v
GR_NUM b2, \base
GR_NUM r3, \gr
.word 0xE700 | ((v1&15) << 4) | r3
.word (b2 << 12) | (\disp)
MRXBOPC 0, 0x3f, v1
.endm
/* Vector integer instructions */
/* VECTOR AND */
.macro VN vr1, vr2, vr3
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC 0, 0x68, v1, v2, v3
.endm
/* VECTOR CHECKSUM */
.macro VCKSM vr1, vr2, vr3
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC 0, 0x66, v1, v2, v3
.endm
/* VECTOR EXCLUSIVE OR */
.macro VX vr1, vr2, vr3
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC 0, 0x6D, v1, v2, v3
.endm
/* VECTOR GALOIS FIELD MULTIPLY SUM */
.macro VGFM vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0xB4, v1, v2, v3
.endm
.macro VGFMB vr1, vr2, vr3
VGFM \vr1, \vr2, \vr3, 0
.endm
.macro VGFMH vr1, vr2, vr3
VGFM \vr1, \vr2, \vr3, 1
.endm
.macro VGFMF vr1, vr2, vr3
VGFM \vr1, \vr2, \vr3, 2
.endm
.macro VGFMG vr1, vr2, vr3
VGFM \vr1, \vr2, \vr3, 3
.endm
/* VECTOR GALOIS FIELD MULTIPLY SUM AND ACCUMULATE */
.macro VGFMA vr1, vr2, vr3, vr4, m5
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
VX_NUM v4, \vr4
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12) | (\m5 << 8)
MRXBOPC (v4&15), 0xBC, v1, v2, v3, v4
.endm
.macro VGFMAB vr1, vr2, vr3, vr4
VGFMA \vr1, \vr2, \vr3, \vr4, 0
.endm
.macro VGFMAH vr1, vr2, vr3, vr4
VGFMA \vr1, \vr2, \vr3, \vr4, 1
.endm
.macro VGFMAF vr1, vr2, vr3, vr4
VGFMA \vr1, \vr2, \vr3, \vr4, 2
.endm
.macro VGFMAG vr1, vr2, vr3, vr4
VGFMA \vr1, \vr2, \vr3, \vr4, 3
.endm
/* VECTOR SHIFT RIGHT LOGICAL BY BYTE */
.macro VSRLB vr1, vr2, vr3
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC 0, 0x7D, v1, v2, v3
.endm
/* VECTOR REPLICATE IMMEDIATE */
.macro VREPI vr1, imm2, m3
VX_NUM v1, \vr1
.word 0xE700 | ((v1&15) << 4)
.word \imm2
MRXBOPC \m3, 0x45, v1
.endm
.macro VREPIB vr1, imm2
VREPI \vr1, \imm2, 0
.endm
.macro VREPIH vr1, imm2
VREPI \vr1, \imm2, 1
.endm
.macro VREPIF vr1, imm2
VREPI \vr1, \imm2, 2
.endm
.macro VREPIG vr1, imm2
VREP \vr1, \imm2, 3
.endm
/* VECTOR ADD */
.macro VA vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0xF3, v1, v2, v3
.endm
.macro VAB vr1, vr2, vr3
VA \vr1, \vr2, \vr3, 0
.endm
.macro VAH vr1, vr2, vr3
VA \vr1, \vr2, \vr3, 1
.endm
.macro VAF vr1, vr2, vr3
VA \vr1, \vr2, \vr3, 2
.endm
.macro VAG vr1, vr2, vr3
VA \vr1, \vr2, \vr3, 3
.endm
.macro VAQ vr1, vr2, vr3
VA \vr1, \vr2, \vr3, 4
.endm
/* VECTOR ELEMENT SHIFT RIGHT ARITHMETIC */
.macro VESRAV vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0x7A, v1, v2, v3
.endm
.macro VESRAVB vr1, vr2, vr3
VESRAV \vr1, \vr2, \vr3, 0
.endm
.macro VESRAVH vr1, vr2, vr3
VESRAV \vr1, \vr2, \vr3, 1
.endm
.macro VESRAVF vr1, vr2, vr3
VESRAV \vr1, \vr2, \vr3, 2
.endm
.macro VESRAVG vr1, vr2, vr3
VESRAV \vr1, \vr2, \vr3, 3
.endm
/* VECTOR ELEMENT ROTATE LEFT LOGICAL */
.macro VERLL vr1, vr3, disp, base="%r0", m4
VX_NUM v1, \vr1
VX_NUM v3, \vr3
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | (v3&15)
.word (b2 << 12) | (\disp)
MRXBOPC \m4, 0x33, v1, v3
.endm
.macro VERLLB vr1, vr3, disp, base="%r0"
VERLL \vr1, \vr3, \disp, \base, 0
.endm
.macro VERLLH vr1, vr3, disp, base="%r0"
VERLL \vr1, \vr3, \disp, \base, 1
.endm
.macro VERLLF vr1, vr3, disp, base="%r0"
VERLL \vr1, \vr3, \disp, \base, 2
.endm
.macro VERLLG vr1, vr3, disp, base="%r0"
VERLL \vr1, \vr3, \disp, \base, 3
.endm
/* VECTOR SHIFT LEFT DOUBLE BY BYTE */
.macro VSLDB vr1, vr2, vr3, imm4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12) | (\imm4)
MRXBOPC 0, 0x77, v1, v2, v3
.endm
#endif /* __ASSEMBLER__ */
#endif /* __ASM_S390_FPU_INSN_ASM_H */
@@ -0,0 +1,483 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Support for Floating Point and Vector Instructions
*
*/
#ifndef __ASM_S390_FPU_INSN_H
#define __ASM_S390_FPU_INSN_H
#include <asm/fpu-insn-asm.h>
#ifndef __ASSEMBLER__
#include <linux/instrumented.h>
#include <linux/kmsan.h>
#include <asm/asm-extable.h>
asm(".include \"asm/insn-common-asm.h\"\n");
asm(".include \"asm/fpu-insn-asm.h\"\n");
/*
* Various small helper functions, which can and should be used within
* kernel fpu code sections. Each function represents only one floating
* point or vector instruction (except for helper functions which require
* exception handling).
*
* This allows to use floating point and vector instructions like C
* functions, which has the advantage that all supporting code, like
* e.g. loops, can be written in easy to read C code.
*
* Each of the helper functions provides support for code instrumentation,
* like e.g. KASAN. Therefore instrumentation is also covered automatically
* when using these functions.
*
* In order to ensure that code generated with the helper functions stays
* within kernel fpu sections, which are guarded with kernel_fpu_begin()
* and kernel_fpu_end() calls, each function has a mandatory "memory"
* barrier.
*/
static __always_inline void fpu_cefbr(u8 f1, s32 val)
{
asm volatile("cefbr %[f1],%[val]"
:
: [f1] "I" (f1), [val] "d" (val)
: "memory");
}
static __always_inline unsigned long fpu_cgebr(u8 f2, u8 mode)
{
unsigned long val;
asm volatile("cgebr %[val],%[mode],%[f2]"
: [val] "=d" (val)
: [f2] "I" (f2), [mode] "I" (mode)
: "memory");
return val;
}
static __always_inline void fpu_debr(u8 f1, u8 f2)
{
asm volatile("debr %[f1],%[f2]"
:
: [f1] "I" (f1), [f2] "I" (f2)
: "memory");
}
static __always_inline void fpu_ld(unsigned short fpr, freg_t *reg)
{
instrument_read(reg, sizeof(*reg));
asm volatile("ld %[fpr],%[reg]"
:
: [fpr] "I" (fpr), [reg] "Q" (reg->ui)
: "memory");
}
static __always_inline void fpu_ldgr(u8 f1, u32 val)
{
asm volatile("ldgr %[f1],%[val]"
:
: [f1] "I" (f1), [val] "d" (val)
: "memory");
}
static __always_inline void fpu_lfpc(unsigned int *fpc)
{
instrument_read(fpc, sizeof(*fpc));
asm volatile("lfpc %[fpc]"
:
: [fpc] "Q" (*fpc)
: "memory");
}
/**
* fpu_lfpc_safe - Load floating point control register safely.
* @fpc: new value for floating point control register
*
* Load floating point control register. This may lead to an exception,
* since a saved value may have been modified by user space (ptrace,
* signal return, kvm registers) to an invalid value. In such a case
* set the floating point control register to zero.
*/
static inline void fpu_lfpc_safe(unsigned int *fpc)
{
instrument_read(fpc, sizeof(*fpc));
asm_inline volatile(
" lfpc %[fpc]\n"
"0: nopr %%r7\n"
EX_TABLE_FPC(0b, 0b)
:
: [fpc] "Q" (*fpc)
: "memory");
}
static __always_inline void fpu_std(unsigned short fpr, freg_t *reg)
{
instrument_write(reg, sizeof(*reg));
asm volatile("std %[fpr],%[reg]"
: [reg] "=Q" (reg->ui)
: [fpr] "I" (fpr)
: "memory");
}
static __always_inline void fpu_sfpc(unsigned int fpc)
{
asm volatile("sfpc %[fpc]"
:
: [fpc] "d" (fpc)
: "memory");
}
static __always_inline void fpu_stfpc(unsigned int *fpc)
{
instrument_write(fpc, sizeof(*fpc));
asm volatile("stfpc %[fpc]"
: [fpc] "=Q" (*fpc)
:
: "memory");
}
static __always_inline void fpu_vab(u8 v1, u8 v2, u8 v3)
{
asm volatile("VAB %[v1],%[v2],%[v3]"
:
: [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3)
: "memory");
}
static __always_inline void fpu_vcksm(u8 v1, u8 v2, u8 v3)
{
asm volatile("VCKSM %[v1],%[v2],%[v3]"
:
: [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3)
: "memory");
}
static __always_inline void fpu_vesravb(u8 v1, u8 v2, u8 v3)
{
asm volatile("VESRAVB %[v1],%[v2],%[v3]"
:
: [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3)
: "memory");
}
static __always_inline void fpu_vgfmag(u8 v1, u8 v2, u8 v3, u8 v4)
{
asm volatile("VGFMAG %[v1],%[v2],%[v3],%[v4]"
:
: [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3), [v4] "I" (v4)
: "memory");
}
static __always_inline void fpu_vgfmg(u8 v1, u8 v2, u8 v3)
{
asm volatile("VGFMG %[v1],%[v2],%[v3]"
:
: [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3)
: "memory");
}
#ifdef CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS
static __always_inline void fpu_vl(u8 v1, const void *vxr)
{
instrument_read(vxr, sizeof(__vector128));
asm volatile("VL %[v1],%O[vxr],,%R[vxr]"
:
: [vxr] "Q" (*(__vector128 *)vxr),
[v1] "I" (v1)
: "memory");
}
#else /* CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS */
static __always_inline void fpu_vl(u8 v1, const void *vxr)
{
instrument_read(vxr, sizeof(__vector128));
asm volatile(
" la 1,%[vxr]\n"
" VL %[v1],0,,1"
:
: [vxr] "R" (*(__vector128 *)vxr),
[v1] "I" (v1)
: "memory", "1");
}
#endif /* CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS */
static __always_inline void fpu_vleib(u8 v, s16 val, u8 index)
{
asm volatile("VLEIB %[v],%[val],%[index]"
:
: [v] "I" (v), [val] "K" (val), [index] "I" (index)
: "memory");
}
static __always_inline void fpu_vleig(u8 v, s16 val, u8 index)
{
asm volatile("VLEIG %[v],%[val],%[index]"
:
: [v] "I" (v), [val] "K" (val), [index] "I" (index)
: "memory");
}
static __always_inline u64 fpu_vlgvf(u8 v, u16 index)
{
u64 val;
asm volatile("VLGVF %[val],%[v],%[index]"
: [val] "=d" (val)
: [v] "I" (v), [index] "L" (index)
: "memory");
return val;
}
#ifdef CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS
static __always_inline void fpu_vll(u8 v1, u32 index, const void *vxr)
{
unsigned int size;
size = min(index + 1, sizeof(__vector128));
instrument_read(vxr, size);
asm volatile("VLL %[v1],%[index],%O[vxr],%R[vxr]"
:
: [vxr] "Q" (*(u8 *)vxr),
[index] "d" (index),
[v1] "I" (v1)
: "memory");
}
#else /* CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS */
static __always_inline void fpu_vll(u8 v1, u32 index, const void *vxr)
{
unsigned int size;
size = min(index + 1, sizeof(__vector128));
instrument_read(vxr, size);
asm volatile(
" la 1,%[vxr]\n"
" VLL %[v1],%[index],0,1"
:
: [vxr] "R" (*(u8 *)vxr),
[index] "d" (index),
[v1] "I" (v1)
: "memory", "1");
}
#endif /* CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS */
#ifdef CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS
#define fpu_vlm(_v1, _v3, _vxrs) \
({ \
unsigned int size = ((_v3) - (_v1) + 1) * sizeof(__vector128); \
struct { \
__vector128 _v[(_v3) - (_v1) + 1]; \
} *_v = (void *)(_vxrs); \
\
instrument_read(_v, size); \
asm volatile("VLM %[v1],%[v3],%O[vxrs],%R[vxrs]" \
: \
: [vxrs] "Q" (*_v), \
[v1] "I" (_v1), [v3] "I" (_v3) \
: "memory"); \
(_v3) - (_v1) + 1; \
})
#else /* CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS */
#define fpu_vlm(_v1, _v3, _vxrs) \
({ \
unsigned int size = ((_v3) - (_v1) + 1) * sizeof(__vector128); \
struct { \
__vector128 _v[(_v3) - (_v1) + 1]; \
} *_v = (void *)(_vxrs); \
\
instrument_read(_v, size); \
asm volatile( \
" la 1,%[vxrs]\n" \
" VLM %[v1],%[v3],0,1" \
: \
: [vxrs] "R" (*_v), \
[v1] "I" (_v1), [v3] "I" (_v3) \
: "memory", "1"); \
(_v3) - (_v1) + 1; \
})
#endif /* CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS */
static __always_inline void fpu_vlr(u8 v1, u8 v2)
{
asm volatile("VLR %[v1],%[v2]"
:
: [v1] "I" (v1), [v2] "I" (v2)
: "memory");
}
static __always_inline void fpu_vlvgf(u8 v, u32 val, u16 index)
{
asm volatile("VLVGF %[v],%[val],%[index]"
:
: [v] "I" (v), [val] "d" (val), [index] "L" (index)
: "memory");
}
static __always_inline void fpu_vn(u8 v1, u8 v2, u8 v3)
{
asm volatile("VN %[v1],%[v2],%[v3]"
:
: [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3)
: "memory");
}
static __always_inline void fpu_vperm(u8 v1, u8 v2, u8 v3, u8 v4)
{
asm volatile("VPERM %[v1],%[v2],%[v3],%[v4]"
:
: [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3), [v4] "I" (v4)
: "memory");
}
static __always_inline void fpu_vrepib(u8 v1, s16 i2)
{
asm volatile("VREPIB %[v1],%[i2]"
:
: [v1] "I" (v1), [i2] "K" (i2)
: "memory");
}
static __always_inline void fpu_vsrlb(u8 v1, u8 v2, u8 v3)
{
asm volatile("VSRLB %[v1],%[v2],%[v3]"
:
: [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3)
: "memory");
}
#ifdef CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS
static __always_inline void fpu_vst(u8 v1, const void *vxr)
{
instrument_write(vxr, sizeof(__vector128));
asm volatile("VST %[v1],%O[vxr],,%R[vxr]"
: [vxr] "=Q" (*(__vector128 *)vxr)
: [v1] "I" (v1)
: "memory");
}
#else /* CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS */
static __always_inline void fpu_vst(u8 v1, const void *vxr)
{
instrument_write(vxr, sizeof(__vector128));
asm volatile(
" la 1,%[vxr]\n"
" VST %[v1],0,,1"
: [vxr] "=R" (*(__vector128 *)vxr)
: [v1] "I" (v1)
: "memory", "1");
}
#endif /* CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS */
#ifdef CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS
static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr)
{
unsigned int size;
size = min(index + 1, sizeof(__vector128));
instrument_write(vxr, size);
asm volatile("VSTL %[v1],%[index],%O[vxr],%R[vxr]"
: [vxr] "=Q" (*(u8 *)vxr)
: [index] "d" (index), [v1] "I" (v1)
: "memory");
kmsan_unpoison_memory(vxr, size);
}
#else /* CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS */
static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr)
{
unsigned int size;
size = min(index + 1, sizeof(__vector128));
instrument_write(vxr, size);
asm volatile(
" la 1,%[vxr]\n"
" VSTL %[v1],%[index],0,1"
: [vxr] "=R" (*(u8 *)vxr)
: [index] "d" (index), [v1] "I" (v1)
: "memory", "1");
kmsan_unpoison_memory(vxr, size);
}
#endif /* CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS */
#ifdef CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS
#define fpu_vstm(_v1, _v3, _vxrs) \
({ \
unsigned int size = ((_v3) - (_v1) + 1) * sizeof(__vector128); \
struct { \
__vector128 _v[(_v3) - (_v1) + 1]; \
} *_v = (void *)(_vxrs); \
\
instrument_write(_v, size); \
asm volatile("VSTM %[v1],%[v3],%O[vxrs],%R[vxrs]" \
: [vxrs] "=Q" (*_v) \
: [v1] "I" (_v1), [v3] "I" (_v3) \
: "memory"); \
(_v3) - (_v1) + 1; \
})
#else /* CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS */
#define fpu_vstm(_v1, _v3, _vxrs) \
({ \
unsigned int size = ((_v3) - (_v1) + 1) * sizeof(__vector128); \
struct { \
__vector128 _v[(_v3) - (_v1) + 1]; \
} *_v = (void *)(_vxrs); \
\
instrument_write(_v, size); \
asm volatile( \
" la 1,%[vxrs]\n" \
" VSTM %[v1],%[v3],0,1" \
: [vxrs] "=R" (*_v) \
: [v1] "I" (_v1), [v3] "I" (_v3) \
: "memory", "1"); \
(_v3) - (_v1) + 1; \
})
#endif /* CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS */
static __always_inline void fpu_vupllf(u8 v1, u8 v2)
{
asm volatile("VUPLLF %[v1],%[v2]"
:
: [v1] "I" (v1), [v2] "I" (v2)
: "memory");
}
static __always_inline void fpu_vx(u8 v1, u8 v2, u8 v3)
{
asm volatile("VX %[v1],%[v2],%[v3]"
:
: [v1] "I" (v1), [v2] "I" (v2), [v3] "I" (v3)
: "memory");
}
static __always_inline void fpu_vzero(u8 v)
{
asm volatile("VZERO %[v]"
:
: [v] "I" (v)
: "memory");
}
#endif /* __ASSEMBLER__ */
#endif /* __ASM_S390_FPU_INSN_H */
@@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* FPU data structures
*
* Copyright IBM Corp. 2015
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
*/
#ifndef _ASM_S390_FPU_TYPES_H
#define _ASM_S390_FPU_TYPES_H
#include <asm/sigcontext.h>
struct fpu {
u32 fpc;
__vector128 vxrs[__NUM_VXRS] __aligned(8);
};
struct kernel_fpu_hdr {
int mask;
u32 fpc;
};
struct kernel_fpu {
struct kernel_fpu_hdr hdr;
__vector128 vxrs[] __aligned(8);
};
#define KERNEL_FPU_STRUCT(vxr_size) \
struct kernel_fpu_##vxr_size { \
struct kernel_fpu_hdr hdr; \
__vector128 vxrs[vxr_size] __aligned(8); \
}
KERNEL_FPU_STRUCT(8);
KERNEL_FPU_STRUCT(16);
KERNEL_FPU_STRUCT(32);
#define DECLARE_KERNEL_FPU_ONSTACK(vxr_size, name) \
struct kernel_fpu_##vxr_size name __uninitialized
#define DECLARE_KERNEL_FPU_ONSTACK8(name) \
DECLARE_KERNEL_FPU_ONSTACK(8, name)
#define DECLARE_KERNEL_FPU_ONSTACK16(name) \
DECLARE_KERNEL_FPU_ONSTACK(16, name)
#define DECLARE_KERNEL_FPU_ONSTACK32(name) \
DECLARE_KERNEL_FPU_ONSTACK(32, name)
#endif /* _ASM_S390_FPU_TYPES_H */
+290
View File
@@ -0,0 +1,290 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* In-kernel FPU support functions
*
*
* Consider these guidelines before using in-kernel FPU functions:
*
* 1. Use kernel_fpu_begin() and kernel_fpu_end() to enclose all in-kernel
* use of floating-point or vector registers and instructions.
*
* 2. For kernel_fpu_begin(), specify the vector register range you want to
* use with the KERNEL_VXR_* constants. Consider these usage guidelines:
*
* a) If your function typically runs in process-context, use the lower
* half of the vector registers, for example, specify KERNEL_VXR_LOW.
* b) If your function typically runs in soft-irq or hard-irq context,
* prefer using the upper half of the vector registers, for example,
* specify KERNEL_VXR_HIGH.
*
* If you adhere to these guidelines, an interrupted process context
* does not require to save and restore vector registers because of
* disjoint register ranges.
*
* Also note that the __kernel_fpu_begin()/__kernel_fpu_end() functions
* includes logic to save and restore up to 16 vector registers at once.
*
* 3. You can nest kernel_fpu_begin()/kernel_fpu_end() by using different
* struct kernel_fpu states. Vector registers that are in use by outer
* levels are saved and restored. You can minimize the save and restore
* effort by choosing disjoint vector register ranges.
*
* 5. To use vector floating-point instructions, specify the KERNEL_FPC
* flag to save and restore floating-point controls in addition to any
* vector register range.
*
* 6. To use floating-point registers and instructions only, specify the
* KERNEL_FPR flag. This flag triggers a save and restore of vector
* registers V0 to V15 and floating-point controls.
*
* Copyright IBM Corp. 2015
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
*/
#ifndef _ASM_S390_FPU_H
#define _ASM_S390_FPU_H
#include <linux/cpufeature.h>
#include <linux/processor.h>
#include <linux/preempt.h>
#include <linux/string.h>
#include <linux/sched.h>
#include <asm/sigcontext.h>
#include <asm/fpu-types.h>
#include <asm/fpu-insn.h>
enum {
KERNEL_FPC_BIT = 0,
KERNEL_VXR_V0V7_BIT,
KERNEL_VXR_V8V15_BIT,
KERNEL_VXR_V16V23_BIT,
KERNEL_VXR_V24V31_BIT,
};
#define KERNEL_FPC BIT(KERNEL_FPC_BIT)
#define KERNEL_VXR_V0V7 BIT(KERNEL_VXR_V0V7_BIT)
#define KERNEL_VXR_V8V15 BIT(KERNEL_VXR_V8V15_BIT)
#define KERNEL_VXR_V16V23 BIT(KERNEL_VXR_V16V23_BIT)
#define KERNEL_VXR_V24V31 BIT(KERNEL_VXR_V24V31_BIT)
#define KERNEL_VXR_LOW (KERNEL_VXR_V0V7 | KERNEL_VXR_V8V15)
#define KERNEL_VXR_MID (KERNEL_VXR_V8V15 | KERNEL_VXR_V16V23)
#define KERNEL_VXR_HIGH (KERNEL_VXR_V16V23 | KERNEL_VXR_V24V31)
#define KERNEL_VXR (KERNEL_VXR_LOW | KERNEL_VXR_HIGH)
#define KERNEL_FPR (KERNEL_FPC | KERNEL_VXR_LOW)
void load_fpu_state(struct fpu *state, int flags);
void save_fpu_state(struct fpu *state, int flags);
void __kernel_fpu_begin(struct kernel_fpu *state, int flags);
void __kernel_fpu_end(struct kernel_fpu *state, int flags);
static __always_inline void save_vx_regs(__vector128 *vxrs)
{
fpu_vstm(0, 15, &vxrs[0]);
fpu_vstm(16, 31, &vxrs[16]);
}
static __always_inline void load_vx_regs(__vector128 *vxrs)
{
fpu_vlm(0, 15, &vxrs[0]);
fpu_vlm(16, 31, &vxrs[16]);
}
static __always_inline void __save_fp_regs(freg_t *fprs, unsigned int offset)
{
fpu_std(0, &fprs[0 * offset]);
fpu_std(1, &fprs[1 * offset]);
fpu_std(2, &fprs[2 * offset]);
fpu_std(3, &fprs[3 * offset]);
fpu_std(4, &fprs[4 * offset]);
fpu_std(5, &fprs[5 * offset]);
fpu_std(6, &fprs[6 * offset]);
fpu_std(7, &fprs[7 * offset]);
fpu_std(8, &fprs[8 * offset]);
fpu_std(9, &fprs[9 * offset]);
fpu_std(10, &fprs[10 * offset]);
fpu_std(11, &fprs[11 * offset]);
fpu_std(12, &fprs[12 * offset]);
fpu_std(13, &fprs[13 * offset]);
fpu_std(14, &fprs[14 * offset]);
fpu_std(15, &fprs[15 * offset]);
}
static __always_inline void __load_fp_regs(freg_t *fprs, unsigned int offset)
{
fpu_ld(0, &fprs[0 * offset]);
fpu_ld(1, &fprs[1 * offset]);
fpu_ld(2, &fprs[2 * offset]);
fpu_ld(3, &fprs[3 * offset]);
fpu_ld(4, &fprs[4 * offset]);
fpu_ld(5, &fprs[5 * offset]);
fpu_ld(6, &fprs[6 * offset]);
fpu_ld(7, &fprs[7 * offset]);
fpu_ld(8, &fprs[8 * offset]);
fpu_ld(9, &fprs[9 * offset]);
fpu_ld(10, &fprs[10 * offset]);
fpu_ld(11, &fprs[11 * offset]);
fpu_ld(12, &fprs[12 * offset]);
fpu_ld(13, &fprs[13 * offset]);
fpu_ld(14, &fprs[14 * offset]);
fpu_ld(15, &fprs[15 * offset]);
}
static __always_inline void save_fp_regs(freg_t *fprs)
{
__save_fp_regs(fprs, sizeof(freg_t) / sizeof(freg_t));
}
static __always_inline void load_fp_regs(freg_t *fprs)
{
__load_fp_regs(fprs, sizeof(freg_t) / sizeof(freg_t));
}
static __always_inline void save_fp_regs_vx(__vector128 *vxrs)
{
freg_t *fprs = (freg_t *)&vxrs[0].high;
__save_fp_regs(fprs, sizeof(__vector128) / sizeof(freg_t));
}
static __always_inline void load_fp_regs_vx(__vector128 *vxrs)
{
freg_t *fprs = (freg_t *)&vxrs[0].high;
__load_fp_regs(fprs, sizeof(__vector128) / sizeof(freg_t));
}
static inline void load_user_fpu_regs(void)
{
struct thread_struct *thread = &current->thread;
if (!thread->ufpu_flags)
return;
load_fpu_state(&thread->ufpu, thread->ufpu_flags);
thread->ufpu_flags = 0;
}
static __always_inline void __save_user_fpu_regs(struct thread_struct *thread, int flags)
{
save_fpu_state(&thread->ufpu, flags);
__atomic_or(flags, &thread->ufpu_flags);
}
static inline void save_user_fpu_regs(void)
{
struct thread_struct *thread = &current->thread;
int mask, flags;
mask = __atomic_or(KERNEL_FPC | KERNEL_VXR, &thread->kfpu_flags);
flags = ~READ_ONCE(thread->ufpu_flags) & (KERNEL_FPC | KERNEL_VXR);
if (flags)
__save_user_fpu_regs(thread, flags);
barrier();
WRITE_ONCE(thread->kfpu_flags, mask);
}
static __always_inline void _kernel_fpu_begin(struct kernel_fpu *state, int flags)
{
struct thread_struct *thread = &current->thread;
int mask, uflags;
mask = __atomic_or(flags, &thread->kfpu_flags);
state->hdr.mask = mask;
uflags = READ_ONCE(thread->ufpu_flags);
if ((uflags & flags) != flags)
__save_user_fpu_regs(thread, ~uflags & flags);
if (mask & flags)
__kernel_fpu_begin(state, flags);
}
static __always_inline void _kernel_fpu_end(struct kernel_fpu *state, int flags)
{
int mask = state->hdr.mask;
if (mask & flags)
__kernel_fpu_end(state, flags);
barrier();
WRITE_ONCE(current->thread.kfpu_flags, mask);
}
void __kernel_fpu_invalid_size(void);
static __always_inline void kernel_fpu_check_size(int flags, unsigned int size)
{
unsigned int cnt = 0;
if (flags & KERNEL_VXR_V0V7)
cnt += 8;
if (flags & KERNEL_VXR_V8V15)
cnt += 8;
if (flags & KERNEL_VXR_V16V23)
cnt += 8;
if (flags & KERNEL_VXR_V24V31)
cnt += 8;
if (cnt != size)
__kernel_fpu_invalid_size();
}
#define kernel_fpu_begin(state, flags) \
{ \
typeof(state) s = (state); \
int _flags = (flags); \
\
kernel_fpu_check_size(_flags, ARRAY_SIZE(s->vxrs)); \
_kernel_fpu_begin((struct kernel_fpu *)s, _flags); \
}
#define kernel_fpu_end(state, flags) \
{ \
typeof(state) s = (state); \
int _flags = (flags); \
\
kernel_fpu_check_size(_flags, ARRAY_SIZE(s->vxrs)); \
_kernel_fpu_end((struct kernel_fpu *)s, _flags); \
}
static inline void save_kernel_fpu_regs(struct thread_struct *thread)
{
if (!thread->kfpu_flags)
return;
save_fpu_state(&thread->kfpu, thread->kfpu_flags);
}
static inline void restore_kernel_fpu_regs(struct thread_struct *thread)
{
if (!thread->kfpu_flags)
return;
load_fpu_state(&thread->kfpu, thread->kfpu_flags);
}
static inline void convert_vx_to_fp(freg_t *fprs, __vector128 *vxrs)
{
int i;
for (i = 0; i < __NUM_FPRS; i++)
fprs[i].ui = vxrs[i].high;
}
static inline void convert_fp_to_vx(__vector128 *vxrs, freg_t *fprs)
{
int i;
for (i = 0; i < __NUM_FPRS; i++)
vxrs[i].high = fprs[i].ui;
}
static inline void fpregs_store(_s390_fp_regs *fpregs, struct fpu *fpu)
{
fpregs->pad = 0;
fpregs->fpc = fpu->fpc;
convert_vx_to_fp((freg_t *)&fpregs->fprs, fpu->vxrs);
}
static inline void fpregs_load(_s390_fp_regs *fpregs, struct fpu *fpu)
{
fpu->fpc = fpregs->fpc;
convert_fp_to_vx(fpu->vxrs, (freg_t *)&fpregs->fprs);
}
#endif /* _ASM_S390_FPU_H */
+149
View File
@@ -0,0 +1,149 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_FTRACE_H
#define _ASM_S390_FTRACE_H
#define ARCH_SUPPORTS_FTRACE_OPS 1
#define MCOUNT_INSN_SIZE 6
#ifndef __ASSEMBLER__
#include <asm/stacktrace.h>
static __always_inline unsigned long return_address(unsigned int n)
{
struct stack_frame *sf;
if (!n)
return (unsigned long)__builtin_return_address(0);
sf = (struct stack_frame *)current_frame_address();
do {
sf = (struct stack_frame *)sf->back_chain;
if (!sf)
return 0;
} while (--n);
return sf->gprs[8];
}
#define ftrace_return_address(n) return_address(n)
void ftrace_caller(void);
extern void *ftrace_func;
struct dyn_arch_ftrace { };
#define MCOUNT_ADDR 0
#define FTRACE_ADDR ((unsigned long)ftrace_caller)
#define KPROBE_ON_FTRACE_NOP 0
#define KPROBE_ON_FTRACE_CALL 1
struct module;
struct dyn_ftrace;
struct ftrace_ops;
bool ftrace_need_init_nop(void);
#define ftrace_need_init_nop ftrace_need_init_nop
int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
#define ftrace_init_nop ftrace_init_nop
static inline unsigned long ftrace_call_adjust(unsigned long addr)
{
return addr;
}
#define ftrace_get_symaddr(fentry_ip) ((unsigned long)(fentry_ip))
#include <linux/ftrace_regs.h>
static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs)
{
struct pt_regs *regs = &arch_ftrace_regs(fregs)->regs;
if (test_pt_regs_flag(regs, PIF_FTRACE_FULL_REGS))
return regs;
return NULL;
}
static __always_inline void
ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs,
unsigned long ip)
{
arch_ftrace_regs(fregs)->regs.psw.addr = ip;
}
#undef ftrace_regs_get_frame_pointer
static __always_inline unsigned long
ftrace_regs_get_frame_pointer(struct ftrace_regs *fregs)
{
return ftrace_regs_get_stack_pointer(fregs);
}
static __always_inline unsigned long
ftrace_regs_get_return_address(const struct ftrace_regs *fregs)
{
return arch_ftrace_regs(fregs)->regs.gprs[14];
}
#define arch_ftrace_fill_perf_regs(fregs, _regs) do { \
(_regs)->psw.mask = 0; \
(_regs)->psw.addr = arch_ftrace_regs(fregs)->regs.psw.addr; \
(_regs)->gprs[15] = arch_ftrace_regs(fregs)->regs.gprs[15]; \
} while (0)
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
/*
* When an ftrace registered caller is tracing a function that is
* also set by a register_ftrace_direct() call, it needs to be
* differentiated in the ftrace_caller trampoline. To do this,
* place the direct caller in the ORIG_GPR2 part of pt_regs. This
* tells the ftrace_caller that there's a direct caller.
*/
static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsigned long addr)
{
struct pt_regs *regs = &arch_ftrace_regs(fregs)->regs;
regs->orig_gpr2 = addr;
}
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
static inline bool arch_syscall_match_sym_name(const char *sym,
const char *name)
{
/* Skip the __s390x_ prefix. */
return !strcmp(sym + 7, name) || !strcmp(sym + 8, name);
}
void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
struct ftrace_ops *op, struct ftrace_regs *fregs);
#define ftrace_graph_func ftrace_graph_func
#endif /* __ASSEMBLER__ */
#ifdef CONFIG_FUNCTION_TRACER
#define FTRACE_NOP_INSN .word 0xc004, 0x0000, 0x0000 /* brcl 0,0 */
#ifndef CC_USING_HOTPATCH
#define FTRACE_GEN_MCOUNT_RECORD(name) \
.section __mcount_loc, "a", @progbits; \
.quad name; \
.previous;
#else /* !CC_USING_HOTPATCH */
#define FTRACE_GEN_MCOUNT_RECORD(name)
#endif /* !CC_USING_HOTPATCH */
#define FTRACE_GEN_NOP_ASM(name) \
FTRACE_GEN_MCOUNT_RECORD(name) \
FTRACE_NOP_INSN
#else /* CONFIG_FUNCTION_TRACER */
#define FTRACE_GEN_NOP_ASM(name)
#endif /* CONFIG_FUNCTION_TRACER */
#endif /* _ASM_S390_FTRACE_H */
@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef DIV_ROUND_UP
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#endif
#define SIZEOF_MCOUNT_LOC_ENTRY 8
#define SIZEOF_FTRACE_HOTPATCH_TRAMPOLINE 24
#define FTRACE_HOTPATCH_TRAMPOLINES_SIZE(n) \
DIV_ROUND_UP(SIZEOF_FTRACE_HOTPATCH_TRAMPOLINE * (n), \
SIZEOF_MCOUNT_LOC_ENTRY)
#ifdef CONFIG_FUNCTION_TRACER
#define FTRACE_HOTPATCH_TRAMPOLINES_TEXT \
. = ALIGN(8); \
__ftrace_hotpatch_trampolines_start = .; \
. = . + FTRACE_HOTPATCH_TRAMPOLINES_SIZE(__stop_mcount_loc - \
__start_mcount_loc); \
__ftrace_hotpatch_trampolines_end = .;
#else
#define FTRACE_HOTPATCH_TRAMPOLINES_TEXT
#endif
+102
View File
@@ -0,0 +1,102 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_FUTEX_H
#define _ASM_S390_FUTEX_H
#include <linux/instrumented.h>
#include <linux/uaccess.h>
#include <linux/futex.h>
#include <asm/asm-extable.h>
#include <asm/mmu_context.h>
#include <asm/errno.h>
#define FUTEX_OP_FUNC(name, insn) \
static uaccess_kmsan_or_inline int \
__futex_atomic_##name(int oparg, int *old, u32 __user *uaddr) \
{ \
bool sacf_flag; \
int rc, new; \
\
instrument_copy_from_user_before(old, uaddr, sizeof(*old)); \
sacf_flag = enable_sacf_uaccess(); \
asm_inline volatile( \
" sacf 256\n" \
"0: l %[old],%[uaddr]\n" \
"1:"insn \
"2: cs %[old],%[new],%[uaddr]\n" \
"3: jl 1b\n" \
" lhi %[rc],0\n" \
"4: sacf 768\n" \
EX_TABLE_UA_FAULT(0b, 4b, %[rc]) \
EX_TABLE_UA_FAULT(1b, 4b, %[rc]) \
EX_TABLE_UA_FAULT(2b, 4b, %[rc]) \
EX_TABLE_UA_FAULT(3b, 4b, %[rc]) \
: [rc] "=d" (rc), [old] "=&d" (*old), \
[new] "=&d" (new), [uaddr] "+Q" (*uaddr) \
: [oparg] "d" (oparg) \
: "cc"); \
disable_sacf_uaccess(sacf_flag); \
if (!rc) \
instrument_copy_from_user_after(old, uaddr, sizeof(*old), 0); \
return rc; \
}
FUTEX_OP_FUNC(set, "lr %[new],%[oparg]\n")
FUTEX_OP_FUNC(add, "lr %[new],%[old]\n ar %[new],%[oparg]\n")
FUTEX_OP_FUNC(or, "lr %[new],%[old]\n or %[new],%[oparg]\n")
FUTEX_OP_FUNC(and, "lr %[new],%[old]\n nr %[new],%[oparg]\n")
FUTEX_OP_FUNC(xor, "lr %[new],%[old]\n xr %[new],%[oparg]\n")
static inline
int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
{
int old, rc;
switch (op) {
case FUTEX_OP_SET:
rc = __futex_atomic_set(oparg, &old, uaddr);
break;
case FUTEX_OP_ADD:
rc = __futex_atomic_add(oparg, &old, uaddr);
break;
case FUTEX_OP_OR:
rc = __futex_atomic_or(oparg, &old, uaddr);
break;
case FUTEX_OP_ANDN:
rc = __futex_atomic_and(~oparg, &old, uaddr);
break;
case FUTEX_OP_XOR:
rc = __futex_atomic_xor(oparg, &old, uaddr);
break;
default:
rc = -ENOSYS;
}
if (!rc)
*oval = old;
return rc;
}
static uaccess_kmsan_or_inline
int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval)
{
bool sacf_flag;
int rc;
instrument_copy_from_user_before(uval, uaddr, sizeof(*uval));
sacf_flag = enable_sacf_uaccess();
asm_inline volatile(
" sacf 256\n"
"0: cs %[old],%[new],%[uaddr]\n"
"1: lhi %[rc],0\n"
"2: sacf 768\n"
EX_TABLE_UA_FAULT(0b, 2b, %[rc])
EX_TABLE_UA_FAULT(1b, 2b, %[rc])
: [rc] "=d" (rc), [old] "+d" (oldval), [uaddr] "+Q" (*uaddr)
: [new] "d" (newval)
: "cc", "memory");
disable_sacf_uaccess(sacf_flag);
*uval = oldval;
instrument_copy_from_user_after(uval, uaddr, sizeof(*uval), 0);
return rc;
}
#endif /* _ASM_S390_FUTEX_H */
@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Helper functions for KVM guest address space mapping code
*
* Copyright IBM Corp. 2025
*/
#ifndef _ASM_S390_GMAP_HELPERS_H
#define _ASM_S390_GMAP_HELPERS_H
void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr);
void gmap_helper_discard(struct mm_struct *mm, unsigned long vmaddr, unsigned long end);
int gmap_helper_disable_cow_sharing(void);
void gmap_helper_try_set_pte_unused(struct mm_struct *mm, unsigned long vmaddr);
pte_t *try_get_locked_pte(struct mm_struct *mm, unsigned long addr, spinlock_t **ptl);
#endif /* _ASM_S390_GMAP_HELPERS_H */
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* S390 version
* Copyright IBM Corp. 1999, 2000
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
* Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
*
* Derived from "include/asm-i386/hardirq.h"
*/
#ifndef __ASM_HARDIRQ_H
#define __ASM_HARDIRQ_H
#include <asm/lowcore.h>
#define local_softirq_pending() (get_lowcore()->softirq_pending)
#define set_softirq_pending(x) (get_lowcore()->softirq_pending = (x))
#define or_softirq_pending(x) (get_lowcore()->softirq_pending |= (x))
#define __ARCH_IRQ_STAT
#define __ARCH_IRQ_EXIT_IRQS_DISABLED
static inline void ack_bad_irq(unsigned int irq)
{
printk(KERN_CRIT "unexpected IRQ trap at vector %02x\n", irq);
}
#endif /* __ASM_HARDIRQ_H */
@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 2024
*/
#ifndef _ASM_HIPERDISPATCH_H
#define _ASM_HIPERDISPATCH_H
void hd_reset_state(void);
void hd_add_core(int cpu);
void hd_disable_hiperdispatch(void);
int hd_enable_hiperdispatch(void);
#endif /* _ASM_HIPERDISPATCH_H */
+100
View File
@@ -0,0 +1,100 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* IBM System z Huge TLB Page Support for Kernel.
*
* Copyright IBM Corp. 2008
* Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com>
*/
#ifndef _ASM_S390_HUGETLB_H
#define _ASM_S390_HUGETLB_H
#include <linux/cpufeature.h>
#include <linux/pgtable.h>
#include <linux/swap.h>
#include <linux/swapops.h>
#include <asm/page.h>
#define hugepages_supported() cpu_has_edat1()
#define __HAVE_ARCH_HUGE_SET_HUGE_PTE_AT
void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte, unsigned long sz);
void __set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte);
#define __HAVE_ARCH_HUGE_PTEP_GET
pte_t huge_ptep_get(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
pte_t __huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
pte_t *ptep);
#define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR
static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
unsigned long addr, pte_t *ptep,
unsigned long sz)
{
return __huge_ptep_get_and_clear(mm, addr, ptep);
}
#define __HAVE_ARCH_HUGE_PTE_CLEAR
static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, unsigned long sz)
{
if ((pte_val(ptep_get(ptep)) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
set_pte(ptep, __pte(_REGION3_ENTRY_EMPTY));
else
set_pte(ptep, __pte(_SEGMENT_ENTRY_EMPTY));
}
#define __HAVE_ARCH_HUGE_PTEP_CLEAR_FLUSH
static inline pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
unsigned long address, pte_t *ptep)
{
return __huge_ptep_get_and_clear(vma->vm_mm, address, ptep);
}
#define __HAVE_ARCH_HUGE_PTEP_SET_ACCESS_FLAGS
static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep,
pte_t pte, int dirty)
{
int changed = !pte_same(huge_ptep_get(vma->vm_mm, addr, ptep), pte);
if (changed) {
__huge_ptep_get_and_clear(vma->vm_mm, addr, ptep);
__set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
}
return changed;
}
#define __HAVE_ARCH_HUGE_PTEP_SET_WRPROTECT
static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
{
pte_t pte = __huge_ptep_get_and_clear(mm, addr, ptep);
__set_huge_pte_at(mm, addr, ptep, pte_wrprotect(pte));
}
#define __HAVE_ARCH_HUGE_PTE_MKUFFD_WP
static inline pte_t huge_pte_mkuffd_wp(pte_t pte)
{
return pte;
}
#define __HAVE_ARCH_HUGE_PTE_CLEAR_UFFD_WP
static inline pte_t huge_pte_clear_uffd_wp(pte_t pte)
{
return pte;
}
#define __HAVE_ARCH_HUGE_PTE_UFFD_WP
static inline int huge_pte_uffd_wp(pte_t pte)
{
return 0;
}
#include <asm-generic/hugetlb.h>
#endif /* _ASM_S390_HUGETLB_H */
@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _HW_IRQ_H
#define _HW_IRQ_H
#include <linux/msi.h>
#include <linux/pci.h>
void __init init_airq_interrupts(void);
void __init init_cio_interrupts(void);
#endif
+336
View File
@@ -0,0 +1,336 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* Copyright IBM Corp. 2000
*
* History of changes
* 07/24/00 new file
* 05/04/02 code restructuring.
*/
#ifndef _S390_IDALS_H
#define _S390_IDALS_H
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <asm/dma-types.h>
#include <asm/cio.h>
#define IDA_SIZE_SHIFT 12
#define IDA_BLOCK_SIZE (1UL << IDA_SIZE_SHIFT)
#define IDA_2K_SIZE_SHIFT 11
#define IDA_2K_BLOCK_SIZE (1UL << IDA_2K_SIZE_SHIFT)
/*
* Test if an address/length pair needs an idal list.
*/
static inline bool idal_is_needed(void *vaddr, unsigned int length)
{
dma64_t paddr = virt_to_dma64(vaddr);
return (((__force unsigned long)(paddr) + length - 1) >> 31) != 0;
}
/*
* Return the number of idal words needed for an address/length pair.
*/
static inline unsigned int idal_nr_words(void *vaddr, unsigned int length)
{
unsigned int cidaw;
cidaw = (unsigned long)vaddr & (IDA_BLOCK_SIZE - 1);
cidaw += length + IDA_BLOCK_SIZE - 1;
cidaw >>= IDA_SIZE_SHIFT;
return cidaw;
}
/*
* Return the number of 2K IDA words needed for an address/length pair.
*/
static inline unsigned int idal_2k_nr_words(void *vaddr, unsigned int length)
{
unsigned int cidaw;
cidaw = (unsigned long)vaddr & (IDA_2K_BLOCK_SIZE - 1);
cidaw += length + IDA_2K_BLOCK_SIZE - 1;
cidaw >>= IDA_2K_SIZE_SHIFT;
return cidaw;
}
/*
* Create the list of idal words for an address/length pair.
*/
static inline dma64_t *idal_create_words(dma64_t *idaws, void *vaddr, unsigned int length)
{
dma64_t paddr = virt_to_dma64(vaddr);
unsigned int cidaw;
*idaws++ = paddr;
cidaw = idal_nr_words(vaddr, length);
paddr = dma64_and(paddr, -IDA_BLOCK_SIZE);
while (--cidaw > 0) {
paddr = dma64_add(paddr, IDA_BLOCK_SIZE);
*idaws++ = paddr;
}
return idaws;
}
/*
* Sets the address of the data in CCW.
* If necessary it allocates an IDAL and sets the appropriate flags.
*/
static inline int set_normalized_cda(struct ccw1 *ccw, void *vaddr)
{
unsigned int nridaws;
dma64_t *idal;
if (ccw->flags & CCW_FLAG_IDA)
return -EINVAL;
nridaws = idal_nr_words(vaddr, ccw->count);
if (nridaws > 0) {
idal = kzalloc_objs(*idal, nridaws, GFP_ATOMIC | GFP_DMA);
if (!idal)
return -ENOMEM;
idal_create_words(idal, vaddr, ccw->count);
ccw->flags |= CCW_FLAG_IDA;
vaddr = idal;
}
ccw->cda = virt_to_dma32(vaddr);
return 0;
}
/*
* Releases any allocated IDAL related to the CCW.
*/
static inline void clear_normalized_cda(struct ccw1 *ccw)
{
if (ccw->flags & CCW_FLAG_IDA) {
kfree(dma32_to_virt(ccw->cda));
ccw->flags &= ~CCW_FLAG_IDA;
}
ccw->cda = 0;
}
/*
* Idal buffer extension
*/
struct idal_buffer {
size_t size;
size_t page_order;
dma64_t data[];
};
/*
* Allocate an idal buffer
*/
static inline struct idal_buffer *idal_buffer_alloc(size_t size, int page_order)
{
int nr_chunks, nr_ptrs, i;
struct idal_buffer *ib;
void *vaddr;
nr_ptrs = (size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_SHIFT;
nr_chunks = (PAGE_SIZE << page_order) >> IDA_SIZE_SHIFT;
ib = kmalloc_flex(*ib, data, nr_ptrs, GFP_DMA | GFP_KERNEL);
if (!ib)
return ERR_PTR(-ENOMEM);
ib->size = size;
ib->page_order = page_order;
for (i = 0; i < nr_ptrs; i++) {
if (i & (nr_chunks - 1)) {
ib->data[i] = dma64_add(ib->data[i - 1], IDA_BLOCK_SIZE);
continue;
}
vaddr = (void *)__get_free_pages(GFP_KERNEL, page_order);
if (!vaddr)
goto error;
ib->data[i] = virt_to_dma64(vaddr);
}
return ib;
error:
while (i >= nr_chunks) {
i -= nr_chunks;
vaddr = dma64_to_virt(ib->data[i]);
free_pages((unsigned long)vaddr, ib->page_order);
}
kfree(ib);
return ERR_PTR(-ENOMEM);
}
/*
* Free an idal buffer.
*/
static inline void idal_buffer_free(struct idal_buffer *ib)
{
int nr_chunks, nr_ptrs, i;
void *vaddr;
nr_ptrs = (ib->size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_SHIFT;
nr_chunks = (PAGE_SIZE << ib->page_order) >> IDA_SIZE_SHIFT;
for (i = 0; i < nr_ptrs; i += nr_chunks) {
vaddr = dma64_to_virt(ib->data[i]);
free_pages((unsigned long)vaddr, ib->page_order);
}
kfree(ib);
}
/*
* Allocate an array of IDAL buffers to cover a total data size of @size. The
* resulting array is null-terminated.
*
* The amount of individual IDAL buffers is determined based on @size.
* Each IDAL buffer can have a maximum size of @CCW_MAX_BYTE_COUNT.
*/
static inline struct idal_buffer **idal_buffer_array_alloc(size_t size, int page_order)
{
struct idal_buffer **ibs;
size_t ib_size; /* Size of a single idal buffer */
int count; /* Amount of individual idal buffers */
int i;
count = (size + CCW_MAX_BYTE_COUNT - 1) / CCW_MAX_BYTE_COUNT;
ibs = kmalloc_objs(*ibs, count + 1);
for (i = 0; i < count; i++) {
/* Determine size for the current idal buffer */
ib_size = min(size, CCW_MAX_BYTE_COUNT);
size -= ib_size;
ibs[i] = idal_buffer_alloc(ib_size, page_order);
if (IS_ERR(ibs[i])) {
while (i--)
idal_buffer_free(ibs[i]);
kfree(ibs);
ibs = NULL;
return ERR_PTR(-ENOMEM);
}
}
ibs[i] = NULL;
return ibs;
}
/*
* Free array of IDAL buffers
*/
static inline void idal_buffer_array_free(struct idal_buffer ***ibs)
{
struct idal_buffer **p;
if (!ibs || !*ibs)
return;
for (p = *ibs; *p; p++)
idal_buffer_free(*p);
kfree(*ibs);
*ibs = NULL;
}
/*
* Determine size of IDAL buffer array
*/
static inline int idal_buffer_array_size(struct idal_buffer **ibs)
{
int size = 0;
while (ibs && *ibs) {
size++;
ibs++;
}
return size;
}
/*
* Determine total data size covered by IDAL buffer array
*/
static inline size_t idal_buffer_array_datasize(struct idal_buffer **ibs)
{
size_t size = 0;
while (ibs && *ibs) {
size += (*ibs)->size;
ibs++;
}
return size;
}
/*
* Test if a idal list is really needed.
*/
static inline bool __idal_buffer_is_needed(struct idal_buffer *ib)
{
if (ib->size > (PAGE_SIZE << ib->page_order))
return true;
return idal_is_needed(dma64_to_virt(ib->data[0]), ib->size);
}
/*
* Set channel data address to idal buffer.
*/
static inline void idal_buffer_set_cda(struct idal_buffer *ib, struct ccw1 *ccw)
{
void *vaddr;
if (__idal_buffer_is_needed(ib)) {
/* Setup idals */
ccw->cda = virt_to_dma32(ib->data);
ccw->flags |= CCW_FLAG_IDA;
} else {
/*
* No idals needed - use direct addressing. Convert from
* dma64_t to virt and then to dma32_t only because of type
* checking. The physical address is known to be below 2GB.
*/
vaddr = dma64_to_virt(ib->data[0]);
ccw->cda = virt_to_dma32(vaddr);
}
ccw->count = ib->size;
}
/*
* Copy count bytes from an idal buffer to user memory
*/
static inline size_t idal_buffer_to_user(struct idal_buffer *ib, void __user *to, size_t count)
{
size_t left;
void *vaddr;
int i;
BUG_ON(count > ib->size);
for (i = 0; count > IDA_BLOCK_SIZE; i++) {
vaddr = dma64_to_virt(ib->data[i]);
left = copy_to_user(to, vaddr, IDA_BLOCK_SIZE);
if (left)
return left + count - IDA_BLOCK_SIZE;
to = (void __user *)to + IDA_BLOCK_SIZE;
count -= IDA_BLOCK_SIZE;
}
vaddr = dma64_to_virt(ib->data[i]);
return copy_to_user(to, vaddr, count);
}
/*
* Copy count bytes from user memory to an idal buffer
*/
static inline size_t idal_buffer_from_user(struct idal_buffer *ib, const void __user *from, size_t count)
{
size_t left;
void *vaddr;
int i;
BUG_ON(count > ib->size);
for (i = 0; count > IDA_BLOCK_SIZE; i++) {
vaddr = dma64_to_virt(ib->data[i]);
left = copy_from_user(vaddr, from, IDA_BLOCK_SIZE);
if (left)
return left + count - IDA_BLOCK_SIZE;
from = (void __user *)from + IDA_BLOCK_SIZE;
count -= IDA_BLOCK_SIZE;
}
vaddr = dma64_to_virt(ib->data[i]);
return copy_from_user(vaddr, from, count);
}
#endif
+27
View File
@@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 2014
*
* Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
#ifndef _S390_IDLE_H
#define _S390_IDLE_H
#include <linux/percpu-defs.h>
#include <linux/types.h>
#include <asm/tod_types.h>
struct s390_idle_data {
#ifdef CONFIG_NO_HZ_COMMON
bool in_idle;
#endif
unsigned long timer_idle_enter;
unsigned long mt_cycles_enter[8];
union tod_clock clock_idle_enter;
union tod_clock clock_idle_exit;
};
DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
#endif /* _S390_IDLE_H */
@@ -0,0 +1,53 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Assembler helper macros to generate .byte/.word code for instructions
* that are unknown to older binutils versions.
*/
#ifndef __ASM_S390_INSN_COMMON_ASM_H
#define __ASM_S390_INSN_COMMON_ASM_H
#ifdef __ASSEMBLER__
/*
* GR_NUM - Retrieve general-purpose register number
*
* @opd: Operand to store register number
* @gr: String designation register in the format "%rN"
*/
.macro GR_NUM opd gr
\opd = 255
.irp rs,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
.ifc \gr,%r\rs
\opd = \rs
.endif
.endr
.if \opd == 255
\opd = \gr
.endif
.endm
/*
* VX_NUM - Retrieve vector register number
*
* @opd: Operand to store register number
* @vxr: String designation register in the format "%vN"
*
* The vector register number is used for as input number to the
* instruction and, as well as, to compute the RXB field of the
* instruction.
*/
.macro VX_NUM opd vxr
\opd = 255
.irp vs,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
.ifc \vxr,%v\vs
\opd = \vs
.endif
.endr
.if \opd == 255
\opd = \vxr
.endif
.endm
#endif /* __ASSEMBLER__ */
#endif /* __ASM_S390_INSN_COMMON_ASM_H */
+95
View File
@@ -0,0 +1,95 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* S390 version
* Copyright IBM Corp. 1999
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
*
* Derived from "include/asm-i386/io.h"
*/
#ifndef _S390_IO_H
#define _S390_IO_H
#include <linux/kernel.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/pci_io.h>
#define xlate_dev_mem_ptr xlate_dev_mem_ptr
#define kc_xlate_dev_mem_ptr xlate_dev_mem_ptr
void *xlate_dev_mem_ptr(phys_addr_t phys);
#define unxlate_dev_mem_ptr unxlate_dev_mem_ptr
#define kc_unxlate_dev_mem_ptr unxlate_dev_mem_ptr
void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr);
#define IO_SPACE_LIMIT 0
/*
* I/O memory mapping functions.
*/
#define ioremap_prot ioremap_prot
#define iounmap iounmap
#define _PAGE_IOREMAP pgprot_val(PAGE_KERNEL)
#define ioremap_wc(addr, size) \
ioremap_prot((addr), (size), pgprot_writecombine(PAGE_KERNEL))
static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
{
return NULL;
}
static inline void ioport_unmap(void __iomem *p)
{
}
#ifdef CONFIG_PCI
/*
* s390 needs a private implementation of pci_iomap since ioremap with its
* offset parameter isn't sufficient. That's because BAR spaces are not
* disjunctive on s390 so we need the bar parameter of pci_iomap to find
* the corresponding device and create the mapping cookie.
*/
#define pci_iomap pci_iomap
#define pci_iomap_range pci_iomap_range
#define pci_iounmap pci_iounmap
#define pci_iomap_wc pci_iomap_wc
#define pci_iomap_wc_range pci_iomap_wc_range
#define memcpy_fromio(dst, src, count) zpci_memcpy_fromio(dst, src, count)
#define memcpy_toio(dst, src, count) zpci_memcpy_toio(dst, src, count)
#define memset_io(dst, val, count) zpci_memset_io(dst, val, count)
#define mmiowb() zpci_barrier()
#define __raw_readb zpci_read_u8
#define __raw_readw zpci_read_u16
#define __raw_readl zpci_read_u32
#define __raw_readq zpci_read_u64
#define __raw_writeb zpci_write_u8
#define __raw_writew zpci_write_u16
#define __raw_writel zpci_write_u32
#define __raw_writeq zpci_write_u64
/* combine single writes by using store-block insn */
static inline void __iowrite32_copy(void __iomem *to, const void *from,
size_t count)
{
zpci_memcpy_toio(to, from, count * 4);
}
#define __iowrite32_copy __iowrite32_copy
static inline void __iowrite64_copy(void __iomem *to, const void *from,
size_t count)
{
zpci_memcpy_toio(to, from, count * 8);
}
#define __iowrite64_copy __iowrite64_copy
#endif /* CONFIG_PCI */
#include <asm-generic/io.h>
#endif
+170
View File
@@ -0,0 +1,170 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* s390 (re)ipl support
*
* Copyright IBM Corp. 2007
*/
#ifndef _ASM_S390_IPL_H
#define _ASM_S390_IPL_H
#include <asm/lowcore.h>
#include <asm/types.h>
#include <asm/cio.h>
#include <asm/setup.h>
#include <asm/page.h>
#include <uapi/asm/ipl.h>
struct ipl_parameter_block {
struct ipl_pl_hdr hdr;
union {
struct ipl_pb_hdr pb0_hdr;
struct ipl_pb0_common common;
struct ipl_pb0_fcp fcp;
struct ipl_pb0_ccw ccw;
struct ipl_pb0_eckd eckd;
struct ipl_pb0_nvme nvme;
char raw[PAGE_SIZE - sizeof(struct ipl_pl_hdr)];
};
} __packed __aligned(PAGE_SIZE);
#define NSS_NAME_SIZE 8
#define IPL_BP_FCP_LEN (sizeof(struct ipl_pl_hdr) + \
sizeof(struct ipl_pb0_fcp))
#define IPL_BP0_FCP_LEN (sizeof(struct ipl_pb0_fcp))
#define IPL_BP_NVME_LEN (sizeof(struct ipl_pl_hdr) + \
sizeof(struct ipl_pb0_nvme))
#define IPL_BP0_NVME_LEN (sizeof(struct ipl_pb0_nvme))
#define IPL_BP_CCW_LEN (sizeof(struct ipl_pl_hdr) + \
sizeof(struct ipl_pb0_ccw))
#define IPL_BP0_CCW_LEN (sizeof(struct ipl_pb0_ccw))
#define IPL_BP_ECKD_LEN (sizeof(struct ipl_pl_hdr) + \
sizeof(struct ipl_pb0_eckd))
#define IPL_BP0_ECKD_LEN (sizeof(struct ipl_pb0_eckd))
#define IPL_MAX_SUPPORTED_VERSION (0)
#define IPL_RB_CERT_UNKNOWN ((unsigned short)-1)
#define DIAG308_VMPARM_SIZE (64)
#define DIAG308_SCPDATA_OFFSET offsetof(struct ipl_parameter_block, \
fcp.scp_data)
#define DIAG308_SCPDATA_SIZE (PAGE_SIZE - DIAG308_SCPDATA_OFFSET)
struct save_area;
struct save_area * __init save_area_alloc(bool is_boot_cpu);
struct save_area * __init save_area_boot_cpu(void);
void __init save_area_add_regs(struct save_area *, void *regs);
void __init save_area_add_vxrs(struct save_area *, __vector128 *vxrs);
extern void s390_reset_system(void);
extern size_t ipl_block_get_ascii_vmparm(char *dest, size_t size,
const struct ipl_parameter_block *ipb);
enum ipl_type {
IPL_TYPE_UNKNOWN = 1,
IPL_TYPE_CCW = 2,
IPL_TYPE_FCP = 4,
IPL_TYPE_FCP_DUMP = 8,
IPL_TYPE_NSS = 16,
IPL_TYPE_NVME = 32,
IPL_TYPE_NVME_DUMP = 64,
IPL_TYPE_ECKD = 128,
IPL_TYPE_ECKD_DUMP = 256,
};
struct ipl_info
{
enum ipl_type type;
union {
struct {
struct ccw_dev_id dev_id;
} ccw;
struct {
struct ccw_dev_id dev_id;
} eckd;
struct {
struct ccw_dev_id dev_id;
u64 wwpn;
u64 lun;
} fcp;
struct {
u32 fid;
u32 nsid;
} nvme;
struct {
char name[NSS_NAME_SIZE + 1];
} nss;
} data;
};
extern struct ipl_info ipl_info;
extern void setup_ipl(void);
extern void set_os_info_reipl_block(void);
static inline bool is_ipl_type_dump(void)
{
return (ipl_info.type == IPL_TYPE_FCP_DUMP) ||
(ipl_info.type == IPL_TYPE_ECKD_DUMP) ||
(ipl_info.type == IPL_TYPE_NVME_DUMP);
}
struct ipl_report {
struct ipl_parameter_block *ipib;
struct list_head components;
struct list_head certificates;
size_t size;
};
struct ipl_report_component {
struct list_head list;
struct ipl_rb_component_entry entry;
};
struct ipl_report_certificate {
struct list_head list;
struct ipl_rb_certificate_entry entry;
void *key;
};
struct kexec_buf;
struct ipl_report *ipl_report_init(struct ipl_parameter_block *ipib);
void *ipl_report_finish(struct ipl_report *report);
int ipl_report_free(struct ipl_report *report);
int ipl_report_add_component(struct ipl_report *report, struct kexec_buf *kbuf,
unsigned char flags, unsigned short cert);
int ipl_report_add_certificate(struct ipl_report *report, void *key,
unsigned long addr, unsigned long len);
/*
* DIAG 308 support
*/
enum diag308_subcode {
DIAG308_CLEAR_RESET = 0,
DIAG308_LOAD_NORMAL_RESET = 1,
DIAG308_REL_HSA = 2,
DIAG308_LOAD_CLEAR = 3,
DIAG308_LOAD_NORMAL_DUMP = 4,
DIAG308_SET = 5,
DIAG308_STORE = 6,
DIAG308_LOAD_NORMAL = 7,
};
enum diag308_subcode_flags {
DIAG308_FLAG_EI = 1UL << 16,
};
enum diag308_rc {
DIAG308_RC_OK = 0x0001,
DIAG308_RC_NOCONFIG = 0x0102,
};
extern int diag308(unsigned long subcode, void *addr);
extern void store_status(void (*fn)(void *), void *data);
extern void lgr_info_log(void);
#endif /* _ASM_S390_IPL_H */
+125
View File
@@ -0,0 +1,125 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_IRQ_H
#define _ASM_IRQ_H
#define EXT_INTERRUPT 0
#define IO_INTERRUPT 1
#define THIN_INTERRUPT 2
#define NR_IRQS_BASE 3
#define NR_IRQS NR_IRQS_BASE
#define NR_IRQS_LEGACY NR_IRQS_BASE
/* External interruption codes */
#define EXT_IRQ_INTERRUPT_KEY 0x0040
#define EXT_IRQ_CLK_COMP 0x1004
#define EXT_IRQ_CPU_TIMER 0x1005
#define EXT_IRQ_WARNING_TRACK 0x1007
#define EXT_IRQ_MALFUNC_ALERT 0x1200
#define EXT_IRQ_EMERGENCY_SIG 0x1201
#define EXT_IRQ_EXTERNAL_CALL 0x1202
#define EXT_IRQ_TIMING_ALERT 0x1406
#define EXT_IRQ_MEASURE_ALERT 0x1407
#define EXT_IRQ_SERVICE_SIG 0x2401
#define EXT_IRQ_CP_SERVICE 0x2603
#define EXT_IRQ_IUCV 0x4000
#ifndef __ASSEMBLER__
#include <linux/hardirq.h>
#include <linux/percpu.h>
#include <linux/cache.h>
#include <linux/types.h>
#include <asm/ctlreg.h>
enum interruption_class {
IRQEXT_CLK,
IRQEXT_EXC,
IRQEXT_EMS,
IRQEXT_TMR,
IRQEXT_TLA,
IRQEXT_PFL,
IRQEXT_DSD,
IRQEXT_VRT,
IRQEXT_SCP,
IRQEXT_IUC,
IRQEXT_CMS,
IRQEXT_CMC,
IRQEXT_FTP,
IRQEXT_WTI,
IRQIO_CIO,
IRQIO_DAS,
IRQIO_C15,
IRQIO_C70,
IRQIO_TAP,
IRQIO_VMR,
IRQIO_CTC,
IRQIO_ADM,
IRQIO_CSC,
IRQIO_VIR,
IRQIO_QAI,
IRQIO_APB,
IRQIO_PCF,
IRQIO_PCD,
IRQIO_MSI,
IRQIO_VAI,
IRQIO_GAL,
NMI_NMI,
CPU_RST,
NR_ARCH_IRQS
};
struct irq_stat {
unsigned int irqs[NR_ARCH_IRQS];
};
DECLARE_PER_CPU_SHARED_ALIGNED(struct irq_stat, irq_stat);
static __always_inline void inc_irq_stat(enum interruption_class irq)
{
__this_cpu_inc(irq_stat.irqs[irq]);
}
struct ext_code {
union {
struct {
unsigned short subcode;
unsigned short code;
};
unsigned int int_code;
};
};
typedef void (*ext_int_handler_t)(struct ext_code, unsigned int, unsigned long);
int register_external_irq(u16 code, ext_int_handler_t handler);
int unregister_external_irq(u16 code, ext_int_handler_t handler);
enum irq_subclass {
IRQ_SUBCLASS_MEASUREMENT_ALERT = 5,
IRQ_SUBCLASS_SERVICE_SIGNAL = 9,
IRQ_SUBCLASS_WARNING_TRACK = 33,
};
#define CR0_IRQ_SUBCLASS_MASK \
(CR0_WARNING_TRACK | \
CR0_MALFUNCTION_ALERT_SUBMASK | \
CR0_EMERGENCY_SIGNAL_SUBMASK | \
CR0_EXTERNAL_CALL_SUBMASK | \
CR0_CLOCK_COMPARATOR_SUBMASK | \
CR0_CPU_TIMER_SUBMASK | \
CR0_SERVICE_SIGNAL_SUBMASK | \
CR0_INTERRUPT_KEY_SUBMASK | \
CR0_MEASUREMENT_ALERT_SUBMASK | \
CR0_ETR_SUBMASK | \
CR0_IUCV)
void irq_subclass_register(enum irq_subclass subclass);
void irq_subclass_unregister(enum irq_subclass subclass);
#define irq_canonicalize(irq) (irq)
#endif /* __ASSEMBLER__ */
#endif /* _ASM_IRQ_H */
@@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_IRQ_WORK_H
#define _ASM_S390_IRQ_WORK_H
static inline bool arch_irq_work_has_interrupt(void)
{
return true;
}
#endif /* _ASM_S390_IRQ_WORK_H */
@@ -0,0 +1,89 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 2006, 2010
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
#ifndef __ASM_IRQFLAGS_H
#define __ASM_IRQFLAGS_H
#include <linux/types.h>
#define ARCH_IRQ_ENABLED (3UL << (BITS_PER_LONG - 8))
/* store then OR system mask. */
#define __arch_local_irq_stosm(__or) \
({ \
unsigned long __mask; \
asm volatile( \
" stosm %0,%1" \
: "=Q" (__mask) : "i" (__or) : "memory"); \
__mask; \
})
/* store then AND system mask. */
#define __arch_local_irq_stnsm(__and) \
({ \
unsigned long __mask; \
asm volatile( \
" stnsm %0,%1" \
: "=Q" (__mask) : "i" (__and) : "memory"); \
__mask; \
})
/* set system mask. */
static __always_inline void __arch_local_irq_ssm(unsigned long flags)
{
asm volatile("ssm %0" : : "Q" (flags) : "memory");
}
#ifdef CONFIG_KMSAN
#define arch_local_irq_attributes noinline notrace __no_sanitize_memory __maybe_unused
#else
#define arch_local_irq_attributes __always_inline
#endif
static arch_local_irq_attributes unsigned long arch_local_save_flags(void)
{
return __arch_local_irq_stnsm(0xff);
}
static arch_local_irq_attributes unsigned long arch_local_irq_save(void)
{
return __arch_local_irq_stnsm(0xfc);
}
static __always_inline void arch_local_irq_disable(void)
{
arch_local_irq_save();
}
static arch_local_irq_attributes void arch_local_irq_enable_external(void)
{
__arch_local_irq_stosm(0x01);
}
static arch_local_irq_attributes void arch_local_irq_enable(void)
{
__arch_local_irq_stosm(0x03);
}
/* This only restores external and I/O interrupt state */
static __always_inline void arch_local_irq_restore(unsigned long flags)
{
/* only disabled->disabled and disabled->enabled is valid */
if (flags & ARCH_IRQ_ENABLED)
arch_local_irq_enable();
}
static __always_inline bool arch_irqs_disabled_flags(unsigned long flags)
{
return !(flags & ARCH_IRQ_ENABLED);
}
static __always_inline bool arch_irqs_disabled(void)
{
return arch_irqs_disabled_flags(arch_local_save_flags());
}
#endif /* __ASM_IRQFLAGS_H */
+31
View File
@@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_ISC_H
#define _ASM_S390_ISC_H
#include <linux/types.h>
/*
* I/O interruption subclasses used by drivers.
* Please add all used iscs here so that it is possible to distribute
* isc usage between drivers.
* Reminder: 0 is highest priority, 7 lowest.
*/
#define MAX_ISC 7
/* Regular I/O interrupts. */
#define IO_SCH_ISC 3 /* regular I/O subchannels */
#define CONSOLE_ISC 1 /* console I/O subchannel */
#define EADM_SCH_ISC 4 /* EADM subchannels */
#define CHSC_SCH_ISC 7 /* CHSC subchannels */
#define VFIO_CCW_ISC IO_SCH_ISC /* VFIO-CCW I/O subchannels */
/* Adapter interrupts. */
#define QDIO_AIRQ_ISC IO_SCH_ISC /* I/O subchannel in qdio mode */
#define PCI_ISC 2 /* PCI I/O subchannels */
#define GAL_ISC 5 /* GIB alert */
#define AP_ISC 6 /* adjunct processor (crypto) devices */
/* Functions for registration of I/O interruption subclasses */
void isc_register(unsigned int isc);
void isc_unregister(unsigned int isc);
#endif /* _ASM_S390_ISC_H */
+31
View File
@@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Functions for incremental construction of fcx enabled I/O control blocks.
*
* Copyright IBM Corp. 2008
* Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
*/
#ifndef _ASM_S390_ITCW_H
#define _ASM_S390_ITCW_H
#include <linux/types.h>
#include <asm/fcx.h>
#define ITCW_OP_READ 0
#define ITCW_OP_WRITE 1
struct itcw;
struct tcw *itcw_get_tcw(struct itcw *itcw);
size_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws);
struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg,
int max_tidaws, int intrg_max_tidaws);
struct dcw *itcw_add_dcw(struct itcw *itcw, u8 cmd, u8 flags, void *cd,
u8 cd_count, u32 count);
struct tidaw *itcw_add_tidaw(struct itcw *itcw, u8 flags, void *addr,
u32 count);
void itcw_set_data(struct itcw *itcw, void *addr, int use_tidal);
void itcw_finalize(struct itcw *itcw);
#endif /* _ASM_S390_ITCW_H */
@@ -0,0 +1,60 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_JUMP_LABEL_H
#define _ASM_S390_JUMP_LABEL_H
#define HAVE_JUMP_LABEL_BATCH
#ifndef __ASSEMBLER__
#include <linux/types.h>
#include <linux/stringify.h>
#define JUMP_LABEL_NOP_SIZE 6
#ifdef CONFIG_CC_IS_CLANG
#define JUMP_LABEL_STATIC_KEY_CONSTRAINT "i"
#elif __GNUC__ < 9
#define JUMP_LABEL_STATIC_KEY_CONSTRAINT "X"
#else
#define JUMP_LABEL_STATIC_KEY_CONSTRAINT "jdd"
#endif
#define ARCH_JUMP_TABLE_ENTRY(key, label, local_label) \
".pushsection __jump_table,\"aw\"\n" \
".balign 8\n" \
".long " local_label "-.," label "-.\n" \
".quad " key "-.\n" \
".popsection\n"
/*
* We use a brcl 0,<offset> instruction for jump labels so it
* can be easily distinguished from a hotpatch generated instruction.
*/
#define ARCH_STATIC_BRANCH_ASM(key, label) \
"0: brcl 0," label "\n" \
ARCH_JUMP_TABLE_ENTRY(key, label, "0b")
#define ARCH_STATIC_BRANCH_JUMP_ASM(key, label) \
"0: brcl 15," label "\n" \
ARCH_JUMP_TABLE_ENTRY(key, label, "0b")
static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{
asm goto(ARCH_STATIC_BRANCH_ASM("%0+%1", "%l[label]")
: : JUMP_LABEL_STATIC_KEY_CONSTRAINT (key), "i" (branch) : : label);
return false;
label:
return true;
}
static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
{
asm goto(ARCH_STATIC_BRANCH_JUMP_ASM("%0+%1", "%l[label]")
: : JUMP_LABEL_STATIC_KEY_CONSTRAINT (key), "i" (branch) : : label);
return false;
label:
return true;
}
#endif /* __ASSEMBLER__ */
#endif
+18
View File
@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_KASAN_H
#define __ASM_KASAN_H
#include <linux/const.h>
#ifdef CONFIG_KASAN
#define KASAN_SHADOW_SCALE_SHIFT 3
#define KASAN_SHADOW_SIZE \
(_AC(1, UL) << (_REGION1_SHIFT - KASAN_SHADOW_SCALE_SHIFT))
#define KASAN_SHADOW_OFFSET _AC(CONFIG_KASAN_SHADOW_OFFSET, UL)
#define KASAN_SHADOW_START KASAN_SHADOW_OFFSET
#define KASAN_SHADOW_END (KASAN_SHADOW_START + KASAN_SHADOW_SIZE)
#endif
#endif
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _S390_KDEBUG_H
#define _S390_KDEBUG_H
/*
* Feb 2006 Ported to s390 <grundym@us.ibm.com>
*/
struct pt_regs;
enum die_val {
DIE_OOPS = 1,
DIE_BPT,
DIE_SSTEP,
DIE_PANIC,
DIE_NMI,
DIE_DIE,
DIE_NMIWATCHDOG,
DIE_KERNELDEBUG,
DIE_TRAP,
DIE_GPF,
DIE_CALL,
DIE_NMI_IPI,
};
extern void __noreturn die(struct pt_regs *, const char *);
#endif
+113
View File
@@ -0,0 +1,113 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 2005
*
* Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
*
*/
#ifndef _S390_KEXEC_H
#define _S390_KEXEC_H
#include <linux/module.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/setup.h>
/*
* KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
* I.e. Maximum page that is mapped directly into kernel memory,
* and kmap is not required.
*/
/* Maximum physical address we can use pages from */
#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
/* Maximum address we can reach in physical address mode */
#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
/* Maximum address we can use for the control pages */
/* Not more than 2GB */
#define KEXEC_CONTROL_MEMORY_LIMIT (1UL<<31)
/* Allocate control page with GFP_DMA */
#define KEXEC_CONTROL_MEMORY_GFP (GFP_DMA | __GFP_NORETRY)
/* Maximum address we can use for the crash control pages */
#define KEXEC_CRASH_CONTROL_MEMORY_LIMIT (-1UL)
/* Allocate one page for the pdp and the second for the code */
#define KEXEC_CONTROL_PAGE_SIZE 4096
/* Alignment of crashkernel memory */
#define KEXEC_CRASH_MEM_ALIGN HPAGE_SIZE
/* The native architecture */
#define KEXEC_ARCH KEXEC_ARCH_S390
/* Allow kexec_file to load a segment to 0 */
#define KEXEC_BUF_MEM_UNKNOWN -1
/* Provide a dummy definition to avoid build failures. */
static inline void crash_setup_regs(struct pt_regs *newregs,
struct pt_regs *oldregs) { }
struct kimage;
struct s390_load_data {
/* Pointer to the kernel buffer. Used to register cmdline etc.. */
void *kernel_buf;
/* Load address of the kernel_buf. */
unsigned long kernel_mem;
/* Parmarea in the kernel buffer. */
struct parmarea *parm;
/* Total size of loaded segments in memory. Used as an offset. */
size_t memsz;
struct ipl_report *report;
};
int s390_verify_sig(const char *kernel, unsigned long kernel_len);
void *kexec_file_add_components(struct kimage *image,
int (*add_kernel)(struct kimage *image,
struct s390_load_data *data));
int arch_kexec_do_relocs(int r_type, void *loc, unsigned long val,
unsigned long addr);
#define ARCH_HAS_KIMAGE_ARCH
struct kimage_arch {
void *ipl_buf;
};
extern const struct kexec_file_ops s390_kexec_image_ops;
extern const struct kexec_file_ops s390_kexec_elf_ops;
#ifdef CONFIG_CRASH_DUMP
void crash_free_reserved_phys_range(unsigned long begin, unsigned long end);
#define crash_free_reserved_phys_range crash_free_reserved_phys_range
void arch_kexec_protect_crashkres(void);
#define arch_kexec_protect_crashkres arch_kexec_protect_crashkres
void arch_kexec_unprotect_crashkres(void);
#define arch_kexec_unprotect_crashkres arch_kexec_unprotect_crashkres
bool is_kdump_kernel(void);
#define is_kdump_kernel is_kdump_kernel
#endif
#ifdef CONFIG_KEXEC_FILE
struct purgatory_info;
int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
Elf_Shdr *section,
const Elf_Shdr *relsec,
const Elf_Shdr *symtab);
#define arch_kexec_apply_relocations_add arch_kexec_apply_relocations_add
int arch_kimage_file_post_load_cleanup(struct kimage *image);
#define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup
#endif
#endif /*_S390_KEXEC_H */
@@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_KFENCE_H
#define _ASM_S390_KFENCE_H
#include <linux/mm.h>
#include <linux/kfence.h>
#include <asm/set_memory.h>
#include <asm/page.h>
void __kernel_map_pages(struct page *page, int numpages, int enable);
static __always_inline bool arch_kfence_init_pool(void)
{
#ifdef CONFIG_KFENCE
unsigned long pool_pages = KFENCE_POOL_SIZE >> PAGE_SHIFT;
set_memory_4k((unsigned long)__kfence_pool, pool_pages);
#endif
return true;
}
#define arch_kfence_test_address(addr) ((addr) & PAGE_MASK)
static inline bool kfence_protect_page(unsigned long addr, bool protect)
{
__kernel_map_pages(virt_to_page((void *)addr), 1, !protect);
return true;
}
#endif /* _ASM_S390_KFENCE_H */
+59
View File
@@ -0,0 +1,59 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_KMSAN_H
#define _ASM_S390_KMSAN_H
#include <asm/lowcore.h>
#include <asm/page.h>
#include <linux/kmsan.h>
#include <linux/mmzone.h>
#include <linux/stddef.h>
#ifndef MODULE
static inline bool is_lowcore_addr(void *addr)
{
return addr >= (void *)get_lowcore() &&
addr < (void *)(get_lowcore() + 1);
}
static inline void *arch_kmsan_get_meta_or_null(void *addr, bool is_origin)
{
if (is_lowcore_addr(addr)) {
/*
* Different lowcores accessed via S390_lowcore are described
* by the same struct page. Resolve the prefix manually in
* order to get a distinct struct page.
*/
addr += (void *)lowcore_ptr[raw_smp_processor_id()] -
(void *)get_lowcore();
if (KMSAN_WARN_ON(is_lowcore_addr(addr)))
return NULL;
return kmsan_get_metadata(addr, is_origin);
}
return NULL;
}
static inline bool kmsan_virt_addr_valid(void *addr)
{
bool ret;
/*
* pfn_valid() relies on RCU, and may call into the scheduler on exiting
* the critical section. However, this would result in recursion with
* KMSAN. Therefore, disable preemption here, and re-enable preemption
* below while suppressing reschedules to avoid recursion.
*
* Note, this sacrifices occasionally breaking scheduling guarantees.
* Although, a kernel compiled with KMSAN has already given up on any
* performance guarantees due to being heavily instrumented.
*/
preempt_disable();
ret = virt_addr_valid(addr);
preempt_enable_no_resched();
return ret;
}
#endif /* !MODULE */
#endif /* _ASM_S390_KMSAN_H */
@@ -0,0 +1,80 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef _ASM_S390_KPROBES_H
#define _ASM_S390_KPROBES_H
/*
* Kernel Probes (KProbes)
*
* Copyright IBM Corp. 2002, 2006
*
* 2002-Oct Created by Vamsi Krishna S <vamsi_krishna@in.ibm.com> Kernel
* Probes initial implementation ( includes suggestions from
* Rusty Russell).
* 2004-Nov Modified for PPC64 by Ananth N Mavinakayanahalli
* <ananth@in.ibm.com>
* 2005-Dec Used as a template for s390 by Mike Grundy
* <grundym@us.ibm.com>
*/
#include <linux/types.h>
#include <asm/ctlreg.h>
#include <asm-generic/kprobes.h>
#define BREAKPOINT_INSTRUCTION 0x0002
#define FIXUP_PSW_NORMAL 0x08
#define FIXUP_BRANCH_NOT_TAKEN 0x04
#define FIXUP_RETURN_REGISTER 0x02
#define FIXUP_NOT_REQUIRED 0x01
int probe_is_prohibited_opcode(u16 *insn);
int probe_get_fixup_type(u16 *insn);
int probe_is_insn_relative_long(u16 *insn);
#ifdef CONFIG_KPROBES
#include <linux/ptrace.h>
#include <linux/percpu.h>
#include <linux/sched/task_stack.h>
#define __ARCH_WANT_KPROBES_INSN_SLOT
struct pt_regs;
struct kprobe;
typedef u16 kprobe_opcode_t;
/* Maximum instruction size is 3 (16bit) halfwords: */
#define MAX_INSN_SIZE 0x0003
#define MAX_STACK_SIZE 64
#define MIN_STACK_SIZE(ADDR) (((MAX_STACK_SIZE) < \
(((unsigned long)task_stack_page(current)) + THREAD_SIZE - (ADDR))) \
? (MAX_STACK_SIZE) \
: (((unsigned long)task_stack_page(current)) + THREAD_SIZE - (ADDR)))
#define kretprobe_blacklist_size 0
/* Architecture specific copy of original instruction */
struct arch_specific_insn {
/* copy of original instruction */
kprobe_opcode_t *insn;
};
struct prev_kprobe {
struct kprobe *kp;
unsigned long status;
};
/* per-cpu kprobe control block */
struct kprobe_ctlblk {
unsigned long kprobe_status;
unsigned long kprobe_saved_imask;
struct ctlreg kprobe_saved_ctl[3];
struct prev_kprobe prev_kprobe;
};
void arch_remove_kprobe(struct kprobe *p);
int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
#define flush_insn_slot(p) do { } while (0)
#endif /* CONFIG_KPROBES */
#endif /* _ASM_S390_KPROBES_H */
@@ -0,0 +1,784 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* definition for kernel virtual machines on s390
*
* Copyright IBM Corp. 2008, 2018
*
* Author(s): Carsten Otte <cotte@de.ibm.com>
*/
#ifndef ASM_KVM_HOST_H
#define ASM_KVM_HOST_H
#include <linux/types.h>
#include <linux/hrtimer.h>
#include <linux/interrupt.h>
#include <linux/kvm_types.h>
#include <linux/kvm.h>
#include <linux/seqlock.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/mmu_notifier.h>
#include <asm/kvm_host_types.h>
#include <asm/debug.h>
#include <asm/cpu.h>
#include <asm/fpu.h>
#include <asm/isc.h>
#include <asm/guarded_storage.h>
#define KVM_HAVE_MMU_RWLOCK
#define KVM_MAX_VCPUS 255
#define KVM_INTERNAL_MEM_SLOTS 1
/*
* These seem to be used for allocating ->chip in the routing table, which we
* don't use. 1 is as small as we can get to reduce the needed memory. If we
* need to look at ->chip later on, we'll need to revisit this.
*/
#define KVM_NR_IRQCHIPS 1
#define KVM_IRQCHIP_NUM_PINS 1
#define KVM_HALT_POLL_NS_DEFAULT 50000
/* s390-specific vcpu->requests bit members */
#define KVM_REQ_ENABLE_IBS KVM_ARCH_REQ(0)
#define KVM_REQ_DISABLE_IBS KVM_ARCH_REQ(1)
#define KVM_REQ_ICPT_OPEREXC KVM_ARCH_REQ(2)
#define KVM_REQ_START_MIGRATION KVM_ARCH_REQ(3)
#define KVM_REQ_STOP_MIGRATION KVM_ARCH_REQ(4)
#define KVM_REQ_VSIE_RESTART KVM_ARCH_REQ(5)
#define KVM_REQ_REFRESH_GUEST_PREFIX \
KVM_ARCH_REQ_FLAGS(6, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
struct kvm_vcpu_stat {
struct kvm_vcpu_stat_generic generic;
u64 exit_userspace;
u64 exit_null;
u64 exit_external_request;
u64 exit_io_request;
u64 exit_external_interrupt;
u64 exit_stop_request;
u64 exit_validity;
u64 exit_instruction;
u64 exit_pei;
u64 halt_no_poll_steal;
u64 instruction_lctl;
u64 instruction_lctlg;
u64 instruction_stctl;
u64 instruction_stctg;
u64 exit_program_interruption;
u64 exit_instr_and_program;
u64 exit_operation_exception;
u64 deliver_ckc;
u64 deliver_cputm;
u64 deliver_external_call;
u64 deliver_emergency_signal;
u64 deliver_service_signal;
u64 deliver_virtio;
u64 deliver_stop_signal;
u64 deliver_prefix_signal;
u64 deliver_restart_signal;
u64 deliver_program;
u64 deliver_io;
u64 deliver_machine_check;
u64 exit_wait_state;
u64 inject_ckc;
u64 inject_cputm;
u64 inject_external_call;
u64 inject_emergency_signal;
u64 inject_mchk;
u64 inject_pfault_init;
u64 inject_program;
u64 inject_restart;
u64 inject_set_prefix;
u64 inject_stop_signal;
u64 instruction_epsw;
u64 instruction_gs;
u64 instruction_io_other;
u64 instruction_lpsw;
u64 instruction_lpswe;
u64 instruction_lpswey;
u64 instruction_pfmf;
u64 instruction_ptff;
u64 instruction_sck;
u64 instruction_sckpf;
u64 instruction_stidp;
u64 instruction_spx;
u64 instruction_stpx;
u64 instruction_stap;
u64 instruction_iske;
u64 instruction_ri;
u64 instruction_rrbe;
u64 instruction_sske;
u64 instruction_ipte_interlock;
u64 instruction_stsi;
u64 instruction_stfl;
u64 instruction_tb;
u64 instruction_tpi;
u64 instruction_tprot;
u64 instruction_tsch;
u64 instruction_sie;
u64 instruction_essa;
u64 instruction_sthyi;
u64 instruction_sigp_sense;
u64 instruction_sigp_sense_running;
u64 instruction_sigp_external_call;
u64 instruction_sigp_emergency;
u64 instruction_sigp_cond_emergency;
u64 instruction_sigp_start;
u64 instruction_sigp_stop;
u64 instruction_sigp_stop_store_status;
u64 instruction_sigp_store_status;
u64 instruction_sigp_store_adtl_status;
u64 instruction_sigp_arch;
u64 instruction_sigp_prefix;
u64 instruction_sigp_restart;
u64 instruction_sigp_init_cpu_reset;
u64 instruction_sigp_cpu_reset;
u64 instruction_sigp_unknown;
u64 instruction_diagnose_10;
u64 instruction_diagnose_44;
u64 instruction_diagnose_9c;
u64 diag_9c_ignored;
u64 diag_9c_forward;
u64 instruction_diagnose_258;
u64 instruction_diagnose_308;
u64 instruction_diagnose_500;
u64 instruction_diagnose_other;
u64 pfault_sync;
u64 signal_exits;
};
#define PGM_OPERATION 0x01
#define PGM_PRIVILEGED_OP 0x02
#define PGM_EXECUTE 0x03
#define PGM_PROTECTION 0x04
#define PGM_ADDRESSING 0x05
#define PGM_SPECIFICATION 0x06
#define PGM_DATA 0x07
#define PGM_FIXED_POINT_OVERFLOW 0x08
#define PGM_FIXED_POINT_DIVIDE 0x09
#define PGM_DECIMAL_OVERFLOW 0x0a
#define PGM_DECIMAL_DIVIDE 0x0b
#define PGM_HFP_EXPONENT_OVERFLOW 0x0c
#define PGM_HFP_EXPONENT_UNDERFLOW 0x0d
#define PGM_HFP_SIGNIFICANCE 0x0e
#define PGM_HFP_DIVIDE 0x0f
#define PGM_SEGMENT_TRANSLATION 0x10
#define PGM_PAGE_TRANSLATION 0x11
#define PGM_TRANSLATION_SPEC 0x12
#define PGM_SPECIAL_OPERATION 0x13
#define PGM_OPERAND 0x15
#define PGM_TRACE_TABEL 0x16
#define PGM_VECTOR_PROCESSING 0x1b
#define PGM_SPACE_SWITCH 0x1c
#define PGM_HFP_SQUARE_ROOT 0x1d
#define PGM_PC_TRANSLATION_SPEC 0x1f
#define PGM_AFX_TRANSLATION 0x20
#define PGM_ASX_TRANSLATION 0x21
#define PGM_LX_TRANSLATION 0x22
#define PGM_EX_TRANSLATION 0x23
#define PGM_PRIMARY_AUTHORITY 0x24
#define PGM_SECONDARY_AUTHORITY 0x25
#define PGM_LFX_TRANSLATION 0x26
#define PGM_LSX_TRANSLATION 0x27
#define PGM_ALET_SPECIFICATION 0x28
#define PGM_ALEN_TRANSLATION 0x29
#define PGM_ALE_SEQUENCE 0x2a
#define PGM_ASTE_VALIDITY 0x2b
#define PGM_ASTE_SEQUENCE 0x2c
#define PGM_EXTENDED_AUTHORITY 0x2d
#define PGM_LSTE_SEQUENCE 0x2e
#define PGM_ASTE_INSTANCE 0x2f
#define PGM_STACK_FULL 0x30
#define PGM_STACK_EMPTY 0x31
#define PGM_STACK_SPECIFICATION 0x32
#define PGM_STACK_TYPE 0x33
#define PGM_STACK_OPERATION 0x34
#define PGM_ASCE_TYPE 0x38
#define PGM_REGION_FIRST_TRANS 0x39
#define PGM_REGION_SECOND_TRANS 0x3a
#define PGM_REGION_THIRD_TRANS 0x3b
#define PGM_SECURE_STORAGE_ACCESS 0x3d
#define PGM_NON_SECURE_STORAGE_ACCESS 0x3e
#define PGM_SECURE_STORAGE_VIOLATION 0x3f
#define PGM_MONITOR 0x40
#define PGM_PER 0x80
#define PGM_CRYPTO_OPERATION 0x119
/* irq types in ascend order of priorities */
enum irq_types {
IRQ_PEND_SET_PREFIX = 0,
IRQ_PEND_RESTART,
IRQ_PEND_SIGP_STOP,
IRQ_PEND_IO_ISC_7,
IRQ_PEND_IO_ISC_6,
IRQ_PEND_IO_ISC_5,
IRQ_PEND_IO_ISC_4,
IRQ_PEND_IO_ISC_3,
IRQ_PEND_IO_ISC_2,
IRQ_PEND_IO_ISC_1,
IRQ_PEND_IO_ISC_0,
IRQ_PEND_VIRTIO,
IRQ_PEND_PFAULT_DONE,
IRQ_PEND_PFAULT_INIT,
IRQ_PEND_EXT_HOST,
IRQ_PEND_EXT_SERVICE,
IRQ_PEND_EXT_SERVICE_EV,
IRQ_PEND_EXT_TIMING,
IRQ_PEND_EXT_CPU_TIMER,
IRQ_PEND_EXT_CLOCK_COMP,
IRQ_PEND_EXT_EXTERNAL,
IRQ_PEND_EXT_EMERGENCY,
IRQ_PEND_EXT_MALFUNC,
IRQ_PEND_EXT_IRQ_KEY,
IRQ_PEND_MCHK_REP,
IRQ_PEND_PROG,
IRQ_PEND_SVC,
IRQ_PEND_MCHK_EX,
IRQ_PEND_COUNT
};
/* We have 2M for virtio device descriptor pages. Smallest amount of
* memory per page is 24 bytes (1 queue), so (2048*1024) / 24 = 87381
*/
#define KVM_S390_MAX_VIRTIO_IRQS 87381
/*
* Repressible (non-floating) machine check interrupts
* subclass bits in MCIC
*/
#define MCHK_EXTD_BIT 58
#define MCHK_DEGR_BIT 56
#define MCHK_WARN_BIT 55
#define MCHK_REP_MASK ((1UL << MCHK_DEGR_BIT) | \
(1UL << MCHK_EXTD_BIT) | \
(1UL << MCHK_WARN_BIT))
/* Exigent machine check interrupts subclass bits in MCIC */
#define MCHK_SD_BIT 63
#define MCHK_PD_BIT 62
#define MCHK_EX_MASK ((1UL << MCHK_SD_BIT) | (1UL << MCHK_PD_BIT))
#define IRQ_PEND_EXT_MASK ((1UL << IRQ_PEND_EXT_IRQ_KEY) | \
(1UL << IRQ_PEND_EXT_CLOCK_COMP) | \
(1UL << IRQ_PEND_EXT_CPU_TIMER) | \
(1UL << IRQ_PEND_EXT_MALFUNC) | \
(1UL << IRQ_PEND_EXT_EMERGENCY) | \
(1UL << IRQ_PEND_EXT_EXTERNAL) | \
(1UL << IRQ_PEND_EXT_TIMING) | \
(1UL << IRQ_PEND_EXT_HOST) | \
(1UL << IRQ_PEND_EXT_SERVICE) | \
(1UL << IRQ_PEND_EXT_SERVICE_EV) | \
(1UL << IRQ_PEND_VIRTIO) | \
(1UL << IRQ_PEND_PFAULT_INIT) | \
(1UL << IRQ_PEND_PFAULT_DONE))
#define IRQ_PEND_IO_MASK ((1UL << IRQ_PEND_IO_ISC_0) | \
(1UL << IRQ_PEND_IO_ISC_1) | \
(1UL << IRQ_PEND_IO_ISC_2) | \
(1UL << IRQ_PEND_IO_ISC_3) | \
(1UL << IRQ_PEND_IO_ISC_4) | \
(1UL << IRQ_PEND_IO_ISC_5) | \
(1UL << IRQ_PEND_IO_ISC_6) | \
(1UL << IRQ_PEND_IO_ISC_7))
#define IRQ_PEND_MCHK_MASK ((1UL << IRQ_PEND_MCHK_REP) | \
(1UL << IRQ_PEND_MCHK_EX))
#define IRQ_PEND_EXT_II_MASK ((1UL << IRQ_PEND_EXT_CPU_TIMER) | \
(1UL << IRQ_PEND_EXT_CLOCK_COMP) | \
(1UL << IRQ_PEND_EXT_EMERGENCY) | \
(1UL << IRQ_PEND_EXT_EXTERNAL) | \
(1UL << IRQ_PEND_EXT_SERVICE) | \
(1UL << IRQ_PEND_EXT_SERVICE_EV))
struct kvm_s390_interrupt_info {
struct list_head list;
u64 type;
union {
struct kvm_s390_io_info io;
struct kvm_s390_ext_info ext;
struct kvm_s390_pgm_info pgm;
struct kvm_s390_emerg_info emerg;
struct kvm_s390_extcall_info extcall;
struct kvm_s390_prefix_info prefix;
struct kvm_s390_stop_info stop;
struct kvm_s390_mchk_info mchk;
};
};
struct kvm_s390_irq_payload {
struct kvm_s390_io_info io;
struct kvm_s390_ext_info ext;
struct kvm_s390_pgm_info pgm;
struct kvm_s390_emerg_info emerg;
struct kvm_s390_extcall_info extcall;
struct kvm_s390_prefix_info prefix;
struct kvm_s390_stop_info stop;
struct kvm_s390_mchk_info mchk;
};
struct kvm_s390_local_interrupt {
spinlock_t lock;
DECLARE_BITMAP(sigp_emerg_pending, KVM_MAX_VCPUS);
struct kvm_s390_irq_payload irq;
unsigned long pending_irqs;
};
#define FIRQ_LIST_IO_ISC_0 0
#define FIRQ_LIST_IO_ISC_1 1
#define FIRQ_LIST_IO_ISC_2 2
#define FIRQ_LIST_IO_ISC_3 3
#define FIRQ_LIST_IO_ISC_4 4
#define FIRQ_LIST_IO_ISC_5 5
#define FIRQ_LIST_IO_ISC_6 6
#define FIRQ_LIST_IO_ISC_7 7
#define FIRQ_LIST_PFAULT 8
#define FIRQ_LIST_VIRTIO 9
#define FIRQ_LIST_COUNT 10
#define FIRQ_CNTR_IO 0
#define FIRQ_CNTR_SERVICE 1
#define FIRQ_CNTR_VIRTIO 2
#define FIRQ_CNTR_PFAULT 3
#define FIRQ_MAX_COUNT 4
/* mask the AIS mode for a given ISC */
#define AIS_MODE_MASK(isc) (0x80 >> isc)
#define KVM_S390_AIS_MODE_ALL 0
#define KVM_S390_AIS_MODE_SINGLE 1
struct kvm_s390_float_interrupt {
unsigned long pending_irqs;
unsigned long masked_irqs;
spinlock_t lock;
struct list_head lists[FIRQ_LIST_COUNT];
int counters[FIRQ_MAX_COUNT];
struct kvm_s390_mchk_info mchk;
struct kvm_s390_ext_info srv_signal;
int last_sleep_cpu;
spinlock_t ais_lock;
u8 simm;
u8 nimm;
};
struct kvm_hw_wp_info_arch {
unsigned long addr;
unsigned long phys_addr;
int len;
char *old_data;
};
struct kvm_hw_bp_info_arch {
unsigned long addr;
int len;
};
/*
* Only the upper 16 bits of kvm_guest_debug->control are arch specific.
* Further KVM_GUESTDBG flags which an be used from userspace can be found in
* arch/s390/include/uapi/asm/kvm.h
*/
#define KVM_GUESTDBG_EXIT_PENDING 0x10000000
#define guestdbg_enabled(vcpu) \
(vcpu->guest_debug & KVM_GUESTDBG_ENABLE)
#define guestdbg_sstep_enabled(vcpu) \
(vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
#define guestdbg_hw_bp_enabled(vcpu) \
(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
#define guestdbg_exit_pending(vcpu) (guestdbg_enabled(vcpu) && \
(vcpu->guest_debug & KVM_GUESTDBG_EXIT_PENDING))
#define KVM_GUESTDBG_VALID_MASK \
(KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP |\
KVM_GUESTDBG_USE_HW_BP | KVM_GUESTDBG_EXIT_PENDING)
struct kvm_guestdbg_info_arch {
unsigned long cr0;
unsigned long cr9;
unsigned long cr10;
unsigned long cr11;
struct kvm_hw_bp_info_arch *hw_bp_info;
struct kvm_hw_wp_info_arch *hw_wp_info;
int nr_hw_bp;
int nr_hw_wp;
unsigned long last_bp;
};
struct kvm_s390_pv_vcpu {
u64 handle;
unsigned long stor_base;
};
struct kvm_vcpu_arch {
struct kvm_s390_sie_block *sie_block;
/* if vsie is active, currently executed shadow sie control block */
struct kvm_s390_sie_block *vsie_block;
unsigned int host_acrs[NUM_ACRS];
struct gs_cb *host_gscb;
struct kvm_s390_local_interrupt local_int;
struct hrtimer ckc_timer;
struct kvm_s390_pgm_info pgm;
struct gmap *gmap;
struct kvm_guestdbg_info_arch guestdbg;
unsigned long pfault_token;
unsigned long pfault_select;
unsigned long pfault_compare;
bool cputm_enabled;
/*
* The seqcount protects updates to cputm_start and sie_block.cputm,
* this way we can have non-blocking reads with consistent values.
* Only the owning VCPU thread (vcpu->cpu) is allowed to change these
* values and to start/stop/enable/disable cpu timer accounting.
*/
seqcount_t cputm_seqcount;
__u64 cputm_start;
bool gs_enabled;
bool skey_enabled;
/* Indicator if the access registers have been loaded from guest */
bool acrs_loaded;
bool initialized;
struct kvm_s390_pv_vcpu pv;
union diag318_info diag318_info;
struct kvm_s390_mmu_cache *mc;
};
struct kvm_vm_stat {
struct kvm_vm_stat_generic generic;
u64 inject_io;
u64 io_390_adapter_map;
u64 io_390_adapter_unmap;
u64 io_390_inatomic;
u64 io_flic_inject_airq;
u64 io_set_adapter_int;
u64 io_390_inatomic_no_inject;
u64 inject_float_mchk;
u64 inject_pfault_done;
u64 inject_service_signal;
u64 inject_virtio;
u64 aen_forward;
u64 gmap_shadow_create;
u64 gmap_shadow_reuse;
u64 gmap_shadow_r1_entry;
u64 gmap_shadow_r2_entry;
u64 gmap_shadow_r3_entry;
u64 gmap_shadow_sg_entry;
u64 gmap_shadow_pg_entry;
};
struct kvm_arch_memory_slot {
};
struct s390_map_info {
struct list_head list;
__u64 guest_addr;
__u64 addr;
struct page *page;
/*
* True if the page is long-term pinned. False if long-term pinning
* failed and this entry exists only to preserve MAP/UNMAP symmetry.
*/
bool pinned;
};
struct s390_io_adapter {
unsigned int id;
int isc;
bool maskable;
bool masked;
bool swap;
bool suppressible;
spinlock_t maps_lock;
struct list_head maps;
unsigned int nr_maps;
};
#define MAX_S390_IO_ADAPTERS ((MAX_ISC + 1) * 8)
#define MAX_S390_ADAPTER_MAPS 256
/* maximum size of facilities and facility mask is 2k bytes */
#define S390_ARCH_FAC_LIST_SIZE_BYTE (1<<11)
#define S390_ARCH_FAC_LIST_SIZE_U64 \
(S390_ARCH_FAC_LIST_SIZE_BYTE / sizeof(u64))
#define S390_ARCH_FAC_MASK_SIZE_BYTE S390_ARCH_FAC_LIST_SIZE_BYTE
#define S390_ARCH_FAC_MASK_SIZE_U64 \
(S390_ARCH_FAC_MASK_SIZE_BYTE / sizeof(u64))
struct kvm_s390_cpu_model {
/* facility mask supported by kvm & hosting machine */
__u64 fac_mask[S390_ARCH_FAC_MASK_SIZE_U64];
struct kvm_s390_vm_cpu_subfunc subfuncs;
/* facility list requested by guest (in dma page) */
__u64 *fac_list;
u64 cpuid;
unsigned short ibc;
/* subset of available UV-features for pv-guests enabled by user space */
struct kvm_s390_vm_cpu_uv_feat uv_feat_guest;
};
#define S390_ARCH_FAC_FORMAT_2 2
struct kvm_s390_flcb2 {
union {
struct {
u8 reserved0[7];
u8 length;
};
u64 header_val;
};
u64 facilities[S390_ARCH_FAC_LIST_SIZE_U64];
};
typedef int (*crypto_hook)(struct kvm_vcpu *vcpu);
struct kvm_s390_crypto {
struct kvm_s390_crypto_cb *crycb;
struct rw_semaphore pqap_hook_rwsem;
crypto_hook *pqap_hook;
__u32 crycbd;
__u8 aes_kw;
__u8 dea_kw;
__u8 apie;
};
#define APCB0_MASK_SIZE 1
struct kvm_s390_apcb0 {
__u64 apm[APCB0_MASK_SIZE]; /* 0x0000 */
__u64 aqm[APCB0_MASK_SIZE]; /* 0x0008 */
__u64 adm[APCB0_MASK_SIZE]; /* 0x0010 */
__u64 reserved18; /* 0x0018 */
};
#define APCB1_MASK_SIZE 4
struct kvm_s390_apcb1 {
__u64 apm[APCB1_MASK_SIZE]; /* 0x0000 */
__u64 aqm[APCB1_MASK_SIZE]; /* 0x0020 */
__u64 adm[APCB1_MASK_SIZE]; /* 0x0040 */
__u64 reserved60[4]; /* 0x0060 */
};
struct kvm_s390_crypto_cb {
struct kvm_s390_apcb0 apcb0; /* 0x0000 */
__u8 reserved20[0x0048 - 0x0020]; /* 0x0020 */
__u8 dea_wrapping_key_mask[24]; /* 0x0048 */
__u8 aes_wrapping_key_mask[32]; /* 0x0060 */
struct kvm_s390_apcb1 apcb1; /* 0x0080 */
};
struct kvm_s390_gisa {
union {
struct { /* common to all formats */
u32 next_alert;
u8 ipm;
u8 reserved01[2];
u8 iam;
};
struct { /* format 0 */
u32 next_alert;
u8 ipm;
u8 reserved01;
u8 : 6;
u8 g : 1;
u8 c : 1;
u8 iam;
u8 reserved02[4];
u32 airq_count;
} g0;
struct { /* format 1 */
u32 next_alert;
u8 ipm;
u8 simm;
u8 nimm;
u8 iam;
u8 aism[8];
u8 : 6;
u8 g : 1;
u8 c : 1;
u8 reserved03[11];
u32 airq_count;
} g1;
struct {
u64 word[4];
} u64;
};
};
struct kvm_s390_gib {
u32 alert_list_origin;
u32 reserved01;
u8:5;
u8 nisc:3;
u8 reserved03[3];
u32 reserved04[5];
};
/*
* sie_page2 has to be allocated as DMA because fac_list, crycb and
* gisa need 31bit addresses in the sie control block.
*/
struct sie_page2 {
__u64 fac_list[S390_ARCH_FAC_LIST_SIZE_U64]; /* 0x0000 */
struct kvm_s390_crypto_cb crycb; /* 0x0800 */
struct kvm_s390_gisa gisa; /* 0x0900 */
struct kvm *kvm; /* 0x0920 */
u8 reserved928[0x1000 - 0x928]; /* 0x0928 */
};
struct vsie_page;
struct kvm_s390_vsie {
struct mutex mutex;
struct radix_tree_root addr_to_page;
int page_count;
int next;
struct vsie_page *pages[KVM_MAX_VCPUS];
};
struct kvm_s390_gisa_iam {
u8 mask;
spinlock_t ref_lock;
u32 ref_count[MAX_ISC + 1];
};
struct kvm_s390_gisa_interrupt {
struct kvm_s390_gisa *origin;
struct kvm_s390_gisa_iam alert;
struct hrtimer timer;
u64 expires;
DECLARE_BITMAP(kicked_mask, KVM_MAX_VCPUS);
};
struct kvm_s390_pv {
u64 handle;
u64 guest_len;
unsigned long stor_base;
void *stor_var;
bool dumping;
void *set_aside;
struct list_head need_cleanup;
struct mmu_notifier mmu_notifier;
/* Protects against concurrent import-like operations */
struct mutex import_lock;
};
struct kvm_s390_mmu_cache;
struct kvm_arch {
struct esca_block *sca;
debug_info_t *dbf;
struct kvm_s390_float_interrupt float_int;
struct kvm_device *flic;
struct gmap *gmap;
unsigned long mem_limit;
int css_support;
int use_irqchip;
int use_cmma;
int use_pfmfi;
int use_skf;
int use_zpci_interp;
int user_cpu_state_ctrl;
int user_sigp;
int user_stsi;
int user_instr0;
int user_operexec;
int allow_vsie_esamode;
struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];
wait_queue_head_t ipte_wq;
int ipte_lock_count;
struct mutex ipte_mutex;
spinlock_t start_stop_lock;
struct sie_page2 *sie_page2;
struct kvm_s390_cpu_model model;
struct kvm_s390_crypto crypto;
struct kvm_s390_vsie vsie;
u8 epdx;
u64 epoch;
int migration_mode;
atomic64_t cmma_dirty_pages;
/* subset of available cpu features enabled by user space */
DECLARE_BITMAP(cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
/* indexed by vcpu_idx */
DECLARE_BITMAP(idle_mask, KVM_MAX_VCPUS);
struct kvm_s390_gisa_interrupt gisa_int;
struct kvm_s390_pv pv;
struct list_head kzdev_list;
spinlock_t kzdev_list_lock;
struct kvm_s390_mmu_cache *mc;
};
#define KVM_HVA_ERR_BAD (-1UL)
#define KVM_HVA_ERR_RO_BAD (-2UL)
static inline bool kvm_is_error_hva(unsigned long addr)
{
return IS_ERR_VALUE(addr);
}
#define ASYNC_PF_PER_VCPU 64
struct kvm_arch_async_pf {
unsigned long pfault_token;
};
bool kvm_arch_can_dequeue_async_page_present(struct kvm_vcpu *vcpu);
void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu,
struct kvm_async_pf *work);
bool kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
struct kvm_async_pf *work);
void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
struct kvm_async_pf *work);
static inline void kvm_arch_async_page_present_queued(struct kvm_vcpu *vcpu) {}
void kvm_arch_crypto_clear_masks(struct kvm *kvm);
void kvm_arch_crypto_set_masks(struct kvm *kvm, unsigned long *apm,
unsigned long *aqm, unsigned long *adm);
#define SIE64_RETURN_NORMAL 0
#define SIE64_RETURN_MCCK 1
int __sie64a(phys_addr_t sie_block_phys, struct kvm_s390_sie_block *sie_block, u64 *rsa,
unsigned long gasce);
static inline int sie64a(struct kvm_s390_sie_block *sie_block, u64 *rsa, unsigned long gasce)
{
return __sie64a(virt_to_phys(sie_block), sie_block, rsa, gasce);
}
extern char sie_exit;
bool kvm_s390_pv_is_protected(struct kvm *kvm);
bool kvm_s390_pv_cpu_is_protected(struct kvm_vcpu *vcpu);
extern int kvm_s390_enter_exit_sie(struct kvm_s390_sie_block *scb,
u64 *gprs, unsigned long gasce);
extern int kvm_s390_gisc_register(struct kvm *kvm, u32 gisc);
extern int kvm_s390_gisc_unregister(struct kvm *kvm, u32 gisc);
bool kvm_s390_is_gpa_in_memslot(struct kvm *kvm, gpa_t gpa);
static inline void kvm_arch_free_memslot(struct kvm *kvm,
struct kvm_memory_slot *slot) {}
static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
static inline void kvm_arch_flush_shadow_all(struct kvm *kvm) {}
static inline void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
struct kvm_memory_slot *slot) {}
static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {}
static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {}
#define __KVM_HAVE_ARCH_VM_FREE
void kvm_arch_free_vm(struct kvm *kvm);
struct zpci_kvm_hook {
int (*kvm_register)(void *opaque, struct kvm *kvm);
void (*kvm_unregister)(void *opaque);
};
extern struct zpci_kvm_hook zpci_kvm_hook;
#endif
@@ -0,0 +1,347 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_KVM_HOST_TYPES_H
#define _ASM_KVM_HOST_TYPES_H
#include <linux/atomic.h>
#include <linux/types.h>
#define KVM_S390_BSCA_CPU_SLOTS 64
#define KVM_S390_ESCA_CPU_SLOTS 248
#define SIGP_CTRL_C 0x80
#define SIGP_CTRL_SCN_MASK 0x3f
union bsca_sigp_ctrl {
__u8 value;
struct {
__u8 c : 1;
__u8 r : 1;
__u8 scn : 6;
};
};
union esca_sigp_ctrl {
__u16 value;
struct {
__u8 c : 1;
__u8 reserved: 7;
__u8 scn;
};
};
struct esca_entry {
union esca_sigp_ctrl sigp_ctrl;
__u16 reserved1[3];
__u64 sda;
__u64 reserved2[6];
};
struct bsca_entry {
__u8 reserved0;
union bsca_sigp_ctrl sigp_ctrl;
__u16 reserved[3];
__u64 sda;
__u64 reserved2[2];
};
union ipte_control {
unsigned long val;
struct {
unsigned long k : 1;
unsigned long kh : 31;
unsigned long kg : 32;
};
};
/*
* Utility is defined as two bytes but having it four bytes wide
* generates more efficient code. Since the following bytes are
* reserved this makes no functional difference.
*/
union sca_utility {
__u32 val;
struct {
__u32 mtcr : 1;
__u32 : 31;
};
};
struct bsca_block {
union ipte_control ipte_control;
__u64 reserved[5];
__u64 mcn;
union sca_utility utility;
__u8 reserved2[4];
struct bsca_entry cpu[KVM_S390_BSCA_CPU_SLOTS];
};
struct esca_block {
union ipte_control ipte_control;
__u64 reserved1[6];
union sca_utility utility;
__u8 reserved2[4];
__u64 mcn[4];
__u64 reserved3[20];
struct esca_entry cpu[KVM_S390_ESCA_CPU_SLOTS];
};
/*
* This struct is used to store some machine check info from lowcore
* for machine checks that happen while the guest is running.
* This info in host's lowcore might be overwritten by a second machine
* check from host when host is in the machine check's high-level handling.
* The size is 24 bytes.
*/
struct mcck_volatile_info {
__u64 mcic;
__u64 failing_storage_address;
__u32 ext_damage_code;
__u32 reserved;
};
#define CR0_INITIAL_MASK (CR0_UNUSED_56 | CR0_INTERRUPT_KEY_SUBMASK | \
CR0_MEASUREMENT_ALERT_SUBMASK)
#define CR14_INITIAL_MASK (CR14_UNUSED_32 | CR14_UNUSED_33 | \
CR14_EXTERNAL_DAMAGE_SUBMASK)
#define SIDAD_SIZE_MASK 0xff
#define sida_addr(sie_block) phys_to_virt((sie_block)->sidad & PAGE_MASK)
#define sida_size(sie_block) \
((((sie_block)->sidad & SIDAD_SIZE_MASK) + 1) * PAGE_SIZE)
#define CPUSTAT_STOPPED 0x80000000
#define CPUSTAT_WAIT 0x10000000
#define CPUSTAT_ECALL_PEND 0x08000000
#define CPUSTAT_STOP_INT 0x04000000
#define CPUSTAT_IO_INT 0x02000000
#define CPUSTAT_EXT_INT 0x01000000
#define CPUSTAT_RUNNING 0x00800000
#define CPUSTAT_RETAINED 0x00400000
#define CPUSTAT_TIMING_SUB 0x00020000
#define CPUSTAT_SIE_SUB 0x00010000
#define CPUSTAT_RRF 0x00008000
#define CPUSTAT_SLSV 0x00004000
#define CPUSTAT_SLSR 0x00002000
#define CPUSTAT_ZARCH 0x00000800
#define CPUSTAT_MCDS 0x00000100
#define CPUSTAT_KSS 0x00000200
#define CPUSTAT_SM 0x00000080
#define CPUSTAT_IBS 0x00000040
#define CPUSTAT_GED2 0x00000010
#define CPUSTAT_G 0x00000008
#define CPUSTAT_GED 0x00000004
#define CPUSTAT_J 0x00000002
#define CPUSTAT_P 0x00000001
struct kvm_s390_sie_block {
atomic_t cpuflags; /* 0x0000 */
__u32 : 1; /* 0x0004 */
__u32 prefix : 19;
__u32 ibc : 12;
__u8 reserved08[4]; /* 0x0008 */
#define PROG_IN_SIE (1<<0)
__u32 prog0c; /* 0x000c */
union {
__u8 reserved10[16]; /* 0x0010 */
struct {
__u64 pv_handle_cpu;
__u64 pv_handle_config;
};
};
#define PROG_BLOCK_SIE (1<<0)
#define PROG_REQUEST (1<<1)
atomic_t prog20; /* 0x0020 */
__u8 reserved24[4]; /* 0x0024 */
__u64 cputm; /* 0x0028 */
__u64 ckc; /* 0x0030 */
__u64 epoch; /* 0x0038 */
__u32 svcc; /* 0x0040 */
#define LCTL_CR0 0x8000
#define LCTL_CR6 0x0200
#define LCTL_CR9 0x0040
#define LCTL_CR10 0x0020
#define LCTL_CR11 0x0010
#define LCTL_CR14 0x0002
__u16 lctl; /* 0x0044 */
__s16 icpua; /* 0x0046 */
#define ICTL_OPEREXC 0x80000000
#define ICTL_PINT 0x20000000
#define ICTL_LPSW 0x00400000
#define ICTL_STCTL 0x00040000
#define ICTL_ISKE 0x00004000
#define ICTL_SSKE 0x00002000
#define ICTL_RRBE 0x00001000
#define ICTL_TPROT 0x00000200
__u32 ictl; /* 0x0048 */
#define ECA_CEI 0x80000000
#define ECA_IB 0x40000000
#define ECA_SIGPI 0x10000000
#define ECA_MVPGI 0x01000000
#define ECA_AIV 0x00200000
#define ECA_VX 0x00020000
#define ECA_PROTEXCI 0x00002000
#define ECA_APIE 0x00000008
#define ECA_SII 0x00000001
__u32 eca; /* 0x004c */
#define ICPT_INST 0x04
#define ICPT_PROGI 0x08
#define ICPT_INSTPROGI 0x0C
#define ICPT_EXTREQ 0x10
#define ICPT_EXTINT 0x14
#define ICPT_IOREQ 0x18
#define ICPT_WAIT 0x1c
#define ICPT_VALIDITY 0x20
#define ICPT_STOP 0x28
#define ICPT_OPEREXC 0x2C
#define ICPT_PARTEXEC 0x38
#define ICPT_IOINST 0x40
#define ICPT_KSS 0x5c
#define ICPT_MCHKREQ 0x60
#define ICPT_INT_ENABLE 0x64
#define ICPT_PV_INSTR 0x68
#define ICPT_PV_NOTIFY 0x6c
#define ICPT_PV_PREF 0x70
__u8 icptcode; /* 0x0050 */
__u8 icptstatus; /* 0x0051 */
__u16 ihcpu; /* 0x0052 */
__u8 reserved54; /* 0x0054 */
#define IICTL_CODE_NONE 0x00
#define IICTL_CODE_MCHK 0x01
#define IICTL_CODE_EXT 0x02
#define IICTL_CODE_IO 0x03
#define IICTL_CODE_RESTART 0x04
#define IICTL_CODE_SPECIFICATION 0x10
#define IICTL_CODE_OPERAND 0x11
__u8 iictl; /* 0x0055 */
__u16 ipa; /* 0x0056 */
__u32 ipb; /* 0x0058 */
__u32 scaoh; /* 0x005c */
#define FPF_BPBC 0x20
__u8 fpf; /* 0x0060 */
#define ECB_GS 0x40
#define ECB_TE 0x10
#define ECB_SPECI 0x08
#define ECB_SRSI 0x04
#define ECB_HOSTPROTINT 0x02
#define ECB_PTF 0x01
__u8 ecb; /* 0x0061 */
#define ECB2_CMMA 0x80
#define ECB2_IEP 0x20
#define ECB2_PFMFI 0x08
#define ECB2_ESCA 0x04
#define ECB2_ZPCI_LSI 0x02
__u8 ecb2; /* 0x0062 */
#define ECB3_AISI 0x20
#define ECB3_AISII 0x10
#define ECB3_DEA 0x08
#define ECB3_AES 0x04
#define ECB3_RI 0x01
__u8 ecb3; /* 0x0063 */
#define ESCA_SCAOL_MASK ~0x3fU
__u32 scaol; /* 0x0064 */
__u8 sdf; /* 0x0068 */
__u8 epdx; /* 0x0069 */
__u8 cpnc; /* 0x006a */
__u8 reserved6b; /* 0x006b */
__u32 todpr; /* 0x006c */
#define GISA_FORMAT1 0x00000001
__u32 gd; /* 0x0070 */
__u8 reserved74[12]; /* 0x0074 */
__u64 mso; /* 0x0080 */
__u64 msl; /* 0x0088 */
psw_t gpsw; /* 0x0090 */
__u64 gg14; /* 0x00a0 */
__u64 gg15; /* 0x00a8 */
__u8 reservedb0[8]; /* 0x00b0 */
#define HPID_KVM 0x4
#define HPID_VSIE 0x5
__u8 hpid; /* 0x00b8 */
__u8 reservedb9[7]; /* 0x00b9 */
union {
struct {
__u32 eiparams; /* 0x00c0 */
__u16 extcpuaddr; /* 0x00c4 */
__u16 eic; /* 0x00c6 */
};
__u64 mcic; /* 0x00c0 */
} __packed;
__u32 reservedc8; /* 0x00c8 */
union {
struct {
__u16 pgmilc; /* 0x00cc */
__u16 iprcc; /* 0x00ce */
};
__u32 edc; /* 0x00cc */
} __packed;
union {
struct {
__u32 dxc; /* 0x00d0 */
__u16 mcn; /* 0x00d4 */
__u8 perc; /* 0x00d6 */
__u8 peratmid; /* 0x00d7 */
};
__u64 faddr; /* 0x00d0 */
} __packed;
__u64 peraddr; /* 0x00d8 */
__u8 eai; /* 0x00e0 */
__u8 peraid; /* 0x00e1 */
__u8 oai; /* 0x00e2 */
__u8 armid; /* 0x00e3 */
__u8 reservede4[4]; /* 0x00e4 */
union {
__u64 tecmc; /* 0x00e8 */
struct {
__u16 subchannel_id; /* 0x00e8 */
__u16 subchannel_nr; /* 0x00ea */
__u32 io_int_parm; /* 0x00ec */
__u32 io_int_word; /* 0x00f0 */
};
} __packed;
__u8 reservedf4[8]; /* 0x00f4 */
#define CRYCB_FORMAT_MASK 0x00000003
#define CRYCB_FORMAT0 0x00000000
#define CRYCB_FORMAT1 0x00000001
#define CRYCB_FORMAT2 0x00000003
__u32 crycbd; /* 0x00fc */
__u64 gcr[16]; /* 0x0100 */
union {
__u64 gbea; /* 0x0180 */
__u64 sidad;
};
__u8 reserved188[8]; /* 0x0188 */
__u64 sdnxo; /* 0x0190 */
__u8 reserved198[8]; /* 0x0198 */
__u32 fac; /* 0x01a0 */
__u8 reserved1a4[20]; /* 0x01a4 */
__u64 cbrlo; /* 0x01b8 */
__u8 reserved1c0[8]; /* 0x01c0 */
#define ECD_HOSTREGMGMT 0x20000000
#define ECD_MEF 0x08000000
#define ECD_ETOKENF 0x02000000
#define ECD_ECC 0x00200000
#define ECD_HMAC 0x00004000
__u32 ecd; /* 0x01c8 */
__u8 reserved1cc[18]; /* 0x01cc */
__u64 pp; /* 0x01de */
__u8 reserved1e6[2]; /* 0x01e6 */
__u64 itdba; /* 0x01e8 */
__u64 riccbd; /* 0x01f0 */
__u64 gvrd; /* 0x01f8 */
} __packed __aligned(512);
struct kvm_s390_itdb {
__u8 data[256];
};
struct sie_page {
struct kvm_s390_sie_block sie_block;
struct mcck_volatile_info mcck_info; /* 0x0200 */
__u8 reserved218[360]; /* 0x0218 */
__u64 pv_grregs[16]; /* 0x0380 */
__u8 reserved400[512]; /* 0x0400 */
struct kvm_s390_itdb itdb; /* 0x0600 */
__u8 reserved700[2304]; /* 0x0700 */
};
#endif /* _ASM_KVM_HOST_TYPES_H */
@@ -0,0 +1,123 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* definition for paravirtual devices on s390
*
* Copyright IBM Corp. 2008
*
* Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
*/
/*
* Hypercalls for KVM on s390. The calling convention is similar to the
* s390 ABI, so we use R2-R6 for parameters 1-5. In addition we use R1
* as hypercall number and R7 as parameter 6. The return value is
* written to R2. We use the diagnose instruction as hypercall. To avoid
* conflicts with existing diagnoses for LPAR and z/VM, we do not use
* the instruction encoded number, but specify the number in R1 and
* use 0x500 as KVM hypercall
*
* Copyright IBM Corp. 2007,2008
* Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
*/
#ifndef __S390_KVM_PARA_H
#define __S390_KVM_PARA_H
#include <uapi/asm/kvm_para.h>
#include <asm/diag.h>
#define HYPERCALL_FMT_0
#define HYPERCALL_FMT_1 , "0" (r2)
#define HYPERCALL_FMT_2 , "d" (r3) HYPERCALL_FMT_1
#define HYPERCALL_FMT_3 , "d" (r4) HYPERCALL_FMT_2
#define HYPERCALL_FMT_4 , "d" (r5) HYPERCALL_FMT_3
#define HYPERCALL_FMT_5 , "d" (r6) HYPERCALL_FMT_4
#define HYPERCALL_FMT_6 , "d" (r7) HYPERCALL_FMT_5
#define HYPERCALL_PARM_0
#define HYPERCALL_PARM_1 , unsigned long arg1
#define HYPERCALL_PARM_2 HYPERCALL_PARM_1, unsigned long arg2
#define HYPERCALL_PARM_3 HYPERCALL_PARM_2, unsigned long arg3
#define HYPERCALL_PARM_4 HYPERCALL_PARM_3, unsigned long arg4
#define HYPERCALL_PARM_5 HYPERCALL_PARM_4, unsigned long arg5
#define HYPERCALL_PARM_6 HYPERCALL_PARM_5, unsigned long arg6
#define HYPERCALL_REGS_0
#define HYPERCALL_REGS_1 \
register unsigned long r2 asm("2") = arg1
#define HYPERCALL_REGS_2 \
HYPERCALL_REGS_1; \
register unsigned long r3 asm("3") = arg2
#define HYPERCALL_REGS_3 \
HYPERCALL_REGS_2; \
register unsigned long r4 asm("4") = arg3
#define HYPERCALL_REGS_4 \
HYPERCALL_REGS_3; \
register unsigned long r5 asm("5") = arg4
#define HYPERCALL_REGS_5 \
HYPERCALL_REGS_4; \
register unsigned long r6 asm("6") = arg5
#define HYPERCALL_REGS_6 \
HYPERCALL_REGS_5; \
register unsigned long r7 asm("7") = arg6
#define HYPERCALL_ARGS_0
#define HYPERCALL_ARGS_1 , arg1
#define HYPERCALL_ARGS_2 HYPERCALL_ARGS_1, arg2
#define HYPERCALL_ARGS_3 HYPERCALL_ARGS_2, arg3
#define HYPERCALL_ARGS_4 HYPERCALL_ARGS_3, arg4
#define HYPERCALL_ARGS_5 HYPERCALL_ARGS_4, arg5
#define HYPERCALL_ARGS_6 HYPERCALL_ARGS_5, arg6
#define GENERATE_KVM_HYPERCALL_FUNC(args) \
static inline \
long __kvm_hypercall##args(unsigned long nr HYPERCALL_PARM_##args) \
{ \
register unsigned long __nr asm("1") = nr; \
register long __rc asm("2"); \
HYPERCALL_REGS_##args; \
\
asm volatile ( \
" diag 2,4,0x500" \
: "=d" (__rc) \
: "d" (__nr) HYPERCALL_FMT_##args \
: "memory", "cc"); \
return __rc; \
} \
\
static inline \
long kvm_hypercall##args(unsigned long nr HYPERCALL_PARM_##args) \
{ \
diag_stat_inc(DIAG_STAT_X500); \
return __kvm_hypercall##args(nr HYPERCALL_ARGS_##args); \
}
GENERATE_KVM_HYPERCALL_FUNC(0)
GENERATE_KVM_HYPERCALL_FUNC(1)
GENERATE_KVM_HYPERCALL_FUNC(2)
GENERATE_KVM_HYPERCALL_FUNC(3)
GENERATE_KVM_HYPERCALL_FUNC(4)
GENERATE_KVM_HYPERCALL_FUNC(5)
GENERATE_KVM_HYPERCALL_FUNC(6)
/* kvm on s390 is always paravirtualization enabled */
static inline int kvm_para_available(void)
{
return 1;
}
/* No feature bits are currently assigned for kvm on s390 */
static inline unsigned int kvm_arch_para_features(void)
{
return 0;
}
static inline unsigned int kvm_arch_para_hints(void)
{
return 0;
}
static inline bool kvm_check_and_clear_guest_paused(void)
{
return false;
}
#endif /* __S390_KVM_PARA_H */
@@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_LINKAGE_H
#define __ASM_LINKAGE_H
#include <linux/stringify.h>
#define __ALIGN .balign CONFIG_FUNCTION_ALIGNMENT, 0x07
#define __ALIGN_STR __stringify(__ALIGN)
#define _THIS_IP_ ({ unsigned long __ip; asm volatile("larl %0, ." : "=d" (__ip)); __ip; })
#endif
+257
View File
@@ -0,0 +1,257 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 1999, 2012
* Author(s): Hartmut Penner <hp@de.ibm.com>,
* Martin Schwidefsky <schwidefsky@de.ibm.com>,
* Denis Joseph Barrow,
*/
#ifndef _ASM_S390_LOWCORE_H
#define _ASM_S390_LOWCORE_H
#include <linux/types.h>
#include <asm/tod_types.h>
#include <asm/machine.h>
#include <asm/ptrace.h>
#include <asm/ctlreg.h>
#include <asm/cpu.h>
#include <asm/types.h>
#include <asm/alternative.h>
#define LC_ORDER 1
#define LC_PAGES 2
#define LOWCORE_ALT_ADDRESS _AC(0x70000, UL)
#ifndef __ASSEMBLER__
struct pgm_tdb {
u64 data[32];
};
struct lowcore {
__u8 pad_0x0000[0x0014-0x0000]; /* 0x0000 */
__u32 ipl_parmblock_ptr; /* 0x0014 */
__u8 pad_0x0018[0x0080-0x0018]; /* 0x0018 */
__u32 ext_params; /* 0x0080 */
union {
struct {
__u16 ext_cpu_addr; /* 0x0084 */
__u16 ext_int_code; /* 0x0086 */
};
__u32 ext_int_code_addr;
};
__u32 svc_int_code; /* 0x0088 */
union {
struct {
__u16 pgm_ilc; /* 0x008c */
__u16 pgm_code; /* 0x008e */
};
__u32 pgm_int_code;
};
__u32 data_exc_code; /* 0x0090 */
__u16 mon_class_num; /* 0x0094 */
union {
struct {
__u8 per_code; /* 0x0096 */
__u8 per_atmid; /* 0x0097 */
};
__u16 per_code_combined;
};
__u64 per_address; /* 0x0098 */
__u8 exc_access_id; /* 0x00a0 */
__u8 per_access_id; /* 0x00a1 */
__u8 op_access_id; /* 0x00a2 */
__u8 ar_mode_id; /* 0x00a3 */
__u8 pad_0x00a4[0x00a8-0x00a4]; /* 0x00a4 */
__u64 trans_exc_code; /* 0x00a8 */
__u64 monitor_code; /* 0x00b0 */
union {
struct {
__u16 subchannel_id; /* 0x00b8 */
__u16 subchannel_nr; /* 0x00ba */
__u32 io_int_parm; /* 0x00bc */
__u32 io_int_word; /* 0x00c0 */
};
struct tpi_info tpi_info; /* 0x00b8 */
};
__u8 pad_0x00c4[0x00c8-0x00c4]; /* 0x00c4 */
__u32 stfl_fac_list; /* 0x00c8 */
__u8 pad_0x00cc[0x00e8-0x00cc]; /* 0x00cc */
__u64 mcck_interruption_code; /* 0x00e8 */
__u8 pad_0x00f0[0x00f4-0x00f0]; /* 0x00f0 */
__u32 external_damage_code; /* 0x00f4 */
__u64 failing_storage_address; /* 0x00f8 */
__u8 pad_0x0100[0x0110-0x0100]; /* 0x0100 */
__u64 pgm_last_break; /* 0x0110 */
__u8 pad_0x0118[0x0120-0x0118]; /* 0x0118 */
psw_t restart_old_psw; /* 0x0120 */
psw_t external_old_psw; /* 0x0130 */
psw_t svc_old_psw; /* 0x0140 */
psw_t program_old_psw; /* 0x0150 */
psw_t mcck_old_psw; /* 0x0160 */
psw_t io_old_psw; /* 0x0170 */
__u8 pad_0x0180[0x01a0-0x0180]; /* 0x0180 */
psw_t restart_psw; /* 0x01a0 */
psw_t external_new_psw; /* 0x01b0 */
psw_t svc_new_psw; /* 0x01c0 */
psw_t program_new_psw; /* 0x01d0 */
psw_t mcck_new_psw; /* 0x01e0 */
psw_t io_new_psw; /* 0x01f0 */
/* Save areas. */
__u64 save_area[8]; /* 0x0200 */
__u64 stack_canary; /* 0x0240 */
__u8 pad_0x0248[0x0280-0x0248]; /* 0x0248 */
__u64 save_area_restart[1]; /* 0x0280 */
__u64 pcpu; /* 0x0288 */
/* Return psws. */
psw_t return_psw; /* 0x0290 */
psw_t return_mcck_psw; /* 0x02a0 */
__u64 last_break; /* 0x02b0 */
/* CPU accounting and timing values. */
__u64 sys_enter_timer; /* 0x02b8 */
__u64 mcck_enter_timer; /* 0x02c0 */
__u64 exit_timer; /* 0x02c8 */
__u64 user_timer; /* 0x02d0 */
__u64 guest_timer; /* 0x02d8 */
__u64 system_timer; /* 0x02e0 */
__u64 hardirq_timer; /* 0x02e8 */
__u64 softirq_timer; /* 0x02f0 */
__u64 steal_timer; /* 0x02f8 */
__u64 avg_steal_timer; /* 0x0300 */
__u64 last_update_timer; /* 0x0308 */
__u64 last_update_clock; /* 0x0310 */
union tod_clock int_clock; /* 0x0318 */
__u64 clock_comparator; /* 0x0328 */
__u8 pad_0x0330[0x0340-0x0330]; /* 0x0330 */
/* Current process. */
__u64 current_task; /* 0x0340 */
__u64 kernel_stack; /* 0x0348 */
/* Interrupt, DAT-off and restartstack. */
__u64 async_stack; /* 0x0350 */
__u64 nodat_stack; /* 0x0358 */
__u64 restart_stack; /* 0x0360 */
__u64 mcck_stack; /* 0x0368 */
/* Restart function and parameter. */
__u64 restart_fn; /* 0x0370 */
__u64 restart_data; /* 0x0378 */
__u32 restart_source; /* 0x0380 */
__u32 restart_flags; /* 0x0384 */
/* Address space pointer. */
struct ctlreg kernel_asce; /* 0x0388 */
struct ctlreg user_asce; /* 0x0390 */
/*
* The lpp and current_pid fields form a
* 64-bit value that is set as program
* parameter with the LPP instruction.
*/
__u32 lpp; /* 0x0398 */
__u32 current_pid; /* 0x039c */
/* SMP info area */
__u32 cpu_nr; /* 0x03a0 */
__u32 softirq_pending; /* 0x03a4 */
__s32 preempt_count; /* 0x03a8 */
__u32 spinlock_lockval; /* 0x03ac */
__u32 spinlock_index; /* 0x03b0 */
__u8 pad_0x03b4[0x03b8-0x03b4]; /* 0x03b4 */
__u64 percpu_offset; /* 0x03b8 */
__u8 percpu_register; /* 0x03c0 */
__u8 pad_0x03c1[0x0400-0x03c1]; /* 0x03c1 */
__u32 return_lpswe; /* 0x0400 */
__u32 return_mcck_lpswe; /* 0x0404 */
__u8 pad_0x040a[0x0e00-0x0408]; /* 0x0408 */
/*
* 0xe00 contains the address of the IPL Parameter Information
* block. Dump tools need IPIB for IPL after dump.
* Note: do not change the position of any fields in 0x0e00-0x0f00
*/
__u64 ipib; /* 0x0e00 */
__u32 ipib_checksum; /* 0x0e08 */
__u64 vmcore_info; /* 0x0e0c */
__u8 pad_0x0e14[0x0e18-0x0e14]; /* 0x0e14 */
__u64 os_info; /* 0x0e18 */
__u8 pad_0x0e20[0x11b0-0x0e20]; /* 0x0e20 */
/* Pointer to the machine check extended save area */
__u64 mcesad; /* 0x11b0 */
/* 64 bit extparam used for pfault/diag 250: defined by architecture */
__u64 ext_params2; /* 0x11B8 */
__u8 pad_0x11c0[0x1200-0x11C0]; /* 0x11C0 */
/* CPU register save area: defined by architecture */
__u64 floating_pt_save_area[16]; /* 0x1200 */
__u64 gpregs_save_area[16]; /* 0x1280 */
psw_t psw_save_area; /* 0x1300 */
__u8 pad_0x1310[0x1318-0x1310]; /* 0x1310 */
__u32 prefixreg_save_area; /* 0x1318 */
__u32 fpt_creg_save_area; /* 0x131c */
__u8 pad_0x1320[0x1324-0x1320]; /* 0x1320 */
__u32 tod_progreg_save_area; /* 0x1324 */
__u32 cpu_timer_save_area[2]; /* 0x1328 */
__u32 clock_comp_save_area[2]; /* 0x1330 */
__u64 last_break_save_area; /* 0x1338 */
__u32 access_regs_save_area[16]; /* 0x1340 */
struct ctlreg cregs_save_area[16]; /* 0x1380 */
__u8 pad_0x1400[0x1500-0x1400]; /* 0x1400 */
/* Cryptography-counter designation */
__u64 ccd; /* 0x1500 */
/* AI-extension counter designation */
__u64 aicd; /* 0x1508 */
__u8 pad_0x1510[0x1800-0x1510]; /* 0x1510 */
/* Transaction abort diagnostic block */
struct pgm_tdb pgm_tdb; /* 0x1800 */
__u8 pad_0x1900[0x2000-0x1900]; /* 0x1900 */
} __packed __aligned(8192);
static __always_inline struct lowcore *get_lowcore(void)
{
struct lowcore *lc;
if (__is_defined(__DECOMPRESSOR))
return NULL;
asm_inline(
ALTERNATIVE(" lghi %[lc],0",
" llilh %[lc],%[alt]",
ALT_FEATURE(MFEATURE_LOWCORE))
: [lc] "=d" (lc)
: [alt] "i" (LOWCORE_ALT_ADDRESS >> 16));
return lc;
}
extern struct lowcore *lowcore_ptr[];
static inline void set_prefix(__u32 address)
{
asm volatile("spx %0" : : "Q" (address) : "memory");
}
#else /* __ASSEMBLER__ */
.macro GET_LC reg
ALTERNATIVE "lghi \reg,0", \
__stringify(llilh \reg, LOWCORE_ALT_ADDRESS >> 16), \
ALT_FEATURE(MFEATURE_LOWCORE)
.endm
.macro STMG_LC start, end, savearea
ALTERNATIVE "stmg \start, \end, \savearea", \
__stringify(stmg \start, \end, LOWCORE_ALT_ADDRESS + \savearea), \
ALT_FEATURE(MFEATURE_LOWCORE)
.endm
#endif /* __ASSEMBLER__ */
#endif /* _ASM_S390_LOWCORE_H */
@@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_S390_MACCESS_H
#define __ASM_S390_MACCESS_H
#include <linux/types.h>
#define MEMCPY_REAL_SIZE PAGE_SIZE
#define MEMCPY_REAL_MASK PAGE_MASK
struct iov_iter;
extern unsigned long __memcpy_real_area;
extern pte_t *memcpy_real_ptep;
size_t memcpy_real_iter(struct iov_iter *iter, unsigned long src, size_t count);
int memcpy_real(void *dest, unsigned long src, size_t count);
#ifdef CONFIG_CRASH_DUMP
int copy_oldmem_kernel(void *dst, unsigned long src, size_t count);
#endif
#endif /* __ASM_S390_MACCESS_H */
+104
View File
@@ -0,0 +1,104 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 2024
*/
#ifndef __ASM_S390_MACHINE_H
#define __ASM_S390_MACHINE_H
#include <linux/const.h>
#define MFEATURE_LOWCORE 0
#define MFEATURE_PCI_MIO 1
#define MFEATURE_SCC 2
#define MFEATURE_TLB_GUEST 3
#define MFEATURE_TX 4
#define MFEATURE_ESOP 5
#define MFEATURE_DIAG9C 6
#define MFEATURE_VM 7
#define MFEATURE_KVM 8
#define MFEATURE_LPAR 9
#define MFEATURE_DIAG288 10
#ifndef __ASSEMBLER__
#include <linux/bitops.h>
#include <asm/alternative.h>
extern unsigned long machine_features[1];
#define MAX_MFEATURE_BIT (sizeof(machine_features) * BITS_PER_BYTE)
static inline void __set_machine_feature(unsigned int nr, unsigned long *mfeatures)
{
if (nr >= MAX_MFEATURE_BIT)
return;
__set_bit(nr, mfeatures);
}
static inline void set_machine_feature(unsigned int nr)
{
__set_machine_feature(nr, machine_features);
}
static inline void __clear_machine_feature(unsigned int nr, unsigned long *mfeatures)
{
if (nr >= MAX_MFEATURE_BIT)
return;
__clear_bit(nr, mfeatures);
}
static inline void clear_machine_feature(unsigned int nr)
{
__clear_machine_feature(nr, machine_features);
}
static bool __test_machine_feature(unsigned int nr, unsigned long *mfeatures)
{
if (nr >= MAX_MFEATURE_BIT)
return false;
return test_bit(nr, mfeatures);
}
static bool test_machine_feature(unsigned int nr)
{
return __test_machine_feature(nr, machine_features);
}
static __always_inline bool __test_machine_feature_constant(unsigned int nr)
{
asm goto(
ALTERNATIVE("brcl 15,%l[l_no]", "brcl 0,0", ALT_FEATURE(%[nr]))
:
: [nr] "i" (nr)
:
: l_no);
return true;
l_no:
return false;
}
#define DEFINE_MACHINE_HAS_FEATURE(name, feature) \
static __always_inline bool machine_has_##name(void) \
{ \
if (!__is_defined(__DECOMPRESSOR) && __builtin_constant_p(feature)) \
return __test_machine_feature_constant(feature); \
return test_machine_feature(feature); \
}
DEFINE_MACHINE_HAS_FEATURE(relocated_lowcore, MFEATURE_LOWCORE)
DEFINE_MACHINE_HAS_FEATURE(scc, MFEATURE_SCC)
DEFINE_MACHINE_HAS_FEATURE(tlb_guest, MFEATURE_TLB_GUEST)
DEFINE_MACHINE_HAS_FEATURE(tx, MFEATURE_TX)
DEFINE_MACHINE_HAS_FEATURE(esop, MFEATURE_ESOP)
DEFINE_MACHINE_HAS_FEATURE(diag9c, MFEATURE_DIAG9C)
DEFINE_MACHINE_HAS_FEATURE(vm, MFEATURE_VM)
DEFINE_MACHINE_HAS_FEATURE(kvm, MFEATURE_KVM)
DEFINE_MACHINE_HAS_FEATURE(lpar, MFEATURE_LPAR)
#define machine_is_vm machine_has_vm
#define machine_is_kvm machine_has_kvm
#define machine_is_lpar machine_has_lpar
#endif /* __ASSEMBLER__ */
#endif /* __ASM_S390_MACHINE_H */

Some files were not shown because too many files have changed in this diff Show More