Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a80313ff authored by Gerald Schaefer's avatar Gerald Schaefer Committed by Martin Schwidefsky
Browse files

s390/kernel: introduce .dma sections



With a relocatable kernel that could reside at any place in memory, code
and data that has to stay below 2 GB needs special handling.

This patch introduces .dma sections for such text, data and ex_table.
The sections will be part of the decompressor kernel, so they will not
be relocated and stay below 2 GB. Their location is passed over to the
decompressed / relocated kernel via the .boot.preserved.data section.

The duald and aste for control register setup also need to stay below
2 GB, so move the setup code from arch/s390/kernel/head64.S to
arch/s390/boot/head.S. The duct and linkage_stack could reside above
2 GB, but their content has to be preserved for the decompresed kernel,
so they are also moved into the .dma section.

The start and end address of the .dma sections is added to vmcoreinfo,
for crash support, to help debugging in case the kernel crashed there.

Signed-off-by: default avatarGerald Schaefer <gerald.schaefer@de.ibm.com>
Reviewed-by: default avatarPhilipp Rudo <prudo@linux.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 087c4d74
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char

obj-y	:= head.o als.o startup.o mem_detect.o ipl_parm.o ipl_report.o
obj-y	+= string.o ebcdic.o sclp_early_core.o mem.o ipl_vmparm.o cmdline.o
obj-y	+= ctype.o
obj-y	+= ctype.o text_dma.o
obj-$(CONFIG_PROTECTED_VIRTUALIZATION_GUEST)	+= uv.o
obj-$(CONFIG_RELOCATABLE)	+= machine_kexec_reloc.o
targets	:= bzImage startup.a section_cmp.boot.data section_cmp.boot.preserved.data $(obj-y)
+21 −0
Original line number Diff line number Diff line
@@ -33,6 +33,27 @@ SECTIONS
		*(.data.*)
		_edata = . ;
	}
	/*
	* .dma section for code, data, ex_table that need to stay below 2 GB,
	* even when the kernel is relocate: above 2 GB.
	*/
	_sdma = .;
	.dma.text : {
		. = ALIGN(PAGE_SIZE);
		_stext_dma = .;
		*(.dma.text)
		. = ALIGN(PAGE_SIZE);
		_etext_dma = .;
	}
	. = ALIGN(16);
	.dma.ex_table : {
		_start_dma_ex_table = .;
		KEEP(*(.dma.ex_table))
		_stop_dma_ex_table = .;
	}
	.dma.data : { *(.dma.data) }
	_edma = .;

	BOOT_DATA
	BOOT_DATA_PRESERVED

+31 −1
Original line number Diff line number Diff line
@@ -305,7 +305,7 @@ ENTRY(startup_kdump)
	xc	0x300(256),0x300
	xc	0xe00(256),0xe00
	xc	0xf00(256),0xf00
	lctlg	%c0,%c15,0x200(%r0)	# initialize control registers
	lctlg	%c0,%c15,.Lctl-.LPG0(%r13)	# load control registers
	stcke	__LC_BOOT_CLOCK
	mvc	__LC_LAST_UPDATE_CLOCK(8),__LC_BOOT_CLOCK+1
	spt	6f-.LPG0(%r13)
@@ -319,6 +319,36 @@ ENTRY(startup_kdump)
	.align	8
6:	.long	0x7fffffff,0xffffffff

.Lctl:	.quad	0x04040000		# cr0: AFP registers & secondary space
	.quad	0			# cr1: primary space segment table
	.quad	.Lduct			# cr2: dispatchable unit control table
	.quad	0			# cr3: instruction authorization
	.quad	0xffff			# cr4: instruction authorization
	.quad	.Lduct			# cr5: primary-aste origin
	.quad	0			# cr6:	I/O interrupts
	.quad	0			# cr7:	secondary space segment table
	.quad	0			# cr8:	access registers translation
	.quad	0			# cr9:	tracing off
	.quad	0			# cr10: tracing off
	.quad	0			# cr11: tracing off
	.quad	0			# cr12: tracing off
	.quad	0			# cr13: home space segment table
	.quad	0xc0000000		# cr14: machine check handling off
	.quad	.Llinkage_stack		# cr15: linkage stack operations

	.section .dma.data,"aw",@progbits
.Lduct: .long	0,.Laste,.Laste,0,.Lduald,0,0,0
	.long	0,0,0,0,0,0,0,0
.Llinkage_stack:
	.long	0,0,0x89000000,0,0,0,0x8a000000,0
	.align 64
.Laste:	.quad	0,0xffffffffffffffff,0,0,0,0,0,0
	.align	128
.Lduald:.rept	8
	.long	0x80000000,0,0,0	# invalid access-list entries
	.endr
	.previous

#include "head_kdump.S"

#
+39 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
#include <linux/string.h>
#include <linux/elf.h>
#include <asm/sections.h>
#include <asm/setup.h>
#include <asm/kexec.h>
#include <asm/sclp.h>
#include <asm/diag.h>
#include <asm/uv.h>
#include "compressed/decompressor.h"
#include "boot.h"
@@ -11,6 +13,43 @@
extern char __boot_data_start[], __boot_data_end[];
extern char __boot_data_preserved_start[], __boot_data_preserved_end[];

/*
 * Some code and data needs to stay below 2 GB, even when the kernel would be
 * relocated above 2 GB, because it has to use 31 bit addresses.
 * Such code and data is part of the .dma section, and its location is passed
 * over to the decompressed / relocated kernel via the .boot.preserved.data
 * section.
 */
extern char _sdma[], _edma[];
extern char _stext_dma[], _etext_dma[];
extern struct exception_table_entry _start_dma_ex_table[];
extern struct exception_table_entry _stop_dma_ex_table[];
unsigned long __bootdata_preserved(__sdma) = __pa(&_sdma);
unsigned long __bootdata_preserved(__edma) = __pa(&_edma);
unsigned long __bootdata_preserved(__stext_dma) = __pa(&_stext_dma);
unsigned long __bootdata_preserved(__etext_dma) = __pa(&_etext_dma);
struct exception_table_entry *
	__bootdata_preserved(__start_dma_ex_table) = _start_dma_ex_table;
struct exception_table_entry *
	__bootdata_preserved(__stop_dma_ex_table) = _stop_dma_ex_table;

int _diag210_dma(struct diag210 *addr);
int _diag26c_dma(void *req, void *resp, enum diag26c_sc subcode);
int _diag14_dma(unsigned long rx, unsigned long ry1, unsigned long subcode);
void _diag0c_dma(struct hypfs_diag0c_entry *entry);
void _diag308_reset_dma(void);
struct diag_ops __bootdata_preserved(diag_dma_ops) = {
	.diag210 = _diag210_dma,
	.diag26c = _diag26c_dma,
	.diag14 = _diag14_dma,
	.diag0c = _diag0c_dma,
	.diag308_reset = _diag308_reset_dma
};
static struct diag210 _diag210_tmp_dma __section(".dma.data");
struct diag210 *__bootdata_preserved(__diag210_tmp_dma) = &_diag210_tmp_dma;
void _swsusp_reset_dma(void);
unsigned long __bootdata_preserved(__swsusp_reset_dma) = __pa(_swsusp_reset_dma);

void error(char *x)
{
	sclp_early_printk("\n\n");
+167 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Code that needs to run below 2 GB.
 *
 * Copyright IBM Corp. 2019
 */

#include <linux/linkage.h>
#include <asm/errno.h>
#include <asm/sigp.h>

	.section .dma.text,"ax"
/*
 * Simplified version of expoline thunk. The normal thunks can not be used here,
 * because they might be more than 2 GB away, and not reachable by the relative
 * branch. No comdat, exrl, etc. optimizations used here, because it only
 * affects a few functions that are not performance-relevant.
 */
	.macro BR_EX_DMA_r14
	larl	%r1,0f
	ex	0,0(%r1)
	j	.
0:	br	%r14
	.endm

/*
 * int _diag14_dma(unsigned long rx, unsigned long ry1, unsigned long subcode)
 */
ENTRY(_diag14_dma)
	lgr	%r1,%r2
	lgr	%r2,%r3
	lgr	%r3,%r4
	lhi	%r5,-EIO
	sam31
	diag	%r1,%r2,0x14
.Ldiag14_ex:
	ipm	%r5
	srl	%r5,28
.Ldiag14_fault:
	sam64
	lgfr	%r2,%r5
	BR_EX_DMA_r14
	EX_TABLE_DMA(.Ldiag14_ex, .Ldiag14_fault)

/*
 * int _diag210_dma(struct diag210 *addr)
 */
ENTRY(_diag210_dma)
	lgr	%r1,%r2
	lhi	%r2,-1
	sam31
	diag	%r1,%r0,0x210
.Ldiag210_ex:
	ipm	%r2
	srl	%r2,28
.Ldiag210_fault:
	sam64
	lgfr	%r2,%r2
	BR_EX_DMA_r14
	EX_TABLE_DMA(.Ldiag210_ex, .Ldiag210_fault)

/*
 * int _diag26c_dma(void *req, void *resp, enum diag26c_sc subcode)
 */
ENTRY(_diag26c_dma)
	lghi	%r5,-EOPNOTSUPP
	sam31
	diag	%r2,%r4,0x26c
.Ldiag26c_ex:
	sam64
	lgfr	%r2,%r5
	BR_EX_DMA_r14
	EX_TABLE_DMA(.Ldiag26c_ex, .Ldiag26c_ex)

/*
 * void _diag0c_dma(struct hypfs_diag0c_entry *entry)
 */
ENTRY(_diag0c_dma)
	sam31
	diag	%r2,%r2,0x0c
	sam64
	BR_EX_DMA_r14

/*
 * void _swsusp_reset_dma(void)
 */
ENTRY(_swsusp_reset_dma)
	larl	%r1,restart_entry
	larl	%r2,.Lrestart_diag308_psw
	og	%r1,0(%r2)
	stg	%r1,0(%r0)
	lghi	%r0,0
	diag	%r0,%r0,0x308
restart_entry:
	lhi	%r1,1
	sigp	%r1,%r0,SIGP_SET_ARCHITECTURE
	sam64
	BR_EX_DMA_r14

/*
 * void _diag308_reset_dma(void)
 *
 * Calls diag 308 subcode 1 and continues execution
 */
ENTRY(_diag308_reset_dma)
	larl	%r4,.Lctlregs		# Save control registers
	stctg	%c0,%c15,0(%r4)
	lg	%r2,0(%r4)		# Disable lowcore protection
	nilh	%r2,0xefff
	larl	%r4,.Lctlreg0
	stg	%r2,0(%r4)
	lctlg	%c0,%c0,0(%r4)
	larl	%r4,.Lfpctl		# Floating point control register
	stfpc	0(%r4)
	larl	%r4,.Lprefix		# Save prefix register
	stpx	0(%r4)
	larl	%r4,.Lprefix_zero	# Set prefix register to 0
	spx	0(%r4)
	larl	%r4,.Lcontinue_psw	# Save PSW flags
	epsw	%r2,%r3
	stm	%r2,%r3,0(%r4)
	larl	%r4,restart_part2	# Setup restart PSW at absolute 0
	larl	%r3,.Lrestart_diag308_psw
	og	%r4,0(%r3)		# Save PSW
	lghi	%r3,0
	sturg	%r4,%r3			# Use sturg, because of large pages
	lghi	%r1,1
	lghi	%r0,0
	diag	%r0,%r1,0x308
restart_part2:
	lhi	%r0,0			# Load r0 with zero
	lhi	%r1,2			# Use mode 2 = ESAME (dump)
	sigp	%r1,%r0,SIGP_SET_ARCHITECTURE	# Switch to ESAME mode
	sam64				# Switch to 64 bit addressing mode
	larl	%r4,.Lctlregs		# Restore control registers
	lctlg	%c0,%c15,0(%r4)
	larl	%r4,.Lfpctl		# Restore floating point ctl register
	lfpc	0(%r4)
	larl	%r4,.Lprefix		# Restore prefix register
	spx	0(%r4)
	larl	%r4,.Lcontinue_psw	# Restore PSW flags
	lpswe	0(%r4)
.Lcontinue:
	BR_EX_DMA_r14

	.section .dma.data,"aw",@progbits
.align	8
.Lrestart_diag308_psw:
	.long	0x00080000,0x80000000

.align 8
.Lcontinue_psw:
	.quad	0,.Lcontinue

.align 8
.Lctlreg0:
	.quad	0
.Lctlregs:
	.rept	16
	.quad	0
	.endr
.Lfpctl:
	.long	0
.Lprefix:
	.long	0
.Lprefix_zero:
	.long	0
Loading