forked from horms/kexec-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
LoongArch: PE format image loading support
The LoongArch kernel will mainly use the vmlinux.efi image in PE format, so add it support. I tested this on LoongArch 3A5000 machine and works as expected, kexec: $ sudo kexec -l /boot/vmlinux.efi --reuse-cmdline $ sudo kexec -e kdump: $ sudo kexec -p /boot/vmlinux-kdump.efi --reuse-cmdline --append="nr_cpus=1" # echo c > /proc/sysrq_trigger Signed-off-by: Youling Tang <[email protected]> Signed-off-by: Simon Horman <[email protected]>
- Loading branch information
Showing
6 changed files
with
229 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/* | ||
* LoongArch binary image header. | ||
*/ | ||
|
||
#if !defined(__LOONGARCH_IMAGE_HEADER_H) | ||
#define __LOONGARCH_IMAGE_HEADER_H | ||
|
||
#include <endian.h> | ||
#include <stdint.h> | ||
|
||
/** | ||
* struct loongarch_image_header | ||
* | ||
* @pe_sig: Optional PE format 'MZ' signature. | ||
* @reserved_1: Reserved. | ||
* @kernel_entry: Kernel image entry pointer. | ||
* @image_size: An estimated size of the memory image size in LSB byte order. | ||
* @text_offset: The image load offset in LSB byte order. | ||
* @reserved_2: Reserved. | ||
* @reserved_3: Reserved. | ||
* @pe_header: Optional offset to a PE format header. | ||
**/ | ||
|
||
struct loongarch_image_header { | ||
uint8_t pe_sig[2]; | ||
uint16_t reserved_1[3]; | ||
uint64_t kernel_entry; | ||
uint64_t image_size; | ||
uint64_t text_offset; | ||
uint64_t reserved_2[3]; | ||
uint32_t reserved_3; | ||
uint32_t pe_header; | ||
}; | ||
|
||
static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'}; | ||
|
||
/** | ||
* loongarch_header_check_pe_sig - Helper to check the loongarch image header. | ||
* | ||
* Returns non-zero if 'MZ' signature is found. | ||
*/ | ||
|
||
static inline int loongarch_header_check_pe_sig(const struct loongarch_image_header *h) | ||
{ | ||
if (!h) | ||
return 0; | ||
|
||
return (h->pe_sig[0] == loongarch_image_pe_sig[0] | ||
&& h->pe_sig[1] == loongarch_image_pe_sig[1]); | ||
} | ||
|
||
static inline uint64_t loongarch_header_text_offset( | ||
const struct loongarch_image_header *h) | ||
{ | ||
if (!h) | ||
return 0; | ||
|
||
return le64toh(h->text_offset); | ||
} | ||
|
||
static inline uint64_t loongarch_header_image_size( | ||
const struct loongarch_image_header *h) | ||
{ | ||
if (!h) | ||
return 0; | ||
|
||
return le64toh(h->image_size); | ||
} | ||
|
||
static inline uint64_t loongarch_header_kernel_entry( | ||
const struct loongarch_image_header *h) | ||
{ | ||
if (!h) | ||
return 0; | ||
|
||
return le64toh(h->kernel_entry); | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
/* | ||
* LoongArch kexec PE format binary image support. | ||
* | ||
* Copyright (C) 2022 Loongson Technology Corporation Limited. | ||
* Youling Tang <[email protected]> | ||
* | ||
* derived from kexec-image-arm64.c | ||
* | ||
* This source code is licensed under the GNU General Public License, | ||
* Version 2. See the file COPYING for more details. | ||
*/ | ||
|
||
#define _GNU_SOURCE | ||
|
||
#include <limits.h> | ||
#include <errno.h> | ||
#include <elf.h> | ||
|
||
#include "kexec.h" | ||
#include "kexec-elf.h" | ||
#include "image-header.h" | ||
#include "kexec-syscall.h" | ||
#include "crashdump-loongarch.h" | ||
#include "kexec-loongarch.h" | ||
#include "arch/options.h" | ||
|
||
int pei_loongarch_probe(const char *kernel_buf, off_t kernel_size) | ||
{ | ||
const struct loongarch_image_header *h; | ||
|
||
if (kernel_size < sizeof(struct loongarch_image_header)) { | ||
dbgprintf("%s: No loongarch image header.\n", __func__); | ||
return -1; | ||
} | ||
|
||
h = (const struct loongarch_image_header *)(kernel_buf); | ||
|
||
if (!loongarch_header_check_pe_sig(h)) { | ||
dbgprintf("%s: Bad loongarch PE image header.\n", __func__); | ||
return -1; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
int pei_loongarch_load(int argc, char **argv, const char *buf, | ||
off_t len, struct kexec_info *info) | ||
{ | ||
int result; | ||
unsigned long hole_min = 0; | ||
unsigned long kernel_segment, kernel_entry; | ||
const struct loongarch_image_header *header; | ||
|
||
header = (const struct loongarch_image_header *)(buf); | ||
|
||
if (loongarch_process_image_header(header)) | ||
return EFAILED; | ||
|
||
kernel_segment = loongarch_locate_kernel_segment(info); | ||
|
||
if (kernel_segment == ULONG_MAX) { | ||
dbgprintf("%s: Kernel segment is not allocated\n", __func__); | ||
result = EFAILED; | ||
goto exit; | ||
} | ||
|
||
kernel_entry = virt_to_phys(loongarch_header_kernel_entry(header)); | ||
|
||
dbgprintf("%s: kernel_segment: %016lx\n", __func__, kernel_segment); | ||
dbgprintf("%s: kernel_entry: %016lx\n", __func__, kernel_entry); | ||
dbgprintf("%s: image_size: %016lx\n", __func__, | ||
loongarch_mem.image_size); | ||
dbgprintf("%s: text_offset: %016lx\n", __func__, | ||
loongarch_mem.text_offset); | ||
dbgprintf("%s: phys_offset: %016lx\n", __func__, | ||
loongarch_mem.phys_offset); | ||
dbgprintf("%s: PE format: %s\n", __func__, | ||
(loongarch_header_check_pe_sig(header) ? "yes" : "no")); | ||
|
||
/* Get kernel entry point */ | ||
info->entry = (void *)kernel_entry; | ||
|
||
hole_min = kernel_segment + loongarch_mem.image_size; | ||
|
||
/* Create and initialize elf core header segment */ | ||
if (info->kexec_flags & KEXEC_ON_CRASH) { | ||
result = load_crashdump_segments(info); | ||
if (result) { | ||
dbgprintf("%s: Creating eflcorehdr failed.\n", | ||
__func__); | ||
goto exit; | ||
} | ||
} | ||
|
||
/* Load the kernel */ | ||
add_segment(info, buf, len, kernel_segment, loongarch_mem.image_size); | ||
|
||
/* Prepare and load dtb and initrd data */ | ||
result = loongarch_load_other_segments(info, hole_min); | ||
if (result) { | ||
fprintf(stderr, "kexec: Load dtb and initrd segments failed.\n"); | ||
goto exit; | ||
} | ||
|
||
exit: | ||
if (result) | ||
fprintf(stderr, "kexec: load failed.\n"); | ||
|
||
return result; | ||
} | ||
|
||
void pei_loongarch_usage(void) | ||
{ | ||
printf( | ||
" An LoongArch PE format binary image, uncompressed, little endian.\n" | ||
" Typically a vmlinux.efi file.\n\n"); | ||
} |