summaryrefslogtreecommitdiff
path: root/arch/s390/boot
diff options
context:
space:
mode:
authorVasily Gorbik <gor@linux.ibm.com>2020-10-19 12:01:33 +0300
committerHeiko Carstens <hca@linux.ibm.com>2020-11-20 21:19:10 +0300
commit73045a08cf5549cc7dee14463431fbeb2134dd67 (patch)
treee332a31ea39cbc7748b6b42349544d24db806203 /arch/s390/boot
parent1e632eaa0f4b7f65a81301205ca122024991e1d3 (diff)
downloadlinux-73045a08cf5549cc7dee14463431fbeb2134dd67.tar.xz
s390: unify identity mapping limits handling
Currently we have to consider too many different values which in the end only affect identity mapping size. These are: 1. max_physmem_end - end of physical memory online or standby. Always <= end of the last online memory block (get_mem_detect_end()). 2. CONFIG_MAX_PHYSMEM_BITS - the maximum size of physical memory the kernel is able to support. 3. "mem=" kernel command line option which limits physical memory usage. 4. OLDMEM_BASE which is a kdump memory limit when the kernel is executed as crash kernel. 5. "hsa" size which is a memory limit when the kernel is executed during zfcp/nvme dump. Through out kernel startup and run we juggle all those values at once but that does not bring any amusement, only confusion and complexity. Unify all those values to a single one we should really care, that is our identity mapping size. Signed-off-by: Vasily Gorbik <gor@linux.ibm.com> Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com> Acked-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Diffstat (limited to 'arch/s390/boot')
-rw-r--r--arch/s390/boot/boot.h11
-rw-r--r--arch/s390/boot/ipl_parm.c44
-rw-r--r--arch/s390/boot/kaslr.c3
-rw-r--r--arch/s390/boot/mem_detect.c13
-rw-r--r--arch/s390/boot/startup.c48
5 files changed, 73 insertions, 46 deletions
diff --git a/arch/s390/boot/boot.h b/arch/s390/boot/boot.h
index 4d4536299789..d5cf2e8c5eb4 100644
--- a/arch/s390/boot/boot.h
+++ b/arch/s390/boot/boot.h
@@ -2,20 +2,23 @@
#ifndef BOOT_BOOT_H
#define BOOT_BOOT_H
+#include <linux/types.h>
+
void startup_kernel(void);
-void detect_memory(void);
+unsigned long detect_memory(void);
+bool is_ipl_block_dump(void);
void store_ipl_parmblock(void);
void setup_boot_command_line(void);
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;
-extern int vmalloc_size_set;
extern const char kernel_version[];
+extern unsigned long memory_limit;
+extern int vmalloc_size_set;
+extern int kaslr_enabled;
unsigned long read_ipl_report(unsigned long safe_offset);
diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c
index 33f43a7d03f3..d372a45fe10e 100644
--- a/arch/s390/boot/ipl_parm.c
+++ b/arch/s390/boot/ipl_parm.c
@@ -17,10 +17,9 @@ int __bootdata_preserved(ipl_block_valid);
unsigned int __bootdata_preserved(zlib_dfltcc_support) = ZLIB_DFLTCC_FULL;
unsigned long __bootdata(vmalloc_size) = VMALLOC_DEFAULT_SIZE;
-unsigned long __bootdata(memory_end);
-int __bootdata(memory_end_set);
int __bootdata(noexec_disabled);
+unsigned long memory_limit;
int vmalloc_size_set;
int kaslr_enabled;
@@ -58,6 +57,17 @@ void store_ipl_parmblock(void)
ipl_block_valid = 1;
}
+bool is_ipl_block_dump(void)
+{
+ if (ipl_block.pb0_hdr.pbt == IPL_PBT_FCP &&
+ ipl_block.fcp.opt == IPL_PB0_FCP_OPT_DUMP)
+ return true;
+ if (ipl_block.pb0_hdr.pbt == IPL_PBT_NVME &&
+ ipl_block.nvme.opt == IPL_PB0_NVME_OPT_DUMP)
+ return true;
+ return false;
+}
+
static size_t scpdata_length(const u8 *buf, size_t count)
{
while (count) {
@@ -238,10 +248,8 @@ void parse_boot_command_line(void)
while (*args) {
args = next_arg(args, &param, &val);
- if (!strcmp(param, "mem") && val) {
- memory_end = round_down(memparse(val, NULL), PAGE_SIZE);
- memory_end_set = 1;
- }
+ if (!strcmp(param, "mem") && val)
+ memory_limit = round_down(memparse(val, NULL), PAGE_SIZE);
if (!strcmp(param, "vmalloc") && val) {
vmalloc_size = round_up(memparse(val, NULL), PAGE_SIZE);
@@ -282,27 +290,3 @@ void parse_boot_command_line(void)
#endif
}
}
-
-static inline bool is_ipl_block_dump(void)
-{
- if (ipl_block.pb0_hdr.pbt == IPL_PBT_FCP &&
- ipl_block.fcp.opt == IPL_PB0_FCP_OPT_DUMP)
- return true;
- if (ipl_block.pb0_hdr.pbt == IPL_PBT_NVME &&
- ipl_block.nvme.opt == IPL_PB0_NVME_OPT_DUMP)
- return true;
- return false;
-}
-
-void setup_memory_end(void)
-{
-#ifdef CONFIG_CRASH_DUMP
- if (OLDMEM_BASE) {
- kaslr_enabled = 0;
- } else if (ipl_block_valid && is_ipl_block_dump()) {
- kaslr_enabled = 0;
- if (!sclp_early_get_hsa_size(&memory_end) && memory_end)
- memory_end_set = 1;
- }
-#endif
-}
diff --git a/arch/s390/boot/kaslr.c b/arch/s390/boot/kaslr.c
index 987a9eaf228a..0dd48fbdbaa4 100644
--- a/arch/s390/boot/kaslr.c
+++ b/arch/s390/boot/kaslr.c
@@ -177,8 +177,7 @@ unsigned long get_random_base(unsigned long safe_addr)
unsigned long kasan_needs;
int i;
- if (memory_end_set)
- memory_limit = min(memory_limit, memory_end);
+ memory_limit = min(memory_limit, ident_map_size);
/*
* Avoid putting kernel in the end of physical memory
diff --git a/arch/s390/boot/mem_detect.c b/arch/s390/boot/mem_detect.c
index 62e7c13ce85c..40168e59abd3 100644
--- a/arch/s390/boot/mem_detect.c
+++ b/arch/s390/boot/mem_detect.c
@@ -8,7 +8,6 @@
#include "compressed/decompressor.h"
#include "boot.h"
-unsigned long __bootdata(max_physmem_end);
struct mem_detect_info __bootdata(mem_detect);
/* up to 256 storage elements, 1020 subincrements each */
@@ -149,27 +148,29 @@ static void search_mem_end(void)
add_mem_detect_block(0, (offset + 1) << 20);
}
-void detect_memory(void)
+unsigned long detect_memory(void)
{
+ unsigned long max_physmem_end;
+
sclp_early_get_memsize(&max_physmem_end);
if (!sclp_early_read_storage_info()) {
mem_detect.info_source = MEM_DETECT_SCLP_STOR_INFO;
- return;
+ return max_physmem_end;
}
if (!diag260()) {
mem_detect.info_source = MEM_DETECT_DIAG260;
- return;
+ return max_physmem_end;
}
if (max_physmem_end) {
add_mem_detect_block(0, max_physmem_end);
mem_detect.info_source = MEM_DETECT_SCLP_READ_INFO;
- return;
+ return max_physmem_end;
}
search_mem_end();
mem_detect.info_source = MEM_DETECT_BIN_SEARCH;
- max_physmem_end = get_mem_detect_end();
+ return get_mem_detect_end();
}
diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c
index eeda91fcf7cc..05f8eefa3dcf 100644
--- a/arch/s390/boot/startup.c
+++ b/arch/s390/boot/startup.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/string.h>
#include <linux/elf.h>
+#include <asm/boot_data.h>
#include <asm/sections.h>
#include <asm/cpu_mf.h>
#include <asm/setup.h>
@@ -14,6 +15,7 @@
extern char __boot_data_start[], __boot_data_end[];
extern char __boot_data_preserved_start[], __boot_data_preserved_end[];
unsigned long __bootdata_preserved(__kaslr_offset);
+unsigned long __bootdata(ident_map_size);
/*
* Some code and data needs to stay below 2 GB, even when the kernel would be
@@ -128,6 +130,46 @@ static void handle_relocs(unsigned long offset)
}
/*
+ * Merge information from several sources into a single ident_map_size value.
+ * "ident_map_size" represents the upper limit of physical memory we may ever
+ * reach. It might not be all online memory, but also include standby (offline)
+ * memory. "ident_map_size" could be lower then actual standby or even online
+ * memory present, due to limiting factors. We should never go above this limit.
+ * It is the size of our identity mapping.
+ *
+ * Consider the following factors:
+ * 1. max_physmem_end - end of physical memory online or standby.
+ * Always <= end of the last online memory block (get_mem_detect_end()).
+ * 2. CONFIG_MAX_PHYSMEM_BITS - the maximum size of physical memory the
+ * kernel is able to support.
+ * 3. "mem=" kernel command line option which limits physical memory usage.
+ * 4. OLDMEM_BASE which is a kdump memory limit when the kernel is executed as
+ * crash kernel.
+ * 5. "hsa" size which is a memory limit when the kernel is executed during
+ * zfcp/nvme dump.
+ */
+static void setup_ident_map_size(unsigned long max_physmem_end)
+{
+ unsigned long hsa_size;
+
+ ident_map_size = max_physmem_end;
+ if (memory_limit)
+ ident_map_size = min(ident_map_size, memory_limit);
+ ident_map_size = min(ident_map_size, 1UL << MAX_PHYSMEM_BITS);
+
+#ifdef CONFIG_CRASH_DUMP
+ if (OLDMEM_BASE) {
+ kaslr_enabled = 0;
+ ident_map_size = min(ident_map_size, OLDMEM_SIZE);
+ } else if (ipl_block_valid && is_ipl_block_dump()) {
+ kaslr_enabled = 0;
+ if (!sclp_early_get_hsa_size(&hsa_size) && hsa_size)
+ ident_map_size = min(ident_map_size, hsa_size);
+ }
+#endif
+}
+
+/*
* This function clears the BSS section of the decompressed Linux kernel and NOT the decompressor's.
*/
static void clear_bss_section(void)
@@ -145,8 +187,7 @@ static void setup_vmalloc_size(void)
if (vmalloc_size_set)
return;
- size = (memory_end ?: max_physmem_end) >> 3;
- size = round_up(size, _SEGMENT_SIZE);
+ size = round_up(ident_map_size / 8, _SEGMENT_SIZE);
vmalloc_size = max(size, vmalloc_size);
}
@@ -165,8 +206,7 @@ void startup_kernel(void)
sclp_early_read_info();
setup_boot_command_line();
parse_boot_command_line();
- setup_memory_end();
- detect_memory();
+ setup_ident_map_size(detect_memory());
setup_vmalloc_size();
random_lma = __kaslr_offset = 0;