Skip to content

Commit 8fc5b4d

Browse files
rhvgoyaltorvalds
authored andcommitted
purgatory: core purgatory functionality
Create a stand alone relocatable object purgatory which runs between two kernels. This name, concept and some code has been taken from kexec-tools. Idea is that this code runs after a crash and it runs in minimal environment. So keep it separate from rest of the kernel and in long term we will have to practically do no maintenance of this code. This code also has the logic to do verify sha256 hashes of various segments which have been loaded into memory. So first we verify that the kernel we are jumping to is fine and has not been corrupted and make progress only if checsums are verified. This code also takes care of copying some memory contents to backup region. [[email protected]: run host built programs from objtree] Signed-off-by: Vivek Goyal <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Michael Kerrisk <[email protected]> Cc: Yinghai Lu <[email protected]> Cc: Eric Biederman <[email protected]> Cc: H. Peter Anvin <[email protected]> Cc: Matthew Garrett <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: Dave Young <[email protected]> Cc: WANG Chao <[email protected]> Cc: Baoquan He <[email protected]> Cc: Andy Lutomirski <[email protected]> Signed-off-by: Stephen Rothwell <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent daeba06 commit 8fc5b4d

File tree

8 files changed

+305
-0
lines changed

8 files changed

+305
-0
lines changed

arch/x86/Kbuild

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ obj-$(CONFIG_IA32_EMULATION) += ia32/
1616

1717
obj-y += platform/
1818
obj-y += net/
19+
20+
ifeq ($(CONFIG_X86_64),y)
21+
obj-$(CONFIG_KEXEC) += purgatory/
22+
endif

arch/x86/Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,14 @@ archscripts: scripts_basic
183183
archheaders:
184184
$(Q)$(MAKE) $(build)=arch/x86/syscalls all
185185

186+
archprepare:
187+
ifeq ($(CONFIG_KEXEC),y)
188+
# Build only for 64bit. No loaders for 32bit yet.
189+
ifeq ($(CONFIG_X86_64),y)
190+
$(Q)$(MAKE) $(build)=arch/x86/purgatory arch/x86/purgatory/kexec-purgatory.c
191+
endif
192+
endif
193+
186194
###
187195
# Kernel objects
188196

arch/x86/purgatory/Makefile

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
purgatory-y := purgatory.o stack.o setup-x86_$(BITS).o sha256.o entry64.o string.o
2+
3+
targets += $(purgatory-y)
4+
PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y))
5+
6+
LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined -nostdlib -z nodefaultlib
7+
targets += purgatory.ro
8+
9+
# Default KBUILD_CFLAGS can have -pg option set when FTRACE is enabled. That
10+
# in turn leaves some undefined symbols like __fentry__ in purgatory and not
11+
# sure how to relocate those. Like kexec-tools, use custom flags.
12+
13+
KBUILD_CFLAGS := -fno-strict-aliasing -Wall -Wstrict-prototypes -fno-zero-initialized-in-bss -fno-builtin -ffreestanding -c -MD -Os -mcmodel=large
14+
15+
$(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
16+
$(call if_changed,ld)
17+
18+
targets += kexec-purgatory.c
19+
20+
quiet_cmd_bin2c = BIN2C $@
21+
cmd_bin2c = cat $(obj)/purgatory.ro | $(objtree)/scripts/basic/bin2c kexec_purgatory > $(obj)/kexec-purgatory.c
22+
23+
$(obj)/kexec-purgatory.c: $(obj)/purgatory.ro FORCE
24+
$(call if_changed,bin2c)
25+
26+
27+
# No loaders for 32bits yet.
28+
ifeq ($(CONFIG_X86_64),y)
29+
obj-$(CONFIG_KEXEC) += kexec-purgatory.o
30+
endif

arch/x86/purgatory/entry64.S

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright (C) 2003,2004 Eric Biederman ([email protected])
3+
* Copyright (C) 2014 Red Hat Inc.
4+
5+
* Author(s): Vivek Goyal <[email protected]>
6+
*
7+
* This code has been taken from kexec-tools.
8+
*
9+
* This source code is licensed under the GNU General Public License,
10+
* Version 2. See the file COPYING for more details.
11+
*/
12+
13+
.text
14+
.balign 16
15+
.code64
16+
.globl entry64, entry64_regs
17+
18+
19+
entry64:
20+
/* Setup a gdt that should be preserved */
21+
lgdt gdt(%rip)
22+
23+
/* load the data segments */
24+
movl $0x18, %eax /* data segment */
25+
movl %eax, %ds
26+
movl %eax, %es
27+
movl %eax, %ss
28+
movl %eax, %fs
29+
movl %eax, %gs
30+
31+
/* Setup new stack */
32+
leaq stack_init(%rip), %rsp
33+
pushq $0x10 /* CS */
34+
leaq new_cs_exit(%rip), %rax
35+
pushq %rax
36+
lretq
37+
new_cs_exit:
38+
39+
/* Load the registers */
40+
movq rax(%rip), %rax
41+
movq rbx(%rip), %rbx
42+
movq rcx(%rip), %rcx
43+
movq rdx(%rip), %rdx
44+
movq rsi(%rip), %rsi
45+
movq rdi(%rip), %rdi
46+
movq rsp(%rip), %rsp
47+
movq rbp(%rip), %rbp
48+
movq r8(%rip), %r8
49+
movq r9(%rip), %r9
50+
movq r10(%rip), %r10
51+
movq r11(%rip), %r11
52+
movq r12(%rip), %r12
53+
movq r13(%rip), %r13
54+
movq r14(%rip), %r14
55+
movq r15(%rip), %r15
56+
57+
/* Jump to the new code... */
58+
jmpq *rip(%rip)
59+
60+
.section ".rodata"
61+
.balign 4
62+
entry64_regs:
63+
rax: .quad 0x0
64+
rbx: .quad 0x0
65+
rcx: .quad 0x0
66+
rdx: .quad 0x0
67+
rsi: .quad 0x0
68+
rdi: .quad 0x0
69+
rsp: .quad 0x0
70+
rbp: .quad 0x0
71+
r8: .quad 0x0
72+
r9: .quad 0x0
73+
r10: .quad 0x0
74+
r11: .quad 0x0
75+
r12: .quad 0x0
76+
r13: .quad 0x0
77+
r14: .quad 0x0
78+
r15: .quad 0x0
79+
rip: .quad 0x0
80+
.size entry64_regs, . - entry64_regs
81+
82+
/* GDT */
83+
.section ".rodata"
84+
.balign 16
85+
gdt:
86+
/* 0x00 unusable segment
87+
* 0x08 unused
88+
* so use them as gdt ptr
89+
*/
90+
.word gdt_end - gdt - 1
91+
.quad gdt
92+
.word 0, 0, 0
93+
94+
/* 0x10 4GB flat code segment */
95+
.word 0xFFFF, 0x0000, 0x9A00, 0x00AF
96+
97+
/* 0x18 4GB flat data segment */
98+
.word 0xFFFF, 0x0000, 0x9200, 0x00CF
99+
gdt_end:
100+
stack: .quad 0, 0
101+
stack_init:

arch/x86/purgatory/purgatory.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* purgatory: Runs between two kernels
3+
*
4+
* Copyright (C) 2014 Red Hat Inc.
5+
*
6+
* Author:
7+
* Vivek Goyal <[email protected]>
8+
*
9+
* This source code is licensed under the GNU General Public License,
10+
* Version 2. See the file COPYING for more details.
11+
*/
12+
13+
#include "sha256.h"
14+
#include "../boot/string.h"
15+
16+
struct sha_region {
17+
unsigned long start;
18+
unsigned long len;
19+
};
20+
21+
unsigned long backup_dest = 0;
22+
unsigned long backup_src = 0;
23+
unsigned long backup_sz = 0;
24+
25+
u8 sha256_digest[SHA256_DIGEST_SIZE] = { 0 };
26+
27+
struct sha_region sha_regions[16] = {};
28+
29+
/*
30+
* On x86, second kernel requries first 640K of memory to boot. Copy
31+
* first 640K to a backup region in reserved memory range so that second
32+
* kernel can use first 640K.
33+
*/
34+
static int copy_backup_region(void)
35+
{
36+
if (backup_dest)
37+
memcpy((void *)backup_dest, (void *)backup_src, backup_sz);
38+
39+
return 0;
40+
}
41+
42+
int verify_sha256_digest(void)
43+
{
44+
struct sha_region *ptr, *end;
45+
u8 digest[SHA256_DIGEST_SIZE];
46+
struct sha256_state sctx;
47+
48+
sha256_init(&sctx);
49+
end = &sha_regions[sizeof(sha_regions)/sizeof(sha_regions[0])];
50+
for (ptr = sha_regions; ptr < end; ptr++)
51+
sha256_update(&sctx, (uint8_t *)(ptr->start), ptr->len);
52+
53+
sha256_final(&sctx, digest);
54+
55+
if (memcmp(digest, sha256_digest, sizeof(digest)))
56+
return 1;
57+
58+
return 0;
59+
}
60+
61+
void purgatory(void)
62+
{
63+
int ret;
64+
65+
ret = verify_sha256_digest();
66+
if (ret) {
67+
/* loop forever */
68+
for (;;)
69+
;
70+
}
71+
copy_backup_region();
72+
}

arch/x86/purgatory/setup-x86_64.S

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* purgatory: setup code
3+
*
4+
* Copyright (C) 2003,2004 Eric Biederman ([email protected])
5+
* Copyright (C) 2014 Red Hat Inc.
6+
*
7+
* This code has been taken from kexec-tools.
8+
*
9+
* This source code is licensed under the GNU General Public License,
10+
* Version 2. See the file COPYING for more details.
11+
*/
12+
13+
.text
14+
.globl purgatory_start
15+
.balign 16
16+
purgatory_start:
17+
.code64
18+
19+
/* Load a gdt so I know what the segment registers are */
20+
lgdt gdt(%rip)
21+
22+
/* load the data segments */
23+
movl $0x18, %eax /* data segment */
24+
movl %eax, %ds
25+
movl %eax, %es
26+
movl %eax, %ss
27+
movl %eax, %fs
28+
movl %eax, %gs
29+
30+
/* Setup a stack */
31+
leaq lstack_end(%rip), %rsp
32+
33+
/* Call the C code */
34+
call purgatory
35+
jmp entry64
36+
37+
.section ".rodata"
38+
.balign 16
39+
gdt: /* 0x00 unusable segment
40+
* 0x08 unused
41+
* so use them as the gdt ptr
42+
*/
43+
.word gdt_end - gdt - 1
44+
.quad gdt
45+
.word 0, 0, 0
46+
47+
/* 0x10 4GB flat code segment */
48+
.word 0xFFFF, 0x0000, 0x9A00, 0x00AF
49+
50+
/* 0x18 4GB flat data segment */
51+
.word 0xFFFF, 0x0000, 0x9200, 0x00CF
52+
gdt_end:
53+
54+
.bss
55+
.balign 4096
56+
lstack:
57+
.skip 4096
58+
lstack_end:

arch/x86/purgatory/stack.S

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* purgatory: stack
3+
*
4+
* Copyright (C) 2014 Red Hat Inc.
5+
*
6+
* This source code is licensed under the GNU General Public License,
7+
* Version 2. See the file COPYING for more details.
8+
*/
9+
10+
/* A stack for the loaded kernel.
11+
* Seperate and in the data section so it can be prepopulated.
12+
*/
13+
.data
14+
.balign 4096
15+
.globl stack, stack_end
16+
17+
stack:
18+
.skip 4096
19+
stack_end:

arch/x86/purgatory/string.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* Simple string functions.
3+
*
4+
* Copyright (C) 2014 Red Hat Inc.
5+
*
6+
* Author:
7+
* Vivek Goyal <[email protected]>
8+
*
9+
* This source code is licensed under the GNU General Public License,
10+
* Version 2. See the file COPYING for more details.
11+
*/
12+
13+
#include "../boot/string.c"

0 commit comments

Comments
 (0)