Hello,
This patch series implements the kexec_file_load system call on PowerPC.
This system call moves the reading of the kernel, initrd and the device tree
from the userspace kexec tool to the kernel. This is needed if you want to
do one or both of the following:
1. only allow loading of signed kernels.
2. "measure" (i.e., record the hashes of) the kernel, initrd, kernel
command line and other boot inputs for the Integrity Measurement
Architecture subsystem.
The above are the functions kexec already has built into kexec_file_load.
Yesterday I posted a set of patches which allows a third feature:
3. have IMA pass-on its event log (where integrity measurements are
registered) accross kexec to the second kernel, so that the event
history is preserved.
Because OpenPower uses an intermediary Linux instance as a boot loader
(skiroot), feature 1 is needed to implement secure boot for the platform,
while features 2 and 3 are needed to implement trusted boot.
This patch series starts by removing an x86 assumption from kexec_file:
kexec_add_buffer uses iomem to find reserved memory ranges, but PowerPC
uses the memblock subsystem. A hook is added so that each arch can
specify how memory ranges can be found.
Also, the memory-walking logic in kexec_add_buffer is useful in this
implementation to find a free area for the purgatory's stack, so the
next patch moves that logic to kexec_locate_mem_hole.
The kexec_file_load system call needs to apply relocations to the
purgatory but adding code for that would duplicate functionality with
the module loading mechanism, which also needs to apply relocations to
the kernel modules. Therefore, this patch series factors out the module
relocation code so that it can be shared.
One thing that is still missing is crashkernel support, which I intend
to submit shortly. For now, arch_kexec_kernel_image_probe rejects crash
kernels.
This code is based on kexec-tools, but with many modifications to adapt
it to the kernel environment and facilities. Except the purgatory,
which only has minimal changes.
Changes for v3:
- Rebased series on today's powerpc/next.
- Patch "kexec_file: Generalize kexec_add_buffer.":
- Removed most arguments from arch_kexec_walk_mem and pass kbuf
explicitly.
- Patch "powerpc: Add functions to read ELF files of any endianness.":
- Fixed whitespace issues found by checkpatch.pl.
- Patch "powerpc: Factor out relocation code from module_64.c to
elf_util_64.c.":
- Changed to use the new PPC64_ELF_ABI_v2 macro.
- Patch "powerpc: Add support for loading ELF kernels with
kexec_file_load.":
- Adapted arch_kexec_walk_mem implementation to changes in its
argument list.
- Fixed whitespace and GPL header issues found by checkpatch.pl.
- Patch "powerpc: Add purgatory for kexec_file_load implementation.":
- Fixed whitespace and GPL header issues found by checkpatch.pl.
- Changed to use the new PPC64_ELF_ABI_v2 macro.
Changes for v2:
- All patches: forgot to add Signed-off-by lines in v1, so added them now.
- Patch "kexec_file: Generalize kexec_add_buffer.": broke in two, one
adding arch_kexec_walk_mem and the other adding kexec_locate_mem_hole.
- Patch "powerpc: Implement kexec_file_load.":
- Moved relocation changes and the arch_kexec_walk_mem implementation
to the next patch in the series.
- Removed pr_fmt from machine_kexec_64.c, since the patch doesn't add
any call to pr_debug in that file.
- Changed arch_kexec_kernel_image_probe to reject crash kernels.
Changes for v3:
- Rebased series on today's powerpc/next.
- Patch "kexec_file: Generalize kexec_add_buffer.":
- Removed most arguments from arch_kexec_walk_mem and pass kbuf
explicitly.
- Patch "powerpc: Add functions to read ELF files of any endianness.":
- Fixed whitespace issues found by checkpatch.pl.
- Patch "powerpc: Factor out relocation code from module_64.c to
elf_util_64.c.":
- Changed to use the new PPC64_ELF_ABI_v2 macro.
- Patch "powerpc: Add support for loading ELF kernels with
kexec_file_load.":
- Adapted arch_kexec_walk_mem implementation to changes in its
argument list.
- Fixed whitespace and GPL header issues found by checkpatch.pl.
- Patch "powerpc: Add purgatory for kexec_file_load implementation.":
- Fixed whitespace and GPL header issues found by checkpatch.pl.
- Changed to use the new PPC64_ELF_ABI_v2 macro.
Changes for v2:
- All patches: forgot to add Signed-off-by lines in v1, so added them now.
- Patch "kexec_file: Generalize kexec_add_buffer.": broke in two, one
adding arch_kexec_walk_mem and the other adding kexec_locate_mem_hole.
- Patch "powerpc: Implement kexec_file_load.":
- Moved relocation changes and the arch_kexec_walk_mem implementation
to the next patch in the series.
- Removed pr_fmt from machine_kexec_64.c, since the patch doesn't add
any call to pr_debug in that file.
- Changed arch_kexec_kernel_image_probe to reject crash kernels.
Thiago Jung Bauermann (9):
kexec_file: Remove unused members from struct kexec_buf.
kexec_file: Generalize kexec_add_buffer.
kexec_file: Factor out kexec_locate_mem_hole from kexec_add_buffer.
powerpc: Factor out relocation code from module_64.c to elf_util_64.c.
powerpc: Generalize elf64_apply_relocate_add.
powerpc: Add functions to read ELF files of any endianness.
powerpc: Implement kexec_file_load.
powerpc: Add support for loading ELF kernels with kexec_file_load.
powerpc: Add purgatory for kexec_file_load implementation.
arch/powerpc/Kconfig | 13 +
arch/powerpc/Makefile | 4 +
arch/powerpc/include/asm/elf_util.h | 92 +++++
arch/powerpc/include/asm/kexec_elf_64.h | 10 +
arch/powerpc/include/asm/module.h | 14 +-
arch/powerpc/include/asm/systbl.h | 1 +
arch/powerpc/include/asm/unistd.h | 2 +-
arch/powerpc/include/uapi/asm/unistd.h | 1 +
arch/powerpc/kernel/Makefile | 7 +
arch/powerpc/kernel/elf_util.c | 476 +++++++++++++++++++++++++
arch/powerpc/kernel/elf_util_64.c | 374 ++++++++++++++++++++
arch/powerpc/kernel/kexec_elf_64.c | 560 ++++++++++++++++++++++++++++++
arch/powerpc/kernel/machine_kexec_64.c | 134 +++++++
arch/powerpc/kernel/module_64.c | 328 +++--------------
arch/powerpc/purgatory/.gitignore | 2 +
arch/powerpc/purgatory/Makefile | 36 ++
arch/powerpc/purgatory/console-ppc64.c | 38 ++
arch/powerpc/purgatory/crashdump-ppc64.h | 42 +++
arch/powerpc/purgatory/crashdump_backup.c | 36 ++
arch/powerpc/purgatory/crtsavres.S | 5 +
arch/powerpc/purgatory/hvCall.S | 27 ++
arch/powerpc/purgatory/hvCall.h | 8 +
arch/powerpc/purgatory/kexec-sha256.h | 11 +
arch/powerpc/purgatory/ppc64_asm.h | 20 ++
arch/powerpc/purgatory/printf.c | 164 +++++++++
arch/powerpc/purgatory/purgatory-ppc64.c | 41 +++
arch/powerpc/purgatory/purgatory-ppc64.h | 6 +
arch/powerpc/purgatory/purgatory.c | 62 ++++
arch/powerpc/purgatory/purgatory.h | 11 +
arch/powerpc/purgatory/sha256.c | 6 +
arch/powerpc/purgatory/sha256.h | 1 +
arch/powerpc/purgatory/string.S | 1 +
arch/powerpc/purgatory/v2wrap.S | 134 +++++++
include/linux/kexec.h | 23 +-
kernel/kexec_file.c | 100 ++++--
kernel/kexec_internal.h | 16 -
36 files changed, 2476 insertions(+), 330 deletions(-)
create mode 100644 arch/powerpc/include/asm/elf_util.h
create mode 100644 arch/powerpc/include/asm/kexec_elf_64.h
create mode 100644 arch/powerpc/kernel/elf_util.c
create mode 100644 arch/powerpc/kernel/elf_util_64.c
create mode 100644 arch/powerpc/kernel/kexec_elf_64.c
create mode 100644 arch/powerpc/purgatory/.gitignore
create mode 100644 arch/powerpc/purgatory/Makefile
create mode 100644 arch/powerpc/purgatory/console-ppc64.c
create mode 100644 arch/powerpc/purgatory/crashdump-ppc64.h
create mode 100644 arch/powerpc/purgatory/crashdump_backup.c
create mode 100644 arch/powerpc/purgatory/crtsavres.S
create mode 100644 arch/powerpc/purgatory/hvCall.S
create mode 100644 arch/powerpc/purgatory/hvCall.h
create mode 100644 arch/powerpc/purgatory/kexec-sha256.h
create mode 100644 arch/powerpc/purgatory/ppc64_asm.h
create mode 100644 arch/powerpc/purgatory/printf.c
create mode 100644 arch/powerpc/purgatory/purgatory-ppc64.c
create mode 100644 arch/powerpc/purgatory/purgatory-ppc64.h
create mode 100644 arch/powerpc/purgatory/purgatory.c
create mode 100644 arch/powerpc/purgatory/purgatory.h
create mode 100644 arch/powerpc/purgatory/sha256.c
create mode 100644 arch/powerpc/purgatory/sha256.h
create mode 100644 arch/powerpc/purgatory/string.S
create mode 100644 arch/powerpc/purgatory/v2wrap.S
--
1.9.1
kexec_add_buffer uses kexec_buf.buffer and kexec_buf.bufsz to pass along
its own arguments buffer and bufsz, but since they aren't used anywhere
else, it's pointless.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: Eric Biederman <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
Acked-by: Dave Young <redacted>
---
kernel/kexec_file.c | 6 ++----
kernel/kexec_internal.h | 2 --
2 files changed, 2 insertions(+), 6 deletions(-)
@@ -464,8 +464,6 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,memset(&buf,0,sizeof(structkexec_buf));kbuf=&buf;kbuf->image=image;-kbuf->buffer=buffer;-kbuf->bufsz=bufsz;kbuf->memsz=ALIGN(memsz,PAGE_SIZE);kbuf->buf_align=max(buf_align,PAGE_SIZE);
@@ -489,8 +487,8 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,/* Found a suitable memory range */ksegment=&image->segment[image->nr_segments];-ksegment->kbuf=kbuf->buffer;-ksegment->bufsz=kbuf->bufsz;+ksegment->kbuf=buffer;+ksegment->bufsz=bufsz;ksegment->mem=kbuf->mem;ksegment->memsz=kbuf->memsz;image->nr_segments++;
kexec_locate_mem_hole will be used by the PowerPC kexec_file_load
implementation to find free memory for the purgatory stack.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: Eric Biederman <redacted>
Cc: Dave Young <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
include/linux/kexec.h | 4 ++++
kernel/kexec_file.c | 66 ++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 53 insertions(+), 17 deletions(-)
@@ -227,6 +227,10 @@ extern asmlinkage long sys_kexec_load(unsigned long entry,structkexec_segment__user*segments,unsignedlongflags);externintkernel_kexec(void);+intkexec_locate_mem_hole(structkimage*image,unsignedlongsize,+unsignedlongalign,unsignedlongmin_addr,+unsignedlongmax_addr,booltop_down,+unsignedlong*addr);externintkexec_add_buffer(structkimage*image,char*buffer,unsignedlongbufsz,unsignedlongmemsz,unsignedlongbuf_align,unsignedlongbuf_min,
@@ -449,6 +449,46 @@ int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf,returnwalk_system_ram_res(0,ULONG_MAX,kbuf,func);}+/**+*kexec_locate_mem_hole-findfreememorytoloadsegmentoruseinpurgatory+*@image:kexecimagebeingupdated.+*@size:Memorysize.+*@align:Minimumalignmentneeded.+*@min_addr:Minimumstartingaddress.+*@max_addr:Maximumendaddress.+*@top_downFindthehighestfreememoryregion?+*@addrOnsuccess,willhavestartaddressofthememoryregionfound.+*+*Return:0onsuccess,negativeerrnoonerror.+*/+intkexec_locate_mem_hole(structkimage*image,unsignedlongsize,+unsignedlongalign,unsignedlongmin_addr,+unsignedlongmax_addr,booltop_down,+unsignedlong*addr)+{+intret;+structkexec_bufbuf;++memset(&buf,0,sizeof(structkexec_buf));+buf.image=image;++buf.memsz=size;+buf.buf_align=align;+buf.buf_min=min_addr;+buf.buf_max=max_addr;+buf.top_down=top_down;++ret=arch_kexec_walk_mem(&buf,locate_mem_hole_callback);+if(ret!=1){+/* A suitable memory range could not be found for buffer */+return-EADDRNOTAVAIL;+}++*addr=buf.mem;++return0;+}+/**Helperfunctionforplacingabufferinakexecsegment.Thisassumes*thatkexec_mutexisheld.
@@ -460,8 +500,8 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,{structkexec_segment*ksegment;-structkexec_bufbuf,*kbuf;intret;+unsignedlongaddr,align,size;/* Currently adding segment this way is allowed only in file mode */if(!image->file_mode)
@@ -482,29 +522,21 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,return-EINVAL;}-memset(&buf,0,sizeof(structkexec_buf));-kbuf=&buf;-kbuf->image=image;--kbuf->memsz=ALIGN(memsz,PAGE_SIZE);-kbuf->buf_align=max(buf_align,PAGE_SIZE);-kbuf->buf_min=buf_min;-kbuf->buf_max=buf_max;-kbuf->top_down=top_down;+size=ALIGN(memsz,PAGE_SIZE);+align=max(buf_align,PAGE_SIZE);/* Walk the RAM ranges and allocate a suitable range for the buffer */-ret=arch_kexec_walk_mem(kbuf,locate_mem_hole_callback);-if(ret!=1){-/* A suitable memory range could not be found for buffer */-return-EADDRNOTAVAIL;-}+ret=kexec_locate_mem_hole(image,size,align,buf_min,buf_max,+top_down,&addr);+if(ret)+returnret;/* Found a suitable memory range */ksegment=&image->segment[image->nr_segments];ksegment->kbuf=buffer;ksegment->bufsz=bufsz;-ksegment->mem=kbuf->mem;-ksegment->memsz=kbuf->memsz;+ksegment->mem=addr;+ksegment->memsz=size;image->nr_segments++;*load_addr=ksegment->mem;return0;
A little endian kernel might need to kexec a big endian kernel (the
opposite is less likely but could happen as well), so we can't just cast
the buffer with the binary to ELF structs and use them as is done
elsewhere.
This patch adds functions which do byte-swapping as necessary when
populating the ELF structs. These functions will be used in the next
patch in the series.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
arch/powerpc/include/asm/elf_util.h | 19 ++
arch/powerpc/kernel/Makefile | 2 +-
arch/powerpc/kernel/elf_util.c | 476 ++++++++++++++++++++++++++++++++++++
3 files changed, 496 insertions(+), 1 deletion(-)
@@ -20,6 +20,14 @@#include<linux/elf.h>structelf_info{+/*+*WheretheELFbinarycontentsarekept.+*Memorymanagedbytheuserofthestruct.+*/+constchar*buffer;++conststructelfhdr*ehdr;+conststructelf_phdr*proghdrs;structelf_shdr*sechdrs;/* Index of stubs section. */
This uses all the infrastructure built up by the previous patches
in the series to load an ELF vmlinux file and an initrd. It uses the
flattened device tree at initial_boot_params as a base and adjusts memory
reservations and its /chosen node for the next kernel.
elf64_apply_relocate_add was extended to support relative symbols. This
is necessary because before relocation, the module loading mechanism
adjusts Elf64_Sym.st_value to point to the absolute memory address
while the kexec purgatory relocation code does that during relocation.
The patch also adds relocation types used by the purgatory.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
arch/powerpc/include/asm/elf_util.h | 1 +
arch/powerpc/include/asm/kexec_elf_64.h | 10 +
arch/powerpc/kernel/Makefile | 5 +-
arch/powerpc/kernel/elf_util_64.c | 84 ++++-
arch/powerpc/kernel/kexec_elf_64.c | 560 ++++++++++++++++++++++++++++++++
arch/powerpc/kernel/machine_kexec_64.c | 86 ++++-
arch/powerpc/kernel/module_64.c | 5 +-
7 files changed, 747 insertions(+), 4 deletions(-)
@@ -84,11 +86,13 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info,constchar*strtab,constElf64_Rela*rela,unsignedintnum_rela,void*syms_base,void*loc_base,Elf64_Addraddr_base,+boolrelative_symbols,boolcheck_symbols,constchar*obj_name){unsignedinti;unsignedlong*location;unsignedlongaddress;+unsignedlongsec_base;unsignedlongvalue;constchar*name;Elf64_Sym*sym;
@@ -121,8 +125,36 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info,name,(unsignedlong)sym->st_value,(long)rela[i].r_addend);+if(check_symbols){+/*+*TOCsymbolsappearasundefinedbutshouldbe+*resolvedaswell,soallowthemtobeprocessed.+*/+if(sym->st_shndx==SHN_UNDEF&&+strcmp(name,".TOC.")!=0){+pr_err("Undefined symbol: %s\n",name);+return-ENOEXEC;+}elseif(sym->st_shndx==SHN_COMMON){+pr_err("Symbol '%s' in common section.\n",name);+return-ENOEXEC;+}+}++if(relative_symbols&&sym->st_shndx!=SHN_ABS){+if(sym->st_shndx>=elf_info->ehdr->e_shnum){+pr_err("Invalid section %d for symbol %s\n",+sym->st_shndx,name);+return-ENOEXEC;+}else{+structelf_shdr*sechdrs=elf_info->sechdrs;++sec_base=sechdrs[sym->st_shndx].sh_addr;+}+}else+sec_base=0;+/* `Everything is relative'. */-value=sym->st_value+rela[i].r_addend;+value=sym->st_value+sec_base+rela[i].r_addend;switch(ELF64_R_TYPE(rela[i].r_info)){caseR_PPC64_ADDR32:
@@ -135,6 +167,10 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info,*(unsignedlong*)location=value;break;+caseR_PPC64_REL32:+*(uint32_t*)location=value-(uint32_t)(uint64_t)location;+break;+caseR_PPC64_TOC:*(unsignedlong*)location=my_r2(elf_info);break;
@@ -195,6 +239,21 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info,|(value&0xffff);break;+caseR_PPC64_REL14:+/* Convert value to relative */+value-=address;+if(value+0x8000>0xffff||(value&3)!=0){+pr_err("%s: REL14 %li out of range!\n",obj_name,+(longint)value);+return-ENOEXEC;+}++/* Only replace bits 2 through 16 */+*(uint32_t*)location+=(*(uint32_t*)location&~0xfffc)+|(value&0xfffc);+break;+caseR_PPC_REL24:/* FIXME: Handle weak symbols here --RR */if(sym->st_shndx==SHN_UNDEF){
@@ -0,0 +1,560 @@+/*+*LoadELFvmlinuxfileforthekexec_file_loadsyscall.+*+*Copyright(C)2004AdamLitke(agl@us.ibm.com)+*Copyright(C)2004IBMCorp.+*Copyright(C)2005RSharada(sharada@in.ibm.com)+*Copyright(C)2006MohanKumarM(mohan@in.ibm.com)+*Copyright(C)2016IBMCorporation+*+*Basedonkexec-tools'kexec-elf-exec.candkexec-elf-ppc64.c.+*Heavilymodifiedforthekernelby+*ThiagoJungBauermann<bauerman@linux.vnet.ibm.com>.+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby+*theFreeSoftwareFoundation(version2oftheLicense).+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*/++#define pr_fmt(fmt) "kexec_elf: " fmt++#include<linux/types.h>+#include<linux/slab.h>+#include<linux/kexec.h>+#include<linux/elf.h>+#include<linux/kexec.h>+#include<linux/of_fdt.h>+#include<linux/libfdt.h>+#include<linux/memblock.h>+#include<asm/elf_util.h>++externsize_tkexec_purgatory_size;++#define PURGATORY_STACK_SIZE (16 * 1024)+#define SLAVE_CODE_SIZE 256++/**+*build_elf_exec_info-readELFexecutableandcheckthatwecanuseit+*/+staticintbuild_elf_exec_info(constchar*buf,size_tlen,structelfhdr*ehdr,+structelf_info*elf_info)+{+inti;+intret;++ret=elf_read_from_buffer(buf,len,ehdr,elf_info);+if(ret)+returnret;++if(ehdr->e_type!=ET_EXEC){+pr_err("Not an ELF executable.\n");+gotoerror;+}elseif(!elf_info->proghdrs){+pr_err("No ELF program header.\n");+gotoerror;+}++for(i=0;i<ehdr->e_phnum;i++){+/*+*Kexecdoesnotsupportloadinginterpreters.+*Inadditionthischeckkeepsusfromattempting+*tokexecordinayexecutables.+*/+if(elf_info->proghdrs[i].p_type==PT_INTERP){+pr_err("Requires an ELF interpreter.\n");+gotoerror;+}+}++return0;+error:+elf_free_info(elf_info);+return-ENOEXEC;+}++staticintelf64_probe(constchar*buf,unsignedlonglen)+{+structelfhdrehdr;+structelf_infoelf_info;+intret;++ret=build_elf_exec_info(buf,len,&ehdr,&elf_info);+if(ret)+returnret;++elf_free_info(&elf_info);++returnelf_check_arch(&ehdr)?0:-ENOEXEC;+}++staticboolfind_debug_console(void*fdt,intchosen_node)+{+intlen;+intconsole_node;+constvoid*prop,*colon;++prop=fdt_getprop(fdt,chosen_node,"stdout-path",&len);+if(prop==NULL){+if(len==-FDT_ERR_NOTFOUND){+prop=fdt_getprop(fdt,chosen_node,"linux,stdout-path",+&len);+if(prop==NULL){+pr_debug("Unable to find [linux,]stdout-path.\n");+returnfalse;+}+}else{+pr_debug("Error finding console: %s\n",+fdt_strerror(len));+returnfalse;+}+}++/*+*stdout-pathcanhavea':'separatingthepathfromdevice-specific+*information,soweshouldonlyconsiderwhat'sbeforeit.+*/+colon=strchr(prop,':');+if(colon!=NULL)+len=colon-prop;+else+len-=1;/* Ignore the terminating NUL. */++console_node=fdt_path_offset_namelen(fdt,prop,len);+if(console_node<0){+pr_debug("Error finding console: %s\n",+fdt_strerror(console_node));+returnfalse;+}++if(fdt_node_check_compatible(fdt,console_node,"hvterm1")==0)+returntrue;+elseif(fdt_node_check_compatible(fdt,console_node,+"hvterm-protocol")==0)+returntrue;++returnfalse;+}++staticintsetup_purgatory(structkimage*image,structelf_info*kernel_info,+void*fdt,unsignedlongkernel_load_addr,+unsignedlongfdt_load_addr,unsignedlongstack_top,+intdebug)+{+intret,tree_node;+constvoid*prop;+unsignedlongopal_base,opal_entry;+uint64_ttoc;+unsignedint*slave_code,master_entry;+structelf_infopurg_info;++/* Get the slave code from the new kernel and put it in purgatory. */+slave_code=kmalloc(SLAVE_CODE_SIZE,GFP_KERNEL);+if(!slave_code)+return-ENOMEM;+ret=kexec_purgatory_get_set_symbol(image,"purgatory_start",+slave_code,SLAVE_CODE_SIZE,true);+if(ret){+kfree(slave_code);+returnret;+}+master_entry=slave_code[0];+memcpy(slave_code,+kernel_info->buffer+kernel_info->proghdrs[0].p_offset,+SLAVE_CODE_SIZE);+slave_code[0]=master_entry;+ret=kexec_purgatory_get_set_symbol(image,"purgatory_start",+slave_code,SLAVE_CODE_SIZE,+false);+kfree(slave_code);++ret=kexec_purgatory_get_set_symbol(image,"kernel",&kernel_load_addr,+sizeof(kernel_load_addr),false);+if(ret)+returnret;+ret=kexec_purgatory_get_set_symbol(image,"dt_offset",&fdt_load_addr,+sizeof(fdt_load_addr),false);+if(ret)+returnret;++tree_node=fdt_path_offset(fdt,"/ibm,opal");+if(tree_node>=0){+prop=fdt_getprop(fdt,tree_node,"opal-base-address",NULL);+if(!prop){+pr_err("OPAL address not found in the device tree.\n");+return-EINVAL;+}+opal_base=fdt64_to_cpu((constfdt64_t*)prop);++prop=fdt_getprop(fdt,tree_node,"opal-entry-address",NULL);+if(!prop){+pr_err("OPAL address not found in the device tree.\n");+return-EINVAL;+}+opal_entry=fdt64_to_cpu((constfdt64_t*)prop);++ret=kexec_purgatory_get_set_symbol(image,"opal_base",+&opal_base,+sizeof(opal_base),false);+if(ret)+returnret;+ret=kexec_purgatory_get_set_symbol(image,"opal_entry",+&opal_entry,+sizeof(opal_entry),false);+if(ret)+returnret;+}++ret=kexec_purgatory_get_set_symbol(image,"stack",&stack_top,+sizeof(stack_top),false);+if(ret)+returnret;++elf_init_elf_info(image->purgatory_info.ehdr,+image->purgatory_info.sechdrs,&purg_info);+toc=my_r2(&purg_info);+ret=kexec_purgatory_get_set_symbol(image,"my_toc",&toc,sizeof(toc),+false);+if(ret)+returnret;+pr_debug("Purgatory TOC is at 0x%llx\n",toc);++ret=kexec_purgatory_get_set_symbol(image,"debug",&debug,+sizeof(debug),false);+if(ret)+returnret;+if(!debug)+pr_debug("Disabling purgatory output.\n");++return0;+}++/**+*elf_exec_load-loadELFexecutableimage+*@lowest_load_addr:Onreturn,willbetheaddresswherethefirstPT_LOAD+*sectionwillbeloadedinmemory.+*+*Return:+*0onsuccess,negativevalueonfailure.+*/+staticintelf_exec_load(structkimage*image,structelfhdr*ehdr,+structelf_info*elf_info,+unsignedlong*lowest_load_addr)+{+unsignedlongbase=0,lowest_addr=UINT_MAX;+intret;+size_ti;++/* Read in the PT_LOAD segments. */+for(i=0;i<ehdr->e_phnum;i++){+unsignedlongload_addr;+size_tsize;+conststructelf_phdr*phdr;++phdr=&elf_info->proghdrs[i];+if(phdr->p_type!=PT_LOAD)+continue;++size=phdr->p_filesz;+if(size>phdr->p_memsz)+size=phdr->p_memsz;++ret=kexec_add_buffer(image,+(char*)elf_info->buffer+phdr->p_offset,+size,phdr->p_memsz,phdr->p_align,+phdr->p_paddr+base,ppc64_rma_size,+false,&load_addr);+if(ret)+gotoout;++if(load_addr<lowest_addr)+lowest_addr=load_addr;+}++/* Update entry point to reflect new load address. */+ehdr->e_entry+=base;++*lowest_load_addr=lowest_addr;+ret=0;+out:+returnret;+}++void*elf64_load(structkimage*image,char*kernel_buf,+unsignedlongkernel_len,char*initrd,+unsignedlonginitrd_len,char*cmdline,+unsignedlongcmdline_len)+{+inti;+intret=0,chosen_node;+unsignedintfdt_size;+unsignedlongkernel_load_addr,purgatory_load_addr;+unsignedlonginitrd_load_addr,fdt_load_addr,stack_top;+uint64_toldfdt_addr;+void*fdt;+constvoid*prop;+structelfhdrehdr;+structelf_infoelf_info;+structfdt_reserve_entry*rsvmap;++ret=build_elf_exec_info(kernel_buf,kernel_len,&ehdr,&elf_info);+if(ret)+gotoout;++ret=elf_exec_load(image,&ehdr,&elf_info,&kernel_load_addr);+if(ret)+gotoout;++pr_debug("Loaded the kernel at 0x%lx\n",kernel_load_addr);++ret=kexec_load_purgatory(image,0,ppc64_rma_size,true,+&purgatory_load_addr);+if(ret){+pr_err("Loading purgatory failed.\n");+gotoout;+}++pr_debug("Loaded purgatory at 0x%lx\n",purgatory_load_addr);++fdt_size=fdt_totalsize(initial_boot_params)*2;+fdt=kmalloc(fdt_size,GFP_KERNEL);+if(!fdt){+pr_err("Not enough memory for the device tree.\n");+ret=-ENOMEM;+gotoout;+}+ret=fdt_open_into(initial_boot_params,fdt,fdt_size);+if(ret<0){+pr_err("Error setting up the new device tree.\n");+ret=-EINVAL;+gotoout;+}++/* Remove memory reservation for the current device tree. */+oldfdt_addr=__pa(initial_boot_params);+for(i=0;i<fdt_num_mem_rsv(fdt);i++){+uint64_trsv_start,rsv_size;++ret=fdt_get_mem_rsv(fdt,i,&rsv_start,&rsv_size);+if(ret){+pr_err("Malformed device tree.\n");+ret=-EINVAL;+gotoout;+}++if(rsv_start==oldfdt_addr&&+rsv_size==fdt_totalsize(initial_boot_params)){+ret=fdt_del_mem_rsv(fdt,i);+if(ret){+pr_err("Error deleting fdt reservation.\n");+ret=-EINVAL;+gotoout;+}+pr_debug("Removed old device tree reservation.\n");++break;+}+}++chosen_node=fdt_path_offset(fdt,"/chosen");+if(chosen_node<0){+pr_err("Malformed device tree: /chosen not found.\n");+ret=-EINVAL;+gotoout;+}++/* Did we boot using an initrd? */+prop=fdt_getprop(fdt,chosen_node,"linux,initrd-start",NULL);+if(prop){+uint64_ttmp_start,tmp_end,tmp_size,tmp_sizepg;++tmp_start=fdt64_to_cpu(*((constfdt64_t*)prop));++prop=fdt_getprop(fdt,chosen_node,"linux,initrd-end",NULL);+if(!prop){+pr_err("Malformed device tree.\n");+ret=-EINVAL;+gotoout;+}+tmp_end=fdt64_to_cpu(*((constfdt64_t*)prop));++/*+*kexecreservesexactinitrdsize,whilefirmwaremay+*reserveamultipleofPAGE_SIZE,socheckforboth.+*/+tmp_size=tmp_end-tmp_start;+tmp_sizepg=round_up(tmp_size,PAGE_SIZE);++/* Remove memory reservation for the current initrd. */+for(i=0;i<fdt_num_mem_rsv(fdt);i++){+uint64_trsv_start,rsv_size;++ret=fdt_get_mem_rsv(fdt,i,&rsv_start,&rsv_size);+if(ret){+pr_err("Malformed device tree.\n");+ret=-EINVAL;+gotoout;+}++if(rsv_start==tmp_start&&+(rsv_size==tmp_size||rsv_size==tmp_sizepg)){+ret=fdt_del_mem_rsv(fdt,i);+if(ret){+pr_err("Error deleting fdt reservation.\n");+ret=-EINVAL;+gotoout;+}+pr_debug("Removed old initrd reservation.\n");++/* fdt was modified, offsets may have changed. */+chosen_node=fdt_path_offset(fdt,"/chosen");+if(chosen_node<0){+pr_err("Malformed device tree.\n");+ret=-EINVAL;+gotoout;+}++break;+}+}++/* If there's no new initrd, delete the old initrd's info. */+if(initrd==NULL){+ret=fdt_delprop(fdt,chosen_node,"linux,initrd-start");+if(ret){+pr_err("Error deleting linux,initrd-start.\n");+ret=-EINVAL;+gotoout;+}++ret=fdt_delprop(fdt,chosen_node,"linux,initrd-end");+if(ret){+pr_err("Error deleting linux,initrd-end.\n");+ret=-EINVAL;+gotoout;+}+}+}++if(initrd!=NULL){+ret=kexec_add_buffer(image,initrd,initrd_len,initrd_len,+PAGE_SIZE,0,ppc64_rma_size,false,+&initrd_load_addr);+if(ret)+gotoout;++pr_debug("Loaded initrd at 0x%lx\n",initrd_load_addr);++ret=fdt_setprop_u64(fdt,chosen_node,"linux,initrd-start",+initrd_load_addr);+if(ret<0){+pr_err("Error setting up the new device tree.\n");+ret=-EINVAL;+gotoout;+}+/* initrd-end is the first address after the initrd image. */+ret=fdt_setprop_u64(fdt,chosen_node,"linux,initrd-end",+initrd_load_addr+initrd_len);+if(ret<0){+pr_err("Error setting up the new device tree.\n");+ret=-EINVAL;+gotoout;+}++ret=fdt_add_mem_rsv(fdt,initrd_load_addr,initrd_len);+if(ret){+pr_err("Error reserving initrd memory: %s\n",+fdt_strerror(ret));+ret=-EINVAL;+gotoout;+}+}++if(cmdline_len){+ret=fdt_setprop_string(fdt,chosen_node,"bootargs",cmdline);+if(ret<0){+pr_err("Error setting up the new device tree.\n");+ret=-EINVAL;+gotoout;+}+}else{+ret=fdt_delprop(fdt,chosen_node,"bootargs");+if(ret&&ret!=-FDT_ERR_NOTFOUND){+pr_err("Error deleting bootargs.\n");+ret=-EINVAL;+gotoout;+}+}++ret=fdt_setprop(fdt,chosen_node,"linux,booted-from-kexec",NULL,0);+if(ret){+pr_err("Error setting up the new device tree.\n");+ret=-EINVAL;+gotoout;+}++/*+*Documentation/devicetree/booting-without-of.txtsaysweneedto+*addareservationentryforthedevicetreeblock,but+*early_init_fdt_reserve_selfreservesthememoryevenifthere'sno+*suchentry.We'lladdareservationentryanyway,tobesafeand+*compliant.+*+*Usedummyvalues,wewillcorrecttheminamoment.+*/+ret=fdt_add_mem_rsv(fdt,1,1);+if(ret){+pr_err("Error reserving device tree memory: %s\n",+fdt_strerror(ret));+ret=-EINVAL;+gotoout;+}+fdt_pack(fdt);++ret=kexec_add_buffer(image,fdt,fdt_size,fdt_size,PAGE_SIZE,0,+ppc64_rma_size,true,&fdt_load_addr);+if(ret)+gotoout;++/*+*Fixfdtreservation,nowthatwenowwhereitwillbeloaded+*andhowbigitis.+*/+rsvmap=fdt+fdt_off_mem_rsvmap(fdt);+i=fdt_num_mem_rsv(fdt)-1;+rsvmap[i].address=cpu_to_fdt64(fdt_load_addr);+rsvmap[i].size=cpu_to_fdt64(fdt_totalsize(fdt));++pr_debug("Loaded device tree at 0x%lx\n",fdt_load_addr);++ret=kexec_locate_mem_hole(image,PURGATORY_STACK_SIZE,PAGE_SIZE,0,+ppc64_rma_size,true,&stack_top);+if(ret){+pr_err("Couldn't find free memory for the purgatory stack.\n");+ret=-ENOMEM;+gotoout;+}+stack_top=stack_top+PURGATORY_STACK_SIZE-1;+pr_debug("Purgatory stack is at 0x%lx\n",stack_top);++ret=setup_purgatory(image,&elf_info,fdt,kernel_load_addr,+fdt_load_addr,stack_top,+find_debug_console(fdt,chosen_node));+if(ret)+pr_err("Error setting up the purgatory.\n");++out:+elf_free_info(&elf_info);++/* Make kimage_file_post_load_cleanup free the fdt buffer for us. */+returnret?ERR_PTR(ret):fdt;+}++structkexec_file_opskexec_elf64_ops={+.probe=elf64_probe,+.load=elf64_load,+};
@@ -476,4 +480,84 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)returnimage->fops->cleanup(image->image_loader_data);}++/**+*arch_kexec_walk_mem-callfunc(data)foreachunreservedmemoryblock+*@kbuf:Contextinfoforthesearch.Alsopassedto@func.+*@func:Functiontocallforeachmemoryblock.+*+*Thisfunctionisusedbykexec_add_bufferandkexec_locate_mem_hole+*tofindunreservedmemorytoloadkexecsegmentsinto.+*+*Return:Thememorywalkwillstopwhenfuncreturnsanon-zerovalue+*andthatvaluewillbereturned.Ifallfreeregionsarevisitedwithout+*funcreturningnon-zero,thenzerowillbereturned.+*/+intarch_kexec_walk_mem(structkexec_buf*kbuf,int(*func)(u64,u64,void*))+{+intret=0;+u64i;+phys_addr_tmstart,mend;++if(kbuf->top_down){+for_each_free_mem_range_reverse(i,NUMA_NO_NODE,0,+&mstart,&mend,NULL){+ret=func(mstart,mend,kbuf);+if(ret)+break;+}+}else{+for_each_free_mem_range(i,NUMA_NO_NODE,0,&mstart,&mend,+NULL){+ret=func(mstart,mend,kbuf);+if(ret)+break;+}+}++returnret;+}++/**+*arch_kexec_apply_relocations_add-applypurgatoryrelocations+*@ehdr:PointertoELFheaders.+*@sechdrs:Pointertosectionheaders.+*@relsec:SectionindexofSHT_RELAsection.+*+*Elf64_Shdr.sh_offsethasbeenmodifiedtokeepthepointertothesection+*contents,whileElf64_Shdr.sh_addrpointstothefinaladdressofthe+*sectioninmemory.+*/+intarch_kexec_apply_relocations_add(constElf64_Ehdr*ehdr,+Elf64_Shdr*sechdrs,unsignedintrelsec)+{+/* Section containing the relocation entries. */+Elf64_Shdr*rel_section=&sechdrs[relsec];+constElf64_Rela*rela=(constElf64_Rela*)rel_section->sh_offset;+unsignedintnum_rela=rel_section->sh_size/sizeof(Elf64_Rela);+/* Section to which relocations apply. */+Elf64_Shdr*target_section=&sechdrs[rel_section->sh_info];+/* Associated symbol table. */+Elf64_Shdr*symtabsec=&sechdrs[rel_section->sh_link];+void*syms_base=(void*)symtabsec->sh_offset;+void*loc_base=(void*)target_section->sh_offset;+Elf64_Addraddr_base=target_section->sh_addr;+structelf_infoelf_info;+constchar*strtab;++if(symtabsec->sh_link>=ehdr->e_shnum){+/* Invalid strtab section number */+pr_err("Invalid string table section index %d\n",+symtabsec->sh_link);+return-ENOEXEC;+}+/* String table for the associated symbol table. */+strtab=(constchar*)sechdrs[symtabsec->sh_link].sh_offset;++elf_init_elf_info(ehdr,sechdrs,&elf_info);++returnelf64_apply_relocate_add(&elf_info,strtab,rela,num_rela,+syms_base,loc_base,addr_base,+true,true,"kexec purgatory");+}#endif /* CONFIG_KEXEC_FILE */
@@ -370,6 +371,9 @@ archclean:$(Q)$(MAKE)$(clean)=$(boot)archprepare:checkbin+ifeq ($(CONFIG_KEXEC_FILE),y)+$(Q)$(MAKE)$(build)=arch/powerpc/purgatoryarch/powerpc/purgatory/kexec-purgatory.c+endif# Use the file '.tmp_gas_check' for binutils tests, as gas won't output# to stdout and these checks are run even on install targets.
@@ -0,0 +1,36 @@+purgatory-y:=purgatory.oprintf.ostring.ov2wrap.ohvCall.o\+purgatory-ppc64.oconsole-ppc64.ocrashdump_backup.o\+crtsavres.osha256.o++targets+=$(purgatory-y)+PURGATORY_OBJS=$(addprefix$(obj)/,$(purgatory-y))++LDFLAGS_purgatory.ro:=-epurgatory_start-r--no-undefined-nostartfiles\+-nostdlib-nodefaultlibs+targets+=purgatory.ro++# Default KBUILD_CFLAGS can have -pg option set when FTRACE is enabled. That+# in turn leaves some undefined symbols like __fentry__ in purgatory and not+# sure how to relocate those. Like kexec-tools, use custom flags.++KBUILD_CFLAGS:=-Wall-Wstrict-prototypes-fno-strict-aliasing\+-fno-zero-initialized-in-bss-fno-builtin-ffreestanding\+-fno-PIC-fno-PIE-fno-stack-protector-fno-exceptions\+-msoft-float-MD-Os+KBUILD_CFLAGS+=-m$(CONFIG_WORD_SIZE)++$(obj)/purgatory.ro:$(PURGATORY_OBJS)FORCE+$(callif_changed,ld)++targets+=kexec-purgatory.c++CMD_BIN2C=$(objtree)/scripts/basic/bin2c+quiet_cmd_bin2c=BIN2C$@+cmd_bin2c=$(CMD_BIN2C)kexec_purgatory<$<>$@++$(obj)/kexec-purgatory.c:$(obj)/purgatory.roFORCE+$(callif_changed,bin2c)+@:+++obj-$(CONFIG_KEXEC_FILE)+=kexec-purgatory.o
@@ -0,0 +1,38 @@+/*+*kexec:LinuxbootsLinux+*+*Createdby:MohanKumarM(mohan@in.ibm.com)+*+*Copyright(C)IBMCorporation,2005.Allrightsreserved+*+*Codetakenfromkexec-tools.+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby+*theFreeSoftwareFoundation(version2oftheLicense).+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*/++#include"hvCall.h"+#include<asm/byteorder.h>++externintdebug;++voidputchar(intc)+{+charbuff[8];+unsignedlong*lbuf=(unsignedlong*)buff;++if(!debug)/* running on non pseries */+return;++if(c=='\n')+putchar('\r');++buff[0]=c;+plpar_hcall_norets(H_PUT_TERM_CHAR,0,1,__cpu_to_be64(*lbuf),0);+}
@@ -0,0 +1,36 @@+/*+*kexec:LinuxbootsLinux+*+*Createdby:MohanKumarM(mohan@in.ibm.com)+*+*Copyright(C)IBMCorporation,2005.Allrightsreserved+*+*Codetakenfromkexec-tools.+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby+*theFreeSoftwareFoundation(version2oftheLicense).+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*/++#include"../boot/string.h"+#include"crashdump-ppc64.h"++externunsignedlongbackup_start;++/* Backup first 32KB of memory to backup region reserved by kexec */+voidcrashdump_backup_memory(void)+{+void*dest,*src;++src=(void*)BACKUP_SRC_START;++if(backup_start){+dest=(void*)(backup_start);+memcpy(dest,src,BACKUP_SRC_SIZE);+}+}
@@ -0,0 +1,62 @@+/*+*Codetakenfromkexec-tools.+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby+*theFreeSoftwareFoundation(version2oftheLicense).+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*/++#include"purgatory.h"+#include"sha256.h"+#include"../boot/string.h"+#include"kexec-sha256.h"++structkexec_sha_regionsha_regions[SHA256_REGIONS]={};+u8sha256_digest[SHA256_DIGEST_SIZE]={0};++intverify_sha256_digest(void)+{+structkexec_sha_region*ptr,*end;+u8digest[SHA256_DIGEST_SIZE];+size_ti;+structsha256_statesctx;++sha256_init(&sctx);+end=&sha_regions[sizeof(sha_regions)/sizeof(sha_regions[0])];+for(ptr=sha_regions;ptr<end;ptr++)+sha256_update(&sctx,(uint8_t*)(ptr->start),ptr->len);+sha256_final(&sctx,digest);++if(memcmp(digest,sha256_digest,sizeof(digest))!=0){+printf("sha256 digests do not match :(\n");+printf(" digest: ");+for(i=0;i<sizeof(digest);i++)+printf("%hhx ",digest[i]);+printf("\n");++printf("sha256_digest: ");+for(i=0;i<sizeof(sha256_digest);i++)+printf("%hhx ",sha256_digest[i]);++printf("\n");+return1;+}+return0;+}++voidpurgatory(void)+{+printf("I'm in purgatory\n");+setup_arch();+if(verify_sha256_digest()){+/* loop forever */+for(;;)+;+}+post_verification_setup_arch();+}
@@ -0,0 +1,134 @@+#+# kexec: Linux boots Linux+#+# Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation+# Copyright (C) 2006, Mohan Kumar M (mohan@in.ibm.com), IBM Corporation+#+# Code taken from kexec-tools.+#+# This program is free software; you can redistribute it and/or modify+# it under the terms of the GNU General Public License as published by+# the Free Software Foundation (version 2 of the License).+#+# This program is distributed in the hope that it will be useful,+# but WITHOUT ANY WARRANTY; without even the implied warranty of+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+# GNU General Public License for more details.++#include "ppc64_asm.h"++# v2wrap.S+# a wrapper to call purgatory code to backup first+# 32kB of first kernel into the backup region+# reserved by kexec-tools.+# Invokes ppc64 kernel with the expected arguments+# of kernel(device-tree, phys-offset, 0)++#+# calling convention:+# r3 = physical number of this cpu (all cpus)+# r4 = address of this chunk (master only)+# master enters at purgatory_start (aka first byte of this chunk)+# slaves (additional cpus), if any, enter a copy of the+# first 0x100 bytes of this code relocated to 0x0+#+# in other words,+# a copy of the first 0x100 bytes of this code is copied to 0+# and the slaves are sent to address 0x60+# with r3 = their physical cpu number.++#define LOADADDR(rn,name) \+lisrn,name##@highest; \+orirn,rn,name##@higher; \+rldicrrn,rn,32,31;\+orisrn,rn,name##@h; \+orirn,rn,name##@l++.machineppc64+.align8+.globlpurgatory_start+purgatory_start:bmaster+.orgpurgatory_start+0x5c# ABI: possible run_at_load flag at 0x5c+.globlrun_at_load+run_at_load:+.long0+.sizerun_at_load,.-run_at_load+.orgpurgatory_start+0x60# ABI: slaves start at 60 with r3=phys+slave:b$+.orgpurgatory_start+0x100# ABI: end of copied region+.sizepurgatory_start,.-purgatory_start++#+# The above 0x100 bytes at purgatory_start are replaced with the+# code from the kernel (or next stage) by kexec/arch/ppc64/kexec-elf-ppc64.c+#++master:+or1,1,1# low priority to let other threads catchup+isync+mr17,3# save cpu id to r17+mr15,4# save physical address in reg15++LOADADDR(6,my_toc)+ld2,0(6)#setup toc++LOADADDR(6,stack)+ld1,0(6)#setup stack++subi1,1,112+blDOTSYM(purgatory)+nop++or3,3,3# ok now to high priority, lets boot+lis6,0x1+mtctr6# delay a bit for slaves to catch up+83:bdnz83b# before we overwrite 0-100 again++LOADADDR(16,dt_offset)+ld3,0(16)# load device-tree address+mr16,3# save dt address in reg16+#ifdef __BIG_ENDIAN__+lwz6,20(3)# fetch version number+#else+li4,20+lwbrx6,3,4# fetch BE version number+#endif+cmpwi0,6,2# v2 ?+blt80f+#ifdef __BIG_ENDIAN__+stw17,28(3)# save my cpu number as boot_cpu_phys+#else+li4,28+stwbrx17,3,4# Store my cpu as BE value+#endif+80:+LOADADDR(6,opal_base)# For OPAL early debug+ld8,0(6)# load the OPAL base address in r8+LOADADDR(6,opal_entry)# For OPAL early debug+ld9,0(6)# load the OPAL entry address in r9+LOADADDR(6,kernel)+ld4,0(6)# load the kernel address+LOADADDR(6,run_at_load)# the load flag+lwz7,0(6)# possibly patched by kexec-elf-ppc64+stw7,0x5c(4)# and patch it into the kernel+mr3,16# restore dt address++mfmsr5+andi.10,5,1# test MSR_LE+bnelittle_endian++li5,0# r5 will be 0 for kernel+mtctr4# prepare branch to+bctr# start kernel++little_endian:# book3s-only+mtsrr04# prepare branch to++clrrdi5,5,1# clear MSR_LE+mtsrr15++li5,0# r5 will be 0 for kernel++# skip cache flush, do we care?++rfid# update MSR and start kernel
When apply_relocate_add is called, modules are already loaded at their
final location in memory so Elf64_Shdr.sh_addr can be used for accessing
the section contents as well as the base address for relocations.
This is not the case for kexec's purgatory, because it will only be
copied to its final location right before being executed. Therefore,
it needs to be relocated while it is still in a temporary buffer. In
this case, Elf64_Shdr.sh_addr can't be used to access the sections'
contents.
This patch allows elf64_apply_relocate_add to be used when the ELF
binary is not yet at its final location by adding an addr_base argument
to specify the address at which the section will be loaded, and rela,
loc_base and syms_base to point to the sections' contents.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <redacted>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Torsten Duwe <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
arch/powerpc/include/asm/elf_util.h | 6 ++--
arch/powerpc/kernel/elf_util_64.c | 63 +++++++++++++++++++++++++------------
arch/powerpc/kernel/module_64.c | 17 ++++++++--
3 files changed, 61 insertions(+), 25 deletions(-)
@@ -69,33 +69,56 @@ static void squash_toc_save_inst(const char *name, unsigned long addr) { }*elf64_apply_relocate_add-apply64bitRELArelocations*@elf_info:SupportinformationfortheELFbinarybeingrelocated.*@strtab:Stringtablefortheassociatedsymboltable.-*@symindex:Sectionheaderindexfortheassociatedsymboltable.-*@relsec:Sectionheaderindexfortherelocationstoapply.+*@rela:Contentsofthesectionwiththerelocationstoapply.+*@num_rela:Numberofrelocationentriesinthesection.+*@syms_base:Contentsoftheassociatedsymboltable.+*@loc_base:Contentsofthesectiontowhichrelocationsapply.+*@addr_base:Theaddresswherethesectionwillbeloadedinmemory.*@obj_name:ThenameoftheELFbinary,forinformationmessages.+*+*AppliesRELArelocationstoanELFfilealreadyatitsfinallocation+*inmemory(inwhichcaseloc_base==addr_base),orstillinatemporary+*buffer.*/intelf64_apply_relocate_add(conststructelf_info*elf_info,-constchar*strtab,unsignedintsymindex,-unsignedintrelsec,constchar*obj_name)+constchar*strtab,constElf64_Rela*rela,+unsignedintnum_rela,void*syms_base,+void*loc_base,Elf64_Addraddr_base,+constchar*obj_name){unsignedinti;-Elf64_Shdr*sechdrs=elf_info->sechdrs;-Elf64_Rela*rela=(void*)sechdrs[relsec].sh_addr;-Elf64_Sym*sym;unsignedlong*location;+unsignedlongaddress;unsignedlongvalue;+constchar*name;+Elf64_Sym*sym;++for(i=0;i<num_rela;i++){+/*+*rels[i].r_offsetcontainsthebyteoffsetfromthebeginning+*ofsectiontothestorageunitaffected.+*+*Thisisthelocationtoupdateinthetemporarybufferwhere+*thesectioniscurrentlyloaded.Thesectionwillfinally+*beloadedtoadifferentaddresslater,pointedtoby+*addr_base.+*/+location=loc_base+rela[i].r_offset;++/* Final address of the location. */+address=addr_base+rela[i].r_offset;+/* This is the symbol the relocation is referring to. */+sym=(Elf64_Sym*)syms_base+ELF64_R_SYM(rela[i].r_info);-for(i=0;i<sechdrs[relsec].sh_size/sizeof(*rela);i++){-/* This is where to make the change */-location=(void*)sechdrs[sechdrs[relsec].sh_info].sh_addr-+rela[i].r_offset;-/* This is the symbol it is referring to */-sym=(Elf64_Sym*)sechdrs[symindex].sh_addr-+ELF64_R_SYM(rela[i].r_info);+if(sym->st_name)+name=strtab+sym->st_name;+else+name="<unnamed symbol>";pr_debug("RELOC at %p: %li-type as %s (0x%lx) + %li\n",location,(long)ELF64_R_TYPE(rela[i].r_info),-strtab+sym->st_name,(unsignedlong)sym->st_value,+name,(unsignedlong)sym->st_value,(long)rela[i].r_addend);/* `Everything is relative'. */
@@ -187,7 +210,7 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info,value+=local_entry_offset(sym);/* Convert value to relative */-value-=(unsignedlong)location;+value-=address;if(value+0x2000000>0x3ffffff||(value&3)!=0){pr_err("%s: REL24 %li out of range!\n",obj_name,(longint)value);
@@ -202,7 +225,7 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info,caseR_PPC64_REL64:/* 64 bits relative (used by features fixups) */-*location=value-(unsignedlong)location;+*location=value-address;break;caseR_PPC64_TOCSAVE:
@@ -218,7 +241,7 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info,*OptimizeELFv2largecodemodelentrypointif*theTOCiswithin2GBrangeofcurrentlocation.*/-value=my_r2(elf_info)-(unsignedlong)location;+value=my_r2(elf_info)-address;if(value+0x80008000>0xffffffff)break;/*
@@ -438,16 +438,26 @@ int restore_r2(u32 *instruction, const char *obj_name)return1;}+/*+*Whenthisfunctioniscalled,themoduleisalreadyatitsfinallocationin+*memory,soElf64_Shdr.sh_addrcanbeusedforaccessingthesection+*contentsaswellasthebaseaddressforrelocations.+*/intapply_relocate_add(Elf64_Shdr*sechdrs,constchar*strtab,unsignedintsymindex,unsignedintrelsec,structmodule*me){+Elf64_Shdr*rel_section=&sechdrs[relsec];+void*syms_base=(void*)sechdrs[symindex].sh_addr;+Elf64_Addraddr_base=sechdrs[rel_section->sh_info].sh_addr;+constElf64_Rela*rela=(constElf64_Rela*)rel_section->sh_addr;+unsignedintnum_rela=rel_section->sh_size/sizeof(Elf64_Rela);Elf64_Sym*sym;pr_debug("Applying ADD relocate section %u to %u\n",relsec,-sechdrs[relsec].sh_info);+rel_section->sh_info);/* First time we're called, we can fix up .TOC. */if(!me->arch.toc_fixed){
@@ -459,8 +469,9 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,me->arch.toc_fixed=true;}-returnelf64_apply_relocate_add(&me->arch.elf_info,strtab,symindex,-relsec,me->name);+returnelf64_apply_relocate_add(&me->arch.elf_info,strtab,rela,+num_rela,syms_base,(void*)addr_base,+addr_base,me->name);}#ifdef CONFIG_DYNAMIC_FTRACE
The kexec_file_load system call needs to relocate the purgatory, so
factor out the module relocation code so that it can be shared.
This patch's purpose is to move the ELF relocation logic from
apply_relocate_add to elf_util_64.c with as few changes as
possible. The following changes were needed:
To avoid having module-specific code in a general purpose utility
function, struct elf_info was created to contain the information
needed for ELF binaries manipulation.
my_r2, stub_for_addr and create_stub were changed to use it instead of
having to receive a struct module, since they are called from
elf64_apply_relocate_add.
local_entry_offset and squash_toc_save_inst were only used by
apply_rellocate_add, so they were moved to elf_util_64.c as well.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <redacted>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Torsten Duwe <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
arch/powerpc/include/asm/elf_util.h | 70 ++++++++
arch/powerpc/include/asm/module.h | 14 +-
arch/powerpc/kernel/Makefile | 4 +
arch/powerpc/kernel/elf_util_64.c | 269 +++++++++++++++++++++++++++++++
arch/powerpc/kernel/module_64.c | 312 ++++--------------------------------
5 files changed, 386 insertions(+), 283 deletions(-)
@@ -0,0 +1,70 @@+/*+*UtilityfunctionstoworkwithELFfiles.+*+*Copyright(C)2016,IBMCorporation+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby+*theFreeSoftwareFoundation;eitherversion2,or(atyouroption)+*anylaterversion.+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*/++#ifndef _ASM_POWERPC_ELF_UTIL_H+#define _ASM_POWERPC_ELF_UTIL_H++#include<linux/elf.h>++structelf_info{+structelf_shdr*sechdrs;++/* Index of stubs section. */+unsignedintstubs_section;+/* Index of TOC section. */+unsignedinttoc_section;+};++#ifdef __powerpc64__+#ifdef PPC64_ELF_ABI_v2++/* An address is simply the address of the function. */+typedefunsignedlongfunc_desc_t;+#else++/* An address is address of the OPD entry, which contains address of fn. */+typedefstructppc64_opd_entryfunc_desc_t;+#endif /* PPC64_ELF_ABI_v2 */++/* Like PPC32, we need little trampolines to do > 24-bit jumps (into+thekernelitself).ButonPPC64,theseneedtobeusedforevery+jump,actually,toresetr2(TOC+0x8000).*/+structppc64_stub_entry+{+/* 28 byte jump instruction sequence (7 instructions). We only+*need6instructionsonABIv2butwealwaysallocate7so+*sowedon'thavetomodifythetrampolineloadinstruction.*/+u32jump[7];+/* Used by ftrace to identify stubs */+u32magic;+/* Data for the above code */+func_desc_tfuncdata;+};+#endif++/* r2 is the TOC pointer: it actually points 0x8000 into the TOC (this+givesthevaluemaximumspaninaninstructionwhichusesasigned+offset)*/+staticinlineunsignedlongmy_r2(conststructelf_info*elf_info)+{+returnelf_info->sechdrs[elf_info->toc_section].sh_addr+0x8000;+}++intelf64_apply_relocate_add(conststructelf_info*elf_info,+constchar*strtab,unsignedintsymindex,+unsignedintrelsec,constchar*obj_name);++#endif /* _ASM_POWERPC_ELF_UTIL_H */
@@ -12,7 +12,14 @@#include<linux/list.h>#include<asm/bug.h>#include<asm-generic/module.h>+#include<asm/elf_util.h>+/* Both low and high 16 bits are added as SIGNED additions, so if low+16bitshashighbitset,high16bitsmustbeadjusted.These+macrosdothat(stolenfrombinutils).*/+#define PPC_LO(v) ((v) & 0xffff)+#define PPC_HI(v) (((v) >> 16) & 0xffff)+#define PPC_HA(v) PPC_HI ((v) + 0x8000)#ifndef __powerpc64__/*
@@ -33,8 +40,7 @@ struct ppc_plt_entry {structmod_arch_specific{#ifdef __powerpc64__-unsignedintstubs_section;/* Index of stubs section in module */-unsignedinttoc_section;/* What section is the TOC? */+structelf_infoelf_info;booltoc_fixed;/* Have we fixed up .TOC.? */#ifdef CONFIG_DYNAMIC_FTRACEunsignedlongtoc;
@@ -0,0 +1,269 @@+/*+*UtilityfunctionstoworkwithELFfiles.+*+*Copyright(C)2016,IBMCorporation+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby+*theFreeSoftwareFoundation;eitherversion2,or(atyouroption)+*anylaterversion.+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*/++#include<asm/ppc-opcode.h>+#include<asm/elf_util.h>++/*+*Wejustneedtousethefunctionsdefinedin<asm/module.h>,sojustdeclare+*structmodulehereandavoidhavingtoimport<linux/module.h>.+*/+structmodule;+#include<asm/module.h>++#ifdef PPC64_ELF_ABI_v2+/* PowerPC64 specific values for the Elf64_Sym st_other field. */+#define STO_PPC64_LOCAL_BIT 5+#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT)+#define PPC64_LOCAL_ENTRY_OFFSET(other) \+(((1<<(((other)&STO_PPC64_LOCAL_MASK)>>STO_PPC64_LOCAL_BIT))>>2)<<2)++staticunsignedintlocal_entry_offset(constElf64_Sym*sym)+{+/* sym->st_other indicates offset to local entry point+*(otherwiseitwillassumer12istheaddressofthestart+*offunctionandtrytoderiver2fromit).*/+returnPPC64_LOCAL_ENTRY_OFFSET(sym->st_other);+}+#else+staticunsignedintlocal_entry_offset(constElf64_Sym*sym)+{+return0;+}+#endif++#ifdef CC_USING_MPROFILE_KERNEL+/*+*Incaseof_mcountcalls,donotsavethecurrentcallee'sTOC(inr2)into+*theoriginalcaller'sstackframe.IfwedidwewouldclobberthesavedTOC+*valueoftheoriginalcaller.+*/+staticvoidsquash_toc_save_inst(constchar*name,unsignedlongaddr)+{+structppc64_stub_entry*stub=(structppc64_stub_entry*)addr;++/* Only for calls to _mcount */+if(strcmp("_mcount",name)!=0)+return;++stub->jump[2]=PPC_INST_NOP;+}+#else+staticvoidsquash_toc_save_inst(constchar*name,unsignedlongaddr){}+#endif++/**+*elf64_apply_relocate_add-apply64bitRELArelocations+*@elf_info:SupportinformationfortheELFbinarybeingrelocated.+*@strtab:Stringtablefortheassociatedsymboltable.+*@symindex:Sectionheaderindexfortheassociatedsymboltable.+*@relsec:Sectionheaderindexfortherelocationstoapply.+*@obj_name:ThenameoftheELFbinary,forinformationmessages.+*/+intelf64_apply_relocate_add(conststructelf_info*elf_info,+constchar*strtab,unsignedintsymindex,+unsignedintrelsec,constchar*obj_name)+{+unsignedinti;+Elf64_Shdr*sechdrs=elf_info->sechdrs;+Elf64_Rela*rela=(void*)sechdrs[relsec].sh_addr;+Elf64_Sym*sym;+unsignedlong*location;+unsignedlongvalue;+++for(i=0;i<sechdrs[relsec].sh_size/sizeof(*rela);i++){+/* This is where to make the change */+location=(void*)sechdrs[sechdrs[relsec].sh_info].sh_addr++rela[i].r_offset;+/* This is the symbol it is referring to */+sym=(Elf64_Sym*)sechdrs[symindex].sh_addr++ELF64_R_SYM(rela[i].r_info);++pr_debug("RELOC at %p: %li-type as %s (0x%lx) + %li\n",+location,(long)ELF64_R_TYPE(rela[i].r_info),+strtab+sym->st_name,(unsignedlong)sym->st_value,+(long)rela[i].r_addend);++/* `Everything is relative'. */+value=sym->st_value+rela[i].r_addend;++switch(ELF64_R_TYPE(rela[i].r_info)){+caseR_PPC64_ADDR32:+/* Simply set it */+*(u32*)location=value;+break;++caseR_PPC64_ADDR64:+/* Simply set it */+*(unsignedlong*)location=value;+break;++caseR_PPC64_TOC:+*(unsignedlong*)location=my_r2(elf_info);+break;++caseR_PPC64_TOC16:+/* Subtract TOC pointer */+value-=my_r2(elf_info);+if(value+0x8000>0xffff){+pr_err("%s: bad TOC16 relocation (0x%lx)\n",+obj_name,value);+return-ENOEXEC;+}+*((uint16_t*)location)+=(*((uint16_t*)location)&~0xffff)+|(value&0xffff);+break;++caseR_PPC64_TOC16_LO:+/* Subtract TOC pointer */+value-=my_r2(elf_info);+*((uint16_t*)location)+=(*((uint16_t*)location)&~0xffff)+|(value&0xffff);+break;++caseR_PPC64_TOC16_DS:+/* Subtract TOC pointer */+value-=my_r2(elf_info);+if((value&3)!=0||value+0x8000>0xffff){+pr_err("%s: bad TOC16_DS relocation (0x%lx)\n",+obj_name,value);+return-ENOEXEC;+}+*((uint16_t*)location)+=(*((uint16_t*)location)&~0xfffc)+|(value&0xfffc);+break;++caseR_PPC64_TOC16_LO_DS:+/* Subtract TOC pointer */+value-=my_r2(elf_info);+if((value&3)!=0){+pr_err("%s: bad TOC16_LO_DS relocation (0x%lx)\n",+obj_name,value);+return-ENOEXEC;+}+*((uint16_t*)location)+=(*((uint16_t*)location)&~0xfffc)+|(value&0xfffc);+break;++caseR_PPC64_TOC16_HA:+/* Subtract TOC pointer */+value-=my_r2(elf_info);+value=((value+0x8000)>>16);+*((uint16_t*)location)+=(*((uint16_t*)location)&~0xffff)+|(value&0xffff);+break;++caseR_PPC_REL24:+/* FIXME: Handle weak symbols here --RR */+if(sym->st_shndx==SHN_UNDEF){+/* External: go via stub */+value=stub_for_addr(elf_info,value,obj_name);+if(!value)+return-ENOENT;+if(!restore_r2((u32*)location+1,obj_name))+return-ENOEXEC;++squash_toc_save_inst(strtab+sym->st_name,value);+}else+value+=local_entry_offset(sym);++/* Convert value to relative */+value-=(unsignedlong)location;+if(value+0x2000000>0x3ffffff||(value&3)!=0){+pr_err("%s: REL24 %li out of range!\n",+obj_name,(longint)value);+return-ENOEXEC;+}++/* Only replace bits 2 through 26 */+*(uint32_t*)location+=(*(uint32_t*)location&~0x03fffffc)+|(value&0x03fffffc);+break;++caseR_PPC64_REL64:+/* 64 bits relative (used by features fixups) */+*location=value-(unsignedlong)location;+break;++caseR_PPC64_TOCSAVE:+/*+*Markerrelocindicateswedon'thavetosaver2.+*Thatwouldonlysaveusoneinstruction,soignore+*it.+*/+break;++caseR_PPC64_ENTRY:+/*+*OptimizeELFv2largecodemodelentrypointif+*theTOCiswithin2GBrangeofcurrentlocation.+*/+value=my_r2(elf_info)-(unsignedlong)location;+if(value+0x80008000>0xffffffff)+break;+/*+*Checkforthelargecodemodelprologsequence:+*ldr2,...(r12)+*addr2,r2,r12+*/+if((((uint32_t*)location)[0]&~0xfffc)+!=0xe84c0000)+break;+if(((uint32_t*)location)[1]!=0x7c426214)+break;+/*+*Iffound,replaceitwith:+*addisr2,r12,(.TOC.-func)@ha+*addir2,r12,(.TOC.-func)@l+*/+((uint32_t*)location)[0]=0x3c4c0000+PPC_HA(value);+((uint32_t*)location)[1]=0x38420000+PPC_LO(value);+break;++caseR_PPC64_REL16_HA:+/* Subtract location pointer */+value-=(unsignedlong)location;+value=((value+0x8000)>>16);+*((uint16_t*)location)+=(*((uint16_t*)location)&~0xffff)+|(value&0xffff);+break;++caseR_PPC64_REL16_LO:+/* Subtract location pointer */+value-=(unsignedlong)location;+*((uint16_t*)location)+=(*((uint16_t*)location)&~0xffff)+|(value&0xffff);+break;++default:+pr_err("%s: Unknown ADD relocation: %lu\n",+obj_name,+(unsignedlong)ELF64_R_TYPE(rela[i].r_info));+return-ENOEXEC;+}+}++return0;+}
@@ -43,9 +43,6 @@#ifdef PPC64_ELF_ABI_v2-/* An address is simply the address of the function. */-typedefunsignedlongfunc_desc_t;-staticfunc_desc_tfunc_desc(unsignedlongaddr){returnaddr;
@@ -58,25 +55,8 @@ static unsigned long stub_func_addr(func_desc_t func){returnfunc;}--/* PowerPC64 specific values for the Elf64_Sym st_other field. */-#define STO_PPC64_LOCAL_BIT 5-#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT)-#define PPC64_LOCAL_ENTRY_OFFSET(other) \-(((1<<(((other)&STO_PPC64_LOCAL_MASK)>>STO_PPC64_LOCAL_BIT))>>2)<<2)--staticunsignedintlocal_entry_offset(constElf64_Sym*sym)-{-/* sym->st_other indicates offset to local entry point-*(otherwiseitwillassumer12istheaddressofthestart-*offunctionandtrytoderiver2fromit).*/-returnPPC64_LOCAL_ENTRY_OFFSET(sym->st_other);-}#else-/* An address is address of the OPD entry, which contains address of fn. */-typedefstructppc64_opd_entryfunc_desc_t;-staticfunc_desc_tfunc_desc(unsignedlongaddr){return*(structppc64_opd_entry*)addr;
@@ -89,29 +69,10 @@ static unsigned long stub_func_addr(func_desc_t func){returnfunc.funcaddr;}-staticunsignedintlocal_entry_offset(constElf64_Sym*sym)-{-return0;-}#endif#define STUB_MAGIC 0x73747562 /* stub */-/* Like PPC32, we need little trampolines to do > 24-bit jumps (into-thekernelitself).ButonPPC64,theseneedtobeusedforevery-jump,actually,toresetr2(TOC+0x8000).*/-structppc64_stub_entry-{-/* 28 byte jump instruction sequence (7 instructions). We only-*need6instructionsonABIv2butwealwaysallocate7so-*sowedon'thavetomodifythetrampolineloadinstruction.*/-u32jump[7];-/* Used by ftrace to identify stubs */-u32magic;-/* Data for the above code */-func_desc_tfuncdata;-};-/**PPC64uses24bitjumps,butweneedtojumpintoothermodulesor*thekernelwhichmaybefurther.Sowejumptoastub.
@@ -346,9 +307,9 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr,for(i=1;i<hdr->e_shnum;i++){char*p;if(strcmp(secstrings+sechdrs[i].sh_name,".stubs")==0)-me->arch.stubs_section=i;+me->arch.elf_info.stubs_section=i;elseif(strcmp(secstrings+sechdrs[i].sh_name,".toc")==0)-me->arch.toc_section=i;+me->arch.elf_info.toc_section=i;elseif(strcmp(secstrings+sechdrs[i].sh_name,"__versions")==0)dedotify_versions((void*)hdr+sechdrs[i].sh_offset,sechdrs[i].sh_size);
@@ -364,7 +325,7 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr,+sechdrs[sechdrs[i].sh_link].sh_offset);}-if(!me->arch.stubs_section){+if(!me->arch.elf_info.stubs_section){pr_err("%s: doesn't contain .stubs.\n",me->name);return-ENOEXEC;}
@@ -373,44 +334,32 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr,tosomereasonablevalueincasethemodulecallsouttootherfunctionsviaastub,orifafunctionpointerescapesthemodulebysomemeans.*/-if(!me->arch.toc_section)-me->arch.toc_section=me->arch.stubs_section;+if(!me->arch.elf_info.toc_section)+me->arch.elf_info.toc_section=me->arch.elf_info.stubs_section;/* Override the stubs size */-sechdrs[me->arch.stubs_section].sh_size=get_stubs_size(hdr,sechdrs);-return0;-}+sechdrs[me->arch.elf_info.stubs_section].sh_size=get_stubs_size(hdr,sechdrs);-/* r2 is the TOC pointer: it actually points 0x8000 into the TOC (this-givesthevaluemaximumspaninaninstructionwhichusesasigned-offset)*/-staticinlineunsignedlongmy_r2(constElf64_Shdr*sechdrs,structmodule*me)-{-returnsechdrs[me->arch.toc_section].sh_addr+0x8000;-}+/* For the elf_util functions. */+me->arch.elf_info.sechdrs=sechdrs;-/* Both low and high 16 bits are added as SIGNED additions, so if low-16bitshashighbitset,high16bitsmustbeadjusted.These-macrosdothat(stolenfrombinutils).*/-#define PPC_LO(v) ((v) & 0xffff)-#define PPC_HI(v) (((v) >> 16) & 0xffff)-#define PPC_HA(v) PPC_HI ((v) + 0x8000)+return0;+}/* Patch stub to reference function and correct r2 value. */-staticinlineintcreate_stub(constElf64_Shdr*sechdrs,+staticinlineintcreate_stub(conststructelf_info*elf_info,structppc64_stub_entry*entry,-unsignedlongaddr,-structmodule*me)+unsignedlongaddr,constchar*obj_name){longreladdr;memcpy(entry->jump,ppc64_stub_insns,sizeof(ppc64_stub_insns));/* Stub uses address relative to r2. */-reladdr=(unsignedlong)entry-my_r2(sechdrs,me);+reladdr=(unsignedlong)entry-my_r2(elf_info);if(reladdr>0x7FFFFFFF||reladdr<-(0x80000000L)){pr_err("%s: Address %p of stub out of range of %p.\n",-me->name,(void*)reladdr,(void*)my_r2);+obj_name,(void*)reladdr,(void*)my_r2);return0;}pr_debug("Stub %p get data from reladdr %li\n",entry,reladdr);
@@ -425,17 +374,17 @@ static inline int create_stub(const Elf64_Shdr *sechdrs,/* Create stub to jump to function described in this OPD/ptr: we need thestubtosetuptheTOCptr(r2)forthefunction.*/-staticunsignedlongstub_for_addr(constElf64_Shdr*sechdrs,-unsignedlongaddr,-structmodule*me)+unsignedlongstub_for_addr(conststructelf_info*elf_info,unsignedlongaddr,+constchar*obj_name){+structelf_shdr*stubs_sec=&elf_info->sechdrs[elf_info->stubs_section];structppc64_stub_entry*stubs;unsignedinti,num_stubs;-num_stubs=sechdrs[me->arch.stubs_section].sh_size/sizeof(*stubs);+num_stubs=stubs_sec->sh_size/sizeof(*stubs);/* Find this stub, or if that fails, the next avail. entry */-stubs=(void*)sechdrs[me->arch.stubs_section].sh_addr;+stubs=(void*)stubs_sec->sh_addr;for(i=0;stub_func_addr(stubs[i].funcdata);i++){BUG_ON(i>=num_stubs);
@@ -443,7 +392,7 @@ static unsigned long stub_for_addr(const Elf64_Shdr *sechdrs,return(unsignedlong)&stubs[i];}-if(!create_stub(sechdrs,&stubs[i],addr,me))+if(!create_stub(elf_info,&stubs[i],addr,obj_name))return0;return(unsignedlong)&stubs[i];
@@ -465,24 +414,7 @@ static bool is_early_mcount_callsite(u32 *instruction)returnfalse;}-/*-*Incaseof_mcountcalls,donotsavethecurrentcallee'sTOC(inr2)into-*theoriginalcaller'sstackframe.IfwedidwewouldclobberthesavedTOC-*valueoftheoriginalcaller.-*/-staticvoidsquash_toc_save_inst(constchar*name,unsignedlongaddr)-{-structppc64_stub_entry*stub=(structppc64_stub_entry*)addr;--/* Only for calls to _mcount */-if(strcmp("_mcount",name)!=0)-return;--stub->jump[2]=PPC_INST_NOP;-}#else-staticvoidsquash_toc_save_inst(constchar*name,unsignedlongaddr){}-/* without -mprofile-kernel, mcount calls are never early */staticboolis_early_mcount_callsite(u32*instruction){
@@ -492,13 +424,13 @@ static bool is_early_mcount_callsite(u32 *instruction)/* We expect a noop next: if it is, replace it with instruction torestorer2.*/-staticintrestore_r2(u32*instruction,structmodule*me)+intrestore_r2(u32*instruction,constchar*obj_name){if(*instruction!=PPC_INST_NOP){if(is_early_mcount_callsite(instruction-1))return1;pr_err("%s: Expect noop after relocate, got %08x\n",-me->name,*instruction);+obj_name,*instruction);return0;}/* ld r2,R2_STACK_OFFSET(r1) */
@@ -512,11 +444,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,unsignedintrelsec,structmodule*me){-unsignedinti;-Elf64_Rela*rela=(void*)sechdrs[relsec].sh_addr;Elf64_Sym*sym;-unsignedlong*location;-unsignedlongvalue;pr_debug("Applying ADD relocate section %u to %u\n",relsec,sechdrs[relsec].sh_info);
@@ -527,191 +455,12 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,/* It's theoretically possible that a module doesn't want a*.TOC.sodon'tfailitjustforthat.*/if(sym)-sym->st_value=my_r2(sechdrs,me);+sym->st_value=my_r2(&me->arch.elf_info);me->arch.toc_fixed=true;}-for(i=0;i<sechdrs[relsec].sh_size/sizeof(*rela);i++){-/* This is where to make the change */-location=(void*)sechdrs[sechdrs[relsec].sh_info].sh_addr-+rela[i].r_offset;-/* This is the symbol it is referring to */-sym=(Elf64_Sym*)sechdrs[symindex].sh_addr-+ELF64_R_SYM(rela[i].r_info);--pr_debug("RELOC at %p: %li-type as %s (0x%lx) + %li\n",-location,(long)ELF64_R_TYPE(rela[i].r_info),-strtab+sym->st_name,(unsignedlong)sym->st_value,-(long)rela[i].r_addend);--/* `Everything is relative'. */-value=sym->st_value+rela[i].r_addend;--switch(ELF64_R_TYPE(rela[i].r_info)){-caseR_PPC64_ADDR32:-/* Simply set it */-*(u32*)location=value;-break;--caseR_PPC64_ADDR64:-/* Simply set it */-*(unsignedlong*)location=value;-break;--caseR_PPC64_TOC:-*(unsignedlong*)location=my_r2(sechdrs,me);-break;--caseR_PPC64_TOC16:-/* Subtract TOC pointer */-value-=my_r2(sechdrs,me);-if(value+0x8000>0xffff){-pr_err("%s: bad TOC16 relocation (0x%lx)\n",-me->name,value);-return-ENOEXEC;-}-*((uint16_t*)location)-=(*((uint16_t*)location)&~0xffff)-|(value&0xffff);-break;--caseR_PPC64_TOC16_LO:-/* Subtract TOC pointer */-value-=my_r2(sechdrs,me);-*((uint16_t*)location)-=(*((uint16_t*)location)&~0xffff)-|(value&0xffff);-break;--caseR_PPC64_TOC16_DS:-/* Subtract TOC pointer */-value-=my_r2(sechdrs,me);-if((value&3)!=0||value+0x8000>0xffff){-pr_err("%s: bad TOC16_DS relocation (0x%lx)\n",-me->name,value);-return-ENOEXEC;-}-*((uint16_t*)location)-=(*((uint16_t*)location)&~0xfffc)-|(value&0xfffc);-break;--caseR_PPC64_TOC16_LO_DS:-/* Subtract TOC pointer */-value-=my_r2(sechdrs,me);-if((value&3)!=0){-pr_err("%s: bad TOC16_LO_DS relocation (0x%lx)\n",-me->name,value);-return-ENOEXEC;-}-*((uint16_t*)location)-=(*((uint16_t*)location)&~0xfffc)-|(value&0xfffc);-break;--caseR_PPC64_TOC16_HA:-/* Subtract TOC pointer */-value-=my_r2(sechdrs,me);-value=((value+0x8000)>>16);-*((uint16_t*)location)-=(*((uint16_t*)location)&~0xffff)-|(value&0xffff);-break;--caseR_PPC_REL24:-/* FIXME: Handle weak symbols here --RR */-if(sym->st_shndx==SHN_UNDEF){-/* External: go via stub */-value=stub_for_addr(sechdrs,value,me);-if(!value)-return-ENOENT;-if(!restore_r2((u32*)location+1,me))-return-ENOEXEC;--squash_toc_save_inst(strtab+sym->st_name,value);-}else-value+=local_entry_offset(sym);--/* Convert value to relative */-value-=(unsignedlong)location;-if(value+0x2000000>0x3ffffff||(value&3)!=0){-pr_err("%s: REL24 %li out of range!\n",-me->name,(longint)value);-return-ENOEXEC;-}--/* Only replace bits 2 through 26 */-*(uint32_t*)location-=(*(uint32_t*)location&~0x03fffffc)-|(value&0x03fffffc);-break;--caseR_PPC64_REL64:-/* 64 bits relative (used by features fixups) */-*location=value-(unsignedlong)location;-break;--caseR_PPC64_TOCSAVE:-/*-*Markerrelocindicateswedon'thavetosaver2.-*Thatwouldonlysaveusoneinstruction,soignore-*it.-*/-break;--caseR_PPC64_ENTRY:-/*-*OptimizeELFv2largecodemodelentrypointif-*theTOCiswithin2GBrangeofcurrentlocation.-*/-value=my_r2(sechdrs,me)-(unsignedlong)location;-if(value+0x80008000>0xffffffff)-break;-/*-*Checkforthelargecodemodelprologsequence:-*ldr2,...(r12)-*addr2,r2,r12-*/-if((((uint32_t*)location)[0]&~0xfffc)-!=0xe84c0000)-break;-if(((uint32_t*)location)[1]!=0x7c426214)-break;-/*-*Iffound,replaceitwith:-*addisr2,r12,(.TOC.-func)@ha-*addir2,r12,(.TOC.-func)@l-*/-((uint32_t*)location)[0]=0x3c4c0000+PPC_HA(value);-((uint32_t*)location)[1]=0x38420000+PPC_LO(value);-break;--caseR_PPC64_REL16_HA:-/* Subtract location pointer */-value-=(unsignedlong)location;-value=((value+0x8000)>>16);-*((uint16_t*)location)-=(*((uint16_t*)location)&~0xffff)-|(value&0xffff);-break;--caseR_PPC64_REL16_LO:-/* Subtract location pointer */-value-=(unsignedlong)location;-*((uint16_t*)location)-=(*((uint16_t*)location)&~0xffff)-|(value&0xffff);-break;--default:-pr_err("%s: Unknown ADD relocation: %lu\n",-me->name,-(unsignedlong)ELF64_R_TYPE(rela[i].r_info));-return-ENOEXEC;-}-}--return0;+returnelf64_apply_relocate_add(&me->arch.elf_info,strtab,symindex,+relsec,me->name);}#ifdef CONFIG_DYNAMIC_FTRACE
@@ -745,10 +494,10 @@ static unsigned long create_ftrace_stub(const Elf64_Shdr *sechdrs, struct module};longreladdr;-num_stubs=sechdrs[me->arch.stubs_section].sh_size/sizeof(*entry);+num_stubs=sechdrs[me->arch.elf_info.stubs_section].sh_size/sizeof(*entry);/* Find the next available stub entry */-entry=(void*)sechdrs[me->arch.stubs_section].sh_addr;+entry=(void*)sechdrs[me->arch.elf_info.stubs_section].sh_addr;for(i=0;i<num_stubs&&stub_func_addr(entry->funcdata);i++,entry++);if(i>=num_stubs){
@@ -472,14 +493,7 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,kbuf->top_down=top_down;/* Walk the RAM ranges and allocate a suitable range for the buffer */-if(image->type==KEXEC_TYPE_CRASH)-ret=walk_iomem_res_desc(crashk_res.desc,-IORESOURCE_SYSTEM_RAM|IORESOURCE_BUSY,-crashk_res.start,crashk_res.end,kbuf,-locate_mem_hole_callback);-else-ret=walk_system_ram_res(0,-1,kbuf,-locate_mem_hole_callback);+ret=arch_kexec_walk_mem(kbuf,locate_mem_hole_callback);if(ret!=1){/* A suitable memory range could not be found for buffer */return-EADDRNOTAVAIL;
From: Dave Young <hidden> Date: 2016-06-22 10:18:21
On 06/21/16 at 04:48pm, Thiago Jung Bauermann wrote:
quoted hunk
kexec_locate_mem_hole will be used by the PowerPC kexec_file_load
implementation to find free memory for the purgatory stack.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: Eric Biederman <redacted>
Cc: Dave Young <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
include/linux/kexec.h | 4 ++++
kernel/kexec_file.c | 66 ++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 53 insertions(+), 17 deletions(-)
@@ -227,6 +227,10 @@ extern asmlinkage long sys_kexec_load(unsigned long entry,structkexec_segment__user*segments,unsignedlongflags);externintkernel_kexec(void);+intkexec_locate_mem_hole(structkimage*image,unsignedlongsize,+unsignedlongalign,unsignedlongmin_addr,+unsignedlongmax_addr,booltop_down,+unsignedlong*addr);externintkexec_add_buffer(structkimage*image,char*buffer,unsignedlongbufsz,unsignedlongmemsz,unsignedlongbuf_align,unsignedlongbuf_min,
@@ -449,6 +449,46 @@ int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf,returnwalk_system_ram_res(0,ULONG_MAX,kbuf,func);}+/**+*kexec_locate_mem_hole-findfreememorytoloadsegmentoruseinpurgatory+*@image:kexecimagebeingupdated.+*@size:Memorysize.+*@align:Minimumalignmentneeded.+*@min_addr:Minimumstartingaddress.+*@max_addr:Maximumendaddress.+*@top_downFindthehighestfreememoryregion?+*@addrOnsuccess,willhavestartaddressofthememoryregionfound.+*+*Return:0onsuccess,negativeerrnoonerror.+*/+intkexec_locate_mem_hole(structkimage*image,unsignedlongsize,+unsignedlongalign,unsignedlongmin_addr,+unsignedlongmax_addr,booltop_down,+unsignedlong*addr)+{+intret;+structkexec_bufbuf;++memset(&buf,0,sizeof(structkexec_buf));+buf.image=image;++buf.memsz=size;+buf.buf_align=align;+buf.buf_min=min_addr;+buf.buf_max=max_addr;+buf.top_down=top_down;
Since patch 2/9 moved kexec_buf from internal header file to kexec.h it
will be natural to passing a kexec_buf pointer intead of passing all
these arguments in kexec_locate_mem_hole.
kbuf.mem can be used for addr.
quoted hunk
+
+ ret = arch_kexec_walk_mem(&buf, locate_mem_hole_callback);
+ if (ret != 1) {
+ /* A suitable memory range could not be found for buffer */
+ return -EADDRNOTAVAIL;
+ }
+
+ *addr = buf.mem;
+
+ return 0;
+}
+
/*
* Helper function for placing a buffer in a kexec segment. This assumes
* that kexec_mutex is held.
@@ -460,8 +500,8 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz, { struct kexec_segment *ksegment;- struct kexec_buf buf, *kbuf; int ret;+ unsigned long addr, align, size; /* Currently adding segment this way is allowed only in file mode */ if (!image->file_mode)
@@ -482,29 +522,21 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz, return -EINVAL; }- memset(&buf, 0, sizeof(struct kexec_buf));- kbuf = &buf;- kbuf->image = image;-- kbuf->memsz = ALIGN(memsz, PAGE_SIZE);- kbuf->buf_align = max(buf_align, PAGE_SIZE);- kbuf->buf_min = buf_min;- kbuf->buf_max = buf_max;- kbuf->top_down = top_down;+ size = ALIGN(memsz, PAGE_SIZE);+ align = max(buf_align, PAGE_SIZE); /* Walk the RAM ranges and allocate a suitable range for the buffer */- ret = arch_kexec_walk_mem(kbuf, locate_mem_hole_callback);- if (ret != 1) {- /* A suitable memory range could not be found for buffer */- return -EADDRNOTAVAIL;- }+ ret = kexec_locate_mem_hole(image, size, align, buf_min, buf_max,+ top_down, &addr);+ if (ret)+ return ret; /* Found a suitable memory range */ ksegment = &image->segment[image->nr_segments]; ksegment->kbuf = buffer; ksegment->bufsz = bufsz;- ksegment->mem = kbuf->mem;- ksegment->memsz = kbuf->memsz;+ ksegment->mem = addr;+ ksegment->memsz = size; image->nr_segments++; *load_addr = ksegment->mem; return 0;
From: Dave Young <hidden> Date: 2016-06-22 10:20:56
The patch looks good, but could the subject be more specific?
For example just like the first sentence of the patch descriotion:
Allow architectures to specify their own memory walking function
On 06/21/16 at 04:48pm, Thiago Jung Bauermann wrote:
quoted hunk
Allow architectures to specify different memory walking functions for
kexec_add_buffer. Intel uses iomem to track reserved memory ranges,
but PowerPC uses the memblock subsystem.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: Eric Biederman <redacted>
Cc: Dave Young <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
include/linux/kexec.h | 19 ++++++++++++++++++-
kernel/kexec_file.c | 30 ++++++++++++++++++++++--------
kernel/kexec_internal.h | 14 --------------
3 files changed, 40 insertions(+), 23 deletions(-)
@@ -472,14 +493,7 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,kbuf->top_down=top_down;/* Walk the RAM ranges and allocate a suitable range for the buffer */-if(image->type==KEXEC_TYPE_CRASH)-ret=walk_iomem_res_desc(crashk_res.desc,-IORESOURCE_SYSTEM_RAM|IORESOURCE_BUSY,-crashk_res.start,crashk_res.end,kbuf,-locate_mem_hole_callback);-else-ret=walk_system_ram_res(0,-1,kbuf,-locate_mem_hole_callback);+ret=arch_kexec_walk_mem(kbuf,locate_mem_hole_callback);if(ret!=1){/* A suitable memory range could not be found for buffer */return-EADDRNOTAVAIL;
On Tue, 21 Jun 2016 16:48:32 -0300
Thiago Jung Bauermann [off-list ref] wrote:
Hello,
This patch series implements the kexec_file_load system call on
PowerPC.
This system call moves the reading of the kernel, initrd and the
device tree from the userspace kexec tool to the kernel. This is
needed if you want to do one or both of the following:
1. only allow loading of signed kernels.
2. "measure" (i.e., record the hashes of) the kernel, initrd, kernel
command line and other boot inputs for the Integrity Measurement
Architecture subsystem.
The above are the functions kexec already has built into
kexec_file_load. Yesterday I posted a set of patches which allows a
third feature:
3. have IMA pass-on its event log (where integrity measurements are
registered) accross kexec to the second kernel, so that the event
history is preserved.
OK.. and this is safe? Do both the kernels need to be signed by the
same certificate?
Balbir Singh
Hello Balbir,
Am Mittwoch, 22 Juni 2016, 23:29:46 schrieb Balbir Singh:
On Tue, 21 Jun 2016 16:48:32 -0300
Thiago Jung Bauermann [off-list ref] wrote:
quoted
This patch series implements the kexec_file_load system call on
PowerPC.
This system call moves the reading of the kernel, initrd and the
device tree from the userspace kexec tool to the kernel. This is
needed if you want to do one or both of the following:
1. only allow loading of signed kernels.
2. "measure" (i.e., record the hashes of) the kernel, initrd, kernel
command line and other boot inputs for the Integrity Measurement
Architecture subsystem.
The above are the functions kexec already has built into
kexec_file_load. Yesterday I posted a set of patches which allows a
third feature:
3. have IMA pass-on its event log (where integrity measurements are
registered) accross kexec to the second kernel, so that the event
history is preserved.
OK.. and this is safe? Do both the kernels need to be signed by the
same certificate?
They don't. The integrity of the event log (assuming that is what you mean
by "this" in "this is safe") is guaranteed by the TPM device. Each event in
the measurement list extends a PCR and records its PCR value. It is
cryptographically guaranteed that if you replay the PCR extends recorded in
the event log and in the end of the process they match the current PCR
values in the TPM device, then that event log is correct.
The kernel signature serves to ensure that you only run kernels from an
authorized provider. It doesn't play a role in integrity assurance, which
aims to verify that the machine is really running the code it says it is
running. As I understand it, at least. It's a bit subtle and I could be
missing something...
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Am Mittwoch, 22 Juni 2016, 18:20:47 schrieb Dave Young:
The patch looks good, but could the subject be more specific?
For example just like the first sentence of the patch descriotion:
Allow architectures to specify their own memory walking function
Ok, What about this? I also changed the description to refer to x86 arch
instead of Intel arch.
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Subject: [PATCH 2/9] kexec_file: Allow arch-specific memory walking for
kexec_add_buffer
Allow architectures to specify a different memory walking function for
kexec_add_buffer. x86 uses iomem to track reserved memory ranges, but
PowerPC uses the memblock subsystem.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: Eric Biederman <redacted>
Cc: Dave Young <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
include/linux/kexec.h | 19 ++++++++++++++++++-
kernel/kexec_file.c | 30 ++++++++++++++++++++++--------
kernel/kexec_internal.h | 14 --------------
3 files changed, 40 insertions(+), 23 deletions(-)
@@ -472,14 +493,7 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,kbuf->top_down=top_down;/* Walk the RAM ranges and allocate a suitable range for the buffer */-if(image->type==KEXEC_TYPE_CRASH)-ret=walk_iomem_res_desc(crashk_res.desc,-IORESOURCE_SYSTEM_RAM|IORESOURCE_BUSY,-crashk_res.start,crashk_res.end,kbuf,-locate_mem_hole_callback);-else-ret=walk_system_ram_res(0,-1,kbuf,-locate_mem_hole_callback);+ret=arch_kexec_walk_mem(kbuf,locate_mem_hole_callback);if(ret!=1){/* A suitable memory range could not be found for buffer */return-EADDRNOTAVAIL;
Am Mittwoch, 22 Juni 2016, 18:18:01 schrieb Dave Young:
On 06/21/16 at 04:48pm, Thiago Jung Bauermann wrote:
quoted
+/**
+ * kexec_locate_mem_hole - find free memory to load segment or use in
purgatory + * @image: kexec image being updated.
+ * @size: Memory size.
+ * @align: Minimum alignment needed.
+ * @min_addr: Minimum starting address.
+ * @max_addr: Maximum end address.
+ * @top_down Find the highest free memory region?
+ * @addr On success, will have start address of the memory region
found.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int kexec_locate_mem_hole(struct kimage *image, unsigned long size,
+ unsigned long align, unsigned long min_addr,
+ unsigned long max_addr, bool top_down,
+ unsigned long *addr)
+{
+ int ret;
+ struct kexec_buf buf;
+
+ memset(&buf, 0, sizeof(struct kexec_buf));
+ buf.image = image;
+
+ buf.memsz = size;
+ buf.buf_align = align;
+ buf.buf_min = min_addr;
+ buf.buf_max = max_addr;
+ buf.top_down = top_down;
Since patch 2/9 moved kexec_buf from internal header file to kexec.h it
will be natural to passing a kexec_buf pointer intead of passing all
these arguments in kexec_locate_mem_hole.
kbuf.mem can be used for addr.
Ok. What about this version?
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Subject: [PATCH 3/9] kexec_file: Factor out kexec_locate_mem_hole from
kexec_add_buffer.
kexec_locate_mem_hole will be used by the PowerPC kexec_file_load
implementation to find free memory for the purgatory stack.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: Eric Biederman <redacted>
Cc: Dave Young <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
include/linux/kexec.h | 12 +++++++++---
kernel/kexec_file.c | 25 ++++++++++++++++++++-----
2 files changed, 29 insertions(+), 8 deletions(-)
@@ -449,6 +449,23 @@ int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf,returnwalk_system_ram_res(0,ULONG_MAX,kbuf,func);}+/**+*kexec_locate_mem_hole-findfreememorytoloadsegmentoruseinpurgatory+*@kbuf:Parametersforthememorysearch.+*+*Onsuccess,kbuf->memwillhavethestartaddressofthememoryregionfound.+*+*Return:0onsuccess,negativeerrnoonerror.+*/+intkexec_locate_mem_hole(structkexec_buf*kbuf)+{+intret;++ret=arch_kexec_walk_mem(kbuf,locate_mem_hole_callback);++returnret==1?0:-EADDRNOTAVAIL;+}+/**Helperfunctionforplacingabufferinakexecsegment.Thisassumes*thatkexec_mutexisheld.
@@ -493,11 +510,9 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,kbuf->top_down=top_down;/* Walk the RAM ranges and allocate a suitable range for the buffer */-ret=arch_kexec_walk_mem(kbuf,locate_mem_hole_callback);-if(ret!=1){-/* A suitable memory range could not be found for buffer */-return-EADDRNOTAVAIL;-}+ret=kexec_locate_mem_hole(kbuf);+if(ret)+returnret;/* Found a suitable memory range */ksegment=&image->segment[image->nr_segments];
3. have IMA pass-on its event log (where integrity measurements are
registered) accross kexec to the second kernel, so that the event
history is preserved.
OK.. and this is safe? Do both the kernels need to be signed by the
same certificate?
They don't. The integrity of the event log (assuming that is what you mean
by "this" in "this is safe") is guaranteed by the TPM device. Each event in
the measurement list extends a PCR and records its PCR value. It is
cryptographically guaranteed that if you replay the PCR extends recorded in
the event log and in the end of the process they match the current PCR
values in the TPM device, then that event log is correct.
What I meant was how does the new kernel know that the old kernel did not
cheat while passing on the values? I presume because we trust that kernel
via a signature.
and
How do we know the new kernel is safe to load - I guess via a signature that
the new kernel is signed with (assuming it is present in the key ring).
Balbir Singh
From: Dave Young <hidden> Date: 2016-06-23 02:25:14
On 06/22/16 at 08:30pm, Thiago Jung Bauermann wrote:
Am Mittwoch, 22 Juni 2016, 18:20:47 schrieb Dave Young:
quoted
The patch looks good, but could the subject be more specific?
For example just like the first sentence of the patch descriotion:
Allow architectures to specify their own memory walking function
Ok, What about this? I also changed the description to refer to x86 arch
instead of Intel arch.
It looks good to me.
Thanks
Dave
quoted hunk
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Subject: [PATCH 2/9] kexec_file: Allow arch-specific memory walking for
kexec_add_buffer
Allow architectures to specify a different memory walking function for
kexec_add_buffer. x86 uses iomem to track reserved memory ranges, but
PowerPC uses the memblock subsystem.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: Eric Biederman <redacted>
Cc: Dave Young <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
include/linux/kexec.h | 19 ++++++++++++++++++-
kernel/kexec_file.c | 30 ++++++++++++++++++++++--------
kernel/kexec_internal.h | 14 --------------
3 files changed, 40 insertions(+), 23 deletions(-)
@@ -472,14 +493,7 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,kbuf->top_down=top_down;/* Walk the RAM ranges and allocate a suitable range for the buffer */-if(image->type==KEXEC_TYPE_CRASH)-ret=walk_iomem_res_desc(crashk_res.desc,-IORESOURCE_SYSTEM_RAM|IORESOURCE_BUSY,-crashk_res.start,crashk_res.end,kbuf,-locate_mem_hole_callback);-else-ret=walk_system_ram_res(0,-1,kbuf,-locate_mem_hole_callback);+ret=arch_kexec_walk_mem(kbuf,locate_mem_hole_callback);if(ret!=1){/* A suitable memory range could not be found for buffer */return-EADDRNOTAVAIL;
From: Dave Young <hidden> Date: 2016-06-23 02:30:59
On 06/22/16 at 08:34pm, Thiago Jung Bauermann wrote:
quoted hunk
Am Mittwoch, 22 Juni 2016, 18:18:01 schrieb Dave Young:
quoted
On 06/21/16 at 04:48pm, Thiago Jung Bauermann wrote:
quoted
+/**
+ * kexec_locate_mem_hole - find free memory to load segment or use in
purgatory + * @image: kexec image being updated.
+ * @size: Memory size.
+ * @align: Minimum alignment needed.
+ * @min_addr: Minimum starting address.
+ * @max_addr: Maximum end address.
+ * @top_down Find the highest free memory region?
+ * @addr On success, will have start address of the memory region
found.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int kexec_locate_mem_hole(struct kimage *image, unsigned long size,
+ unsigned long align, unsigned long min_addr,
+ unsigned long max_addr, bool top_down,
+ unsigned long *addr)
+{
+ int ret;
+ struct kexec_buf buf;
+
+ memset(&buf, 0, sizeof(struct kexec_buf));
+ buf.image = image;
+
+ buf.memsz = size;
+ buf.buf_align = align;
+ buf.buf_min = min_addr;
+ buf.buf_max = max_addr;
+ buf.top_down = top_down;
Since patch 2/9 moved kexec_buf from internal header file to kexec.h it
will be natural to passing a kexec_buf pointer intead of passing all
these arguments in kexec_locate_mem_hole.
kbuf.mem can be used for addr.
Ok. What about this version?
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Subject: [PATCH 3/9] kexec_file: Factor out kexec_locate_mem_hole from
kexec_add_buffer.
kexec_locate_mem_hole will be used by the PowerPC kexec_file_load
implementation to find free memory for the purgatory stack.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: Eric Biederman <redacted>
Cc: Dave Young <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
include/linux/kexec.h | 12 +++++++++---
kernel/kexec_file.c | 25 ++++++++++++++++++++-----
2 files changed, 29 insertions(+), 8 deletions(-)
@@ -449,6 +449,23 @@ int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf,returnwalk_system_ram_res(0,ULONG_MAX,kbuf,func);}+/**+*kexec_locate_mem_hole-findfreememorytoloadsegmentoruseinpurgatory+*@kbuf:Parametersforthememorysearch.+*+*Onsuccess,kbuf->memwillhavethestartaddressofthememoryregionfound.+*+*Return:0onsuccess,negativeerrnoonerror.+*/+intkexec_locate_mem_hole(structkexec_buf*kbuf)+{+intret;++ret=arch_kexec_walk_mem(kbuf,locate_mem_hole_callback);++returnret==1?0:-EADDRNOTAVAIL;+}+/**Helperfunctionforplacingabufferinakexecsegment.Thisassumes*thatkexec_mutexisheld.
@@ -493,11 +510,9 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,kbuf->top_down=top_down;/* Walk the RAM ranges and allocate a suitable range for the buffer */-ret=arch_kexec_walk_mem(kbuf,locate_mem_hole_callback);-if(ret!=1){-/* A suitable memory range could not be found for buffer */-return-EADDRNOTAVAIL;-}+ret=kexec_locate_mem_hole(kbuf);+if(ret)+returnret;/* Found a suitable memory range */ksegment=&image->segment[image->nr_segments];
--
1.9.1
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
From: Dave Young <hidden> Date: 2016-06-23 05:44:50
----- Original Message -----
From: "Dave Young" <redacted>
To: "Thiago Jung Bauermann" <redacted>
Cc: linuxppc-dev@lists.ozlabs.org, kexec@lists.infradead.org, linux-kernel@vger.kernel.org, "Eric Biederman" <redacted>
Sent: Thursday, June 23, 2016 10:30:52 AM
Subject: Re: [PATCH v3 3/9] kexec_file: Factor out kexec_locate_mem_hole from kexec_add_buffer.
On 06/22/16 at 08:34pm, Thiago Jung Bauermann wrote:
quoted hunk
Am Mittwoch, 22 Juni 2016, 18:18:01 schrieb Dave Young:
quoted
On 06/21/16 at 04:48pm, Thiago Jung Bauermann wrote:
quoted
+/**
+ * kexec_locate_mem_hole - find free memory to load segment or use in
purgatory + * @image: kexec image being updated.
+ * @size: Memory size.
+ * @align: Minimum alignment needed.
+ * @min_addr: Minimum starting address.
+ * @max_addr: Maximum end address.
+ * @top_down Find the highest free memory region?
+ * @addr On success, will have start address of the memory region
found.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int kexec_locate_mem_hole(struct kimage *image, unsigned long size,
+ unsigned long align, unsigned long min_addr,
+ unsigned long max_addr, bool top_down,
+ unsigned long *addr)
+{
+ int ret;
+ struct kexec_buf buf;
+
+ memset(&buf, 0, sizeof(struct kexec_buf));
+ buf.image = image;
+
+ buf.memsz = size;
+ buf.buf_align = align;
+ buf.buf_min = min_addr;
+ buf.buf_max = max_addr;
+ buf.top_down = top_down;
Since patch 2/9 moved kexec_buf from internal header file to kexec.h it
will be natural to passing a kexec_buf pointer intead of passing all
these arguments in kexec_locate_mem_hole.
kbuf.mem can be used for addr.
Ok. What about this version?
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Subject: [PATCH 3/9] kexec_file: Factor out kexec_locate_mem_hole from
kexec_add_buffer.
kexec_locate_mem_hole will be used by the PowerPC kexec_file_load
implementation to find free memory for the purgatory stack.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: Eric Biederman <redacted>
Cc: Dave Young <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
include/linux/kexec.h | 12 +++++++++---
kernel/kexec_file.c | 25 ++++++++++++++++++++-----
2 files changed, 29 insertions(+), 8 deletions(-)
Hmm, hold on. For declaring a struct in a header file, comment should be
just after each fields, like below, your format is for a function instead:
struct pci_slot {
struct pci_bus *bus; /* The bus this slot is on */
struct list_head list; /* node in list of slots on this bus */
struct hotplug_slot *hotplug; /* Hotplug info (migrate over time) */
unsigned char number; /* PCI_SLOT(pci_dev->devfn) */
struct kobject kobj;
};
BTW, what is @size? there's no size field in kexec_buf. I think it is not
necessary to add these comment, they are easy to understand. If you really
want, please rewrite them correctly, for example "image" description is wrong.
It is not only for searching memory only, top_down description is also bad.
Thanks
Dave
Am Donnerstag, 23 Juni 2016, 01:44:07 schrieb Dave Young:
Hmm, hold on. For declaring a struct in a header file, comment should be
just after each fields, like below, your format is for a function instead:
struct pci_slot {
struct pci_bus *bus; /* The bus this slot is on */
struct list_head list; /* node in list of slots on this
bus */ struct hotplug_slot *hotplug; /* Hotplug info (migrate over
time) */ unsigned char number; /* PCI_SLOT(pci_dev->devfn) */
struct kobject kobj;
};
The comment style you mention above is not extractable documentation. The
style I used is what is described in section "kernel-doc for structs,
unions, enums, and typedefs" in Documentation/kernel-doc-nano-HOWTO.txt.
BTW, what is @size? there's no size field in kexec_buf. I think it is not
necessary to add these comment, they are easy to understand. If you really
want, please rewrite them correctly, for example "image" description is
wrong. It is not only for searching memory only, top_down description is
also bad.
Sorry, I moved these comments from kexec_locate_mem_hole but forgot to
rename the parameters to what they are called in struct kexec_buf. @size
should have been @memsz (other fields also have wrong names, I'll fix them
as well). The image description is correct in the context of where struct
kexec_buf is used and explains what it will be used for in the function
taking kexec_buf as an argument. It is not meant as a general description of
the purpose of struct kimage. What is bad about the description of top_down?
I decided to add these comments because struct kexec_buf is now part of the
kernel API for kexec. kernel-doc-nano-HOWTO.txt says:
We definitely need kernel-doc formatted documentation for functions
that are exported to loadable modules using EXPORT_SYMBOL.
We also look to provide kernel-doc formatted documentation for
functions externally visible to other kernel files (not marked
"static").
We also recommend providing kernel-doc formatted documentation
for private (file "static") routines, for consistency of kernel
source code layout. But this is lower priority and at the
discretion of the MAINTAINER of that kernel source file.
If you think they are not necessary or just add clutter I can leave them
out.
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Am Donnerstag, 23 Juni 2016, 09:57:51 schrieb Balbir Singh:
On 23/06/16 03:02, Thiago Jung Bauermann wrote:
quoted
quoted
quoted
3. have IMA pass-on its event log (where integrity measurements are
registered) accross kexec to the second kernel, so that the event
history is preserved.
OK.. and this is safe? Do both the kernels need to be signed by the
same certificate?
They don't. The integrity of the event log (assuming that is what you
mean by "this" in "this is safe") is guaranteed by the TPM device. Each
event in the measurement list extends a PCR and records its PCR value.
It is cryptographically guaranteed that if you replay the PCR extends
recorded in the event log and in the end of the process they match the
current PCR values in the TPM device, then that event log is correct.
What I meant was how does the new kernel know that the old kernel did not
cheat while passing on the values? I presume because we trust that kernel
via a signature.
Sorry, I still don't understand your concern. What kind of cheating? Which
values? If it's the values in the event log, there's no need to trust the
old kernel. The new kernel knows that the old kernel didn't pass wrong
measurement values in the event log because it can recalculate the PCR
extend operations recorded in the log and compare the results of the replay
with the current PCR values stored in the TPM device. If they match, then
the event log is guaranteed to be correct. If they don't match, either the
memory was corrupted somehow during the kexec process, or the old kernel
tried to pass a falsified event log.
There's no known way to construct an alternative series of PCR extend
operations that will result in the same final value in the PCR register of
the TPM device. If you can do that, you discovered a hash collision attack
on the SHA-1 or SHA-256 algorithms (depending on which algorithm is being
used by IMA in the event log). Or a bug in the TPM device implementation.
and
How do we know the new kernel is safe to load - I guess via a signature
that the new kernel is signed with (assuming it is present in the key
ring).
Correct. That goal is met by signature verification, not by integrity
assurance.
I'll note that even with both of my patch series there's still code missing
for kernel signature verification in PowerPC. I believe there's not a file
format defined yet for how to store a signature in a PowerPC kernel image.
Integrity assurance doesn't depend on kernel signature verification though.
There's value in both my patch series even without kernel signature
verification support. They're complementary features.
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Am Donnerstag, 23 Juni 2016, 09:57:51 schrieb Balbir Singh:
quoted
On 23/06/16 03:02, Thiago Jung Bauermann wrote:
quoted
quoted
quoted
3. have IMA pass-on its event log (where integrity measurements are
registered) accross kexec to the second kernel, so that the event
history is preserved.
OK.. and this is safe? Do both the kernels need to be signed by the
same certificate?
They don't. The integrity of the event log (assuming that is what you
mean by "this" in "this is safe") is guaranteed by the TPM device. Each
event in the measurement list extends a PCR and records its PCR value.
It is cryptographically guaranteed that if you replay the PCR extends
recorded in the event log and in the end of the process they match the
current PCR values in the TPM device, then that event log is correct.
What I meant was how does the new kernel know that the old kernel did not
cheat while passing on the values? I presume because we trust that kernel
via a signature.
Sorry, I still don't understand your concern. What kind of cheating? Which
values? If it's the values in the event log, there's no need to trust the
old kernel. The new kernel knows that the old kernel didn't pass wrong
measurement values in the event log because it can recalculate the PCR
extend operations recorded in the log and compare the results of the replay
with the current PCR values stored in the TPM device. If they match, then
the event log is guaranteed to be correct. If they don't match, either the
memory was corrupted somehow during the kexec process, or the old kernel
tried to pass a falsified event log.
Yep, get it/got it. My concern was anything using passed on the values should
compare the results with the current PCR values.
BTW, what do we gain by passing the values if we are relying on the PCR registers
anyway, can't we directly read them off from there? Aren't we going to ready anyway
to compare, what does passing the values gain?
[snip]
quoted
and
How do we know the new kernel is safe to load - I guess via a signature
that the new kernel is signed with (assuming it is present in the key
ring).
Correct. That goal is met by signature verification, not by integrity
assurance.
I'll note that even with both of my patch series there's still code missing
for kernel signature verification in PowerPC. I believe there's not a file
format defined yet for how to store a signature in a PowerPC kernel image.
Integrity assurance doesn't depend on kernel signature verification though.
There's value in both my patch series even without kernel signature
verification support. They're complementary features.
Am Freitag, 24 Juni 2016, 08:33:24 schrieb Balbir Singh:
On 24/06/16 02:44, Thiago Jung Bauermann wrote:
quoted
Sorry, I still don't understand your concern. What kind of cheating?
Which values? If it's the values in the event log, there's no need to
trust the old kernel. The new kernel knows that the old kernel didn't
pass wrong measurement values in the event log because it can
recalculate the PCR extend operations recorded in the log and compare
the results of the replay with the current PCR values stored in the TPM
device. If they match, then the event log is guaranteed to be correct.
If they don't match, either the memory was corrupted somehow during the
kexec process, or the old kernel tried to pass a falsified event log.
Yep, get it/got it. My concern was anything using passed on the values
should compare the results with the current PCR values.
BTW, what do we gain by passing the values if we are relying on the PCR
registers anyway, can't we directly read them off from there? Aren't we
going to ready anyway to compare, what does passing the values gain?
The PCR values themselves change for reasons that the application/user may
not care about. For example, just changing the order in which measurements
are made changes the final value of the PCR, even if all the measurements
themselves don't change. And in current multi-processor machines this order
does change at each boot, so you can't rely on two boots of the same machine
with the same software to have the same PCR values.
Also, you may want to verify only the measurement of one of the components
and not care about the other components.
With an event log, you can verify the checksum of each measured component
individually, and the PCR value serves to confirm that the event log is
correct. Just having the final PCR value without the event log, you don't
know which measurements were made.
quoted
quoted
and
How do we know the new kernel is safe to load - I guess via a signature
that the new kernel is signed with (assuming it is present in the key
ring).
Correct. That goal is met by signature verification, not by integrity
assurance.
I'll note that even with both of my patch series there's still code
missing for kernel signature verification in PowerPC. I believe there's
not a file format defined yet for how to store a signature in a PowerPC
kernel image.
Integrity assurance doesn't depend on kernel signature verification
though. There's value in both my patch series even without kernel
signature verification support. They're complementary features.
Thanks for clarifying
Thank you for your interest.
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
From: Dave Young <hidden> Date: 2016-06-27 16:20:07
On 06/23/16 at 12:37pm, Thiago Jung Bauermann wrote:
Am Donnerstag, 23 Juni 2016, 01:44:07 schrieb Dave Young:
quoted
Hmm, hold on. For declaring a struct in a header file, comment should be
just after each fields, like below, your format is for a function instead:
struct pci_slot {
struct pci_bus *bus; /* The bus this slot is on */
struct list_head list; /* node in list of slots on this
bus */ struct hotplug_slot *hotplug; /* Hotplug info (migrate over
time) */ unsigned char number; /* PCI_SLOT(pci_dev->devfn) */
struct kobject kobj;
};
The comment style you mention above is not extractable documentation. The
style I used is what is described in section "kernel-doc for structs,
unions, enums, and typedefs" in Documentation/kernel-doc-nano-HOWTO.txt.
You are right and I was wrong!
quoted
BTW, what is @size? there's no size field in kexec_buf. I think it is not
necessary to add these comment, they are easy to understand. If you really
want, please rewrite them correctly, for example "image" description is
wrong. It is not only for searching memory only, top_down description is
also bad.
Sorry, I moved these comments from kexec_locate_mem_hole but forgot to
rename the parameters to what they are called in struct kexec_buf. @size
should have been @memsz (other fields also have wrong names, I'll fix them
as well). The image description is correct in the context of where struct
kexec_buf is used and explains what it will be used for in the function
taking kexec_buf as an argument. It is not meant as a general description of
the purpose of struct kimage. What is bad about the description of top_down?
It is not clear enough to me, I personally think the original one in
source code is better:
/* allocate from top of memory hole */
I decided to add these comments because struct kexec_buf is now part of the
kernel API for kexec. kernel-doc-nano-HOWTO.txt says:
quoted
We definitely need kernel-doc formatted documentation for functions
that are exported to loadable modules using EXPORT_SYMBOL.
We also look to provide kernel-doc formatted documentation for
functions externally visible to other kernel files (not marked
"static").
We also recommend providing kernel-doc formatted documentation
for private (file "static") routines, for consistency of kernel
source code layout. But this is lower priority and at the
discretion of the MAINTAINER of that kernel source file.
If you think they are not necessary or just add clutter I can leave them
out.
Am Dienstag, 28 Juni 2016, 00:19:48 schrieb Dave Young:
On 06/23/16 at 12:37pm, Thiago Jung Bauermann wrote:
quoted
Am Donnerstag, 23 Juni 2016, 01:44:07 schrieb Dave Young:
What is bad about the description of top_down?
It is not clear enough to me, I personally think the original one in
source code is better:
/* allocate from top of memory hole */
Actually I realized there's some discrepancy in how the x86 code uses
top_down and how I need it to work in powerpc. This may be what is confusing
about my comment and the existing comment.
x86 always walks memory from bottom to top but if top_down is true, in each
memory region it will allocate the memory hole in the highest address within
that region. I don't know why it is done that way, though.
On powerpc, the memory walk itself should be from top to bottom, as well as
the memory hole allocation within each memory region.
Should I add a separate top_down argument to kexec_locate_mem_hole to
control if the memory walk should be from top to bottom, and then the
bottom_up member of struct kexec_buf controls where inside each memory
region the memory hole will be allocated?
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Am Montag, 27 Juni 2016, 13:37:58 schrieb Thiago Jung Bauermann:
Should I add a separate top_down argument to kexec_locate_mem_hole to
control if the memory walk should be from top to bottom, and then the
bottom_up member of struct kexec_buf controls where inside each memory
region the memory hole will be allocated?
Er, "...the bottom_up member of struct kexec_buf..." should read "...the
top_down member of struct kexec buf...".
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
From: Dave Young <hidden> Date: 2016-06-27 20:21:38
Please ignore previous reply, I mistakenly send a broken mail without
subject, sorry about it. Resend the reply here.
On 06/27/16 at 01:37pm, Thiago Jung Bauermann wrote:
Am Dienstag, 28 Juni 2016, 00:19:48 schrieb Dave Young:
quoted
On 06/23/16 at 12:37pm, Thiago Jung Bauermann wrote:
quoted
Am Donnerstag, 23 Juni 2016, 01:44:07 schrieb Dave Young:
What is bad about the description of top_down?
It is not clear enough to me, I personally think the original one in
source code is better:
/* allocate from top of memory hole */
Actually I realized there's some discrepancy in how the x86 code uses
top_down and how I need it to work in powerpc. This may be what is confusing
about my comment and the existing comment.
x86 always walks memory from bottom to top but if top_down is true, in each
memory region it will allocate the memory hole in the highest address within
that region. I don't know why it is done that way, though.
I think we did not meaning to do this, considering kdump we have only
one crashkernel region for searching (crashk_res) so it is fine.
For kexec maybe changing the walking function to accept top_down is
reasonable.
Ccing Vivek see if he can remember something..
On powerpc, the memory walk itself should be from top to bottom, as well as
the memory hole allocation within each memory region.
Should I add a separate top_down argument to kexec_locate_mem_hole to
control if the memory walk should be from top to bottom, and then the
bottom_up member of struct kexec_buf controls where inside each memory
region the memory hole will be allocated?
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
From: Dave Young <hidden> Date: 2016-06-28 19:27:53
On 06/27/16 at 04:21pm, Dave Young wrote:
Please ignore previous reply, I mistakenly send a broken mail without
subject, sorry about it. Resend the reply here.
On 06/27/16 at 01:37pm, Thiago Jung Bauermann wrote:
quoted
Am Dienstag, 28 Juni 2016, 00:19:48 schrieb Dave Young:
quoted
On 06/23/16 at 12:37pm, Thiago Jung Bauermann wrote:
quoted
Am Donnerstag, 23 Juni 2016, 01:44:07 schrieb Dave Young:
What is bad about the description of top_down?
It is not clear enough to me, I personally think the original one in
source code is better:
/* allocate from top of memory hole */
Actually I realized there's some discrepancy in how the x86 code uses
top_down and how I need it to work in powerpc. This may be what is confusing
about my comment and the existing comment.
x86 always walks memory from bottom to top but if top_down is true, in each
memory region it will allocate the memory hole in the highest address within
that region. I don't know why it is done that way, though.
I think we did not meaning to do this, considering kdump we have only
one crashkernel region for searching (crashk_res) so it is fine.
For kexec maybe changing the walking function to accept top_down is
reasonable.
Ccing Vivek see if he can remember something..
quoted
On powerpc, the memory walk itself should be from top to bottom, as well as
the memory hole allocation within each memory region.
What is the particular reason in powerpc for a mandatory top to bottom
walking?
quoted
Should I add a separate top_down argument to kexec_locate_mem_hole to
control if the memory walk should be from top to bottom, and then the
bottom_up member of struct kexec_buf controls where inside each memory
region the memory hole will be allocated?
Using one argument for both sounds more reasonable than using a separate
argument for memory walk..
Thanks
Dave
Am Donnerstag, 23 Juni 2016, 10:25:06 schrieb Dave Young:
On 06/22/16 at 08:30pm, Thiago Jung Bauermann wrote:
quoted
Am Mittwoch, 22 Juni 2016, 18:20:47 schrieb Dave Young:
quoted
The patch looks good, but could the subject be more specific?
For example just like the first sentence of the patch descriotion:
Allow architectures to specify their own memory walking function
Ok, What about this? I also changed the description to refer to x86 arch
instead of Intel arch.
It looks good to me.
This version has the struct kexec_buf documentation comments that were
in patch 3/9. I fixed the names of the struct members, and changed their
descriptions to try to be clearer.
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Subject: [PATCH 2/9] kexec_file: Allow arch-specific memory walking for
kexec_add_buffer
Allow architectures to specify a different memory walking function for
kexec_add_buffer. x86 uses iomem to track reserved memory ranges, but
PowerPC uses the memblock subsystem.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: Eric Biederman <redacted>
Cc: Dave Young <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
include/linux/kexec.h | 25 ++++++++++++++++++++++++-
kernel/kexec_file.c | 30 ++++++++++++++++++++++--------
kernel/kexec_internal.h | 14 --------------
3 files changed, 46 insertions(+), 23 deletions(-)
@@ -472,14 +493,7 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,kbuf->top_down=top_down;/* Walk the RAM ranges and allocate a suitable range for the buffer */-if(image->type==KEXEC_TYPE_CRASH)-ret=walk_iomem_res_desc(crashk_res.desc,-IORESOURCE_SYSTEM_RAM|IORESOURCE_BUSY,-crashk_res.start,crashk_res.end,kbuf,-locate_mem_hole_callback);-else-ret=walk_system_ram_res(0,-1,kbuf,-locate_mem_hole_callback);+ret=arch_kexec_walk_mem(kbuf,locate_mem_hole_callback);if(ret!=1){/* A suitable memory range could not be found for buffer */return-EADDRNOTAVAIL;
Am Dienstag, 28 Juni 2016, 15:20:55 schrieb Dave Young:
On 06/27/16 at 04:21pm, Dave Young wrote:
quoted
Please ignore previous reply, I mistakenly send a broken mail without
subject, sorry about it. Resend the reply here.
On 06/27/16 at 01:37pm, Thiago Jung Bauermann wrote:
quoted
Am Dienstag, 28 Juni 2016, 00:19:48 schrieb Dave Young:
quoted
On 06/23/16 at 12:37pm, Thiago Jung Bauermann wrote:
quoted
Am Donnerstag, 23 Juni 2016, 01:44:07 schrieb Dave Young:
What is bad about the description of top_down?
It is not clear enough to me, I personally think the original one in
source code is better:
/* allocate from top of memory hole */
Actually I realized there's some discrepancy in how the x86 code uses
top_down and how I need it to work in powerpc. This may be what is
confusing about my comment and the existing comment.
x86 always walks memory from bottom to top but if top_down is true, in
each memory region it will allocate the memory hole in the highest
address within that region. I don't know why it is done that way,
though.
I think we did not meaning to do this, considering kdump we have only
one crashkernel region for searching (crashk_res) so it is fine.
For kexec maybe changing the walking function to accept top_down is
reasonable.
Ccing Vivek see if he can remember something..
quoted
On powerpc, the memory walk itself should be from top to bottom, as
well as the memory hole allocation within each memory region.
What is the particular reason in powerpc for a mandatory top to bottom
walking?
I'm walking unreserved memory ranges, so reservations made low in memory
(such as the reservation for the initrd) may create a memory hole that is a
lot lower than the true memory limit where I want to allocate from (768 MB).
In this situation, allocating at the highest address in the lowest free
memory range will allocate the buffer very low in memory, and in that case
top_down doesn't mean much.
Walking memory from lowest to highest address but then allocating memory at
the highest address inside the memory range is peculiar and surprising. Is
there a particular reason for it?
If it's an accident and doesn't affect x86, I'd suggest that top_down should
have its expected behavior, which (at least for me) is: allocate from the
highest available memory address within the desired range.
In any case, my patch series allows each architecture to define what
top_down should mean. It doesn't change the behavior in x86, since
the default implementation of arch_kexec_walk_mem ignores
kexec_buf.top_down, and allows powerpc to take top_down into account
when walking memory.
quoted
quoted
Should I add a separate top_down argument to kexec_locate_mem_hole to
control if the memory walk should be from top to bottom, and then the
bottom_up member of struct kexec_buf controls where inside each memory
region the memory hole will be allocated?
Using one argument for both sounds more reasonable than using a separate
argument for memory walk..
I agree. This patch doesn't use a separate top_down argument, it's the same
patch I sent earlier except that the comments to struct kexec_buf are in
patch 2/9. What do you think?
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Subject: [PATCH 3/9] kexec_file: Factor out kexec_locate_mem_hole from
kexec_add_buffer.
kexec_locate_mem_hole will be used by the PowerPC kexec_file_load
implementation to find free memory for the purgatory stack.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: Eric Biederman <redacted>
Cc: Dave Young <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
include/linux/kexec.h | 1 +
kernel/kexec_file.c | 25 ++++++++++++++++++++-----
2 files changed, 21 insertions(+), 5 deletions(-)
@@ -449,6 +449,23 @@ int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf,returnwalk_system_ram_res(0,ULONG_MAX,kbuf,func);}+/**+*kexec_locate_mem_hole-findfreememorytoloadsegmentoruseinpurgatory+*@kbuf:Parametersforthememorysearch.+*+*Onsuccess,kbuf->memwillhavethestartaddressofthememoryregionfound.+*+*Return:0onsuccess,negativeerrnoonerror.+*/+intkexec_locate_mem_hole(structkexec_buf*kbuf)+{+intret;++ret=arch_kexec_walk_mem(kbuf,locate_mem_hole_callback);++returnret==1?0:-EADDRNOTAVAIL;+}+/**Helperfunctionforplacingabufferinakexecsegment.Thisassumes*thatkexec_mutexisheld.
@@ -493,11 +510,9 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,kbuf->top_down=top_down;/* Walk the RAM ranges and allocate a suitable range for the buffer */-ret=arch_kexec_walk_mem(kbuf,locate_mem_hole_callback);-if(ret!=1){-/* A suitable memory range could not be found for buffer */-return-EADDRNOTAVAIL;-}+ret=kexec_locate_mem_hole(kbuf);+if(ret)+returnret;/* Found a suitable memory range */ksegment=&image->segment[image->nr_segments];
From: Dave Young <hidden> Date: 2016-06-29 19:45:32
On 06/28/16 at 07:18pm, Thiago Jung Bauermann wrote:
Am Dienstag, 28 Juni 2016, 15:20:55 schrieb Dave Young:
quoted
On 06/27/16 at 04:21pm, Dave Young wrote:
quoted
Please ignore previous reply, I mistakenly send a broken mail without
subject, sorry about it. Resend the reply here.
On 06/27/16 at 01:37pm, Thiago Jung Bauermann wrote:
quoted
Am Dienstag, 28 Juni 2016, 00:19:48 schrieb Dave Young:
quoted
On 06/23/16 at 12:37pm, Thiago Jung Bauermann wrote:
quoted
Am Donnerstag, 23 Juni 2016, 01:44:07 schrieb Dave Young:
What is bad about the description of top_down?
It is not clear enough to me, I personally think the original one in
source code is better:
/* allocate from top of memory hole */
Actually I realized there's some discrepancy in how the x86 code uses
top_down and how I need it to work in powerpc. This may be what is
confusing about my comment and the existing comment.
x86 always walks memory from bottom to top but if top_down is true, in
each memory region it will allocate the memory hole in the highest
address within that region. I don't know why it is done that way,
though.
I think we did not meaning to do this, considering kdump we have only
one crashkernel region for searching (crashk_res) so it is fine.
For kexec maybe changing the walking function to accept top_down is
reasonable.
Ccing Vivek see if he can remember something..
quoted
On powerpc, the memory walk itself should be from top to bottom, as
well as the memory hole allocation within each memory region.
What is the particular reason in powerpc for a mandatory top to bottom
walking?
I'm walking unreserved memory ranges, so reservations made low in memory
(such as the reservation for the initrd) may create a memory hole that is a
lot lower than the true memory limit where I want to allocate from (768 MB).
In this situation, allocating at the highest address in the lowest free
memory range will allocate the buffer very low in memory, and in that case
top_down doesn't mean much.
Walking memory from lowest to highest address but then allocating memory at
the highest address inside the memory range is peculiar and surprising. Is
there a particular reason for it?
I do not know if there's some historic reason, personally I think it
should be an accident.
If it's an accident and doesn't affect x86, I'd suggest that top_down should
have its expected behavior, which (at least for me) is: allocate from the
highest available memory address within the desired range.
I tend to agree, but we need test it first to see if it breaks something.
In any case, my patch series allows each architecture to define what
top_down should mean. It doesn't change the behavior in x86, since
the default implementation of arch_kexec_walk_mem ignores
kexec_buf.top_down, and allows powerpc to take top_down into account
when walking memory.
quoted
quoted
quoted
Should I add a separate top_down argument to kexec_locate_mem_hole to
control if the memory walk should be from top to bottom, and then the
bottom_up member of struct kexec_buf controls where inside each memory
region the memory hole will be allocated?
Using one argument for both sounds more reasonable than using a separate
argument for memory walk..
I agree. This patch doesn't use a separate top_down argument, it's the same
patch I sent earlier except that the comments to struct kexec_buf are in
patch 2/9. What do you think?
It looks good except one nitpick inline..
quoted hunk
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Subject: [PATCH 3/9] kexec_file: Factor out kexec_locate_mem_hole from
kexec_add_buffer.
kexec_locate_mem_hole will be used by the PowerPC kexec_file_load
implementation to find free memory for the purgatory stack.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: Eric Biederman <redacted>
Cc: Dave Young <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
include/linux/kexec.h | 1 +
kernel/kexec_file.c | 25 ++++++++++++++++++++-----
2 files changed, 21 insertions(+), 5 deletions(-)
@@ -449,6 +449,23 @@ int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf,returnwalk_system_ram_res(0,ULONG_MAX,kbuf,func);}+/**+*kexec_locate_mem_hole-findfreememorytoloadsegmentoruseinpurgatory
It is not necessary to use only for purgatory load..
quoted hunk
+ * @kbuf: Parameters for the memory search.
+ *
+ * On success, kbuf->mem will have the start address of the memory region found.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int kexec_locate_mem_hole(struct kexec_buf *kbuf)
+{
+ int ret;
+
+ ret = arch_kexec_walk_mem(kbuf, locate_mem_hole_callback);
+
+ return ret == 1 ? 0 : -EADDRNOTAVAIL;
+}
+
/*
* Helper function for placing a buffer in a kexec segment. This assumes
* that kexec_mutex is held.
@@ -493,11 +510,9 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz, kbuf->top_down = top_down; /* Walk the RAM ranges and allocate a suitable range for the buffer */- ret = arch_kexec_walk_mem(kbuf, locate_mem_hole_callback);- if (ret != 1) {- /* A suitable memory range could not be found for buffer */- return -EADDRNOTAVAIL;- }+ ret = kexec_locate_mem_hole(kbuf);+ if (ret)+ return ret; /* Found a suitable memory range */ ksegment = &image->segment[image->nr_segments];
From: Dave Young <hidden> Date: 2016-06-29 19:48:21
On 06/28/16 at 07:18pm, Thiago Jung Bauermann wrote:
quoted hunk
Am Donnerstag, 23 Juni 2016, 10:25:06 schrieb Dave Young:
quoted
On 06/22/16 at 08:30pm, Thiago Jung Bauermann wrote:
quoted
Am Mittwoch, 22 Juni 2016, 18:20:47 schrieb Dave Young:
quoted
The patch looks good, but could the subject be more specific?
For example just like the first sentence of the patch descriotion:
Allow architectures to specify their own memory walking function
Ok, What about this? I also changed the description to refer to x86 arch
instead of Intel arch.
It looks good to me.
This version has the struct kexec_buf documentation comments that were
in patch 3/9. I fixed the names of the struct members, and changed their
descriptions to try to be clearer.
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Subject: [PATCH 2/9] kexec_file: Allow arch-specific memory walking for
kexec_add_buffer
Allow architectures to specify a different memory walking function for
kexec_add_buffer. x86 uses iomem to track reserved memory ranges, but
PowerPC uses the memblock subsystem.
Signed-off-by: Thiago Jung Bauermann <redacted>
Cc: Eric Biederman <redacted>
Cc: Dave Young <redacted>
Cc: kexec@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
include/linux/kexec.h | 25 ++++++++++++++++++++++++-
kernel/kexec_file.c | 30 ++++++++++++++++++++++--------
kernel/kexec_internal.h | 14 --------------
3 files changed, 46 insertions(+), 23 deletions(-)
Rethink about the first patch, you dropped the user buffer in kexec_buf
But later your passing IMA digests buffer patchset may need use it.
So keep it in kexec_buf should be better.
For the IMA buffer patchset I'm still reading and learning the
background, will reply them later.
@@ -472,14 +493,7 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz,kbuf->top_down=top_down;/* Walk the RAM ranges and allocate a suitable range for the buffer */-if(image->type==KEXEC_TYPE_CRASH)-ret=walk_iomem_res_desc(crashk_res.desc,-IORESOURCE_SYSTEM_RAM|IORESOURCE_BUSY,-crashk_res.start,crashk_res.end,kbuf,-locate_mem_hole_callback);-else-ret=walk_system_ram_res(0,-1,kbuf,-locate_mem_hole_callback);+ret=arch_kexec_walk_mem(kbuf,locate_mem_hole_callback);if(ret!=1){/* A suitable memory range could not be found for buffer */return-EADDRNOTAVAIL;
Am Mittwoch, 29 Juni 2016, 15:45:18 schrieb Dave Young:
On 06/28/16 at 07:18pm, Thiago Jung Bauermann wrote:
quoted
Am Dienstag, 28 Juni 2016, 15:20:55 schrieb Dave Young:
quoted
On 06/27/16 at 04:21pm, Dave Young wrote:
Using one argument for both sounds more reasonable than using a
separate
argument for memory walk..
I agree. This patch doesn't use a separate top_down argument, it's the
same patch I sent earlier except that the comments to struct kexec_buf
are in patch 2/9. What do you think?
It looks good except one nitpick inline..
quoted
+/**
+ * kexec_locate_mem_hole - find free memory to load segment or use in
purgatory
It is not necessary to use only for purgatory load..
Ok, what about this?
/**
* kexec_locate_mem_hole - find free memory in a given kimage.
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
memory + * @image: kexec image in which memory to search.
+ * @mem: On return will have address of the buffer in memory.
+ * @memsz: Size for the buffer in memory.
+ * @buf_align: Minimum alignment needed.
+ * @buf_min: The buffer can't be placed below this address.
+ * @buf_max: The buffer can't be placed above this address.
+ * @top_down: Allocate from top of memory.
+ */
+struct kexec_buf {
+ struct kimage *image;
+ unsigned long mem;
+ unsigned long memsz;
+ unsigned long buf_align;
+ unsigned long buf_min;
+ unsigned long buf_max;
+ bool top_down;
+};
Rethink about the first patch, you dropped the user buffer in kexec_buf
But later your passing IMA digests buffer patchset may need use it.
So keep it in kexec_buf should be better.
I'm not following. The IMA buffer patchset doesn't use kexec_locate_mem_hole
nor struct kexec_buf.
For the IMA buffer patchset I'm still reading and learning the
background, will reply them later.
Thank you!
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
memory + * @image: kexec image in which memory to search.
+ * @mem: On return will have address of the buffer in memory.
+ * @memsz: Size for the buffer in memory.
+ * @buf_align: Minimum alignment needed.
+ * @buf_min: The buffer can't be placed below this address.
+ * @buf_max: The buffer can't be placed above this address.
+ * @top_down: Allocate from top of memory.
+ */
+struct kexec_buf {
+ struct kimage *image;
+ unsigned long mem;
+ unsigned long memsz;
+ unsigned long buf_align;
+ unsigned long buf_min;
+ unsigned long buf_max;
+ bool top_down;
+};
Rethink about the first patch, you dropped the user buffer in kexec_buf
But later your passing IMA digests buffer patchset may need use it.
So keep it in kexec_buf should be better.
I'm not following. The IMA buffer patchset doesn't use kexec_locate_mem_hole
nor struct kexec_buf.
It does not use kexec_locate_mem_hole, but the buffer being passed is
very similar to a kexec_buf struct, no?
So you may refactor kexec_add_buffer and your new function to pass only kimage
and a kbuf, it will be better than passing all those arguments separately.
quoted
For the IMA buffer patchset I'm still reading and learning the
background, will reply them later.
Thank you!
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
From: Dave Young <hidden> Date: 2016-06-30 15:41:33
On 06/29/16 at 06:09pm, Thiago Jung Bauermann wrote:
Am Mittwoch, 29 Juni 2016, 15:45:18 schrieb Dave Young:
quoted
On 06/28/16 at 07:18pm, Thiago Jung Bauermann wrote:
quoted
Am Dienstag, 28 Juni 2016, 15:20:55 schrieb Dave Young:
quoted
On 06/27/16 at 04:21pm, Dave Young wrote:
Using one argument for both sounds more reasonable than using a
separate
argument for memory walk..
I agree. This patch doesn't use a separate top_down argument, it's the
same patch I sent earlier except that the comments to struct kexec_buf
are in patch 2/9. What do you think?
It looks good except one nitpick inline..
quoted
+/**
+ * kexec_locate_mem_hole - find free memory to load segment or use in
purgatory
quoted
It is not necessary to use only for purgatory load..
Ok, what about this?
/**
* kexec_locate_mem_hole - find free memory in a given kimage.
Hmm, a given kimage sounds not correct, I can not get a better way to
describe it. How about below with a little change to your previous one:
kexec_locate_mem_hole - find a free chunk of memory to load kexec segment.
In powerpc the memory chunk can also be used for the purgatory stack.
Thanks
Dave
Am Donnerstag, 30 Juni 2016, 11:07:00 schrieb Dave Young:
On 06/29/16 at 06:18pm, Thiago Jung Bauermann wrote:
quoted
Am Mittwoch, 29 Juni 2016, 15:47:51 schrieb Dave Young:
quoted
On 06/28/16 at 07:18pm, Thiago Jung Bauermann wrote:
quoted
+/**
+ * struct kexec_buf - parameters for finding a place for a buffer
in
memory + * @image: kexec image in which memory to search.
+ * @mem: On return will have address of the buffer in memory.
+ * @memsz: Size for the buffer in memory.
+ * @buf_align: Minimum alignment needed.
+ * @buf_min: The buffer can't be placed below this address.
+ * @buf_max: The buffer can't be placed above this address.
+ * @top_down: Allocate from top of memory.
+ */
+struct kexec_buf {
+ struct kimage *image;
+ unsigned long mem;
+ unsigned long memsz;
+ unsigned long buf_align;
+ unsigned long buf_min;
+ unsigned long buf_max;
+ bool top_down;
+};
Rethink about the first patch, you dropped the user buffer in
kexec_buf
But later your passing IMA digests buffer patchset may need use it.
So keep it in kexec_buf should be better.
I'm not following. The IMA buffer patchset doesn't use
kexec_locate_mem_hole nor struct kexec_buf.
It does not use kexec_locate_mem_hole, but the buffer being passed is
very similar to a kexec_buf struct, no?
If what you're saying is that the arguments passed to
kexec_add_handover_buffer in the IMA buffer patchset are very similar to the
arguments passed to kexec_add_buffer then yes, it's true.
So you may refactor kexec_add_buffer and your new function to pass only
kimage and a kbuf, it will be better than passing all those arguments
separately.
To be honest I think struct kexec_buf is an implementation detail inside
kexec_locate_mem_hole, made necessary because the callback functions it uses
need to access its arguments. Callers of kexec_locate_mem_hole,
kexec_add_handover_buffer and kexec_add_buffer shouldn't need to know it
exists.
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Am Donnerstag, 30 Juni 2016, 11:41:19 schrieb Dave Young:
On 06/29/16 at 06:09pm, Thiago Jung Bauermann wrote:
quoted
Am Mittwoch, 29 Juni 2016, 15:45:18 schrieb Dave Young:
quoted
On 06/28/16 at 07:18pm, Thiago Jung Bauermann wrote:
quoted
Am Dienstag, 28 Juni 2016, 15:20:55 schrieb Dave Young:
quoted
On 06/27/16 at 04:21pm, Dave Young wrote:
It looks good except one nitpick inline..
quoted
+/**
+ * kexec_locate_mem_hole - find free memory to load segment or use
in
purgatory
It is not necessary to use only for purgatory load..
Ok, what about this?
/**
* kexec_locate_mem_hole - find free memory in a given kimage.
Hmm, a given kimage sounds not correct, I can not get a better way to
describe it. How about below with a little change to your previous one:
kexec_locate_mem_hole - find a free chunk of memory to load kexec segment.
In powerpc the memory chunk can also be used for the purgatory stack.
That describes what the memory currently is used for. If powerpc or any
other architecture starts to use the memory for something else, this comment
would need to be updated. :-)
What the function really does is find free memory in the physical address
space after the currently running kernel hands over control to whatever runs
next. What that memory is used for is decided by the caller of the function.
Since (at least for now), the only things that run next are the purgatory
and the next kernel, what about this?
kexec_locate_mem_hole - find free memory for the purgatory or the next
kernel
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Am Donnerstag, 30 Juni 2016, 12:49:44 schrieb Thiago Jung Bauermann:
Am Donnerstag, 30 Juni 2016, 11:07:00 schrieb Dave Young:
quoted
On 06/29/16 at 06:18pm, Thiago Jung Bauermann wrote:
quoted
I'm not following. The IMA buffer patchset doesn't use
kexec_locate_mem_hole nor struct kexec_buf.
It does not use kexec_locate_mem_hole, but the buffer being passed is
very similar to a kexec_buf struct, no?
If what you're saying is that the arguments passed to
kexec_add_handover_buffer in the IMA buffer patchset are very similar to
the arguments passed to kexec_add_buffer then yes, it's true.
quoted
So you may refactor kexec_add_buffer and your new function to pass only
kimage and a kbuf, it will be better than passing all those arguments
separately.
To be honest I think struct kexec_buf is an implementation detail inside
kexec_locate_mem_hole, made necessary because the callback functions it
uses need to access its arguments. Callers of kexec_locate_mem_hole,
kexec_add_handover_buffer and kexec_add_buffer shouldn't need to know it
exists.
Elaborating a bit more: the argument list for these three functions are
equal or similar because kexec_add_handover_buffer uses kexec_add_buffer,
which uses kexec_locate_mem_hole.
It could be beneficial to have a struct to collect the arguments to these
functions if someone using one of them would be likely to use another one
with the same arguments. In that case, you set up kexec_buf once and then
just pass it whenever you need to call one of those functions.
But that is unlikely to happen. A user of the kexec API will need to use
only one of these functions with a given set of arguments, so they don't
gain anything by setting up a struct.
Syntactically, I also don't think it's clearer to set struct members instead
of simply passing arguments to a function, even if the argument list is
long.
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
From: Dave Young <hidden> Date: 2016-06-30 21:37:39
On 06/30/16 at 01:08pm, Thiago Jung Bauermann wrote:
Am Donnerstag, 30 Juni 2016, 11:41:19 schrieb Dave Young:
quoted
On 06/29/16 at 06:09pm, Thiago Jung Bauermann wrote:
quoted
Am Mittwoch, 29 Juni 2016, 15:45:18 schrieb Dave Young:
quoted
On 06/28/16 at 07:18pm, Thiago Jung Bauermann wrote:
quoted
Am Dienstag, 28 Juni 2016, 15:20:55 schrieb Dave Young:
quoted
On 06/27/16 at 04:21pm, Dave Young wrote:
It looks good except one nitpick inline..
quoted
+/**
+ * kexec_locate_mem_hole - find free memory to load segment or use
in
purgatory
It is not necessary to use only for purgatory load..
Ok, what about this?
/**
* kexec_locate_mem_hole - find free memory in a given kimage.
Hmm, a given kimage sounds not correct, I can not get a better way to
describe it. How about below with a little change to your previous one:
kexec_locate_mem_hole - find a free chunk of memory to load kexec segment.
In powerpc the memory chunk can also be used for the purgatory stack.
That describes what the memory currently is used for. If powerpc or any
other architecture starts to use the memory for something else, this comment
would need to be updated. :-)
What the function really does is find free memory in the physical address
space after the currently running kernel hands over control to whatever runs
next. What that memory is used for is decided by the caller of the function.
Since (at least for now), the only things that run next are the purgatory
and the next kernel, what about this?
kexec_locate_mem_hole - find free memory for the purgatory or the next
kernel
From: Dave Young <hidden> Date: 2016-06-30 21:44:10
On 06/30/16 at 01:42pm, Thiago Jung Bauermann wrote:
Am Donnerstag, 30 Juni 2016, 12:49:44 schrieb Thiago Jung Bauermann:
quoted
Am Donnerstag, 30 Juni 2016, 11:07:00 schrieb Dave Young:
quoted
On 06/29/16 at 06:18pm, Thiago Jung Bauermann wrote:
quoted
I'm not following. The IMA buffer patchset doesn't use
kexec_locate_mem_hole nor struct kexec_buf.
It does not use kexec_locate_mem_hole, but the buffer being passed is
very similar to a kexec_buf struct, no?
If what you're saying is that the arguments passed to
kexec_add_handover_buffer in the IMA buffer patchset are very similar to
the arguments passed to kexec_add_buffer then yes, it's true.
quoted
So you may refactor kexec_add_buffer and your new function to pass only
kimage and a kbuf, it will be better than passing all those arguments
separately.
To be honest I think struct kexec_buf is an implementation detail inside
kexec_locate_mem_hole, made necessary because the callback functions it
uses need to access its arguments. Callers of kexec_locate_mem_hole,
kexec_add_handover_buffer and kexec_add_buffer shouldn't need to know it
exists.
Elaborating a bit more: the argument list for these three functions are
equal or similar because kexec_add_handover_buffer uses kexec_add_buffer,
which uses kexec_locate_mem_hole.
It could be beneficial to have a struct to collect the arguments to these
functions if someone using one of them would be likely to use another one
with the same arguments. In that case, you set up kexec_buf once and then
just pass it whenever you need to call one of those functions.
But that is unlikely to happen. A user of the kexec API will need to use
only one of these functions with a given set of arguments, so they don't
gain anything by setting up a struct.
Syntactically, I also don't think it's clearer to set struct members instead
of simply passing arguments to a function, even if the argument list is
long.
Sorry, I'm not sure I get your points but the long argument list really looks ugly,
since you are introducing more callbacks I still think a cleanup is necessary.
kexec_buffer struct is pretty fine to be a abstract of all these buffers.
Thanks
Dave
Am Donnerstag, 30 Juni 2016, 17:43:57 schrieb Dave Young:
On 06/30/16 at 01:42pm, Thiago Jung Bauermann wrote:
quoted
Am Donnerstag, 30 Juni 2016, 12:49:44 schrieb Thiago Jung Bauermann:
quoted
To be honest I think struct kexec_buf is an implementation detail
inside
kexec_locate_mem_hole, made necessary because the callback functions
it
uses need to access its arguments. Callers of kexec_locate_mem_hole,
kexec_add_handover_buffer and kexec_add_buffer shouldn't need to know
it
exists.
Elaborating a bit more: the argument list for these three functions are
equal or similar because kexec_add_handover_buffer uses
kexec_add_buffer,
which uses kexec_locate_mem_hole.
It could be beneficial to have a struct to collect the arguments to
these
functions if someone using one of them would be likely to use another
one
with the same arguments. In that case, you set up kexec_buf once and
then
just pass it whenever you need to call one of those functions.
But that is unlikely to happen. A user of the kexec API will need to use
only one of these functions with a given set of arguments, so they don't
gain anything by setting up a struct.
Syntactically, I also don't think it's clearer to set struct members
instead of simply passing arguments to a function, even if the argument
list is long.
Sorry, I'm not sure I get your points but the long argument list really
looks ugly, since you are introducing more callbacks I still think a
cleanup is necessary.
kexec_buffer struct is pretty fine to be a abstract of all these buffers.
What I understood from what you said is that making the following change
results in code that is easier to understand:
@@ -650,6 +639,7 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min, const Elf_Shdr *sechdrs_c; Elf_Shdr *sechdrs = NULL; void *purgatory_buf = NULL;+ struct kexec_buf buf; /* * sechdrs_c points to section headers in purgatory and are read
There are 9 calls to kexec_add_buffer in the kernel (including arch/x86,
arch/powerpc/ and kernel/), plus 1 to kexec_locate_mem_hole
and 1 to kexec_add_handover_buffer, so there would be 11 places in
the code settings up kexec_buf. My opinion is that this change doesn't
improve code readability.
Also, I think that kexec_buf abstracts something that, from the
perspective of the user of the kexec API, lives only for the duration
of a single call to either of kexec_add_buffer, kexec_locate_mem_hole,
or kexec_add_handover_buffer. Because of this, there's no need from the
perspective of the API user to initialize this "object", so this just
adds to their cognitive load without any benefit to them.
I understand that this is all somewhat subjective, so if you still disagree
with my points I can provide a patch set implementing the change above.
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
From: Dave Young <hidden> Date: 2016-07-01 18:47:19
On 07/01/16 at 02:51pm, Thiago Jung Bauermann wrote:
quoted hunk
Am Donnerstag, 30 Juni 2016, 17:43:57 schrieb Dave Young:
quoted
On 06/30/16 at 01:42pm, Thiago Jung Bauermann wrote:
quoted
Am Donnerstag, 30 Juni 2016, 12:49:44 schrieb Thiago Jung Bauermann:
quoted
To be honest I think struct kexec_buf is an implementation detail
inside
kexec_locate_mem_hole, made necessary because the callback functions
it
uses need to access its arguments. Callers of kexec_locate_mem_hole,
kexec_add_handover_buffer and kexec_add_buffer shouldn't need to know
it
exists.
Elaborating a bit more: the argument list for these three functions are
equal or similar because kexec_add_handover_buffer uses
kexec_add_buffer,
which uses kexec_locate_mem_hole.
It could be beneficial to have a struct to collect the arguments to
these
functions if someone using one of them would be likely to use another
one
with the same arguments. In that case, you set up kexec_buf once and
then
just pass it whenever you need to call one of those functions.
But that is unlikely to happen. A user of the kexec API will need to use
only one of these functions with a given set of arguments, so they don't
gain anything by setting up a struct.
Syntactically, I also don't think it's clearer to set struct members
instead of simply passing arguments to a function, even if the argument
list is long.
Sorry, I'm not sure I get your points but the long argument list really
looks ugly, since you are introducing more callbacks I still think a
cleanup is necessary.
kexec_buffer struct is pretty fine to be a abstract of all these buffers.
What I understood from what you said is that making the following change
results in code that is easier to understand:
@@ -650,6 +639,7 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min, const Elf_Shdr *sechdrs_c; Elf_Shdr *sechdrs = NULL; void *purgatory_buf = NULL;+ struct kexec_buf buf; /* * sechdrs_c points to section headers in purgatory and are read
There are 9 calls to kexec_add_buffer in the kernel (including arch/x86,
arch/powerpc/ and kernel/), plus 1 to kexec_locate_mem_hole
and 1 to kexec_add_handover_buffer, so there would be 11 places in
the code settings up kexec_buf. My opinion is that this change doesn't
improve code readability.
But the assignment can be moved to the beginning of the function
__kexec_load_purgatory, and avoid the local variables from the very
beginning. Just use kbuf.member instead.
Also, I think that kexec_buf abstracts something that, from the
perspective of the user of the kexec API, lives only for the duration
of a single call to either of kexec_add_buffer, kexec_locate_mem_hole,
or kexec_add_handover_buffer. Because of this, there's no need from the
perspective of the API user to initialize this "object", so this just
adds to their cognitive load without any benefit to them.
I understand that this is all somewhat subjective, so if you still disagree
with my points I can provide a patch set implementing the change above.
I still feel it should be changed if more callbacks being introduced,
though you can regard it is internal api, like above comment we do not
need to assign them seperately, the member values can be assigned
from the beginning.
Thanks
Dave
Am Freitag, 01 Juli 2016, 14:36:02 schrieb Dave Young:
On 07/01/16 at 02:51pm, Thiago Jung Bauermann wrote:
quoted
Am Donnerstag, 30 Juni 2016, 17:43:57 schrieb Dave Young:
quoted
On 06/30/16 at 01:42pm, Thiago Jung Bauermann wrote:
quoted
Am Donnerstag, 30 Juni 2016, 12:49:44 schrieb Thiago Jung Bauermann:
I understand that this is all somewhat subjective, so if you still
disagree with my points I can provide a patch set implementing the
change above.
I still feel it should be changed if more callbacks being introduced,
though you can regard it is internal api, like above comment we do not
need to assign them seperately, the member values can be assigned
from the beginning.
Ok, I'll implement the changes and submit a v4. Thanks for your review.
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
Am Freitag, 01 Juli 2016, 17:02:23 schrieb Thiago Jung Bauermann:
Am Freitag, 01 Juli 2016, 14:36:02 schrieb Dave Young:
quoted
On 07/01/16 at 02:51pm, Thiago Jung Bauermann wrote:
quoted
Am Donnerstag, 30 Juni 2016, 17:43:57 schrieb Dave Young:
quoted
On 06/30/16 at 01:42pm, Thiago Jung Bauermann wrote:
quoted
Am Donnerstag, 30 Juni 2016, 12:49:44 schrieb Thiago Jung Bauermann:
I understand that this is all somewhat subjective, so if you still
disagree with my points I can provide a patch set implementing the
change above.
I still feel it should be changed if more callbacks being introduced,
though you can regard it is internal api, like above comment we do not
need to assign them seperately, the member values can be assigned
from the beginning.
Ok, I'll implement the changes and submit a v4. Thanks for your review.
Sorry for creating more email traffic, but it'll be better if I ask this
before I change all other places in the code. Is the code below what you
have in mind?
In particular, this version doesn't do the memset(&buf, 0, sizeof(buf))
that the previous code I sent earlier did. Is that ok?
@@ -643,13 +632,14 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min, unsigned long max, int top_down) { struct purgatory_info *pi = &image->purgatory_info;- unsigned long align, buf_align, bss_align, buf_sz, bss_sz, bss_pad;- unsigned long memsz, entry, load_addr, curr_load_addr, bss_addr, offset;+ unsigned long align, bss_align, bss_sz, bss_pad;+ unsigned long entry, load_addr, curr_load_addr, bss_addr, offset; unsigned char *buf_addr, *src; int i, ret = 0, entry_sidx = -1; const Elf_Shdr *sechdrs_c; Elf_Shdr *sechdrs = NULL;- void *purgatory_buf = NULL;+ struct kexec_buf buf = { .image = image, .buf_min = min,+ .buf_max = max, .top_down = top_down }; /* * sechdrs_c points to section headers in purgatory and are read
@@ -715,9 +705,9 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min, } /* Determine how much memory is needed to load relocatable object. */- buf_align = 1;+ buf.buf_align = 1; bss_align = 1;- buf_sz = 0;+ buf.bufsz = 0; bss_sz = 0; for (i = 0; i < pi->ehdr->e_shnum; i++) {
@@ -726,10 +716,10 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min, align = sechdrs[i].sh_addralign; if (sechdrs[i].sh_type != SHT_NOBITS) {- if (buf_align < align)- buf_align = align;- buf_sz = ALIGN(buf_sz, align);- buf_sz += sechdrs[i].sh_size;+ if (buf.buf_align < align)+ buf.buf_align = align;+ buf.bufsz = ALIGN(buf.bufsz, align);+ buf.bufsz += sechdrs[i].sh_size; } else { /* bss section */ if (bss_align < align)
@@ -741,32 +731,31 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min, /* Determine the bss padding required to align bss properly */ bss_pad = 0;- if (buf_sz & (bss_align - 1))- bss_pad = bss_align - (buf_sz & (bss_align - 1));+ if (buf.bufsz & (bss_align - 1))+ bss_pad = bss_align - (buf.bufsz & (bss_align - 1));- memsz = buf_sz + bss_pad + bss_sz;+ buf.memsz = buf.bufsz + bss_pad + bss_sz; /* Allocate buffer for purgatory */- purgatory_buf = vzalloc(buf_sz);- if (!purgatory_buf) {+ buf.buffer = vzalloc(buf.bufsz);+ if (!buf.buffer) { ret = -ENOMEM; goto out; }- if (buf_align < bss_align)- buf_align = bss_align;+ if (buf.buf_align < bss_align)+ buf.buf_align = bss_align; /* Add buffer to segment list */- ret = kexec_add_buffer(image, purgatory_buf, buf_sz, memsz,- buf_align, min, max, top_down,- &pi->purgatory_load_addr);+ ret = kexec_add_buffer(&buf); if (ret) goto out;+ pi->purgatory_load_addr = buf.mem; /* Load SHF_ALLOC sections */- buf_addr = purgatory_buf;+ buf_addr = buf.buffer; load_addr = curr_load_addr = pi->purgatory_load_addr;- bss_addr = load_addr + buf_sz + bss_pad;+ bss_addr = load_addr + buf.bufsz + bss_pad; for (i = 0; i < pi->ehdr->e_shnum; i++) { if (!(sechdrs[i].sh_flags & SHF_ALLOC))
@@ -812,11 +801,11 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min, * Used later to identify which section is purgatory and skip it * from checksumming. */- pi->purgatory_buf = purgatory_buf;+ pi->purgatory_buf = buf.buffer; return ret; out: vfree(sechdrs);- vfree(purgatory_buf);+ vfree(buf.buffer); return ret; }
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
From: Dave Young <hidden> Date: 2016-07-05 00:55:48
On 07/01/16 at 05:31pm, Thiago Jung Bauermann wrote:
Am Freitag, 01 Juli 2016, 17:02:23 schrieb Thiago Jung Bauermann:
quoted
Am Freitag, 01 Juli 2016, 14:36:02 schrieb Dave Young:
quoted
On 07/01/16 at 02:51pm, Thiago Jung Bauermann wrote:
quoted
Am Donnerstag, 30 Juni 2016, 17:43:57 schrieb Dave Young:
quoted
On 06/30/16 at 01:42pm, Thiago Jung Bauermann wrote:
quoted
Am Donnerstag, 30 Juni 2016, 12:49:44 schrieb Thiago Jung Bauermann:
I understand that this is all somewhat subjective, so if you still
disagree with my points I can provide a patch set implementing the
change above.
I still feel it should be changed if more callbacks being introduced,
though you can regard it is internal api, like above comment we do not
need to assign them seperately, the member values can be assigned
from the beginning.
Ok, I'll implement the changes and submit a v4. Thanks for your review.
Sorry for creating more email traffic, but it'll be better if I ask this
before I change all other places in the code. Is the code below what you
have in mind?
Thanks for the update, almost except a nitpick :)
quoted hunk
In particular, this version doesn't do the memset(&buf, 0, sizeof(buf))
that the previous code I sent earlier did. Is that ok?
@@ -643,13 +632,14 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min, unsigned long max, int top_down) { struct purgatory_info *pi = &image->purgatory_info;- unsigned long align, buf_align, bss_align, buf_sz, bss_sz, bss_pad;- unsigned long memsz, entry, load_addr, curr_load_addr, bss_addr, offset;+ unsigned long align, bss_align, bss_sz, bss_pad;+ unsigned long entry, load_addr, curr_load_addr, bss_addr, offset; unsigned char *buf_addr, *src; int i, ret = 0, entry_sidx = -1; const Elf_Shdr *sechdrs_c; Elf_Shdr *sechdrs = NULL;- void *purgatory_buf = NULL;+ struct kexec_buf buf = { .image = image, .buf_min = min,+ .buf_max = max, .top_down = top_down }; /* * sechdrs_c points to section headers in purgatory and are read
@@ -715,9 +705,9 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min, } /* Determine how much memory is needed to load relocatable object. */- buf_align = 1;+ buf.buf_align = 1; bss_align = 1;- buf_sz = 0;+ buf.bufsz = 0; bss_sz = 0;
Above chunk can go to the initializatioin of struct kexec buf ealier.
quoted hunk
for (i = 0; i < pi->ehdr->e_shnum; i++) {
@@ -726,10 +716,10 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min, align = sechdrs[i].sh_addralign; if (sechdrs[i].sh_type != SHT_NOBITS) {- if (buf_align < align)- buf_align = align;- buf_sz = ALIGN(buf_sz, align);- buf_sz += sechdrs[i].sh_size;+ if (buf.buf_align < align)+ buf.buf_align = align;+ buf.bufsz = ALIGN(buf.bufsz, align);+ buf.bufsz += sechdrs[i].sh_size; } else { /* bss section */ if (bss_align < align)
@@ -741,32 +731,31 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min, /* Determine the bss padding required to align bss properly */ bss_pad = 0;- if (buf_sz & (bss_align - 1))- bss_pad = bss_align - (buf_sz & (bss_align - 1));+ if (buf.bufsz & (bss_align - 1))+ bss_pad = bss_align - (buf.bufsz & (bss_align - 1));- memsz = buf_sz + bss_pad + bss_sz;+ buf.memsz = buf.bufsz + bss_pad + bss_sz; /* Allocate buffer for purgatory */- purgatory_buf = vzalloc(buf_sz);- if (!purgatory_buf) {+ buf.buffer = vzalloc(buf.bufsz);+ if (!buf.buffer) { ret = -ENOMEM; goto out; }- if (buf_align < bss_align)- buf_align = bss_align;+ if (buf.buf_align < bss_align)+ buf.buf_align = bss_align; /* Add buffer to segment list */- ret = kexec_add_buffer(image, purgatory_buf, buf_sz, memsz,- buf_align, min, max, top_down,- &pi->purgatory_load_addr);+ ret = kexec_add_buffer(&buf); if (ret) goto out;+ pi->purgatory_load_addr = buf.mem; /* Load SHF_ALLOC sections */- buf_addr = purgatory_buf;+ buf_addr = buf.buffer; load_addr = curr_load_addr = pi->purgatory_load_addr;- bss_addr = load_addr + buf_sz + bss_pad;+ bss_addr = load_addr + buf.bufsz + bss_pad; for (i = 0; i < pi->ehdr->e_shnum; i++) { if (!(sechdrs[i].sh_flags & SHF_ALLOC))
@@ -812,11 +801,11 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min, * Used later to identify which section is purgatory and skip it * from checksumming. */- pi->purgatory_buf = purgatory_buf;+ pi->purgatory_buf = buf.buffer; return ret; out: vfree(sechdrs);- vfree(purgatory_buf);+ vfree(buf.buffer); return ret; }
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center