@@ -182,6 +182,7 @@ static void *elf_kexec_load(struct kimage *image, char *kernel_buf,
182182 unsigned long new_kernel_pbase = 0UL ;
183183 unsigned long initrd_pbase = 0UL ;
184184 unsigned long headers_sz ;
185+ unsigned long kernel_start ;
185186 void * fdt , * headers ;
186187 struct elfhdr ehdr ;
187188 struct kexec_buf kbuf ;
@@ -196,6 +197,7 @@ static void *elf_kexec_load(struct kimage *image, char *kernel_buf,
196197 & old_kernel_pbase , & new_kernel_pbase );
197198 if (ret )
198199 goto out ;
200+ kernel_start = image -> start ;
199201 pr_notice ("The entry point of kernel at 0x%lx\n" , image -> start );
200202
201203 /* Add the kernel binary to the image */
@@ -246,6 +248,22 @@ static void *elf_kexec_load(struct kimage *image, char *kernel_buf,
246248 cmdline = modified_cmdline ;
247249 }
248250
251+ #ifdef CONFIG_ARCH_HAS_KEXEC_PURGATORY
252+ /* Add purgatory to the image */
253+ kbuf .top_down = true;
254+ kbuf .mem = KEXEC_BUF_MEM_UNKNOWN ;
255+ ret = kexec_load_purgatory (image , & kbuf );
256+ if (ret ) {
257+ pr_err ("Error loading purgatory ret=%d\n" , ret );
258+ goto out ;
259+ }
260+ ret = kexec_purgatory_get_set_symbol (image , "riscv_kernel_entry" ,
261+ & kernel_start ,
262+ sizeof (kernel_start ), 0 );
263+ if (ret )
264+ pr_err ("Error update purgatory ret=%d\n" , ret );
265+ #endif /* CONFIG_ARCH_HAS_KEXEC_PURGATORY */
266+
249267 /* Add the initrd to the image */
250268 if (initrd != NULL ) {
251269 kbuf .buffer = initrd ;
@@ -291,6 +309,139 @@ static void *elf_kexec_load(struct kimage *image, char *kernel_buf,
291309 return ret ? ERR_PTR (ret ) : NULL ;
292310}
293311
312+ #define RV_X (x , s , n ) (((x) >> (s)) & ((1 << (n)) - 1))
313+ #define RISCV_IMM_BITS 12
314+ #define RISCV_IMM_REACH (1LL << RISCV_IMM_BITS)
315+ #define RISCV_CONST_HIGH_PART (x ) \
316+ (((x) + (RISCV_IMM_REACH >> 1)) & ~(RISCV_IMM_REACH - 1))
317+ #define RISCV_CONST_LOW_PART (x ) ((x) - RISCV_CONST_HIGH_PART(x))
318+
319+ #define ENCODE_ITYPE_IMM (x ) \
320+ (RV_X(x, 0, 12) << 20)
321+ #define ENCODE_BTYPE_IMM (x ) \
322+ ((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | \
323+ (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 1) << 31))
324+ #define ENCODE_UTYPE_IMM (x ) \
325+ (RV_X(x, 12, 20) << 12)
326+ #define ENCODE_JTYPE_IMM (x ) \
327+ ((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | \
328+ (RV_X(x, 12, 8) << 12) | (RV_X(x, 20, 1) << 31))
329+ #define ENCODE_CBTYPE_IMM (x ) \
330+ ((RV_X(x, 1, 2) << 3) | (RV_X(x, 3, 2) << 10) | (RV_X(x, 5, 1) << 2) | \
331+ (RV_X(x, 6, 2) << 5) | (RV_X(x, 8, 1) << 12))
332+ #define ENCODE_CJTYPE_IMM (x ) \
333+ ((RV_X(x, 1, 3) << 3) | (RV_X(x, 4, 1) << 11) | (RV_X(x, 5, 1) << 2) | \
334+ (RV_X(x, 6, 1) << 7) | (RV_X(x, 7, 1) << 6) | (RV_X(x, 8, 2) << 9) | \
335+ (RV_X(x, 10, 1) << 8) | (RV_X(x, 11, 1) << 12))
336+ #define ENCODE_UJTYPE_IMM (x ) \
337+ (ENCODE_UTYPE_IMM(RISCV_CONST_HIGH_PART(x)) | \
338+ (ENCODE_ITYPE_IMM(RISCV_CONST_LOW_PART(x)) << 32))
339+ #define ENCODE_UITYPE_IMM (x ) \
340+ (ENCODE_UTYPE_IMM(x) | (ENCODE_ITYPE_IMM(x) << 32))
341+
342+ #define CLEAN_IMM (type , x ) \
343+ ((~ENCODE_##type##_IMM((uint64_t)(-1))) & (x))
344+
345+ int arch_kexec_apply_relocations_add (struct purgatory_info * pi ,
346+ Elf_Shdr * section ,
347+ const Elf_Shdr * relsec ,
348+ const Elf_Shdr * symtab )
349+ {
350+ const char * strtab , * name , * shstrtab ;
351+ const Elf_Shdr * sechdrs ;
352+ Elf_Rela * relas ;
353+ int i , r_type ;
354+
355+ /* String & section header string table */
356+ sechdrs = (void * )pi -> ehdr + pi -> ehdr -> e_shoff ;
357+ strtab = (char * )pi -> ehdr + sechdrs [symtab -> sh_link ].sh_offset ;
358+ shstrtab = (char * )pi -> ehdr + sechdrs [pi -> ehdr -> e_shstrndx ].sh_offset ;
359+
360+ relas = (void * )pi -> ehdr + relsec -> sh_offset ;
361+
362+ for (i = 0 ; i < relsec -> sh_size / sizeof (* relas ); i ++ ) {
363+ const Elf_Sym * sym ; /* symbol to relocate */
364+ unsigned long addr ; /* final location after relocation */
365+ unsigned long val ; /* relocated symbol value */
366+ unsigned long sec_base ; /* relocated symbol value */
367+ void * loc ; /* tmp location to modify */
368+
369+ sym = (void * )pi -> ehdr + symtab -> sh_offset ;
370+ sym += ELF64_R_SYM (relas [i ].r_info );
371+
372+ if (sym -> st_name )
373+ name = strtab + sym -> st_name ;
374+ else
375+ name = shstrtab + sechdrs [sym -> st_shndx ].sh_name ;
376+
377+ loc = pi -> purgatory_buf ;
378+ loc += section -> sh_offset ;
379+ loc += relas [i ].r_offset ;
380+
381+ if (sym -> st_shndx == SHN_ABS )
382+ sec_base = 0 ;
383+ else if (sym -> st_shndx >= pi -> ehdr -> e_shnum ) {
384+ pr_err ("Invalid section %d for symbol %s\n" ,
385+ sym -> st_shndx , name );
386+ return - ENOEXEC ;
387+ } else
388+ sec_base = pi -> sechdrs [sym -> st_shndx ].sh_addr ;
389+
390+ val = sym -> st_value ;
391+ val += sec_base ;
392+ val += relas [i ].r_addend ;
393+
394+ addr = section -> sh_addr + relas [i ].r_offset ;
395+
396+ r_type = ELF64_R_TYPE (relas [i ].r_info );
397+
398+ switch (r_type ) {
399+ case R_RISCV_BRANCH :
400+ * (u32 * )loc = CLEAN_IMM (BTYPE , * (u32 * )loc ) |
401+ ENCODE_BTYPE_IMM (val - addr );
402+ break ;
403+ case R_RISCV_JAL :
404+ * (u32 * )loc = CLEAN_IMM (JTYPE , * (u32 * )loc ) |
405+ ENCODE_JTYPE_IMM (val - addr );
406+ break ;
407+ /*
408+ * With no R_RISCV_PCREL_LO12_S, R_RISCV_PCREL_LO12_I
409+ * sym is expected to be next to R_RISCV_PCREL_HI20
410+ * in purgatory relsec. Handle it like R_RISCV_CALL
411+ * sym, instead of searching the whole relsec.
412+ */
413+ case R_RISCV_PCREL_HI20 :
414+ case R_RISCV_CALL :
415+ * (u64 * )loc = CLEAN_IMM (UITYPE , * (u64 * )loc ) |
416+ ENCODE_UJTYPE_IMM (val - addr );
417+ break ;
418+ case R_RISCV_RVC_BRANCH :
419+ * (u32 * )loc = CLEAN_IMM (CBTYPE , * (u32 * )loc ) |
420+ ENCODE_CBTYPE_IMM (val - addr );
421+ break ;
422+ case R_RISCV_RVC_JUMP :
423+ * (u32 * )loc = CLEAN_IMM (CJTYPE , * (u32 * )loc ) |
424+ ENCODE_CJTYPE_IMM (val - addr );
425+ break ;
426+ case R_RISCV_ADD32 :
427+ * (u32 * )loc += val ;
428+ break ;
429+ case R_RISCV_SUB32 :
430+ * (u32 * )loc -= val ;
431+ break ;
432+ /* It has been applied by R_RISCV_PCREL_HI20 sym */
433+ case R_RISCV_PCREL_LO12_I :
434+ case R_RISCV_ALIGN :
435+ case R_RISCV_RELAX :
436+ break ;
437+ default :
438+ pr_err ("Unknown rela relocation: %d\n" , r_type );
439+ return - ENOEXEC ;
440+ }
441+ }
442+ return 0 ;
443+ }
444+
294445const struct kexec_file_ops elf_kexec_ops = {
295446 .probe = kexec_elf_probe ,
296447 .load = elf_kexec_load ,
0 commit comments