summaryrefslogtreecommitdiff
path: root/arch/s390/boot
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-09-17 14:04:43 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2019-09-17 14:04:43 -0700
commitd590284419b1d7cc2dc646e9bdde4da19061cf0f (patch)
tree007a94945a82e3010c1847daeeb8f17d8e988929 /arch/s390/boot
parent1e24aaabdee9e07f19b09bd305ffc069b0b07371 (diff)
parent2735913c1079b7dd7ec1d746c13a84ec1b5ea276 (diff)
Merge tag 's390-5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Vasily Gorbik: - Add support for IBM z15 machines. - Add SHA3 and CCA AES cipher key support in zcrypt and pkey refactoring. - Move to arch_stack_walk infrastructure for the stack unwinder. - Various kasan fixes and improvements. - Various command line parsing fixes. - Improve decompressor phase debuggability. - Lift no bss usage restriction for the early code. - Use refcount_t for reference counters for couple of places in mm code. - Logging improvements and return code fix in vfio-ccw code. - Couple of zpci fixes and minor refactoring. - Remove some outdated documentation. - Fix secure boot detection. - Other various minor code clean ups. * tag 's390-5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (48 commits) s390: remove pointless drivers-y in drivers/s390/Makefile s390/cpum_sf: Fix line length and format string s390/pci: fix MSI message data s390: add support for IBM z15 machines s390/crypto: Support for SHA3 via CPACF (MSA6) s390/startup: add pgm check info printing s390/crypto: xts-aes-s390 fix extra run-time crypto self tests finding vfio-ccw: fix error return code in vfio_ccw_sch_init() s390: vfio-ap: fix warning reset not completed s390/base: remove unused s390_base_mcck_handler s390/sclp: Fix bit checked for has_sipl s390/zcrypt: fix wrong handling of cca cipher keygenflags s390/kasan: add kdump support s390/setup: avoid using strncmp with hardcoded length s390/sclp: avoid using strncmp with hardcoded length s390/module: avoid using strncmp with hardcoded length s390/pci: avoid using strncmp with hardcoded length s390/kaslr: reserve memory for kasan usage s390/mem_detect: provide single get_mem_detect_end s390/cmma: reuse kstrtobool for option value parsing ...
Diffstat (limited to 'arch/s390/boot')
-rw-r--r--arch/s390/boot/Makefile2
-rw-r--r--arch/s390/boot/boot.h1
-rw-r--r--arch/s390/boot/compressed/.gitignore3
-rw-r--r--arch/s390/boot/compressed/vmlinux.lds.S3
-rw-r--r--arch/s390/boot/head.S32
-rw-r--r--arch/s390/boot/ipl_parm.c11
-rw-r--r--arch/s390/boot/kaslr.c41
-rw-r--r--arch/s390/boot/mem_detect.c7
-rw-r--r--arch/s390/boot/pgm_check_info.c90
-rw-r--r--arch/s390/boot/startup.c6
10 files changed, 172 insertions, 24 deletions
diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile
index 4cf0bddb7d92..e2c47d3a1c89 100644
--- a/arch/s390/boot/Makefile
+++ b/arch/s390/boot/Makefile
@@ -36,7 +36,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 += version.o ctype.o text_dma.o
+obj-y += version.o pgm_check_info.o ctype.o text_dma.o
obj-$(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) += uv.o
obj-$(CONFIG_RELOCATABLE) += machine_kexec_reloc.o
obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
diff --git a/arch/s390/boot/boot.h b/arch/s390/boot/boot.h
index 1c3b2b257637..2ea603f70c3b 100644
--- a/arch/s390/boot/boot.h
+++ b/arch/s390/boot/boot.h
@@ -10,6 +10,7 @@ void parse_boot_command_line(void);
void setup_memory_end(void);
void verify_facilities(void);
void print_missing_facilities(void);
+void print_pgm_check_info(void);
unsigned long get_random_base(unsigned long safe_addr);
extern int kaslr_enabled;
diff --git a/arch/s390/boot/compressed/.gitignore b/arch/s390/boot/compressed/.gitignore
index 45aeb4f08752..e72fcd7ecebb 100644
--- a/arch/s390/boot/compressed/.gitignore
+++ b/arch/s390/boot/compressed/.gitignore
@@ -1,5 +1,2 @@
-sizes.h
vmlinux
vmlinux.lds
-vmlinux.scr.lds
-vmlinux.bin.full
diff --git a/arch/s390/boot/compressed/vmlinux.lds.S b/arch/s390/boot/compressed/vmlinux.lds.S
index 635217eb3d91..44561b2c3712 100644
--- a/arch/s390/boot/compressed/vmlinux.lds.S
+++ b/arch/s390/boot/compressed/vmlinux.lds.S
@@ -37,9 +37,9 @@ SECTIONS
* .dma section for code, data, ex_table that need to stay below 2 GB,
* even when the kernel is relocate: above 2 GB.
*/
+ . = ALIGN(PAGE_SIZE);
_sdma = .;
.dma.text : {
- . = ALIGN(PAGE_SIZE);
_stext_dma = .;
*(.dma.text)
. = ALIGN(PAGE_SIZE);
@@ -52,6 +52,7 @@ SECTIONS
_stop_dma_ex_table = .;
}
.dma.data : { *(.dma.data) }
+ . = ALIGN(PAGE_SIZE);
_edma = .;
BOOT_DATA
diff --git a/arch/s390/boot/head.S b/arch/s390/boot/head.S
index 2087bed6e60f..4b86a8d3c121 100644
--- a/arch/s390/boot/head.S
+++ b/arch/s390/boot/head.S
@@ -60,8 +60,10 @@ __HEAD
.long 0x02000690,0x60000050
.long 0x020006e0,0x20000050
- .org 0x1a0
+ .org __LC_RST_NEW_PSW # 0x1a0
.quad 0,iplstart
+ .org __LC_PGM_NEW_PSW # 0x1d0
+ .quad 0x0000000180000000,startup_pgm_check_handler
.org 0x200
@@ -352,6 +354,34 @@ ENTRY(startup_kdump)
#include "head_kdump.S"
#
+# This program check is active immediately after kernel start
+# and until early_pgm_check_handler is set in kernel/early.c
+# It simply saves general/control registers and psw in
+# the save area and does disabled wait with a faulty address.
+#
+ENTRY(startup_pgm_check_handler)
+ stmg %r0,%r15,__LC_SAVE_AREA_SYNC
+ la %r1,4095
+ stctg %c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r1)
+ mvc __LC_GPREGS_SAVE_AREA-4095(128,%r1),__LC_SAVE_AREA_SYNC
+ mvc __LC_PSW_SAVE_AREA-4095(16,%r1),__LC_PGM_OLD_PSW
+ mvc __LC_RETURN_PSW(16),__LC_PGM_OLD_PSW
+ ni __LC_RETURN_PSW,0xfc # remove IO and EX bits
+ ni __LC_RETURN_PSW+1,0xfb # remove MCHK bit
+ oi __LC_RETURN_PSW+1,0x2 # set wait state bit
+ larl %r2,.Lold_psw_disabled_wait
+ stg %r2,__LC_PGM_NEW_PSW+8
+ l %r15,.Ldump_info_stack-.Lold_psw_disabled_wait(%r2)
+ brasl %r14,print_pgm_check_info
+.Lold_psw_disabled_wait:
+ la %r1,4095
+ lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
+ lpswe __LC_RETURN_PSW # disabled wait
+.Ldump_info_stack:
+ .long 0x5000 + PAGE_SIZE - STACK_FRAME_OVERHEAD
+ENDPROC(startup_pgm_check_handler)
+
+#
# params at 10400 (setup.h)
# Must be keept in sync with struct parmarea in setup.h
#
diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c
index b8aa6a9f937b..24ef67eb1cef 100644
--- a/arch/s390/boot/ipl_parm.c
+++ b/arch/s390/boot/ipl_parm.c
@@ -7,6 +7,7 @@
#include <asm/sections.h>
#include <asm/boot_data.h>
#include <asm/facility.h>
+#include <asm/pgtable.h>
#include <asm/uv.h>
#include "boot.h"
@@ -14,6 +15,7 @@ char __bootdata(early_command_line)[COMMAND_LINE_SIZE];
struct ipl_parameter_block __bootdata_preserved(ipl_block);
int __bootdata_preserved(ipl_block_valid);
+unsigned long __bootdata(vmalloc_size) = VMALLOC_DEFAULT_SIZE;
unsigned long __bootdata(memory_end);
int __bootdata(memory_end_set);
int __bootdata(noexec_disabled);
@@ -219,18 +221,21 @@ void parse_boot_command_line(void)
while (*args) {
args = next_arg(args, &param, &val);
- if (!strcmp(param, "mem")) {
- memory_end = memparse(val, NULL);
+ if (!strcmp(param, "mem") && val) {
+ memory_end = round_down(memparse(val, NULL), PAGE_SIZE);
memory_end_set = 1;
}
+ if (!strcmp(param, "vmalloc") && val)
+ vmalloc_size = round_up(memparse(val, NULL), PAGE_SIZE);
+
if (!strcmp(param, "noexec")) {
rc = kstrtobool(val, &enabled);
if (!rc && !enabled)
noexec_disabled = 1;
}
- if (!strcmp(param, "facilities"))
+ if (!strcmp(param, "facilities") && val)
modify_fac_list(val);
if (!strcmp(param, "nokaslr"))
diff --git a/arch/s390/boot/kaslr.c b/arch/s390/boot/kaslr.c
index c34a6387ce38..5d12352545c5 100644
--- a/arch/s390/boot/kaslr.c
+++ b/arch/s390/boot/kaslr.c
@@ -3,6 +3,7 @@
* Copyright IBM Corp. 2019
*/
#include <asm/mem_detect.h>
+#include <asm/pgtable.h>
#include <asm/cpacf.h>
#include <asm/timex.h>
#include <asm/sclp.h>
@@ -90,8 +91,10 @@ static unsigned long get_random(unsigned long limit)
unsigned long get_random_base(unsigned long safe_addr)
{
+ unsigned long memory_limit = memory_end_set ? memory_end : 0;
unsigned long base, start, end, kernel_size;
unsigned long block_sum, offset;
+ unsigned long kasan_needs;
int i;
if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && INITRD_START && INITRD_SIZE) {
@@ -100,14 +103,36 @@ unsigned long get_random_base(unsigned long safe_addr)
}
safe_addr = ALIGN(safe_addr, THREAD_SIZE);
+ if ((IS_ENABLED(CONFIG_KASAN))) {
+ /*
+ * Estimate kasan memory requirements, which it will reserve
+ * at the very end of available physical memory. To estimate
+ * that, we take into account that kasan would require
+ * 1/8 of available physical memory (for shadow memory) +
+ * creating page tables for the whole memory + shadow memory
+ * region (1 + 1/8). To keep page tables estimates simple take
+ * the double of combined ptes size.
+ */
+ memory_limit = get_mem_detect_end();
+ if (memory_end_set && memory_limit > memory_end)
+ memory_limit = memory_end;
+
+ /* for shadow memory */
+ kasan_needs = memory_limit / 8;
+ /* for paging structures */
+ kasan_needs += (memory_limit + kasan_needs) / PAGE_SIZE /
+ _PAGE_ENTRIES * _PAGE_TABLE_SIZE * 2;
+ memory_limit -= kasan_needs;
+ }
+
kernel_size = vmlinux.image_size + vmlinux.bss_size;
block_sum = 0;
for_each_mem_detect_block(i, &start, &end) {
- if (memory_end_set) {
- if (start >= memory_end)
+ if (memory_limit) {
+ if (start >= memory_limit)
break;
- if (end > memory_end)
- end = memory_end;
+ if (end > memory_limit)
+ end = memory_limit;
}
if (end - start < kernel_size)
continue;
@@ -125,11 +150,11 @@ unsigned long get_random_base(unsigned long safe_addr)
base = safe_addr;
block_sum = offset = 0;
for_each_mem_detect_block(i, &start, &end) {
- if (memory_end_set) {
- if (start >= memory_end)
+ if (memory_limit) {
+ if (start >= memory_limit)
break;
- if (end > memory_end)
- end = memory_end;
+ if (end > memory_limit)
+ end = memory_limit;
}
if (end - start < kernel_size)
continue;
diff --git a/arch/s390/boot/mem_detect.c b/arch/s390/boot/mem_detect.c
index 5d316fe40480..62e7c13ce85c 100644
--- a/arch/s390/boot/mem_detect.c
+++ b/arch/s390/boot/mem_detect.c
@@ -63,13 +63,6 @@ void add_mem_detect_block(u64 start, u64 end)
mem_detect.count++;
}
-static unsigned long get_mem_detect_end(void)
-{
- if (mem_detect.count)
- return __get_mem_detect_block_ptr(mem_detect.count - 1)->end;
- return 0;
-}
-
static int __diag260(unsigned long rx1, unsigned long rx2)
{
register unsigned long _rx1 asm("2") = rx1;
diff --git a/arch/s390/boot/pgm_check_info.c b/arch/s390/boot/pgm_check_info.c
new file mode 100644
index 000000000000..83b5b7915c32
--- /dev/null
+++ b/arch/s390/boot/pgm_check_info.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <asm/lowcore.h>
+#include <asm/sclp.h>
+#include "boot.h"
+
+const char hex_asc[] = "0123456789abcdef";
+
+#define add_val_as_hex(dst, val) \
+ __add_val_as_hex(dst, (const unsigned char *)&val, sizeof(val))
+
+static char *__add_val_as_hex(char *dst, const unsigned char *src, size_t count)
+{
+ while (count--)
+ dst = hex_byte_pack(dst, *src++);
+ return dst;
+}
+
+static char *add_str(char *dst, char *src)
+{
+ strcpy(dst, src);
+ return dst + strlen(dst);
+}
+
+void print_pgm_check_info(void)
+{
+ struct psw_bits *psw = &psw_bits(S390_lowcore.psw_save_area);
+ unsigned short ilc = S390_lowcore.pgm_ilc >> 1;
+ char buf[256];
+ int row, col;
+ char *p;
+
+ add_str(buf, "Linux version ");
+ strlcat(buf, kernel_version, sizeof(buf));
+ sclp_early_printk(buf);
+
+ p = add_str(buf, "Kernel fault: interruption code ");
+ p = add_val_as_hex(buf + strlen(buf), S390_lowcore.pgm_code);
+ p = add_str(p, " ilc:");
+ *p++ = hex_asc_lo(ilc);
+ add_str(p, "\n");
+ sclp_early_printk(buf);
+
+ p = add_str(buf, "PSW : ");
+ p = add_val_as_hex(p, S390_lowcore.psw_save_area.mask);
+ p = add_str(p, " ");
+ p = add_val_as_hex(p, S390_lowcore.psw_save_area.addr);
+ add_str(p, "\n");
+ sclp_early_printk(buf);
+
+ p = add_str(buf, " R:");
+ *p++ = hex_asc_lo(psw->per);
+ p = add_str(p, " T:");
+ *p++ = hex_asc_lo(psw->dat);
+ p = add_str(p, " IO:");
+ *p++ = hex_asc_lo(psw->io);
+ p = add_str(p, " EX:");
+ *p++ = hex_asc_lo(psw->ext);
+ p = add_str(p, " Key:");
+ *p++ = hex_asc_lo(psw->key);
+ p = add_str(p, " M:");
+ *p++ = hex_asc_lo(psw->mcheck);
+ p = add_str(p, " W:");
+ *p++ = hex_asc_lo(psw->wait);
+ p = add_str(p, " P:");
+ *p++ = hex_asc_lo(psw->pstate);
+ p = add_str(p, " AS:");
+ *p++ = hex_asc_lo(psw->as);
+ p = add_str(p, " CC:");
+ *p++ = hex_asc_lo(psw->cc);
+ p = add_str(p, " PM:");
+ *p++ = hex_asc_lo(psw->pm);
+ p = add_str(p, " RI:");
+ *p++ = hex_asc_lo(psw->ri);
+ p = add_str(p, " EA:");
+ *p++ = hex_asc_lo(psw->eaba);
+ add_str(p, "\n");
+ sclp_early_printk(buf);
+
+ for (row = 0; row < 4; row++) {
+ p = add_str(buf, row == 0 ? "GPRS:" : " ");
+ for (col = 0; col < 4; col++) {
+ p = add_str(p, " ");
+ p = add_val_as_hex(p, S390_lowcore.gpregs_save_area[row * 4 + col]);
+ }
+ add_str(p, "\n");
+ sclp_early_printk(buf);
+ }
+}
diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c
index 7b0d05414618..596ca7cc4d7b 100644
--- a/arch/s390/boot/startup.c
+++ b/arch/s390/boot/startup.c
@@ -112,6 +112,11 @@ static void handle_relocs(unsigned long offset)
}
}
+static void clear_bss_section(void)
+{
+ memset((void *)vmlinux.default_lma + vmlinux.image_size, 0, vmlinux.bss_size);
+}
+
void startup_kernel(void)
{
unsigned long random_lma;
@@ -151,6 +156,7 @@ void startup_kernel(void)
} else if (__kaslr_offset)
memcpy((void *)vmlinux.default_lma, img, vmlinux.image_size);
+ clear_bss_section();
copy_bootdata();
if (IS_ENABLED(CONFIG_RELOCATABLE))
handle_relocs(__kaslr_offset);