2018-07-19 13:11:28 +02:00
// SPDX-License-Identifier: GPL-2.0
# include <linux/string.h>
2019-02-03 21:35:45 +01:00
# include <linux/elf.h>
2020-10-19 11:01:33 +02:00
# include <asm/boot_data.h>
2019-02-03 21:37:20 +01:00
# include <asm/sections.h>
2020-10-09 17:14:02 +02:00
# include <asm/cpu_mf.h>
2018-04-11 11:56:55 +02:00
# include <asm/setup.h>
2020-10-06 22:12:39 +02:00
# include <asm/kasan.h>
2019-02-03 21:35:45 +01:00
# include <asm/kexec.h>
2018-07-25 15:01:11 +02:00
# include <asm/sclp.h>
2019-02-03 21:37:20 +01:00
# include <asm/diag.h>
2019-04-01 19:11:03 +02:00
# include <asm/uv.h>
2018-07-19 13:11:28 +02:00
# include "compressed/decompressor.h"
# include "boot.h"
2021-07-05 19:33:27 +02:00
# include "uv.h"
2018-07-19 13:11:28 +02:00
2019-02-03 21:37:20 +01:00
unsigned long __bootdata_preserved ( __kaslr_offset ) ;
2021-09-27 14:18:26 +02:00
unsigned long __bootdata ( __amode31_base ) ;
2020-10-06 22:12:39 +02:00
unsigned long __bootdata_preserved ( VMALLOC_START ) ;
unsigned long __bootdata_preserved ( VMALLOC_END ) ;
struct page * __bootdata_preserved ( vmemmap ) ;
unsigned long __bootdata_preserved ( vmemmap_size ) ;
unsigned long __bootdata_preserved ( MODULES_VADDR ) ;
unsigned long __bootdata_preserved ( MODULES_END ) ;
2020-10-19 11:01:33 +02:00
unsigned long __bootdata ( ident_map_size ) ;
2021-03-25 12:10:56 +01:00
int __bootdata ( is_full_image ) = 1 ;
2021-06-15 14:15:07 +02:00
struct initrd_data __bootdata ( initrd_data ) ;
2018-04-10 14:14:02 +02:00
2021-05-05 22:01:10 +02:00
u64 __bootdata_preserved ( stfle_fac_list [ 16 ] ) ;
u64 __bootdata_preserved ( alt_stfle_fac_list [ 16 ] ) ;
2021-06-15 14:25:41 +02:00
struct oldmem_data __bootdata_preserved ( oldmem_data ) ;
2021-05-05 22:01:10 +02:00
2018-07-25 15:01:11 +02:00
void error ( char * x )
{
sclp_early_printk ( " \n \n " ) ;
sclp_early_printk ( x ) ;
sclp_early_printk ( " \n \n -- System halted " ) ;
2019-04-30 12:33:45 +02:00
disabled_wait ( ) ;
2018-07-25 15:01:11 +02:00
}
2020-10-09 17:14:02 +02:00
static void setup_lpp ( void )
{
S390_lowcore . current_pid = 0 ;
S390_lowcore . lpp = LPP_MAGIC ;
if ( test_facility ( 40 ) )
lpp ( & S390_lowcore . lpp ) ;
}
2018-04-11 11:56:55 +02:00
# ifdef CONFIG_KERNEL_UNCOMPRESSED
unsigned long mem_safe_offset ( void )
{
return vmlinux . default_lma + vmlinux . image_size + vmlinux . bss_size ;
}
# endif
2019-02-21 14:23:04 +01:00
static void rescue_initrd ( unsigned long addr )
2018-04-11 11:56:55 +02:00
{
if ( ! IS_ENABLED ( CONFIG_BLK_DEV_INITRD ) )
return ;
2021-06-15 14:15:07 +02:00
if ( ! initrd_data . start | | ! initrd_data . size )
2018-04-11 11:56:55 +02:00
return ;
2021-06-15 14:15:07 +02:00
if ( addr < = initrd_data . start )
2018-04-11 11:56:55 +02:00
return ;
2021-06-15 14:15:07 +02:00
memmove ( ( void * ) addr , ( void * ) initrd_data . start , initrd_data . size ) ;
initrd_data . start = addr ;
2018-04-11 11:56:55 +02:00
}
2018-04-10 14:14:02 +02:00
static void copy_bootdata ( void )
{
if ( __boot_data_end - __boot_data_start ! = vmlinux . bootdata_size )
error ( " .boot.data section size mismatch " ) ;
memcpy ( ( void * ) vmlinux . bootdata_off , __boot_data_start , vmlinux . bootdata_size ) ;
2019-04-01 19:10:45 +02:00
if ( __boot_data_preserved_end - __boot_data_preserved_start ! = vmlinux . bootdata_preserved_size )
error ( " .boot.preserved.data section size mismatch " ) ;
memcpy ( ( void * ) vmlinux . bootdata_preserved_off , __boot_data_preserved_start , vmlinux . bootdata_preserved_size ) ;
2018-04-10 14:14:02 +02:00
}
2019-02-03 21:35:45 +01:00
static void handle_relocs ( unsigned long offset )
{
Elf64_Rela * rela_start , * rela_end , * rela ;
int r_type , r_sym , rc ;
Elf64_Addr loc , val ;
Elf64_Sym * dynsym ;
rela_start = ( Elf64_Rela * ) vmlinux . rela_dyn_start ;
rela_end = ( Elf64_Rela * ) vmlinux . rela_dyn_end ;
dynsym = ( Elf64_Sym * ) vmlinux . dynsym_start ;
for ( rela = rela_start ; rela < rela_end ; rela + + ) {
loc = rela - > r_offset + offset ;
2019-10-21 19:56:00 +02:00
val = rela - > r_addend ;
2019-02-03 21:35:45 +01:00
r_sym = ELF64_R_SYM ( rela - > r_info ) ;
2019-10-21 19:56:00 +02:00
if ( r_sym ) {
if ( dynsym [ r_sym ] . st_shndx ! = SHN_UNDEF )
val + = dynsym [ r_sym ] . st_value + offset ;
} else {
/*
* 0 = = undefined symbol table index ( STN_UNDEF ) ,
* used for R_390_RELATIVE , only add KASLR offset
*/
val + = offset ;
}
2019-02-03 21:35:45 +01:00
r_type = ELF64_R_TYPE ( rela - > r_info ) ;
rc = arch_kexec_do_relocs ( r_type , ( void * ) loc , val , 0 ) ;
if ( rc )
error ( " Unknown relocation type " ) ;
}
}
2020-10-19 11:01:33 +02:00
/*
* 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
2021-06-15 14:25:41 +02:00
if ( oldmem_data . start ) {
2020-10-19 11:01:33 +02:00
kaslr_enabled = 0 ;
2021-06-15 14:25:41 +02:00
ident_map_size = min ( ident_map_size , oldmem_data . size ) ;
2020-10-19 11:01:33 +02:00
} 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
}
2020-10-06 22:12:39 +02:00
static void setup_kernel_memory_layout ( void )
{
bool vmalloc_size_verified = false ;
unsigned long vmemmap_off ;
unsigned long vspace_left ;
unsigned long rte_size ;
unsigned long pages ;
unsigned long vmax ;
pages = ident_map_size / PAGE_SIZE ;
/* vmemmap contains a multiple of PAGES_PER_SECTION struct pages */
vmemmap_size = SECTION_ALIGN_UP ( pages ) * sizeof ( struct page ) ;
/* choose kernel address space layout: 4 or 3 levels. */
vmemmap_off = round_up ( ident_map_size , _REGION3_SIZE ) ;
if ( IS_ENABLED ( CONFIG_KASAN ) | |
vmalloc_size > _REGION2_SIZE | |
vmemmap_off + vmemmap_size + vmalloc_size + MODULES_LEN > _REGION2_SIZE )
vmax = _REGION1_SIZE ;
else
vmax = _REGION2_SIZE ;
/* keep vmemmap_off aligned to a top level region table entry */
rte_size = vmax = = _REGION1_SIZE ? _REGION2_SIZE : _REGION3_SIZE ;
MODULES_END = vmax ;
if ( is_prot_virt_host ( ) ) {
/*
* forcing modules and vmalloc area under the ultravisor
* secure storage limit , so that any vmalloc allocation
* we do could be used to back secure guest storage .
*/
adjust_to_uv_max ( & MODULES_END ) ;
}
# ifdef CONFIG_KASAN
if ( MODULES_END < vmax ) {
/* force vmalloc and modules below kasan shadow */
MODULES_END = min ( MODULES_END , KASAN_SHADOW_START ) ;
} else {
/*
* leave vmalloc and modules above kasan shadow but make
* sure they don ' t overlap with it
*/
vmalloc_size = min ( vmalloc_size , vmax - KASAN_SHADOW_END - MODULES_LEN ) ;
vmalloc_size_verified = true ;
vspace_left = KASAN_SHADOW_START ;
}
# endif
MODULES_VADDR = MODULES_END - MODULES_LEN ;
VMALLOC_END = MODULES_VADDR ;
if ( vmalloc_size_verified ) {
VMALLOC_START = VMALLOC_END - vmalloc_size ;
} else {
vmemmap_off = round_up ( ident_map_size , rte_size ) ;
if ( vmemmap_off + vmemmap_size > VMALLOC_END | |
vmalloc_size > VMALLOC_END - vmemmap_off - vmemmap_size ) {
/*
* allow vmalloc area to occupy up to 1 / 2 of
* the rest virtual space left .
*/
vmalloc_size = min ( vmalloc_size , VMALLOC_END / 2 ) ;
}
VMALLOC_START = VMALLOC_END - vmalloc_size ;
vspace_left = VMALLOC_START ;
}
pages = vspace_left / ( PAGE_SIZE + sizeof ( struct page ) ) ;
pages = SECTION_ALIGN_UP ( pages ) ;
vmemmap_off = round_up ( vspace_left - pages * sizeof ( struct page ) , rte_size ) ;
/* keep vmemmap left most starting from a fresh region table entry */
vmemmap_off = min ( vmemmap_off , round_up ( ident_map_size , rte_size ) ) ;
/* take care that identity map is lower then vmemmap */
ident_map_size = min ( ident_map_size , vmemmap_off ) ;
vmemmap_size = SECTION_ALIGN_UP ( ident_map_size / PAGE_SIZE ) * sizeof ( struct page ) ;
VMALLOC_START = max ( vmemmap_off + vmemmap_size , VMALLOC_START ) ;
vmemmap = ( struct page * ) vmemmap_off ;
}
2020-09-02 16:52:06 +02:00
/*
* This function clears the BSS section of the decompressed Linux kernel and NOT the decompressor ' s .
*/
2019-08-11 20:55:18 +02:00
static void clear_bss_section ( void )
{
memset ( ( void * ) vmlinux . default_lma + vmlinux . image_size , 0 , vmlinux . bss_size ) ;
}
2020-09-18 12:25:37 +02:00
/*
* Set vmalloc area size to an 8 th of ( potential ) physical memory
* size , unless size has been set by kernel command line parameter .
*/
static void setup_vmalloc_size ( void )
{
unsigned long size ;
if ( vmalloc_size_set )
return ;
2020-10-19 11:01:33 +02:00
size = round_up ( ident_map_size / 8 , _SEGMENT_SIZE ) ;
2020-09-18 12:25:37 +02:00
vmalloc_size = max ( size , vmalloc_size ) ;
}
2021-08-06 12:55:09 +02:00
static void offset_vmlinux_info ( unsigned long offset )
{
vmlinux . default_lma + = offset ;
* ( unsigned long * ) ( & vmlinux . entry ) + = offset ;
vmlinux . bootdata_off + = offset ;
vmlinux . bootdata_preserved_off + = offset ;
vmlinux . rela_dyn_start + = offset ;
vmlinux . rela_dyn_end + = offset ;
vmlinux . dynsym_start + = offset ;
}
2021-09-27 14:18:26 +02:00
static unsigned long reserve_amode31 ( unsigned long safe_addr )
{
__amode31_base = PAGE_ALIGN ( safe_addr ) ;
return safe_addr + vmlinux . amode31_size ;
}
2018-07-19 13:11:28 +02:00
void startup_kernel ( void )
{
2019-02-03 21:37:20 +01:00
unsigned long random_lma ;
2019-02-21 14:23:04 +01:00
unsigned long safe_addr ;
2018-07-19 16:51:25 +02:00
void * img ;
2018-07-19 13:11:28 +02:00
2021-06-15 14:15:07 +02:00
initrd_data . start = parmarea . initrd_start ;
initrd_data . size = parmarea . initrd_size ;
2021-06-15 14:25:41 +02:00
oldmem_data . start = parmarea . oldmem_base ;
oldmem_data . size = parmarea . oldmem_size ;
2021-06-15 14:15:07 +02:00
2020-10-09 17:14:02 +02:00
setup_lpp ( ) ;
2019-02-21 14:23:04 +01:00
store_ipl_parmblock ( ) ;
safe_addr = mem_safe_offset ( ) ;
2021-09-27 14:18:26 +02:00
safe_addr = reserve_amode31 ( safe_addr ) ;
2019-02-21 14:23:04 +01:00
safe_addr = read_ipl_report ( safe_addr ) ;
2019-04-01 19:11:03 +02:00
uv_query_info ( ) ;
2019-02-21 14:23:04 +01:00
rescue_initrd ( safe_addr ) ;
2018-05-23 11:07:13 +02:00
sclp_early_read_info ( ) ;
2018-05-15 13:28:53 +02:00
setup_boot_command_line ( ) ;
2019-02-27 16:52:42 +01:00
parse_boot_command_line ( ) ;
2021-07-05 19:37:25 +02:00
sanitize_prot_virt_host ( ) ;
2020-10-19 11:01:33 +02:00
setup_ident_map_size ( detect_memory ( ) ) ;
2020-09-18 12:25:37 +02:00
setup_vmalloc_size ( ) ;
2020-10-06 22:12:39 +02:00
setup_kernel_memory_layout ( ) ;
2019-02-03 21:37:20 +01:00
if ( IS_ENABLED ( CONFIG_RANDOMIZE_BASE ) & & kaslr_enabled ) {
random_lma = get_random_base ( safe_addr ) ;
if ( random_lma ) {
__kaslr_offset = random_lma - vmlinux . default_lma ;
img = ( void * ) vmlinux . default_lma ;
2021-08-06 12:55:09 +02:00
offset_vmlinux_info ( __kaslr_offset ) ;
2019-02-03 21:37:20 +01:00
}
}
2018-07-19 13:11:28 +02:00
if ( ! IS_ENABLED ( CONFIG_KERNEL_UNCOMPRESSED ) ) {
2018-07-19 16:51:25 +02:00
img = decompress_kernel ( ) ;
memmove ( ( void * ) vmlinux . default_lma , img , vmlinux . image_size ) ;
2019-02-03 21:37:20 +01:00
} else if ( __kaslr_offset )
memcpy ( ( void * ) vmlinux . default_lma , img , vmlinux . image_size ) ;
2019-08-11 20:55:18 +02:00
clear_bss_section ( ) ;
2018-04-10 14:14:02 +02:00
copy_bootdata ( ) ;
2019-02-03 21:35:45 +01:00
if ( IS_ENABLED ( CONFIG_RELOCATABLE ) )
2019-02-03 21:37:20 +01:00
handle_relocs ( __kaslr_offset ) ;
if ( __kaslr_offset ) {
s390/kaslr: store KASLR offset for early dumps
The KASLR offset is added to vmcoreinfo in arch_crash_save_vmcoreinfo(),
so that it can be found by crash when processing kernel dumps.
However, arch_crash_save_vmcoreinfo() is called during a subsys_initcall,
so if the kernel crashes before that, we have no vmcoreinfo and no KASLR
offset.
Fix this by storing the KASLR offset in the lowcore, where the vmcore_info
pointer will be stored, and where it can be found by crash. In order to
make it distinguishable from a real vmcore_info pointer, mark it as uneven
(KASLR offset itself is aligned to THREAD_SIZE).
When arch_crash_save_vmcoreinfo() stores the real vmcore_info pointer in
the lowcore, it overwrites the KASLR offset. At that point, the KASLR
offset is not yet added to vmcoreinfo, so we also need to move the
mem_assign_absolute() behind the vmcoreinfo_append_str().
Fixes: b2d24b97b2a9 ("s390/kernel: add support for kernel address space layout randomization (KASLR)")
Cc: <stable@vger.kernel.org> # v5.2+
Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
2019-11-19 12:30:53 +01:00
/*
* Save KASLR offset for early dumps , before vmcore_info is set .
* Mark as uneven to distinguish from real vmcore_info pointer .
*/
S390_lowcore . vmcore_info = __kaslr_offset | 0x1UL ;
2019-02-03 21:37:20 +01:00
/* Clear non-relocated kernel */
if ( IS_ENABLED ( CONFIG_KERNEL_UNCOMPRESSED ) )
memset ( img , 0 , vmlinux . image_size ) ;
}
2018-07-19 16:51:25 +02:00
vmlinux . entry ( ) ;
2018-07-19 13:11:28 +02:00
}