Commit | Line | Data |
---|---|---|
8fc5b4d4 VG |
1 | /* |
2 | * purgatory: Runs between two kernels | |
3 | * | |
4 | * Copyright (C) 2014 Red Hat Inc. | |
5 | * | |
6 | * Author: | |
7 | * Vivek Goyal <vgoyal@redhat.com> | |
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 | ||
40c50c1f | 13 | #include <linux/bug.h> |
df6f2801 | 14 | #include <linux/sha256.h> |
40c50c1f TG |
15 | #include <asm/purgatory.h> |
16 | ||
8fc5b4d4 VG |
17 | #include "../boot/string.h" |
18 | ||
40c50c1f TG |
19 | unsigned long purgatory_backup_dest __section(.kexec-purgatory); |
20 | unsigned long purgatory_backup_src __section(.kexec-purgatory); | |
21 | unsigned long purgatory_backup_sz __section(.kexec-purgatory); | |
8fc5b4d4 | 22 | |
40c50c1f | 23 | u8 purgatory_sha256_digest[SHA256_DIGEST_SIZE] __section(.kexec-purgatory); |
8fc5b4d4 | 24 | |
40c50c1f | 25 | struct kexec_sha_region purgatory_sha_regions[KEXEC_SEGMENT_MAX] __section(.kexec-purgatory); |
8fc5b4d4 VG |
26 | |
27 | /* | |
28 | * On x86, second kernel requries first 640K of memory to boot. Copy | |
29 | * first 640K to a backup region in reserved memory range so that second | |
30 | * kernel can use first 640K. | |
31 | */ | |
32 | static int copy_backup_region(void) | |
33 | { | |
40c50c1f TG |
34 | if (purgatory_backup_dest) { |
35 | memcpy((void *)purgatory_backup_dest, | |
36 | (void *)purgatory_backup_src, purgatory_backup_sz); | |
37 | } | |
8fc5b4d4 VG |
38 | return 0; |
39 | } | |
40 | ||
72042a8c | 41 | static int verify_sha256_digest(void) |
8fc5b4d4 | 42 | { |
40c50c1f | 43 | struct kexec_sha_region *ptr, *end; |
8fc5b4d4 VG |
44 | u8 digest[SHA256_DIGEST_SIZE]; |
45 | struct sha256_state sctx; | |
46 | ||
47 | sha256_init(&sctx); | |
40c50c1f TG |
48 | end = purgatory_sha_regions + ARRAY_SIZE(purgatory_sha_regions); |
49 | ||
50 | for (ptr = purgatory_sha_regions; ptr < end; ptr++) | |
8fc5b4d4 VG |
51 | sha256_update(&sctx, (uint8_t *)(ptr->start), ptr->len); |
52 | ||
53 | sha256_final(&sctx, digest); | |
54 | ||
40c50c1f | 55 | if (memcmp(digest, purgatory_sha256_digest, sizeof(digest))) |
8fc5b4d4 VG |
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 | } |