1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * efi_selftest_open_protocol
4 *
5 * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
6 *
7 * This unit test checks that open protocol information is correctly updated
8 * when calling:
9 * HandleProtocol, OpenProtocol, OpenProtocolInformation, CloseProtocol.
10 */
11
12 #include <efi_selftest.h>
13
14 /*
15 * The test currently does not actually call the interface function.
16 * So this is just a dummy structure.
17 */
18 struct interface {
19 void (EFIAPI *inc)(void);
20 };
21
22 static struct efi_boot_services *boottime;
23 static efi_guid_t guid1 =
24 EFI_GUID(0x492a0e38, 0x1442, 0xf819,
25 0x14, 0xaa, 0x4b, 0x8d, 0x09, 0xfe, 0x5a, 0xb9);
26 static efi_handle_t handle1;
27 static struct interface interface1;
28
29 /*
30 * Setup unit test.
31 *
32 * Create a handle and install a protocol interface on it.
33 *
34 * @handle: handle of the loaded image
35 * @systable: system table
36 */
setup(const efi_handle_t img_handle,const struct efi_system_table * systable)37 static int setup(const efi_handle_t img_handle,
38 const struct efi_system_table *systable)
39 {
40 efi_status_t ret;
41
42 boottime = systable->boottime;
43
44 ret = boottime->install_protocol_interface(&handle1, &guid1,
45 EFI_NATIVE_INTERFACE,
46 &interface1);
47 if (ret != EFI_SUCCESS) {
48 efi_st_error("InstallProtocolInterface failed\n");
49 return EFI_ST_FAILURE;
50 }
51 if (!handle1) {
52 efi_st_error
53 ("InstallProtocolInterface failed to create handle\n");
54 return EFI_ST_FAILURE;
55 }
56 return EFI_ST_SUCCESS;
57 }
58
59 /*
60 * Tear down unit test.
61 *
62 */
teardown(void)63 static int teardown(void)
64 {
65 efi_status_t ret;
66
67 if (handle1) {
68 ret = boottime->uninstall_protocol_interface(handle1, &guid1,
69 &interface1);
70 if (ret != EFI_SUCCESS) {
71 efi_st_error("UninstallProtocolInterface failed\n");
72 return EFI_ST_FAILURE;
73 }
74 }
75 return EFI_ST_SUCCESS;
76 }
77
78 /*
79 * Execute unit test.
80 *
81 * Open the installed protocol twice via HandleProtocol() and once via
82 * OpenProtocol(EFI_OPEN_PROTOCOL_GET_PROTOCOL). Read the open protocol
83 * information and check the open counts. Finally close the protocol and
84 * check again.
85 */
execute(void)86 static int execute(void)
87 {
88 void *interface;
89 struct efi_open_protocol_info_entry *entry_buffer;
90 efi_uintn_t entry_count;
91 efi_handle_t firmware_handle;
92 efi_status_t ret;
93
94 ret = boottime->handle_protocol(handle1, &guid1, &interface);
95 if (ret != EFI_SUCCESS) {
96 efi_st_error("HandleProtocol failed\n");
97 return EFI_ST_FAILURE;
98 }
99 if (interface != &interface1) {
100 efi_st_error("HandleProtocol returned wrong interface\n");
101 return EFI_ST_FAILURE;
102 }
103 ret = boottime->open_protocol_information(handle1, &guid1,
104 &entry_buffer, &entry_count);
105 if (ret != EFI_SUCCESS) {
106 efi_st_error("OpenProtocolInformation failed\n");
107 return EFI_ST_FAILURE;
108 }
109 if (entry_count != 1) {
110 efi_st_error("Incorrect OpenProtocolInformation count\n");
111 efi_st_printf("Expected 1, got %u\n",
112 (unsigned int)entry_count);
113 return EFI_ST_FAILURE;
114 }
115 ret = boottime->free_pool(entry_buffer);
116 if (ret != EFI_SUCCESS) {
117 efi_st_error("FreePool failed\n");
118 return EFI_ST_FAILURE;
119 }
120 ret = boottime->handle_protocol(handle1, &guid1, &interface);
121 if (ret != EFI_SUCCESS) {
122 efi_st_error("HandleProtocol failed\n");
123 return EFI_ST_FAILURE;
124 }
125 ret = boottime->open_protocol_information(handle1, &guid1,
126 &entry_buffer, &entry_count);
127 if (ret != EFI_SUCCESS) {
128 efi_st_error("OpenProtocolInformation failed\n");
129 return EFI_ST_FAILURE;
130 }
131 if (entry_count != 1) {
132 efi_st_error("Incorrect OpenProtocolInformation count\n");
133 efi_st_printf("Expected 1, got %u\n",
134 (unsigned int)entry_count);
135 return EFI_ST_FAILURE;
136 }
137 if (entry_buffer[0].open_count != 2) {
138 efi_st_error("Incorrect open count: expected 2 got %u\n",
139 entry_buffer[0].open_count);
140 return EFI_ST_FAILURE;
141 }
142 firmware_handle = entry_buffer[0].agent_handle;
143 ret = boottime->free_pool(entry_buffer);
144 if (ret != EFI_SUCCESS) {
145 efi_st_error("FreePool failed\n");
146 return EFI_ST_FAILURE;
147 }
148 ret = boottime->open_protocol(handle1, &guid1, &interface,
149 firmware_handle, NULL,
150 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
151 if (ret != EFI_SUCCESS) {
152 efi_st_error("OpenProtocol failed\n");
153 return EFI_ST_FAILURE;
154 }
155 ret = boottime->open_protocol_information(handle1, &guid1,
156 &entry_buffer, &entry_count);
157 if (ret != EFI_SUCCESS) {
158 efi_st_error("OpenProtocolInformation failed\n");
159 return EFI_ST_FAILURE;
160 }
161 if (entry_count != 2) {
162 efi_st_error("Incorrect OpenProtocolInformation count\n");
163 efi_st_printf("Expected 2, got %u\n",
164 (unsigned int)entry_count);
165 return EFI_ST_FAILURE;
166 }
167 if (entry_buffer[0].open_count + entry_buffer[1].open_count != 3) {
168 efi_st_error("Incorrect open count: expected 3 got %u\n",
169 entry_buffer[0].open_count +
170 entry_buffer[1].open_count);
171 return EFI_ST_FAILURE;
172 }
173 ret = boottime->free_pool(entry_buffer);
174 if (ret != EFI_SUCCESS) {
175 efi_st_error("FreePool failed\n");
176 return EFI_ST_FAILURE;
177 }
178 ret = boottime->close_protocol(handle1, &guid1, firmware_handle, NULL);
179 if (ret != EFI_SUCCESS) {
180 efi_st_error("CloseProtocol failed\n");
181 return EFI_ST_FAILURE;
182 }
183 ret = boottime->open_protocol_information(handle1, &guid1,
184 &entry_buffer, &entry_count);
185 if (ret != EFI_SUCCESS) {
186 efi_st_error("OpenProtocolInformation failed\n");
187 return EFI_ST_FAILURE;
188 }
189 if (entry_count) {
190 efi_st_error("Incorrect OpenProtocolInformation count\n");
191 efi_st_printf("Expected 0, got %u\n",
192 (unsigned int)entry_count);
193 return EFI_ST_FAILURE;
194 }
195
196 return EFI_ST_SUCCESS;
197 }
198
199 EFI_UNIT_TEST(openprot) = {
200 .name = "open protocol",
201 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
202 .setup = setup,
203 .execute = execute,
204 .teardown = teardown,
205 };
206