Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
d34664f6
Commit
d34664f6
authored
Dec 10, 2018
by
Will Deacon
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-next/kexec' into aarch64/for-next/core
Merge in kexec_file_load() support from Akashi Takahiro.
parents
bc84a2d1
394135c1
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
623 additions
and
90 deletions
+623
-90
arch/arm64/Kconfig
arch/arm64/Kconfig
+33
-0
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/cpufeature.h
+48
-0
arch/arm64/include/asm/image.h
arch/arm64/include/asm/image.h
+59
-0
arch/arm64/include/asm/kexec.h
arch/arm64/include/asm/kexec.h
+19
-0
arch/arm64/kernel/Makefile
arch/arm64/kernel/Makefile
+2
-1
arch/arm64/kernel/cpu-reset.S
arch/arm64/kernel/cpu-reset.S
+4
-4
arch/arm64/kernel/head.S
arch/arm64/kernel/head.S
+2
-1
arch/arm64/kernel/image.h
arch/arm64/kernel/image.h
+13
-8
arch/arm64/kernel/kexec_image.c
arch/arm64/kernel/kexec_image.c
+130
-0
arch/arm64/kernel/machine_kexec.c
arch/arm64/kernel/machine_kexec.c
+10
-2
arch/arm64/kernel/machine_kexec_file.c
arch/arm64/kernel/machine_kexec_file.c
+223
-0
arch/arm64/kernel/relocate_kernel.S
arch/arm64/kernel/relocate_kernel.S
+2
-1
arch/powerpc/kernel/machine_kexec_file_64.c
arch/powerpc/kernel/machine_kexec_file_64.c
+0
-54
arch/s390/kernel/machine_kexec_file.c
arch/s390/kernel/machine_kexec_file.c
+0
-10
include/linux/kexec.h
include/linux/kexec.h
+9
-2
include/linux/pe.h
include/linux/pe.h
+1
-1
include/uapi/asm-generic/unistd.h
include/uapi/asm-generic/unistd.h
+3
-1
kernel/kexec_file.c
kernel/kexec_file.c
+65
-5
No files found.
arch/arm64/Kconfig
View file @
d34664f6
...
...
@@ -905,6 +905,39 @@ config KEXEC
but it is independent of the system firmware. And like a reboot
you can start any kernel with it, not just Linux.
config KEXEC_FILE
bool "kexec file based system call"
select KEXEC_CORE
help
This is new version of kexec system call. This system call is
file based and takes file descriptors as system call argument
for kernel and initramfs as opposed to list of segments as
accepted by previous system call.
config KEXEC_VERIFY_SIG
bool "Verify kernel signature during kexec_file_load() syscall"
depends on KEXEC_FILE
help
Select this option to verify a signature with loaded kernel
image. If configured, any attempt of loading a image without
valid signature will fail.
In addition to that option, you need to enable signature
verification for the corresponding kernel image type being
loaded in order for this to work.
config KEXEC_IMAGE_VERIFY_SIG
bool "Enable Image signature verification support"
default y
depends on KEXEC_VERIFY_SIG
depends on EFI && SIGNED_PE_FILE_VERIFICATION
help
Enable Image signature verification support.
comment "Support for PE file signature verification disabled"
depends on KEXEC_VERIFY_SIG
depends on !EFI || !SIGNED_PE_FILE_VERIFICATION
config CRASH_DUMP
bool "Build kdump crash kernel"
help
...
...
arch/arm64/include/asm/cpufeature.h
View file @
d34664f6
...
...
@@ -489,11 +489,59 @@ static inline bool system_supports_32bit_el0(void)
return
cpus_have_const_cap
(
ARM64_HAS_32BIT_EL0
);
}
static
inline
bool
system_supports_4kb_granule
(
void
)
{
u64
mmfr0
;
u32
val
;
mmfr0
=
read_sanitised_ftr_reg
(
SYS_ID_AA64MMFR0_EL1
);
val
=
cpuid_feature_extract_unsigned_field
(
mmfr0
,
ID_AA64MMFR0_TGRAN4_SHIFT
);
return
val
==
ID_AA64MMFR0_TGRAN4_SUPPORTED
;
}
static
inline
bool
system_supports_64kb_granule
(
void
)
{
u64
mmfr0
;
u32
val
;
mmfr0
=
read_sanitised_ftr_reg
(
SYS_ID_AA64MMFR0_EL1
);
val
=
cpuid_feature_extract_unsigned_field
(
mmfr0
,
ID_AA64MMFR0_TGRAN64_SHIFT
);
return
val
==
ID_AA64MMFR0_TGRAN64_SUPPORTED
;
}
static
inline
bool
system_supports_16kb_granule
(
void
)
{
u64
mmfr0
;
u32
val
;
mmfr0
=
read_sanitised_ftr_reg
(
SYS_ID_AA64MMFR0_EL1
);
val
=
cpuid_feature_extract_unsigned_field
(
mmfr0
,
ID_AA64MMFR0_TGRAN16_SHIFT
);
return
val
==
ID_AA64MMFR0_TGRAN16_SUPPORTED
;
}
static
inline
bool
system_supports_mixed_endian_el0
(
void
)
{
return
id_aa64mmfr0_mixed_endian_el0
(
read_sanitised_ftr_reg
(
SYS_ID_AA64MMFR0_EL1
));
}
static
inline
bool
system_supports_mixed_endian
(
void
)
{
u64
mmfr0
;
u32
val
;
mmfr0
=
read_sanitised_ftr_reg
(
SYS_ID_AA64MMFR0_EL1
);
val
=
cpuid_feature_extract_unsigned_field
(
mmfr0
,
ID_AA64MMFR0_BIGENDEL_SHIFT
);
return
val
==
0x1
;
}
static
inline
bool
system_supports_fpsimd
(
void
)
{
return
!
cpus_have_const_cap
(
ARM64_HAS_NO_FPSIMD
);
...
...
arch/arm64/include/asm/image.h
0 → 100644
View file @
d34664f6
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_IMAGE_H
#define __ASM_IMAGE_H
#define ARM64_IMAGE_MAGIC "ARM\x64"
#define ARM64_IMAGE_FLAG_BE_SHIFT 0
#define ARM64_IMAGE_FLAG_PAGE_SIZE_SHIFT (ARM64_IMAGE_FLAG_BE_SHIFT + 1)
#define ARM64_IMAGE_FLAG_PHYS_BASE_SHIFT \
(ARM64_IMAGE_FLAG_PAGE_SIZE_SHIFT + 2)
#define ARM64_IMAGE_FLAG_BE_MASK 0x1
#define ARM64_IMAGE_FLAG_PAGE_SIZE_MASK 0x3
#define ARM64_IMAGE_FLAG_PHYS_BASE_MASK 0x1
#define ARM64_IMAGE_FLAG_LE 0
#define ARM64_IMAGE_FLAG_BE 1
#define ARM64_IMAGE_FLAG_PAGE_SIZE_4K 1
#define ARM64_IMAGE_FLAG_PAGE_SIZE_16K 2
#define ARM64_IMAGE_FLAG_PAGE_SIZE_64K 3
#define ARM64_IMAGE_FLAG_PHYS_BASE 1
#ifndef __ASSEMBLY__
#define arm64_image_flag_field(flags, field) \
(((flags) >> field##_SHIFT) & field##_MASK)
/*
* struct arm64_image_header - arm64 kernel image header
* See Documentation/arm64/booting.txt for details
*
* @code0: Executable code, or
* @mz_header alternatively used for part of MZ header
* @code1: Executable code
* @text_offset: Image load offset
* @image_size: Effective Image size
* @flags: kernel flags
* @reserved: reserved
* @magic: Magic number
* @reserved5: reserved, or
* @pe_header: alternatively used for PE COFF offset
*/
struct
arm64_image_header
{
__le32
code0
;
__le32
code1
;
__le64
text_offset
;
__le64
image_size
;
__le64
flags
;
__le64
res2
;
__le64
res3
;
__le64
res4
;
__le32
magic
;
__le32
res5
;
};
#endif
/* __ASSEMBLY__ */
#endif
/* __ASM_IMAGE_H */
arch/arm64/include/asm/kexec.h
View file @
d34664f6
...
...
@@ -93,6 +93,25 @@ static inline void crash_prepare_suspend(void) {}
static
inline
void
crash_post_resume
(
void
)
{}
#endif
#ifdef CONFIG_KEXEC_FILE
#define ARCH_HAS_KIMAGE_ARCH
struct
kimage_arch
{
void
*
dtb
;
unsigned
long
dtb_mem
;
};
extern
const
struct
kexec_file_ops
kexec_image_ops
;
struct
kimage
;
extern
int
arch_kimage_file_post_load_cleanup
(
struct
kimage
*
image
);
extern
int
load_other_segments
(
struct
kimage
*
image
,
unsigned
long
kernel_load_addr
,
unsigned
long
kernel_size
,
char
*
initrd
,
unsigned
long
initrd_len
,
char
*
cmdline
);
#endif
#endif
/* __ASSEMBLY__ */
#endif
arch/arm64/kernel/Makefile
View file @
d34664f6
...
...
@@ -49,8 +49,9 @@ arm64-obj-$(CONFIG_ARM64_ACPI_PARKING_PROTOCOL) += acpi_parking_protocol.o
arm64-obj-$(CONFIG_PARAVIRT)
+=
paravirt.o
arm64-obj-$(CONFIG_RANDOMIZE_BASE)
+=
kaslr.o
arm64-obj-$(CONFIG_HIBERNATION)
+=
hibernate.o hibernate-asm.o
arm64-obj-$(CONFIG_KEXEC)
+=
machine_kexec.o relocate_kernel.o
\
arm64-obj-$(CONFIG_KEXEC
_CORE
)
+=
machine_kexec.o relocate_kernel.o
\
cpu-reset.o
arm64-obj-$(CONFIG_KEXEC_FILE)
+=
machine_kexec_file.o kexec_image.o
arm64-obj-$(CONFIG_ARM64_RELOC_TEST)
+=
arm64-reloc-test.o
arm64-reloc-test-y
:=
reloc_test_core.o reloc_test_syms.o
arm64-obj-$(CONFIG_CRASH_DUMP)
+=
crash_dump.o
...
...
arch/arm64/kernel/cpu-reset.S
View file @
d34664f6
...
...
@@ -22,11 +22,11 @@
*
__cpu_soft_restart
(
el2_switch
,
entry
,
arg0
,
arg1
,
arg2
)
-
Helper
for
*
cpu_soft_restart
.
*
*
@
el2_switch
:
Flag
to
indicate
a
swich
to
EL2
is
needed
.
*
@
el2_switch
:
Flag
to
indicate
a
swi
t
ch
to
EL2
is
needed
.
*
@
entry
:
Location
to
jump
to
for
soft
reset
.
*
arg0
:
First
argument
passed
to
@
entry
.
*
arg1
:
Second
argument
passed
to
@
entry
.
*
arg2
:
Third
argument
passed
to
@
entry
.
*
arg0
:
First
argument
passed
to
@
entry
.
(
relocation
list
)
*
arg1
:
Second
argument
passed
to
@
entry
.
(
physical
kernel
entry
)
*
arg2
:
Third
argument
passed
to
@
entry
.
(
physical
dtb
address
)
*
*
Put
the
CPU
into
the
same
state
as
it
would
be
if
it
had
been
reset
,
and
*
branch
to
what
would
be
the
reset
vector
.
It
must
be
executed
with
the
...
...
arch/arm64/kernel/head.S
View file @
d34664f6
...
...
@@ -31,6 +31,7 @@
#include <asm/cache.h>
#include <asm/cputype.h>
#include <asm/elf.h>
#include <asm/image.h>
#include <asm/kernel-pgtable.h>
#include <asm/kvm_arm.h>
#include <asm/memory.h>
...
...
@@ -91,7 +92,7 @@ _head:
.
quad
0
//
reserved
.
quad
0
//
reserved
.
quad
0
//
reserved
.
ascii
"ARM\x64"
//
Magic
number
.
ascii
ARM64_IMAGE_MAGIC
//
Magic
number
#ifdef CONFIG_EFI
.
long
pe_header
-
_head
//
Offset
to
the
PE
header
.
...
...
arch/arm64/kernel/image.h
View file @
d34664f6
...
...
@@ -15,13 +15,15 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __A
SM
_IMAGE_H
#define __A
SM
_IMAGE_H
#ifndef __A
RM64_KERNEL
_IMAGE_H
#define __A
RM64_KERNEL
_IMAGE_H
#ifndef LINKER_SCRIPT
#error This file should only be included in vmlinux.lds.S
#endif
#include <asm/image.h>
/*
* There aren't any ELF relocations we can use to endian-swap values known only
* at link time (e.g. the subtraction of two symbol addresses), so we must get
...
...
@@ -47,19 +49,22 @@
sym##_lo32 = DATA_LE32((data) & 0xffffffff); \
sym##_hi32 = DATA_LE32((data) >> 32)
#define __HEAD_FLAG(field) (__HEAD_FLAG_##field << \
ARM64_IMAGE_FLAG_##field##_SHIFT)
#ifdef CONFIG_CPU_BIG_ENDIAN
#define __HEAD_FLAG_BE
1
#define __HEAD_FLAG_BE
ARM64_IMAGE_FLAG_BE
#else
#define __HEAD_FLAG_BE
0
#define __HEAD_FLAG_BE
ARM64_IMAGE_FLAG_LE
#endif
#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
#define __HEAD_FLAG_PHYS_BASE 1
#define __HEAD_FLAGS (
(__HEAD_FLAG_BE << 0) |
\
(__HEAD_FLAG_PAGE_SIZE << 1) |
\
(__HEAD_FLAG_PHYS_BASE << 3
))
#define __HEAD_FLAGS (
__HEAD_FLAG(BE) |
\
__HEAD_FLAG(PAGE_SIZE) |
\
__HEAD_FLAG(PHYS_BASE
))
/*
* These will output as part of the Image header, which should be little-endian
...
...
@@ -109,4 +114,4 @@ __efistub_screen_info = screen_info;
#endif
#endif
/* __A
SM
_IMAGE_H */
#endif
/* __A
RM64_KERNEL
_IMAGE_H */
arch/arm64/kernel/kexec_image.c
0 → 100644
View file @
d34664f6
// SPDX-License-Identifier: GPL-2.0
/*
* Kexec image loader
* Copyright (C) 2018 Linaro Limited
* Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
*/
#define pr_fmt(fmt) "kexec_file(Image): " fmt
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/kexec.h>
#include <linux/pe.h>
#include <linux/string.h>
#include <linux/verification.h>
#include <asm/byteorder.h>
#include <asm/cpufeature.h>
#include <asm/image.h>
#include <asm/memory.h>
static
int
image_probe
(
const
char
*
kernel_buf
,
unsigned
long
kernel_len
)
{
const
struct
arm64_image_header
*
h
=
(
const
struct
arm64_image_header
*
)(
kernel_buf
);
if
(
!
h
||
(
kernel_len
<
sizeof
(
*
h
)))
return
-
EINVAL
;
if
(
memcmp
(
&
h
->
magic
,
ARM64_IMAGE_MAGIC
,
sizeof
(
h
->
magic
)))
return
-
EINVAL
;
return
0
;
}
static
void
*
image_load
(
struct
kimage
*
image
,
char
*
kernel
,
unsigned
long
kernel_len
,
char
*
initrd
,
unsigned
long
initrd_len
,
char
*
cmdline
,
unsigned
long
cmdline_len
)
{
struct
arm64_image_header
*
h
;
u64
flags
,
value
;
bool
be_image
,
be_kernel
;
struct
kexec_buf
kbuf
;
unsigned
long
text_offset
;
struct
kexec_segment
*
kernel_segment
;
int
ret
;
/* We don't support crash kernels yet. */
if
(
image
->
type
==
KEXEC_TYPE_CRASH
)
return
ERR_PTR
(
-
EOPNOTSUPP
);
/*
* We require a kernel with an unambiguous Image header. Per
* Documentation/booting.txt, this is the case when image_size
* is non-zero (practically speaking, since v3.17).
*/
h
=
(
struct
arm64_image_header
*
)
kernel
;
if
(
!
h
->
image_size
)
return
ERR_PTR
(
-
EINVAL
);
/* Check cpu features */
flags
=
le64_to_cpu
(
h
->
flags
);
be_image
=
arm64_image_flag_field
(
flags
,
ARM64_IMAGE_FLAG_BE
);
be_kernel
=
IS_ENABLED
(
CONFIG_CPU_BIG_ENDIAN
);
if
((
be_image
!=
be_kernel
)
&&
!
system_supports_mixed_endian
())
return
ERR_PTR
(
-
EINVAL
);
value
=
arm64_image_flag_field
(
flags
,
ARM64_IMAGE_FLAG_PAGE_SIZE
);
if
(((
value
==
ARM64_IMAGE_FLAG_PAGE_SIZE_4K
)
&&
!
system_supports_4kb_granule
())
||
((
value
==
ARM64_IMAGE_FLAG_PAGE_SIZE_64K
)
&&
!
system_supports_64kb_granule
())
||
((
value
==
ARM64_IMAGE_FLAG_PAGE_SIZE_16K
)
&&
!
system_supports_16kb_granule
()))
return
ERR_PTR
(
-
EINVAL
);
/* Load the kernel */
kbuf
.
image
=
image
;
kbuf
.
buf_min
=
0
;
kbuf
.
buf_max
=
ULONG_MAX
;
kbuf
.
top_down
=
false
;
kbuf
.
buffer
=
kernel
;
kbuf
.
bufsz
=
kernel_len
;
kbuf
.
mem
=
0
;
kbuf
.
memsz
=
le64_to_cpu
(
h
->
image_size
);
text_offset
=
le64_to_cpu
(
h
->
text_offset
);
kbuf
.
buf_align
=
MIN_KIMG_ALIGN
;
/* Adjust kernel segment with TEXT_OFFSET */
kbuf
.
memsz
+=
text_offset
;
ret
=
kexec_add_buffer
(
&
kbuf
);
if
(
ret
)
return
ERR_PTR
(
ret
);
kernel_segment
=
&
image
->
segment
[
image
->
nr_segments
-
1
];
kernel_segment
->
mem
+=
text_offset
;
kernel_segment
->
memsz
-=
text_offset
;
image
->
start
=
kernel_segment
->
mem
;
pr_debug
(
"Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx
\n
"
,
kernel_segment
->
mem
,
kbuf
.
bufsz
,
kernel_segment
->
memsz
);
/* Load additional data */
ret
=
load_other_segments
(
image
,
kernel_segment
->
mem
,
kernel_segment
->
memsz
,
initrd
,
initrd_len
,
cmdline
);
return
ERR_PTR
(
ret
);
}
#ifdef CONFIG_KEXEC_IMAGE_VERIFY_SIG
static
int
image_verify_sig
(
const
char
*
kernel
,
unsigned
long
kernel_len
)
{
return
verify_pefile_signature
(
kernel
,
kernel_len
,
NULL
,
VERIFYING_KEXEC_PE_SIGNATURE
);
}
#endif
const
struct
kexec_file_ops
kexec_image_ops
=
{
.
probe
=
image_probe
,
.
load
=
image_load
,
#ifdef CONFIG_KEXEC_IMAGE_VERIFY_SIG
.
verify_sig
=
image_verify_sig
,
#endif
};
arch/arm64/kernel/machine_kexec.c
View file @
d34664f6
...
...
@@ -212,9 +212,17 @@ void machine_kexec(struct kimage *kimage)
* uses physical addressing to relocate the new image to its final
* position and transfers control to the image entry point when the
* relocation is complete.
* In kexec case, kimage->start points to purgatory assuming that
* kernel entry and dtb address are embedded in purgatory by
* userspace (kexec-tools).
* In kexec_file case, the kernel starts directly without purgatory.
*/
cpu_soft_restart
(
reboot_code_buffer_phys
,
kimage
->
head
,
kimage
->
start
,
0
);
cpu_soft_restart
(
reboot_code_buffer_phys
,
kimage
->
head
,
kimage
->
start
,
#ifdef CONFIG_KEXEC_FILE
kimage
->
arch
.
dtb_mem
);
#else
0
);
#endif
BUG
();
/* Should never get here. */
}
...
...
arch/arm64/kernel/machine_kexec_file.c
0 → 100644
View file @
d34664f6
// SPDX-License-Identifier: GPL-2.0
/*
* kexec_file for arm64
*
* Copyright (C) 2018 Linaro Limited
* Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
*
* Most code is derived from arm64 port of kexec-tools
*/
#define pr_fmt(fmt) "kexec_file: " fmt
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/kexec.h>
#include <linux/libfdt.h>
#include <linux/memblock.h>
#include <linux/of_fdt.h>
#include <linux/random.h>
#include <linux/string.h>
#include <linux/types.h>
#include <asm/byteorder.h>
/* relevant device tree properties */
#define FDT_PROP_INITRD_START "linux,initrd-start"
#define FDT_PROP_INITRD_END "linux,initrd-end"
#define FDT_PROP_BOOTARGS "bootargs"
#define FDT_PROP_KASLR_SEED "kaslr-seed"
const
struct
kexec_file_ops
*
const
kexec_file_loaders
[]
=
{
&
kexec_image_ops
,
NULL
};
int
arch_kimage_file_post_load_cleanup
(
struct
kimage
*
image
)
{
vfree
(
image
->
arch
.
dtb
);
image
->
arch
.
dtb
=
NULL
;
return
kexec_image_post_load_cleanup_default
(
image
);
}
static
int
setup_dtb
(
struct
kimage
*
image
,
unsigned
long
initrd_load_addr
,
unsigned
long
initrd_len
,
char
*
cmdline
,
void
*
dtb
)
{
int
off
,
ret
;
ret
=
fdt_path_offset
(
dtb
,
"/chosen"
);
if
(
ret
<
0
)
goto
out
;
off
=
ret
;
/* add bootargs */
if
(
cmdline
)
{
ret
=
fdt_setprop_string
(
dtb
,
off
,
FDT_PROP_BOOTARGS
,
cmdline
);
if
(
ret
)
goto
out
;
}
else
{
ret
=
fdt_delprop
(
dtb
,
off
,
FDT_PROP_BOOTARGS
);
if
(
ret
&&
(
ret
!=
-
FDT_ERR_NOTFOUND
))
goto
out
;
}
/* add initrd-* */
if
(
initrd_load_addr
)
{
ret
=
fdt_setprop_u64
(
dtb
,
off
,
FDT_PROP_INITRD_START
,
initrd_load_addr
);
if
(
ret
)
goto
out
;
ret
=
fdt_setprop_u64
(
dtb
,
off
,
FDT_PROP_INITRD_END
,
initrd_load_addr
+
initrd_len
);
if
(
ret
)
goto
out
;
}
else
{
ret
=
fdt_delprop
(
dtb
,
off
,
FDT_PROP_INITRD_START
);
if
(
ret
&&
(
ret
!=
-
FDT_ERR_NOTFOUND
))
goto
out
;
ret
=
fdt_delprop
(
dtb
,
off
,
FDT_PROP_INITRD_END
);
if
(
ret
&&
(
ret
!=
-
FDT_ERR_NOTFOUND
))
goto
out
;
}
/* add kaslr-seed */
ret
=
fdt_delprop
(
dtb
,
off
,
FDT_PROP_KASLR_SEED
);
if
(
ret
&&
(
ret
!=
-
FDT_ERR_NOTFOUND
))
goto
out
;
if
(
rng_is_initialized
())
{
u64
seed
=
get_random_u64
();
ret
=
fdt_setprop_u64
(
dtb
,
off
,
FDT_PROP_KASLR_SEED
,
seed
);
if
(
ret
)
goto
out
;
}
else
{
pr_notice
(
"RNG is not initialised: omitting
\"
%s
\"
property
\n
"
,
FDT_PROP_KASLR_SEED
);
}
out:
if
(
ret
)
return
(
ret
==
-
FDT_ERR_NOSPACE
)
?
-
ENOMEM
:
-
EINVAL
;
return
0
;
}
/*
* More space needed so that we can add initrd, bootargs and kaslr-seed.
*/
#define DTB_EXTRA_SPACE 0x1000
static
int
create_dtb
(
struct
kimage
*
image
,
unsigned
long
initrd_load_addr
,
unsigned
long
initrd_len
,
char
*
cmdline
,
void
**
dtb
)
{
void
*
buf
;
size_t
buf_size
;
int
ret
;
buf_size
=
fdt_totalsize
(
initial_boot_params
)
+
strlen
(
cmdline
)
+
DTB_EXTRA_SPACE
;
for
(;;)
{
buf
=
vmalloc
(
buf_size
);
if
(
!
buf
)
return
-
ENOMEM
;
/* duplicate a device tree blob */
ret
=
fdt_open_into
(
initial_boot_params
,
buf
,
buf_size
);
if
(
ret
)
return
-
EINVAL
;
ret
=
setup_dtb
(
image
,
initrd_load_addr
,
initrd_len
,
cmdline
,
buf
);
if
(
ret
)
{
vfree
(
buf
);
if
(
ret
==
-
ENOMEM
)
{
/* unlikely, but just in case */
buf_size
+=
DTB_EXTRA_SPACE
;
continue
;
}
else
{
return
ret
;
}
}
/* trim it */
fdt_pack
(
buf
);
*
dtb
=
buf
;
return
0
;
}
}
int
load_other_segments
(
struct
kimage
*
image
,
unsigned
long
kernel_load_addr
,
unsigned
long
kernel_size
,
char
*
initrd
,
unsigned
long
initrd_len
,
char
*
cmdline
)
{
struct
kexec_buf
kbuf
;
void
*
dtb
=
NULL
;
unsigned
long
initrd_load_addr
=
0
,
dtb_len
;
int
ret
=
0
;
kbuf
.
image
=
image
;
/* not allocate anything below the kernel */
kbuf
.
buf_min
=
kernel_load_addr
+
kernel_size
;
/* load initrd */
if
(
initrd
)
{
kbuf
.
buffer
=
initrd
;
kbuf
.
bufsz
=
initrd_len
;
kbuf
.
mem
=
0
;
kbuf
.
memsz
=
initrd_len
;
kbuf
.
buf_align
=
0
;
/* within 1GB-aligned window of up to 32GB in size */
kbuf
.
buf_max
=
round_down
(
kernel_load_addr
,
SZ_1G
)
+
(
unsigned
long
)
SZ_1G
*
32
;
kbuf
.
top_down
=
false
;
ret
=
kexec_add_buffer
(
&
kbuf
);
if
(
ret
)
goto
out_err
;
initrd_load_addr
=
kbuf
.
mem
;
pr_debug
(
"Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx
\n
"
,
initrd_load_addr
,
initrd_len
,
initrd_len
);
}
/* load dtb */
ret
=
create_dtb
(
image
,
initrd_load_addr
,
initrd_len
,
cmdline
,
&
dtb
);
if
(
ret
)
{
pr_err
(
"Preparing for new dtb failed
\n
"
);
goto
out_err
;
}
dtb_len
=
fdt_totalsize
(
dtb
);
kbuf
.
buffer
=
dtb
;
kbuf
.
bufsz
=
dtb_len
;
kbuf
.
mem
=
0
;
kbuf
.
memsz
=
dtb_len
;
/* not across 2MB boundary */
kbuf
.
buf_align
=
SZ_2M
;
kbuf
.
buf_max
=
ULONG_MAX
;
kbuf
.
top_down
=
true
;
ret
=
kexec_add_buffer
(
&
kbuf
);
if
(
ret
)
goto
out_err
;
image
->
arch
.
dtb
=
dtb
;
image
->
arch
.
dtb_mem
=
kbuf
.
mem
;
pr_debug
(
"Loaded dtb at 0x%lx bufsz=0x%lx memsz=0x%lx
\n
"
,
kbuf
.
mem
,
dtb_len
,
dtb_len
);
return
0
;
out_err:
vfree
(
dtb
);
return
ret
;
}
arch/arm64/kernel/relocate_kernel.S
View file @
d34664f6
...
...
@@ -32,6 +32,7 @@
ENTRY
(
arm64_relocate_new_kernel
)
/
*
Setup
the
list
loop
variables
.
*/
mov
x18
,
x2
/*
x18
=
dtb
address
*/
mov
x17
,
x1
/*
x17
=
kimage_start
*/
mov
x16
,
x0
/*
x16
=
kimage_head
*/
raw_dcache_line_size
x15
,
x0
/*
x15
=
dcache
line
size
*/
...
...
@@ -107,7 +108,7 @@ ENTRY(arm64_relocate_new_kernel)
isb
/
*
Start
new
image
.
*/
mov
x0
,
x
zr
mov
x0
,
x
18
mov
x1
,
xzr
mov
x2
,
xzr
mov
x3
,
xzr
...
...
arch/powerpc/kernel/machine_kexec_file_64.c
View file @
d34664f6
...
...
@@ -24,7 +24,6 @@
#include <linux/slab.h>
#include <linux/kexec.h>
#include <linux/memblock.h>
#include <linux/of_fdt.h>
#include <linux/libfdt.h>
#include <asm/ima.h>
...
...
@@ -46,59 +45,6 @@ int arch_kexec_kernel_image_probe(struct kimage *image, void *buf,
return
kexec_image_probe_default
(
image
,
buf
,
buf_len
);
}
/**
* arch_kexec_walk_mem - call func(data) for each unreserved memory block
* @kbuf: Context info for the search. Also passed to @func.
* @func: Function to call for each memory block.
*
* This function is used by kexec_add_buffer and kexec_locate_mem_hole
* to find unreserved memory to load kexec segments into.
*
* Return: The memory walk will stop when func returns a non-zero value
* and that value will be returned. If all free regions are visited without
* func returning non-zero, then zero will be returned.
*/
int
arch_kexec_walk_mem
(
struct
kexec_buf
*
kbuf
,
int
(
*
func
)(
struct
resource
*
,
void
*
))
{
int
ret
=
0
;
u64
i
;
phys_addr_t
mstart
,
mend
;
struct
resource
res
=
{
};
if
(
kbuf
->
top_down
)
{
for_each_free_mem_range_reverse
(
i
,
NUMA_NO_NODE
,
0
,
&
mstart
,
&
mend
,
NULL
)
{
/*
* In memblock, end points to the first byte after the
* range while in kexec, end points to the last byte
* in the range.
*/
res
.
start
=
mstart
;
res
.
end
=
mend
-
1
;
ret
=
func
(
&
res
,
kbuf
);
if
(
ret
)
break
;
}
}
else
{
for_each_free_mem_range
(
i
,
NUMA_NO_NODE
,
0
,
&
mstart
,
&
mend
,
NULL
)
{
/*
* In memblock, end points to the first byte after the
* range while in kexec, end points to the last byte
* in the range.
*/
res
.
start
=
mstart
;
res
.
end
=
mend
-
1
;
ret
=
func
(
&
res
,
kbuf
);
if
(
ret
)
break
;
}
}
return
ret
;
}
/**
* setup_purgatory - initialize the purgatory's global variables
* @image: kexec image.
...
...
arch/s390/kernel/machine_kexec_file.c
View file @
d34664f6
...
...
@@ -134,16 +134,6 @@ int kexec_file_add_initrd(struct kimage *image, struct s390_load_data *data,
return
ret
;
}
/*
* The kernel is loaded to a fixed location. Turn off kexec_locate_mem_hole
* and provide kbuf->mem by hand.
*/
int
arch_kexec_walk_mem
(
struct
kexec_buf
*
kbuf
,
int
(
*
func
)(
struct
resource
*
,
void
*
))
{
return
1
;
}
int
arch_kexec_apply_relocations_add
(
struct
purgatory_info
*
pi
,
Elf_Shdr
*
section
,
const
Elf_Shdr
*
relsec
,
...
...
include/linux/kexec.h
View file @
d34664f6
...
...
@@ -143,6 +143,15 @@ extern const struct kexec_file_ops * const kexec_file_loaders[];
int
kexec_image_probe_default
(
struct
kimage
*
image
,
void
*
buf
,
unsigned
long
buf_len
);
int
kexec_image_post_load_cleanup_default
(
struct
kimage
*
image
);
/*
* If kexec_buf.mem is set to this value, kexec_locate_mem_hole()
* will try to allocate free memory. Arch may overwrite it.
*/
#ifndef KEXEC_BUF_MEM_UNKNOWN
#define KEXEC_BUF_MEM_UNKNOWN 0
#endif
/**
* struct kexec_buf - parameters for finding a place for a buffer in memory
...
...
@@ -183,8 +192,6 @@ int __weak arch_kexec_apply_relocations(struct purgatory_info *pi,
const
Elf_Shdr
*
relsec
,
const
Elf_Shdr
*
symtab
);
int
__weak
arch_kexec_walk_mem
(
struct
kexec_buf
*
kbuf
,
int
(
*
func
)(
struct
resource
*
,
void
*
));
extern
int
kexec_add_buffer
(
struct
kexec_buf
*
kbuf
);
int
kexec_locate_mem_hole
(
struct
kexec_buf
*
kbuf
);
...
...
include/linux/pe.h
View file @
d34664f6
...
...
@@ -166,7 +166,7 @@ struct mz_hdr {
uint16_t
oem_info
;
/* oem specific */
uint16_t
reserved1
[
10
];
/* reserved */
uint32_t
peaddr
;
/* address of pe header */
char
message
[
64
];
/* message to print */
char
message
[];
/* message to print */
};
struct
mz_reloc
{
...
...
include/uapi/asm-generic/unistd.h
View file @
d34664f6
...
...
@@ -738,9 +738,11 @@ __SYSCALL(__NR_statx, sys_statx)
__SC_COMP
(
__NR_io_pgetevents
,
sys_io_pgetevents
,
compat_sys_io_pgetevents
)
#define __NR_rseq 293
__SYSCALL
(
__NR_rseq
,
sys_rseq
)
#define __NR_kexec_file_load 294
__SYSCALL
(
__NR_kexec_file_load
,
sys_kexec_file_load
)
#undef __NR_syscalls
#define __NR_syscalls 29
4
#define __NR_syscalls 29
5
/*
* 32 bit systems traditionally used different
...
...
kernel/kexec_file.c
View file @
d34664f6
...
...
@@ -16,6 +16,7 @@
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/kexec.h>
#include <linux/memblock.h>
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/fs.h>
...
...
@@ -76,7 +77,7 @@ void * __weak arch_kexec_kernel_image_load(struct kimage *image)
return
kexec_image_load_default
(
image
);
}
static
int
kexec_image_post_load_cleanup_default
(
struct
kimage
*
image
)
int
kexec_image_post_load_cleanup_default
(
struct
kimage
*
image
)
{
if
(
!
image
->
fops
||
!
image
->
fops
->
cleanup
)
return
0
;
...
...
@@ -499,8 +500,60 @@ static int locate_mem_hole_callback(struct resource *res, void *arg)
return
locate_mem_hole_bottom_up
(
start
,
end
,
kbuf
);
}
#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
static
int
kexec_walk_memblock
(
struct
kexec_buf
*
kbuf
,
int
(
*
func
)(
struct
resource
*
,
void
*
))
{
return
0
;
}
#else
static
int
kexec_walk_memblock
(
struct
kexec_buf
*
kbuf
,
int
(
*
func
)(
struct
resource
*
,
void
*
))
{
int
ret
=
0
;
u64
i
;
phys_addr_t
mstart
,
mend
;
struct
resource
res
=
{
};
if
(
kbuf
->
image
->
type
==
KEXEC_TYPE_CRASH
)
return
func
(
&
crashk_res
,
kbuf
);
if
(
kbuf
->
top_down
)
{
for_each_free_mem_range_reverse
(
i
,
NUMA_NO_NODE
,
MEMBLOCK_NONE
,
&
mstart
,
&
mend
,
NULL
)
{
/*
* In memblock, end points to the first byte after the
* range while in kexec, end points to the last byte
* in the range.
*/
res
.
start
=
mstart
;
res
.
end
=
mend
-
1
;
ret
=
func
(
&
res
,
kbuf
);
if
(
ret
)
break
;
}
}
else
{
for_each_free_mem_range
(
i
,
NUMA_NO_NODE
,
MEMBLOCK_NONE
,
&
mstart
,
&
mend
,
NULL
)
{
/*
* In memblock, end points to the first byte after the
* range while in kexec, end points to the last byte
* in the range.
*/
res
.
start
=
mstart
;
res
.
end
=
mend
-
1
;
ret
=
func
(
&
res
,
kbuf
);
if
(
ret
)
break
;
}
}
return
ret
;
}
#endif
/**
*
arch_kexec_walk_mem
- call func(data) on free memory regions
*
kexec_walk_resources
- call func(data) on free memory regions
* @kbuf: Context info for the search. Also passed to @func.
* @func: Function to call for each memory region.
*
...
...
@@ -508,8 +561,8 @@ static int locate_mem_hole_callback(struct resource *res, void *arg)
* and that value will be returned. If all free regions are visited without
* func returning non-zero, then zero will be returned.
*/
int
__weak
arch_kexec_walk_mem
(
struct
kexec_buf
*
kbuf
,
int
(
*
func
)(
struct
resource
*
,
void
*
))
static
int
kexec_walk_resources
(
struct
kexec_buf
*
kbuf
,
int
(
*
func
)(
struct
resource
*
,
void
*
))
{
if
(
kbuf
->
image
->
type
==
KEXEC_TYPE_CRASH
)
return
walk_iomem_res_desc
(
crashk_res
.
desc
,
...
...
@@ -532,7 +585,14 @@ int kexec_locate_mem_hole(struct kexec_buf *kbuf)
{
int
ret
;
ret
=
arch_kexec_walk_mem
(
kbuf
,
locate_mem_hole_callback
);
/* Arch knows where to place */
if
(
kbuf
->
mem
!=
KEXEC_BUF_MEM_UNKNOWN
)
return
0
;
if
(
IS_ENABLED
(
CONFIG_ARCH_DISCARD_MEMBLOCK
))
ret
=
kexec_walk_resources
(
kbuf
,
locate_mem_hole_callback
);
else
ret
=
kexec_walk_memblock
(
kbuf
,
locate_mem_hole_callback
);
return
ret
==
1
?
0
:
-
EADDRNOTAVAIL
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment