s390/kexec_file: Add purgatory

The common code expects the architecture to have a purgatory that runs
between the two kernels. Add it now. For simplicity first skip crash
support.

Signed-off-by: Philipp Rudo <prudo@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
Philipp Rudo 2017-08-28 15:32:36 +02:00 committed by Martin Schwidefsky
parent 15ceb8c936
commit 840798a1f5
7 changed files with 198 additions and 0 deletions

View File

@ -8,3 +8,4 @@ obj-$(CONFIG_APPLDATA_BASE) += appldata/
obj-y += net/
obj-$(CONFIG_PCI) += pci/
obj-$(CONFIG_NUMA) += numa/
obj-$(CONFIG_ARCH_HAS_KEXEC_PURGATORY) += purgatory/

View File

@ -51,6 +51,10 @@ config KEXEC
def_bool y
select KEXEC_CORE
config ARCH_HAS_KEXEC_PURGATORY
def_bool y
depends on KEXEC_FILE
config AUDIT_ARCH
def_bool y

View File

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 2018
*
* Author(s): Philipp Rudo <prudo@linux.vnet.ibm.com>
*/
#ifndef _S390_PURGATORY_H_
#define _S390_PURGATORY_H_
#ifndef __ASSEMBLY__
#include <linux/purgatory.h>
int verify_sha256_digest(void);
#endif /* __ASSEMBLY__ */
#endif /* _S390_PURGATORY_H_ */

View File

@ -10,6 +10,7 @@
#include <linux/kbuild.h>
#include <linux/kvm_host.h>
#include <linux/sched.h>
#include <linux/purgatory.h>
#include <asm/idle.h>
#include <asm/vdso.h>
#include <asm/pgtable.h>
@ -204,5 +205,9 @@ int main(void)
OFFSET(__GMAP_ASCE, gmap, asce);
OFFSET(__SIE_PROG0C, kvm_s390_sie_block, prog0c);
OFFSET(__SIE_PROG20, kvm_s390_sie_block, prog20);
/* kexec_sha_region */
OFFSET(__KEXEC_SHA_REGION_START, kexec_sha_region, start);
OFFSET(__KEXEC_SHA_REGION_LEN, kexec_sha_region, len);
DEFINE(__KEXEC_SHA_REGION_SIZE, sizeof(struct kexec_sha_region));
return 0;
}

View File

@ -0,0 +1,37 @@
# SPDX-License-Identifier: GPL-2.0
OBJECT_FILES_NON_STANDARD := y
purgatory-y := head.o purgatory.o string.o sha256.o mem.o
targets += $(purgatory-y) purgatory.ro kexec-purgatory.c
PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y))
$(obj)/sha256.o: $(srctree)/lib/sha256.c
$(call if_changed_rule,cc_o_c)
$(obj)/mem.o: $(srctree)/arch/s390/lib/mem.S
$(call if_changed_rule,as_o_S)
$(obj)/string.o: $(srctree)/arch/s390/lib/string.c
$(call if_changed_rule,cc_o_c)
LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined -nostdlib
LDFLAGS_purgatory.ro += -z nodefaultlib
KBUILD_CFLAGS := -fno-strict-aliasing -Wall -Wstrict-prototypes
KBUILD_CFLAGS += -Wno-pointer-sign -Wno-sign-compare
KBUILD_CFLAGS += -fno-zero-initialized-in-bss -fno-builtin -ffreestanding
KBUILD_CFLAGS += -c -MD -Os -m64
KBUILD_CFLAGS += $(call cc-option,-fno-PIE)
$(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
$(call if_changed,ld)
CMD_BIN2C = $(objtree)/scripts/basic/bin2c
quiet_cmd_bin2c = BIN2C $@
cmd_bin2c = $(CMD_BIN2C) kexec_purgatory < $< > $@
$(obj)/kexec-purgatory.c: $(obj)/purgatory.ro FORCE
$(call if_changed,bin2c)
obj-$(CONFIG_ARCH_HAS_KEXEC_PURGATORY) += kexec-purgatory.o

View File

@ -0,0 +1,96 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Purgatory setup code
*
* Copyright IBM Corp. 2018
*
* Author(s): Philipp Rudo <prudo@linux.vnet.ibm.com>
*/
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/page.h>
#include <asm/sigp.h>
/* The purgatory is the code running between two kernels. It's main purpose
* is to verify that the next kernel was not corrupted after load and to
* start it.
*/
.macro START_NEXT_KERNEL base
lg %r4,kernel_entry-\base(%r13)
lg %r5,load_psw_mask-\base(%r13)
ogr %r4,%r5
stg %r4,0(%r0)
xgr %r0,%r0
diag %r0,%r0,0x308
.endm
.text
.align PAGE_SIZE
ENTRY(purgatory_start)
/* The purgatory might be called after a diag308 so better set
* architecture and addressing mode.
*/
lhi %r1,1
sigp %r1,%r0,SIGP_SET_ARCHITECTURE
sam64
larl %r5,gprregs
stmg %r6,%r15,0(%r5)
basr %r13,0
.base_crash:
/* Setup stack */
larl %r15,purgatory_end
aghi %r15,-160
.do_checksum_verification:
brasl %r14,verify_sha256_digest
cghi %r2,0 /* checksum match */
jne .disabled_wait
/* start normal kernel */
START_NEXT_KERNEL .base_crash
.disabled_wait:
lpswe disabled_wait_psw-.base_crash(%r13)
load_psw_mask:
.long 0x00080000,0x80000000
.align 8
disabled_wait_psw:
.quad 0x0002000180000000
.quad 0x0000000000000000 + .do_checksum_verification
gprregs:
.rept 10
.quad 0
.endr
purgatory_sha256_digest:
.global purgatory_sha256_digest
.rept 32 /* SHA256_DIGEST_SIZE */
.byte 0
.endr
purgatory_sha_regions:
.global purgatory_sha_regions
.rept 16 * __KEXEC_SHA_REGION_SIZE /* KEXEC_SEGMENTS_MAX */
.byte 0
.endr
kernel_entry:
.global kernel_entry
.quad 0
.align PAGE_SIZE
stack:
.skip PAGE_SIZE
.align PAGE_SIZE
purgatory_end:

View File

@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Purgatory code running between two kernels.
*
* Copyright IBM Corp. 2018
*
* Author(s): Philipp Rudo <prudo@linux.vnet.ibm.com>
*/
#include <linux/kexec.h>
#include <linux/sha256.h>
#include <linux/string.h>
#include <asm/purgatory.h>
struct kexec_sha_region purgatory_sha_regions[KEXEC_SEGMENT_MAX];
u8 purgatory_sha256_digest[SHA256_DIGEST_SIZE];
u64 kernel_entry;
int verify_sha256_digest(void)
{
struct kexec_sha_region *ptr, *end;
u8 digest[SHA256_DIGEST_SIZE];
struct sha256_state sctx;
sha256_init(&sctx);
end = purgatory_sha_regions + ARRAY_SIZE(purgatory_sha_regions);
for (ptr = purgatory_sha_regions; ptr < end; ptr++)
sha256_update(&sctx, (uint8_t *)(ptr->start), ptr->len);
sha256_final(&sctx, digest);
if (memcmp(digest, purgatory_sha256_digest, sizeof(digest)))
return 1;
return 0;
}