mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	s390/kexec_file: Add kexec_file_load system call
This patch adds the kexec_file_load system call to s390 as well as the arch specific functions common code requires to work. Loaders for the different file types will be added later. Signed-off-by: Philipp Rudo <prudo@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
		
							parent
							
								
									840798a1f5
								
							
						
					
					
						commit
						71406883fd
					
				
					 6 changed files with 144 additions and 0 deletions
				
			
		| 
						 | 
					@ -51,6 +51,19 @@ config KEXEC
 | 
				
			||||||
	def_bool y
 | 
						def_bool y
 | 
				
			||||||
	select KEXEC_CORE
 | 
						select KEXEC_CORE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config KEXEC_FILE
 | 
				
			||||||
 | 
						bool "kexec file based system call"
 | 
				
			||||||
 | 
						select KEXEC_CORE
 | 
				
			||||||
 | 
						select BUILD_BIN2C
 | 
				
			||||||
 | 
						depends on CRYPTO
 | 
				
			||||||
 | 
						depends on CRYPTO_SHA256
 | 
				
			||||||
 | 
						depends on CRYPTO_SHA256_S390
 | 
				
			||||||
 | 
						---help---
 | 
				
			||||||
 | 
						  This is new version of kexec system call. This system call is
 | 
				
			||||||
 | 
						  file based and takes file descriptors as system call argument
 | 
				
			||||||
 | 
						  for kernel and initramfs as opposed to list of segments as
 | 
				
			||||||
 | 
						  accepted by previous system call.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config ARCH_HAS_KEXEC_PURGATORY
 | 
					config ARCH_HAS_KEXEC_PURGATORY
 | 
				
			||||||
	def_bool y
 | 
						def_bool y
 | 
				
			||||||
	depends on KEXEC_FILE
 | 
						depends on KEXEC_FILE
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -719,3 +719,4 @@ CONFIG_APPLDATA_BASE=y
 | 
				
			||||||
CONFIG_KVM=m
 | 
					CONFIG_KVM=m
 | 
				
			||||||
CONFIG_KVM_S390_UCONTROL=y
 | 
					CONFIG_KVM_S390_UCONTROL=y
 | 
				
			||||||
CONFIG_VHOST_NET=m
 | 
					CONFIG_VHOST_NET=m
 | 
				
			||||||
 | 
					CONFIG_KEXEC_FILE=y
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -82,6 +82,8 @@ obj-$(CONFIG_FUNCTION_TRACER)	+= mcount.o ftrace.o
 | 
				
			||||||
obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
 | 
					obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
 | 
				
			||||||
obj-$(CONFIG_UPROBES)		+= uprobes.o
 | 
					obj-$(CONFIG_UPROBES)		+= uprobes.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-$(CONFIG_KEXEC_FILE)	+= machine_kexec_file.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o perf_cpum_cf.o perf_cpum_sf.o
 | 
					obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o perf_cpum_cf.o perf_cpum_sf.o
 | 
				
			||||||
obj-$(CONFIG_PERF_EVENTS)	+= perf_cpum_cf_events.o perf_regs.o
 | 
					obj-$(CONFIG_PERF_EVENTS)	+= perf_cpum_cf_events.o perf_regs.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -182,3 +182,4 @@ COMPAT_SYSCALL_WRAP6(copy_file_range, int, fd_in, loff_t __user *, off_in, int,
 | 
				
			||||||
COMPAT_SYSCALL_WRAP2(s390_guarded_storage, int, command, struct gs_cb *, gs_cb);
 | 
					COMPAT_SYSCALL_WRAP2(s390_guarded_storage, int, command, struct gs_cb *, gs_cb);
 | 
				
			||||||
COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer);
 | 
					COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer);
 | 
				
			||||||
COMPAT_SYSCALL_WRAP4(s390_sthyi, unsigned long, code, void __user *, info, u64 __user *, rc, unsigned long, flags);
 | 
					COMPAT_SYSCALL_WRAP4(s390_sthyi, unsigned long, code, void __user *, info, u64 __user *, rc, unsigned long, flags);
 | 
				
			||||||
 | 
					COMPAT_SYSCALL_WRAP5(kexec_file_load, int, kernel_fd, int, initrd_fd, unsigned long, cmdline_len, const char __user *, cmdline_ptr, unsigned long, flags)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										126
									
								
								arch/s390/kernel/machine_kexec_file.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								arch/s390/kernel/machine_kexec_file.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,126 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * s390 code for kexec_file_load system call
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright IBM Corp. 2018
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author(s): Philipp Rudo <prudo@linux.vnet.ibm.com>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/elf.h>
 | 
				
			||||||
 | 
					#include <linux/kexec.h>
 | 
				
			||||||
 | 
					#include <asm/setup.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct kexec_file_ops * const kexec_file_loaders[] = {
 | 
				
			||||||
 | 
						NULL,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The kernel is loaded to a fixed location. Turn off kexec_locate_mem_hole
 | 
				
			||||||
 | 
					 * and provide kbuf->mem by hand.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int arch_kexec_walk_mem(struct kexec_buf *kbuf,
 | 
				
			||||||
 | 
								int (*func)(struct resource *, void *))
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
 | 
				
			||||||
 | 
									     Elf_Shdr *section,
 | 
				
			||||||
 | 
									     const Elf_Shdr *relsec,
 | 
				
			||||||
 | 
									     const Elf_Shdr *symtab)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Elf_Rela *relas;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						relas = (void *)pi->ehdr + relsec->sh_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < relsec->sh_size / sizeof(*relas); i++) {
 | 
				
			||||||
 | 
							const Elf_Sym *sym;	/* symbol to relocate */
 | 
				
			||||||
 | 
							unsigned long addr;	/* final location after relocation */
 | 
				
			||||||
 | 
							unsigned long val;	/* relocated symbol value */
 | 
				
			||||||
 | 
							void *loc;		/* tmp location to modify */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sym = (void *)pi->ehdr + symtab->sh_offset;
 | 
				
			||||||
 | 
							sym += ELF64_R_SYM(relas[i].r_info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (sym->st_shndx == SHN_UNDEF)
 | 
				
			||||||
 | 
								return -ENOEXEC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (sym->st_shndx == SHN_COMMON)
 | 
				
			||||||
 | 
								return -ENOEXEC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (sym->st_shndx >= pi->ehdr->e_shnum &&
 | 
				
			||||||
 | 
							    sym->st_shndx != SHN_ABS)
 | 
				
			||||||
 | 
								return -ENOEXEC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							loc = pi->purgatory_buf;
 | 
				
			||||||
 | 
							loc += section->sh_offset;
 | 
				
			||||||
 | 
							loc += relas[i].r_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							val = sym->st_value;
 | 
				
			||||||
 | 
							if (sym->st_shndx != SHN_ABS)
 | 
				
			||||||
 | 
								val += pi->sechdrs[sym->st_shndx].sh_addr;
 | 
				
			||||||
 | 
							val += relas[i].r_addend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							addr = section->sh_addr + relas[i].r_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (ELF64_R_TYPE(relas[i].r_info)) {
 | 
				
			||||||
 | 
							case R_390_8:		/* Direct 8 bit.   */
 | 
				
			||||||
 | 
								*(u8 *)loc = val;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case R_390_12:		/* Direct 12 bit.  */
 | 
				
			||||||
 | 
								*(u16 *)loc &= 0xf000;
 | 
				
			||||||
 | 
								*(u16 *)loc |= val & 0xfff;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case R_390_16:		/* Direct 16 bit.  */
 | 
				
			||||||
 | 
								*(u16 *)loc = val;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case R_390_20:		/* Direct 20 bit.  */
 | 
				
			||||||
 | 
								*(u32 *)loc &= 0xf00000ff;
 | 
				
			||||||
 | 
								*(u32 *)loc |= (val & 0xfff) << 16;	/* DL */
 | 
				
			||||||
 | 
								*(u32 *)loc |= (val & 0xff000) >> 4;	/* DH */
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case R_390_32:		/* Direct 32 bit.  */
 | 
				
			||||||
 | 
								*(u32 *)loc = val;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case R_390_64:		/* Direct 64 bit.  */
 | 
				
			||||||
 | 
								*(u64 *)loc = val;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case R_390_PC16:	/* PC relative 16 bit.	*/
 | 
				
			||||||
 | 
								*(u16 *)loc = (val - addr);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case R_390_PC16DBL:	/* PC relative 16 bit shifted by 1.  */
 | 
				
			||||||
 | 
								*(u16 *)loc = (val - addr) >> 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case R_390_PC32DBL:	/* PC relative 32 bit shifted by 1.  */
 | 
				
			||||||
 | 
								*(u32 *)loc = (val - addr) >> 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case R_390_PC32:	/* PC relative 32 bit.	*/
 | 
				
			||||||
 | 
								*(u32 *)loc = (val - addr);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case R_390_PC64:	/* PC relative 64 bit.	*/
 | 
				
			||||||
 | 
								*(u64 *)loc = (val - addr);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int arch_kexec_kernel_image_probe(struct kimage *image, void *buf,
 | 
				
			||||||
 | 
									  unsigned long buf_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* A kernel must be at least large enough to contain head.S. During
 | 
				
			||||||
 | 
						 * load memory in head.S will be accessed, e.g. to register the next
 | 
				
			||||||
 | 
						 * command line. If the next kernel were smaller the current kernel
 | 
				
			||||||
 | 
						 * will panic at load.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * 0x11000 = sizeof(head.S)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (buf_len < 0x11000)
 | 
				
			||||||
 | 
							return -ENOEXEC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return kexec_image_probe_default(image, buf, buf_len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -388,3 +388,4 @@
 | 
				
			||||||
378  common	s390_guarded_storage	sys_s390_guarded_storage	compat_sys_s390_guarded_storage
 | 
					378  common	s390_guarded_storage	sys_s390_guarded_storage	compat_sys_s390_guarded_storage
 | 
				
			||||||
379  common	statx			sys_statx			compat_sys_statx
 | 
					379  common	statx			sys_statx			compat_sys_statx
 | 
				
			||||||
380  common	s390_sthyi		sys_s390_sthyi			compat_sys_s390_sthyi
 | 
					380  common	s390_sthyi		sys_s390_sthyi			compat_sys_s390_sthyi
 | 
				
			||||||
 | 
					381  common	kexec_file_load		sys_kexec_file_load		compat_sys_kexec_file_load
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue