Skip to content

Commit 6067891

Browse files
hcahcaVasily Gorbik
authored andcommitted
s390/boot: Add exception table support
The early boot code contains various open-coded inline assemblies with exception handling. In order to handle possible exceptions each of them changes the program check new psw, and restores it. In order to simplify the various inline assemblies add simple exception table support: the program check handler is called with a fully populated pt_regs on the stack and may change the psw and register members. When the program check handler returns the psw and registers from pt_regs will be used to continue execution. The program check handler searches the exception table for an entry which matches the address of the program check. If such an entry is found the psw address within pt_regs on the stack is replaced with a fixup address, and execution continues at the new address. If no entry is found the psw is changed to a disabled wait psw and execution stops. Before entering the C part of the program check handler the address of the program check new psw is replaced to a minimalistic handler. This is supposed to help against program check loops. If an exception happens while in program check processing the register contents of the original exception are restored and a disabled wait psw is loaded. Acked-by: Alexander Gordeev <[email protected]> Signed-off-by: Heiko Carstens <[email protected]> Signed-off-by: Vasily Gorbik <[email protected]>
1 parent b10ac5d commit 6067891

File tree

5 files changed

+39
-11
lines changed

5 files changed

+39
-11
lines changed

arch/s390/boot/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char
2626

2727
obj-y := head.o als.o startup.o physmem_info.o ipl_parm.o ipl_report.o vmem.o
2828
obj-y += string.o ebcdic.o sclp_early_core.o mem.o ipl_vmparm.o cmdline.o
29-
obj-y += version.o pgm_check_info.o ctype.o ipl_data.o relocs.o alternative.o
29+
obj-y += version.o pgm_check.o ctype.o ipl_data.o relocs.o alternative.o
3030
obj-y += uv.o printk.o
3131
obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
3232
obj-y += $(if $(CONFIG_KERNEL_UNCOMPRESSED),,decompressor.o) info.o

arch/s390/boot/boot.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ void verify_facilities(void);
6565
void print_missing_facilities(void);
6666
void sclp_early_setup_buffer(void);
6767
void alt_debug_setup(char *str);
68-
void print_pgm_check_info(struct pt_regs *regs);
68+
void do_pgm_check(struct pt_regs *regs);
6969
unsigned long randomize_within_range(unsigned long size, unsigned long align,
7070
unsigned long min, unsigned long max);
7171
void setup_vmem(unsigned long kernel_start, unsigned long kernel_end, unsigned long asce_limit);

arch/s390/boot/head.S

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -293,12 +293,6 @@ SYM_CODE_END(startup_normal)
293293

294294
#include "head_kdump.S"
295295

296-
#
297-
# This program check is active immediately after kernel start
298-
# and until early_pgm_check_handler is set in kernel/early.c
299-
# It simply saves general/control registers and psw in
300-
# the save area and does disabled wait with a faulty address.
301-
#
302296
SYM_CODE_START_LOCAL(startup_pgm_check_handler)
303297
stmg %r8,%r15,__LC_SAVE_AREA
304298
la %r8,4095
@@ -318,7 +312,12 @@ SYM_CODE_START_LOCAL(startup_pgm_check_handler)
318312
mvc __PT_R0(128,%r2),__LC_GPREGS_SAVE_AREA-4095(%r8)
319313
mvc __PT_LAST_BREAK(8,%r2),__LC_PGM_LAST_BREAK
320314
mvc __PT_INT_CODE(4,%r2),__LC_PGM_INT_CODE
321-
brasl %r14,print_pgm_check_info
315+
brasl %r14,do_pgm_check
316+
larl %r9,startup_pgm_check_handler
317+
stg %r9,__LC_PGM_NEW_PSW+8
318+
mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15)
319+
lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15)
320+
lpswe __LC_RETURN_PSW
322321
.Lold_psw_disabled_wait:
323322
la %r8,4095
324323
lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r8)

arch/s390/boot/pgm_check_info.c renamed to arch/s390/boot/pgm_check.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,36 @@ void print_stacktrace(unsigned long sp)
3232
}
3333
}
3434

35-
void print_pgm_check_info(struct pt_regs *regs)
35+
extern struct exception_table_entry __start___ex_table[];
36+
extern struct exception_table_entry __stop___ex_table[];
37+
38+
static inline unsigned long extable_insn(const struct exception_table_entry *x)
39+
{
40+
return (unsigned long)&x->insn + x->insn;
41+
}
42+
43+
static bool ex_handler(struct pt_regs *regs)
44+
{
45+
const struct exception_table_entry *ex;
46+
47+
for (ex = __start___ex_table; ex < __stop___ex_table; ex++) {
48+
if (extable_insn(ex) != regs->psw.addr)
49+
continue;
50+
if (ex->type != EX_TYPE_FIXUP)
51+
return false;
52+
regs->psw.addr = extable_fixup(ex);
53+
return true;
54+
}
55+
return false;
56+
}
57+
58+
void do_pgm_check(struct pt_regs *regs)
3659
{
3760
struct psw_bits *psw = &psw_bits(regs->psw);
3861
unsigned long *gpregs = regs->gprs;
3962

63+
if (ex_handler(regs))
64+
return;
4065
if (bootdebug)
4166
boot_rb_dump();
4267
boot_emerg("Linux version %s\n", kernel_version);
@@ -60,4 +85,8 @@ void print_pgm_check_info(struct pt_regs *regs)
6085
print_stacktrace(gpregs[15]);
6186
boot_emerg("Last Breaking-Event-Address:\n");
6287
boot_emerg(" [<%016lx>] %pS\n", regs->last_break, (void *)regs->last_break);
88+
/* Convert to disabled wait PSW */
89+
psw->io = 0;
90+
psw->ext = 0;
91+
psw->wait = 1;
6392
}

arch/s390/boot/vmlinux.lds.S

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ SECTIONS
4040
*(.rodata.*)
4141
_erodata = . ;
4242
}
43+
EXCEPTION_TABLE(16)
4344
.got : {
4445
*(.got)
4546
}
@@ -165,7 +166,6 @@ SECTIONS
165166
/DISCARD/ : {
166167
COMMON_DISCARDS
167168
*(.eh_frame)
168-
*(__ex_table)
169169
*(*__ksymtab*)
170170
*(___kcrctab*)
171171
}

0 commit comments

Comments
 (0)