Merge branch 'x86-topology-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-block.git] / arch / x86 / purgatory / purgatory.c
CommitLineData
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
17unsigned long purgatory_backup_dest __section(.kexec-purgatory);
18unsigned long purgatory_backup_src __section(.kexec-purgatory);
19unsigned long purgatory_backup_sz __section(.kexec-purgatory);
8fc5b4d4 20
40c50c1f 21u8 purgatory_sha256_digest[SHA256_DIGEST_SIZE] __section(.kexec-purgatory);
8fc5b4d4 22
40c50c1f 23struct 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 */
30static 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 39static 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
59void 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}