18f75582aSVasily Gorbik // SPDX-License-Identifier: GPL-2.0 28f75582aSVasily Gorbik #include <linux/string.h> 3805bc0bcSGerald Schaefer #include <linux/elf.h> 473045a08SVasily Gorbik #include <asm/boot_data.h> 5a80313ffSGerald Schaefer #include <asm/sections.h> 6d7e7fbbaSVasily Gorbik #include <asm/cpu_mf.h> 715426ca4SVasily Gorbik #include <asm/setup.h> 8805bc0bcSGerald Schaefer #include <asm/kexec.h> 97516fc11SVasily Gorbik #include <asm/sclp.h> 10a80313ffSGerald Schaefer #include <asm/diag.h> 115abb9351SVasily Gorbik #include <asm/uv.h> 128f75582aSVasily Gorbik #include "compressed/decompressor.h" 138f75582aSVasily Gorbik #include "boot.h" 148f75582aSVasily Gorbik 15d1b52a43SVasily Gorbik extern char __boot_data_start[], __boot_data_end[]; 16bf9921a9SGerald Schaefer extern char __boot_data_preserved_start[], __boot_data_preserved_end[]; 17b2d24b97SGerald Schaefer unsigned long __bootdata_preserved(__kaslr_offset); 1873045a08SVasily Gorbik unsigned long __bootdata(ident_map_size); 19d1b52a43SVasily Gorbik 20*17e89e13SSven Schnelle u64 __bootdata_preserved(stfle_fac_list[16]); 21*17e89e13SSven Schnelle u64 __bootdata_preserved(alt_stfle_fac_list[16]); 22*17e89e13SSven Schnelle 23a80313ffSGerald Schaefer /* 24a80313ffSGerald Schaefer * Some code and data needs to stay below 2 GB, even when the kernel would be 25a80313ffSGerald Schaefer * relocated above 2 GB, because it has to use 31 bit addresses. 26a80313ffSGerald Schaefer * Such code and data is part of the .dma section, and its location is passed 27a80313ffSGerald Schaefer * over to the decompressed / relocated kernel via the .boot.preserved.data 28a80313ffSGerald Schaefer * section. 29a80313ffSGerald Schaefer */ 30a80313ffSGerald Schaefer extern char _sdma[], _edma[]; 31a80313ffSGerald Schaefer extern char _stext_dma[], _etext_dma[]; 32a80313ffSGerald Schaefer extern struct exception_table_entry _start_dma_ex_table[]; 33a80313ffSGerald Schaefer extern struct exception_table_entry _stop_dma_ex_table[]; 34a80313ffSGerald Schaefer unsigned long __bootdata_preserved(__sdma) = __pa(&_sdma); 35a80313ffSGerald Schaefer unsigned long __bootdata_preserved(__edma) = __pa(&_edma); 36a80313ffSGerald Schaefer unsigned long __bootdata_preserved(__stext_dma) = __pa(&_stext_dma); 37a80313ffSGerald Schaefer unsigned long __bootdata_preserved(__etext_dma) = __pa(&_etext_dma); 38a80313ffSGerald Schaefer struct exception_table_entry * 39a80313ffSGerald Schaefer __bootdata_preserved(__start_dma_ex_table) = _start_dma_ex_table; 40a80313ffSGerald Schaefer struct exception_table_entry * 41a80313ffSGerald Schaefer __bootdata_preserved(__stop_dma_ex_table) = _stop_dma_ex_table; 42a80313ffSGerald Schaefer 43a80313ffSGerald Schaefer int _diag210_dma(struct diag210 *addr); 44a80313ffSGerald Schaefer int _diag26c_dma(void *req, void *resp, enum diag26c_sc subcode); 45a80313ffSGerald Schaefer int _diag14_dma(unsigned long rx, unsigned long ry1, unsigned long subcode); 46a80313ffSGerald Schaefer void _diag0c_dma(struct hypfs_diag0c_entry *entry); 47a80313ffSGerald Schaefer void _diag308_reset_dma(void); 48a80313ffSGerald Schaefer struct diag_ops __bootdata_preserved(diag_dma_ops) = { 49a80313ffSGerald Schaefer .diag210 = _diag210_dma, 50a80313ffSGerald Schaefer .diag26c = _diag26c_dma, 51a80313ffSGerald Schaefer .diag14 = _diag14_dma, 52a80313ffSGerald Schaefer .diag0c = _diag0c_dma, 53a80313ffSGerald Schaefer .diag308_reset = _diag308_reset_dma 54a80313ffSGerald Schaefer }; 5533def849SJoe Perches static struct diag210 _diag210_tmp_dma __section(".dma.data"); 56a80313ffSGerald Schaefer struct diag210 *__bootdata_preserved(__diag210_tmp_dma) = &_diag210_tmp_dma; 57a80313ffSGerald Schaefer 587516fc11SVasily Gorbik void error(char *x) 597516fc11SVasily Gorbik { 607516fc11SVasily Gorbik sclp_early_printk("\n\n"); 617516fc11SVasily Gorbik sclp_early_printk(x); 627516fc11SVasily Gorbik sclp_early_printk("\n\n -- System halted"); 637516fc11SVasily Gorbik 6498587c2dSMartin Schwidefsky disabled_wait(); 657516fc11SVasily Gorbik } 667516fc11SVasily Gorbik 67d7e7fbbaSVasily Gorbik static void setup_lpp(void) 68d7e7fbbaSVasily Gorbik { 69d7e7fbbaSVasily Gorbik S390_lowcore.current_pid = 0; 70d7e7fbbaSVasily Gorbik S390_lowcore.lpp = LPP_MAGIC; 71d7e7fbbaSVasily Gorbik if (test_facility(40)) 72d7e7fbbaSVasily Gorbik lpp(&S390_lowcore.lpp); 73d7e7fbbaSVasily Gorbik } 74d7e7fbbaSVasily Gorbik 7515426ca4SVasily Gorbik #ifdef CONFIG_KERNEL_UNCOMPRESSED 7615426ca4SVasily Gorbik unsigned long mem_safe_offset(void) 7715426ca4SVasily Gorbik { 7815426ca4SVasily Gorbik return vmlinux.default_lma + vmlinux.image_size + vmlinux.bss_size; 7915426ca4SVasily Gorbik } 8015426ca4SVasily Gorbik #endif 8115426ca4SVasily Gorbik 829641b8ccSMartin Schwidefsky static void rescue_initrd(unsigned long addr) 8315426ca4SVasily Gorbik { 8415426ca4SVasily Gorbik if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD)) 8515426ca4SVasily Gorbik return; 8615426ca4SVasily Gorbik if (!INITRD_START || !INITRD_SIZE) 8715426ca4SVasily Gorbik return; 889641b8ccSMartin Schwidefsky if (addr <= INITRD_START) 8915426ca4SVasily Gorbik return; 909641b8ccSMartin Schwidefsky memmove((void *)addr, (void *)INITRD_START, INITRD_SIZE); 919641b8ccSMartin Schwidefsky INITRD_START = addr; 9215426ca4SVasily Gorbik } 9315426ca4SVasily Gorbik 94d1b52a43SVasily Gorbik static void copy_bootdata(void) 95d1b52a43SVasily Gorbik { 96d1b52a43SVasily Gorbik if (__boot_data_end - __boot_data_start != vmlinux.bootdata_size) 97d1b52a43SVasily Gorbik error(".boot.data section size mismatch"); 98d1b52a43SVasily Gorbik memcpy((void *)vmlinux.bootdata_off, __boot_data_start, vmlinux.bootdata_size); 99bf9921a9SGerald Schaefer if (__boot_data_preserved_end - __boot_data_preserved_start != vmlinux.bootdata_preserved_size) 100bf9921a9SGerald Schaefer error(".boot.preserved.data section size mismatch"); 101bf9921a9SGerald Schaefer memcpy((void *)vmlinux.bootdata_preserved_off, __boot_data_preserved_start, vmlinux.bootdata_preserved_size); 102d1b52a43SVasily Gorbik } 103d1b52a43SVasily Gorbik 104805bc0bcSGerald Schaefer static void handle_relocs(unsigned long offset) 105805bc0bcSGerald Schaefer { 106805bc0bcSGerald Schaefer Elf64_Rela *rela_start, *rela_end, *rela; 107805bc0bcSGerald Schaefer int r_type, r_sym, rc; 108805bc0bcSGerald Schaefer Elf64_Addr loc, val; 109805bc0bcSGerald Schaefer Elf64_Sym *dynsym; 110805bc0bcSGerald Schaefer 111805bc0bcSGerald Schaefer rela_start = (Elf64_Rela *) vmlinux.rela_dyn_start; 112805bc0bcSGerald Schaefer rela_end = (Elf64_Rela *) vmlinux.rela_dyn_end; 113805bc0bcSGerald Schaefer dynsym = (Elf64_Sym *) vmlinux.dynsym_start; 114805bc0bcSGerald Schaefer for (rela = rela_start; rela < rela_end; rela++) { 115805bc0bcSGerald Schaefer loc = rela->r_offset + offset; 116ac49303dSGerald Schaefer val = rela->r_addend; 117805bc0bcSGerald Schaefer r_sym = ELF64_R_SYM(rela->r_info); 118ac49303dSGerald Schaefer if (r_sym) { 119ac49303dSGerald Schaefer if (dynsym[r_sym].st_shndx != SHN_UNDEF) 120ac49303dSGerald Schaefer val += dynsym[r_sym].st_value + offset; 121ac49303dSGerald Schaefer } else { 122ac49303dSGerald Schaefer /* 123ac49303dSGerald Schaefer * 0 == undefined symbol table index (STN_UNDEF), 124ac49303dSGerald Schaefer * used for R_390_RELATIVE, only add KASLR offset 125ac49303dSGerald Schaefer */ 126ac49303dSGerald Schaefer val += offset; 127ac49303dSGerald Schaefer } 128805bc0bcSGerald Schaefer r_type = ELF64_R_TYPE(rela->r_info); 129805bc0bcSGerald Schaefer rc = arch_kexec_do_relocs(r_type, (void *) loc, val, 0); 130805bc0bcSGerald Schaefer if (rc) 131805bc0bcSGerald Schaefer error("Unknown relocation type"); 132805bc0bcSGerald Schaefer } 133805bc0bcSGerald Schaefer } 134805bc0bcSGerald Schaefer 135980d5f9aSAlexander Egorenkov /* 13673045a08SVasily Gorbik * Merge information from several sources into a single ident_map_size value. 13773045a08SVasily Gorbik * "ident_map_size" represents the upper limit of physical memory we may ever 13873045a08SVasily Gorbik * reach. It might not be all online memory, but also include standby (offline) 13973045a08SVasily Gorbik * memory. "ident_map_size" could be lower then actual standby or even online 14073045a08SVasily Gorbik * memory present, due to limiting factors. We should never go above this limit. 14173045a08SVasily Gorbik * It is the size of our identity mapping. 14273045a08SVasily Gorbik * 14373045a08SVasily Gorbik * Consider the following factors: 14473045a08SVasily Gorbik * 1. max_physmem_end - end of physical memory online or standby. 14573045a08SVasily Gorbik * Always <= end of the last online memory block (get_mem_detect_end()). 14673045a08SVasily Gorbik * 2. CONFIG_MAX_PHYSMEM_BITS - the maximum size of physical memory the 14773045a08SVasily Gorbik * kernel is able to support. 14873045a08SVasily Gorbik * 3. "mem=" kernel command line option which limits physical memory usage. 14973045a08SVasily Gorbik * 4. OLDMEM_BASE which is a kdump memory limit when the kernel is executed as 15073045a08SVasily Gorbik * crash kernel. 15173045a08SVasily Gorbik * 5. "hsa" size which is a memory limit when the kernel is executed during 15273045a08SVasily Gorbik * zfcp/nvme dump. 15373045a08SVasily Gorbik */ 15473045a08SVasily Gorbik static void setup_ident_map_size(unsigned long max_physmem_end) 15573045a08SVasily Gorbik { 15673045a08SVasily Gorbik unsigned long hsa_size; 15773045a08SVasily Gorbik 15873045a08SVasily Gorbik ident_map_size = max_physmem_end; 15973045a08SVasily Gorbik if (memory_limit) 16073045a08SVasily Gorbik ident_map_size = min(ident_map_size, memory_limit); 16173045a08SVasily Gorbik ident_map_size = min(ident_map_size, 1UL << MAX_PHYSMEM_BITS); 16273045a08SVasily Gorbik 16373045a08SVasily Gorbik #ifdef CONFIG_CRASH_DUMP 16473045a08SVasily Gorbik if (OLDMEM_BASE) { 16573045a08SVasily Gorbik kaslr_enabled = 0; 16673045a08SVasily Gorbik ident_map_size = min(ident_map_size, OLDMEM_SIZE); 16773045a08SVasily Gorbik } else if (ipl_block_valid && is_ipl_block_dump()) { 16873045a08SVasily Gorbik kaslr_enabled = 0; 16973045a08SVasily Gorbik if (!sclp_early_get_hsa_size(&hsa_size) && hsa_size) 17073045a08SVasily Gorbik ident_map_size = min(ident_map_size, hsa_size); 17173045a08SVasily Gorbik } 17273045a08SVasily Gorbik #endif 17373045a08SVasily Gorbik } 17473045a08SVasily Gorbik 17573045a08SVasily Gorbik /* 176980d5f9aSAlexander Egorenkov * This function clears the BSS section of the decompressed Linux kernel and NOT the decompressor's. 177980d5f9aSAlexander Egorenkov */ 1782e83e0ebSVasily Gorbik static void clear_bss_section(void) 1792e83e0ebSVasily Gorbik { 1802e83e0ebSVasily Gorbik memset((void *)vmlinux.default_lma + vmlinux.image_size, 0, vmlinux.bss_size); 1812e83e0ebSVasily Gorbik } 1822e83e0ebSVasily Gorbik 18390178c19SHeiko Carstens /* 18490178c19SHeiko Carstens * Set vmalloc area size to an 8th of (potential) physical memory 18590178c19SHeiko Carstens * size, unless size has been set by kernel command line parameter. 18690178c19SHeiko Carstens */ 18790178c19SHeiko Carstens static void setup_vmalloc_size(void) 18890178c19SHeiko Carstens { 18990178c19SHeiko Carstens unsigned long size; 19090178c19SHeiko Carstens 19190178c19SHeiko Carstens if (vmalloc_size_set) 19290178c19SHeiko Carstens return; 19373045a08SVasily Gorbik size = round_up(ident_map_size / 8, _SEGMENT_SIZE); 19490178c19SHeiko Carstens vmalloc_size = max(size, vmalloc_size); 19590178c19SHeiko Carstens } 19690178c19SHeiko Carstens 1978f75582aSVasily Gorbik void startup_kernel(void) 1988f75582aSVasily Gorbik { 199b2d24b97SGerald Schaefer unsigned long random_lma; 2009641b8ccSMartin Schwidefsky unsigned long safe_addr; 201369f91c3SVasily Gorbik void *img; 2028f75582aSVasily Gorbik 203d7e7fbbaSVasily Gorbik setup_lpp(); 20449698745SVasily Gorbik store_ipl_parmblock(); 2059641b8ccSMartin Schwidefsky safe_addr = mem_safe_offset(); 2069641b8ccSMartin Schwidefsky safe_addr = read_ipl_report(safe_addr); 2079641b8ccSMartin Schwidefsky uv_query_info(); 2089641b8ccSMartin Schwidefsky rescue_initrd(safe_addr); 2099641b8ccSMartin Schwidefsky sclp_early_read_info(); 21049698745SVasily Gorbik setup_boot_command_line(); 211b5e80459SVasily Gorbik parse_boot_command_line(); 21273045a08SVasily Gorbik setup_ident_map_size(detect_memory()); 21390178c19SHeiko Carstens setup_vmalloc_size(); 214b2d24b97SGerald Schaefer 215b2d24b97SGerald Schaefer random_lma = __kaslr_offset = 0; 216b2d24b97SGerald Schaefer if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_enabled) { 217b2d24b97SGerald Schaefer random_lma = get_random_base(safe_addr); 218b2d24b97SGerald Schaefer if (random_lma) { 219b2d24b97SGerald Schaefer __kaslr_offset = random_lma - vmlinux.default_lma; 220b2d24b97SGerald Schaefer img = (void *)vmlinux.default_lma; 221b2d24b97SGerald Schaefer vmlinux.default_lma += __kaslr_offset; 222b2d24b97SGerald Schaefer vmlinux.entry += __kaslr_offset; 223b2d24b97SGerald Schaefer vmlinux.bootdata_off += __kaslr_offset; 224b2d24b97SGerald Schaefer vmlinux.bootdata_preserved_off += __kaslr_offset; 225b2d24b97SGerald Schaefer vmlinux.rela_dyn_start += __kaslr_offset; 226b2d24b97SGerald Schaefer vmlinux.rela_dyn_end += __kaslr_offset; 227b2d24b97SGerald Schaefer vmlinux.dynsym_start += __kaslr_offset; 228b2d24b97SGerald Schaefer } 229b2d24b97SGerald Schaefer } 230b2d24b97SGerald Schaefer 2318f75582aSVasily Gorbik if (!IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED)) { 232369f91c3SVasily Gorbik img = decompress_kernel(); 233369f91c3SVasily Gorbik memmove((void *)vmlinux.default_lma, img, vmlinux.image_size); 234b2d24b97SGerald Schaefer } else if (__kaslr_offset) 235b2d24b97SGerald Schaefer memcpy((void *)vmlinux.default_lma, img, vmlinux.image_size); 236b2d24b97SGerald Schaefer 2372e83e0ebSVasily Gorbik clear_bss_section(); 238d1b52a43SVasily Gorbik copy_bootdata(); 239805bc0bcSGerald Schaefer if (IS_ENABLED(CONFIG_RELOCATABLE)) 240b2d24b97SGerald Schaefer handle_relocs(__kaslr_offset); 241b2d24b97SGerald Schaefer 242b2d24b97SGerald Schaefer if (__kaslr_offset) { 243a9f2f686SGerald Schaefer /* 244a9f2f686SGerald Schaefer * Save KASLR offset for early dumps, before vmcore_info is set. 245a9f2f686SGerald Schaefer * Mark as uneven to distinguish from real vmcore_info pointer. 246a9f2f686SGerald Schaefer */ 247a9f2f686SGerald Schaefer S390_lowcore.vmcore_info = __kaslr_offset | 0x1UL; 248b2d24b97SGerald Schaefer /* Clear non-relocated kernel */ 249b2d24b97SGerald Schaefer if (IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED)) 250b2d24b97SGerald Schaefer memset(img, 0, vmlinux.image_size); 251b2d24b97SGerald Schaefer } 252369f91c3SVasily Gorbik vmlinux.entry(); 2538f75582aSVasily Gorbik } 254