Skip to content

Commit

Permalink
Merge tag 's390-5.14-2' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…git/s390/linux

Pull more s390 updates from Vasily Gorbik:

 - Fix preempt_count initialization.

 - Rework call_on_stack() macro to add proper type handling and avoid
   possible register corruption.

 - More error prone "register asm" removal and fixes.

 - Fix syscall restarting when multiple signals are coming in. This adds
   minimalistic trampolines to vdso so we can return from signal without
   using the stack which requires pgm check handler hacks when NX is
   enabled.

 - Remove HAVE_IRQ_EXIT_ON_IRQ_STACK since this is no longer true after
   switch to generic entry.

 - Fix protected virtualization secure storage access exception
   handling.

 - Make machine check C handler always enter with DAT enabled and move
   register validation to C code.

 - Fix tinyconfig boot problem by avoiding MONITOR CALL without
   CONFIG_BUG.

 - Increase asm symbols alignment to 16 to make it consistent with
   compilers.

 - Enable concurrent access to the CPU Measurement Counter Facility.

 - Add support for dynamic AP bus size limit and rework ap_dqap to deal
   with messages greater than recv buffer.

* tag 's390-5.14-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (41 commits)
  s390: preempt: Fix preempt_count initialization
  s390/linkage: increase asm symbols alignment to 16
  s390: rename CALL_ON_STACK_NORETURN() to call_on_stack_noreturn()
  s390: add type checking to CALL_ON_STACK_NORETURN() macro
  s390: remove old CALL_ON_STACK() macro
  s390/softirq: use call_on_stack() macro
  s390/lib: use call_on_stack() macro
  s390/smp: use call_on_stack() macro
  s390/kexec: use call_on_stack() macro
  s390/irq: use call_on_stack() macro
  s390/mm: use call_on_stack() macro
  s390: introduce proper type handling call_on_stack() macro
  s390/irq: simplify on_async_stack()
  s390/irq: inline do_softirq_own_stack()
  s390/irq: simplify do_softirq_own_stack()
  s390/ap: get rid of register asm in ap_dqap()
  s390: rename PIF_SYSCALL_RESTART to PIF_EXECVE_PGSTE_RESTART
  s390: move restart of execve() syscall
  s390/signal: remove sigreturn on stack
  s390/signal: switch to using vdso for sigreturn and syscall restart
  ...
  • Loading branch information
torvalds committed Jul 10, 2021
2 parents 379cf80 + 6a942f5 commit e98e03d
Show file tree
Hide file tree
Showing 66 changed files with 2,110 additions and 1,721 deletions.
2 changes: 1 addition & 1 deletion arch/s390/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ config S390
select HAVE_GCC_PLUGINS
select HAVE_GENERIC_VDSO
select HAVE_IOREMAP_PROT if PCI
select HAVE_IRQ_EXIT_ON_IRQ_STACK
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZ4
Expand Down Expand Up @@ -438,6 +437,7 @@ config COMPAT
select COMPAT_OLD_SIGACTION
select HAVE_UID16
depends on MULTIUSER
depends on !CC_IS_CLANG
help
Select this option if you want to enable your system kernel to
handle system-calls from ELF binaries for 31 bit ESA. This option
Expand Down
13 changes: 13 additions & 0 deletions arch/s390/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,19 @@ archheaders:
archprepare:
$(Q)$(MAKE) $(build)=$(syscalls) kapi
$(Q)$(MAKE) $(build)=$(tools) kapi
ifeq ($(KBUILD_EXTMOD),)
# We need to generate vdso-offsets.h before compiling certain files in kernel/.
# In order to do that, we should use the archprepare target, but we can't since
# asm-offsets.h is included in some files used to generate vdso-offsets.h, and
# asm-offsets.h is built in prepare0, for which archprepare is a dependency.
# Therefore we need to generate the header after prepare0 has been made, hence
# this hack.
prepare: vdso_prepare
vdso_prepare: prepare0
$(Q)$(MAKE) $(build)=arch/s390/kernel/vdso64 include/generated/vdso64-offsets.h
$(if $(CONFIG_COMPAT),$(Q)$(MAKE) \
$(build)=arch/s390/kernel/vdso32 include/generated/vdso32-offsets.h)
endif

# Don't use tabs in echo arguments
define archhelp
Expand Down
1 change: 1 addition & 0 deletions arch/s390/boot/startup.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ unsigned long __bootdata_preserved(vmemmap_size);
unsigned long __bootdata_preserved(MODULES_VADDR);
unsigned long __bootdata_preserved(MODULES_END);
unsigned long __bootdata(ident_map_size);
int __bootdata(is_full_image) = 1;

u64 __bootdata_preserved(stfle_fac_list[16]);
u64 __bootdata_preserved(alt_stfle_fac_list[16]);
Expand Down
1 change: 1 addition & 0 deletions arch/s390/boot/uv.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ void uv_query_info(void)
uv_info.max_sec_stor_addr = ALIGN(uvcb.max_guest_stor_addr, PAGE_SIZE);
uv_info.max_num_sec_conf = uvcb.max_num_sec_conf;
uv_info.max_guest_cpu_id = uvcb.max_guest_cpu_id;
uv_info.uv_feature_indications = uvcb.uv_feature_indications;
}

#ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
Expand Down
220 changes: 142 additions & 78 deletions arch/s390/include/asm/ap.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,20 @@ struct ap_queue_status {
*/
static inline bool ap_instructions_available(void)
{
register unsigned long reg0 asm ("0") = AP_MKQID(0, 0);
register unsigned long reg1 asm ("1") = 0;
register unsigned long reg2 asm ("2") = 0;
unsigned long reg0 = AP_MKQID(0, 0);
unsigned long reg1 = 0;

asm volatile(
" .long 0xb2af0000\n" /* PQAP(TAPQ) */
"0: la %0,1\n"
" lgr 0,%[reg0]\n" /* qid into gr0 */
" lghi 1,0\n" /* 0 into gr1 */
" lghi 2,0\n" /* 0 into gr2 */
" .long 0xb2af0000\n" /* PQAP(TAPQ) */
"0: la %[reg1],1\n" /* 1 into reg1 */
"1:\n"
EX_TABLE(0b, 1b)
: "+d" (reg1), "+d" (reg2)
: "d" (reg0)
: "cc");
: [reg1] "+&d" (reg1)
: [reg0] "d" (reg0)
: "cc", "0", "1", "2");
return reg1 != 0;
}

Expand All @@ -77,14 +79,18 @@ static inline bool ap_instructions_available(void)
*/
static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info)
{
register unsigned long reg0 asm ("0") = qid;
register struct ap_queue_status reg1 asm ("1");
register unsigned long reg2 asm ("2");

asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */
: "=d" (reg1), "=d" (reg2)
: "d" (reg0)
: "cc");
struct ap_queue_status reg1;
unsigned long reg2;

asm volatile(
" lgr 0,%[qid]\n" /* qid into gr0 */
" lghi 2,0\n" /* 0 into gr2 */
" .long 0xb2af0000\n" /* PQAP(TAPQ) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
" lgr %[reg2],2\n" /* gr2 into reg2 */
: [reg1] "=&d" (reg1), [reg2] "=&d" (reg2)
: [qid] "d" (qid)
: "cc", "0", "1", "2");
if (info)
*info = reg2;
return reg1;
Expand Down Expand Up @@ -115,14 +121,16 @@ static inline struct ap_queue_status ap_test_queue(ap_qid_t qid,
*/
static inline struct ap_queue_status ap_rapq(ap_qid_t qid)
{
register unsigned long reg0 asm ("0") = qid | (1UL << 24);
register struct ap_queue_status reg1 asm ("1");
unsigned long reg0 = qid | (1UL << 24); /* fc 1UL is RAPQ */
struct ap_queue_status reg1;

asm volatile(
".long 0xb2af0000" /* PQAP(RAPQ) */
: "=d" (reg1)
: "d" (reg0)
: "cc");
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
" .long 0xb2af0000\n" /* PQAP(RAPQ) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
: [reg1] "=&d" (reg1)
: [reg0] "d" (reg0)
: "cc", "0", "1");
return reg1;
}

Expand All @@ -134,14 +142,16 @@ static inline struct ap_queue_status ap_rapq(ap_qid_t qid)
*/
static inline struct ap_queue_status ap_zapq(ap_qid_t qid)
{
register unsigned long reg0 asm ("0") = qid | (2UL << 24);
register struct ap_queue_status reg1 asm ("1");
unsigned long reg0 = qid | (2UL << 24); /* fc 2UL is ZAPQ */
struct ap_queue_status reg1;

asm volatile(
".long 0xb2af0000" /* PQAP(ZAPQ) */
: "=d" (reg1)
: "d" (reg0)
: "cc");
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
" .long 0xb2af0000\n" /* PQAP(ZAPQ) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
: [reg1] "=&d" (reg1)
: [reg0] "d" (reg0)
: "cc", "0", "1");
return reg1;
}

Expand Down Expand Up @@ -172,18 +182,20 @@ struct ap_config_info {
*/
static inline int ap_qci(struct ap_config_info *config)
{
register unsigned long reg0 asm ("0") = 4UL << 24;
register unsigned long reg1 asm ("1") = -EOPNOTSUPP;
register struct ap_config_info *reg2 asm ("2") = config;
unsigned long reg0 = 4UL << 24; /* fc 4UL is QCI */
unsigned long reg1 = -EOPNOTSUPP;
struct ap_config_info *reg2 = config;

asm volatile(
".long 0xb2af0000\n" /* PQAP(QCI) */
"0: la %0,0\n"
" lgr 0,%[reg0]\n" /* QCI fc into gr0 */
" lgr 2,%[reg2]\n" /* ptr to config into gr2 */
" .long 0xb2af0000\n" /* PQAP(QCI) */
"0: la %[reg1],0\n" /* good case, QCI fc available */
"1:\n"
EX_TABLE(0b, 1b)
: "+d" (reg1)
: "d" (reg0), "d" (reg2)
: "cc", "memory");
: [reg1] "+&d" (reg1)
: [reg0] "d" (reg0), [reg2] "d" (reg2)
: "cc", "memory", "0", "2");

return reg1;
}
Expand Down Expand Up @@ -220,21 +232,25 @@ static inline struct ap_queue_status ap_aqic(ap_qid_t qid,
struct ap_qirq_ctrl qirqctrl,
void *ind)
{
register unsigned long reg0 asm ("0") = qid | (3UL << 24);
register union {
unsigned long reg0 = qid | (3UL << 24); /* fc 3UL is AQIC */
union {
unsigned long value;
struct ap_qirq_ctrl qirqctrl;
struct ap_queue_status status;
} reg1 asm ("1");
register void *reg2 asm ("2") = ind;
} reg1;
void *reg2 = ind;

reg1.qirqctrl = qirqctrl;

asm volatile(
".long 0xb2af0000" /* PQAP(AQIC) */
: "+d" (reg1)
: "d" (reg0), "d" (reg2)
: "cc");
" lgr 0,%[reg0]\n" /* qid param into gr0 */
" lgr 1,%[reg1]\n" /* irq ctrl into gr1 */
" lgr 2,%[reg2]\n" /* ni addr into gr2 */
" .long 0xb2af0000\n" /* PQAP(AQIC) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
: [reg1] "+&d" (reg1)
: [reg0] "d" (reg0), [reg2] "d" (reg2)
: "cc", "0", "1", "2");

return reg1.status;
}
Expand Down Expand Up @@ -268,21 +284,24 @@ union ap_qact_ap_info {
static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit,
union ap_qact_ap_info *apinfo)
{
register unsigned long reg0 asm ("0") = qid | (5UL << 24)
| ((ifbit & 0x01) << 22);
register union {
unsigned long reg0 = qid | (5UL << 24) | ((ifbit & 0x01) << 22);
union {
unsigned long value;
struct ap_queue_status status;
} reg1 asm ("1");
register unsigned long reg2 asm ("2");
} reg1;
unsigned long reg2;

reg1.value = apinfo->val;

asm volatile(
".long 0xb2af0000" /* PQAP(QACT) */
: "+d" (reg1), "=d" (reg2)
: "d" (reg0)
: "cc");
" lgr 0,%[reg0]\n" /* qid param into gr0 */
" lgr 1,%[reg1]\n" /* qact in info into gr1 */
" .long 0xb2af0000\n" /* PQAP(QACT) */
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
" lgr %[reg2],2\n" /* qact out info into reg2 */
: [reg1] "+&d" (reg1), [reg2] "=&d" (reg2)
: [reg0] "d" (reg0)
: "cc", "0", "1", "2");
apinfo->val = reg2;
return reg1.status;
}
Expand All @@ -303,19 +322,24 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid,
unsigned long long psmid,
void *msg, size_t length)
{
register unsigned long reg0 asm ("0") = qid | 0x40000000UL;
register struct ap_queue_status reg1 asm ("1");
register unsigned long reg2 asm ("2") = (unsigned long) msg;
register unsigned long reg3 asm ("3") = (unsigned long) length;
register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32);
register unsigned long reg5 asm ("5") = psmid & 0xffffffff;
unsigned long reg0 = qid | 0x40000000UL; /* 0x4... is last msg part */
union register_pair nqap_r1, nqap_r2;
struct ap_queue_status 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 (
"0: .long 0xb2ad0042\n" /* NQAP */
" brc 2,0b"
: "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3)
: "d" (reg4), "d" (reg5)
: "cc", "memory");
" 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\n" /* gr1 (status) into reg1 */
: [reg0] "+&d" (reg0), [reg1] "=&d" (reg1),
[nqap_r2] "+&d" (nqap_r2.pair)
: [nqap_r1] "d" (nqap_r1.pair)
: "cc", "memory", "0", "1");
return reg1;
}

Expand All @@ -325,6 +349,8 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid,
* @psmid: Pointer to program supplied message identifier
* @msg: The message text
* @length: The message length
* @reslength: Resitual length on return
* @resgr0: input: gr0 value (only used if != 0), output: resitual gr0 content
*
* Returns AP queue status structure.
* Condition code 1 on DQAP means the receive has taken place
Expand All @@ -336,27 +362,65 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid,
* 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 long *psmid,
void *msg, size_t length)
void *msg, size_t length,
size_t *reslength,
unsigned long *resgr0)
{
register unsigned long reg0 asm("0") = qid | 0x80000000UL;
register struct ap_queue_status reg1 asm ("1");
register unsigned long reg2 asm("2") = 0UL;
register unsigned long reg4 asm("4") = (unsigned long) msg;
register unsigned long reg5 asm("5") = (unsigned long) length;
register unsigned long reg6 asm("6") = 0UL;
register unsigned long reg7 asm("7") = 0UL;
unsigned long reg0 = resgr0 && *resgr0 ? *resgr0 : qid | 0x80000000UL;
struct ap_queue_status reg1;
unsigned long reg2;
union register_pair rp1, rp2;

rp1.even = 0UL;
rp1.odd = 0UL;
rp2.even = (unsigned long)msg;
rp2.odd = (unsigned long)length;

asm volatile(
"0: .long 0xb2ae0064\n" /* DQAP */
" brc 6,0b\n"
: "+d" (reg0), "=d" (reg1), "+d" (reg2),
"+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7)
: : "cc", "memory");
*psmid = (((unsigned long long) reg6) << 32) + reg7;
" 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\n" /* gr2 (res length) into reg2 */
: [reg0] "+&d" (reg0), [reg1] "=&d" (reg1), [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.response_code = 0xFF;
if (resgr0)
*resgr0 = reg0;
} else {
*psmid = (((unsigned long long)rp1.even) << 32) + rp1.odd;
if (resgr0)
*resgr0 = 0;
}

return reg1;
}

Expand Down
Loading

0 comments on commit e98e03d

Please sign in to comment.