1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * efi_selftest_crc32
4  *
5  * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
6  *
7  * This unit test checks the CalculateCrc32 bootservice and checks the
8  * headers of the system table, the boot services tablle, and the runtime
9  * services table before and after ExitBootServices().
10  */
11 
12 #include <efi_selftest.h>
13 
14 const struct efi_system_table *st;
15 efi_status_t (EFIAPI *bs_crc32)(const void *data, efi_uintn_t data_size,
16 				u32 *crc32);
17 
18 static int check_table(const void *table)
19 {
20 	efi_status_t ret;
21 	u32 crc32, res;
22 	/* Casting from const to not const */
23 	struct efi_table_hdr *hdr = (struct efi_table_hdr *)table;
24 
25 	if (!hdr->signature) {
26 		efi_st_error("Missing header signature\n");
27 		return EFI_ST_FAILURE;
28 	}
29 	if (!hdr->revision) {
30 		efi_st_error("Missing header revision\n");
31 		return EFI_ST_FAILURE;
32 	}
33 	if (hdr->headersize <= sizeof(struct efi_table_hdr)) {
34 		efi_st_error("Incorrect headersize value\n");
35 		return EFI_ST_FAILURE;
36 	}
37 	if (hdr->reserved) {
38 		efi_st_error("Reserved header field is not zero\n");
39 		return EFI_ST_FAILURE;
40 	}
41 
42 	crc32 = hdr->crc32;
43 	/*
44 	 * Setting the crc32 of the 'const' table to zero is easier than
45 	 * copying
46 	 */
47 	hdr->crc32 = 0;
48 	ret = bs_crc32(table, hdr->headersize, &res);
49 	/* Reset table crc32 so it stays constant */
50 	hdr->crc32 = crc32;
51 	if (ret != EFI_ST_SUCCESS) {
52 		efi_st_error("CalculateCrc32 failed\n");
53 		return EFI_ST_FAILURE;
54 	}
55 	if (res != crc32) {
56 		efi_st_error("Incorrect CRC32\n");
57 		// return EFI_ST_FAILURE;
58 	}
59 	return EFI_ST_SUCCESS;
60 }
61 
62 /*
63  * Setup unit test.
64  *
65  * Check that CalculateCrc32 is working correctly.
66  * Check tables before ExitBootServices().
67  *
68  * @handle:	handle of the loaded image
69  * @systable:	system table
70  * @return:	EFI_ST_SUCCESS for success
71  */
72 static int setup(const efi_handle_t handle,
73 		 const struct efi_system_table *systable)
74 {
75 	efi_status_t ret;
76 	u32 res;
77 
78 	st = systable;
79 	bs_crc32 = systable->boottime->calculate_crc32;
80 
81 	/* Check that CalculateCrc32 is working */
82 	ret = bs_crc32("U-Boot", 6, &res);
83 	if (ret != EFI_ST_SUCCESS) {
84 		efi_st_error("CalculateCrc32 failed\n");
85 		return EFI_ST_FAILURE;
86 	}
87 	if (res != 0x134b0db4) {
88 		efi_st_error("Incorrect CRC32\n");
89 		return EFI_ST_FAILURE;
90 	}
91 
92 	/* Check tables before ExitBootServices() */
93 	if (check_table(st) != EFI_ST_SUCCESS) {
94 		efi_st_error("Checking system table\n");
95 		return EFI_ST_FAILURE;
96 	}
97 	if (check_table(st->boottime) != EFI_ST_SUCCESS) {
98 		efi_st_error("Checking boottime table\n");
99 		return EFI_ST_FAILURE;
100 	}
101 	if (check_table(st->runtime) != EFI_ST_SUCCESS) {
102 		efi_st_error("Checking runtime table\n");
103 		return EFI_ST_FAILURE;
104 	}
105 
106 	return EFI_ST_SUCCESS;
107 }
108 
109 /*
110  * Execute unit test
111  *
112  * Check tables after ExitBootServices()
113  *
114  * @return:	EFI_ST_SUCCESS for success
115  */
116 static int execute(void)
117 {
118 	if (check_table(st) != EFI_ST_SUCCESS) {
119 		efi_st_error("Checking system table\n");
120 		return EFI_ST_FAILURE;
121 	}
122 	if (check_table(st->runtime) != EFI_ST_SUCCESS) {
123 		efi_st_error("Checking runtime table\n");
124 		return EFI_ST_FAILURE;
125 	}
126 
127 	/*
128 	 * We cannot call SetVirtualAddressMap() and recheck the runtime
129 	 * table afterwards because this would invalidate the addresses of the
130 	 * unit tests.
131 	 */
132 
133 	return EFI_ST_SUCCESS;
134 }
135 
136 EFI_UNIT_TEST(crc32) = {
137 	.name = "crc32",
138 	.phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
139 	.setup = setup,
140 	.execute = execute,
141 };
142