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