Commit 853540c84fdad4c2b0755c0041e87efba376aec2

Authored by Heinrich Schuchardt
Committed by Alexander Graf
1 parent ac02019616

efi_selftest: colored test output

Add color coding to output:
test section    blue
success         green
errors          red
todo            yellow
summary         white
others          light gray

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Simon Glass <sjg@chromium.org>
[agraf: Fold in move of set_attribute before the print]
Signed-off-by: Alexander Graf <agraf@suse.de>

Showing 3 changed files with 40 additions and 25 deletions Inline Diff

include/efi_selftest.h
1 /* 1 /*
2 * EFI application loader 2 * EFI application loader
3 * 3 *
4 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> 4 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
5 * 5 *
6 * SPDX-License-Identifier: GPL-2.0+ 6 * SPDX-License-Identifier: GPL-2.0+
7 */ 7 */
8 8
9 #ifndef _EFI_SELFTEST_H 9 #ifndef _EFI_SELFTEST_H
10 #define _EFI_SELFTEST_H 10 #define _EFI_SELFTEST_H
11 11
12 #include <common.h> 12 #include <common.h>
13 #include <efi.h> 13 #include <efi.h>
14 #include <efi_api.h> 14 #include <efi_api.h>
15 #include <efi_loader.h> 15 #include <efi_loader.h>
16 #include <linker_lists.h> 16 #include <linker_lists.h>
17 17
18 #define EFI_ST_SUCCESS 0 18 #define EFI_ST_SUCCESS 0
19 #define EFI_ST_FAILURE 1 19 #define EFI_ST_FAILURE 1
20 20
21 /* 21 /*
22 * Prints a message.
23 */
24 #define efi_st_printf(...) \
25 (efi_st_printc(-1, __VA_ARGS__))
26
27 /*
22 * Prints an error message. 28 * Prints an error message.
23 * 29 *
24 * @... format string followed by fields to print 30 * @... format string followed by fields to print
25 */ 31 */
26 #define efi_st_error(...) \ 32 #define efi_st_error(...) \
27 (efi_st_printf("%s(%u):\nERROR: ", __FILE__, __LINE__), \ 33 (efi_st_printc(EFI_LIGHTRED, "%s(%u):\nERROR: ", __FILE__, __LINE__), \
28 efi_st_printf(__VA_ARGS__)) \ 34 efi_st_printc(EFI_LIGHTRED, __VA_ARGS__))
29 35
30 /* 36 /*
31 * Prints a TODO message. 37 * Prints a TODO message.
32 * 38 *
33 * @... format string followed by fields to print 39 * @... format string followed by fields to print
34 */ 40 */
35 #define efi_st_todo(...) \ 41 #define efi_st_todo(...) \
36 (efi_st_printf("%s(%u):\nTODO: ", __FILE__, __LINE__), \ 42 (efi_st_printc(EFI_YELLOW, "%s(%u):\nTODO: ", __FILE__, __LINE__), \
37 efi_st_printf(__VA_ARGS__)) \ 43 efi_st_printc(EFI_YELLOW, __VA_ARGS__)) \
38 44
39 /* 45 /*
40 * A test may be setup and executed at boottime, 46 * A test may be setup and executed at boottime,
41 * it may be setup at boottime and executed at runtime, 47 * it may be setup at boottime and executed at runtime,
42 * or it may be setup and executed at runtime. 48 * or it may be setup and executed at runtime.
43 */ 49 */
44 enum efi_test_phase { 50 enum efi_test_phase {
45 EFI_EXECUTE_BEFORE_BOOTTIME_EXIT = 1, 51 EFI_EXECUTE_BEFORE_BOOTTIME_EXIT = 1,
46 EFI_SETUP_BEFORE_BOOTTIME_EXIT, 52 EFI_SETUP_BEFORE_BOOTTIME_EXIT,
47 EFI_SETUP_AFTER_BOOTTIME_EXIT, 53 EFI_SETUP_AFTER_BOOTTIME_EXIT,
48 }; 54 };
49 55
50 extern struct efi_simple_text_output_protocol *con_out; 56 extern struct efi_simple_text_output_protocol *con_out;
51 extern struct efi_simple_input_interface *con_in; 57 extern struct efi_simple_input_interface *con_in;
52 58
53 /* 59 /*
54 * Exit the boot services. 60 * Exit the boot services.
55 * 61 *
56 * The size of the memory map is determined. 62 * The size of the memory map is determined.
57 * Pool memory is allocated to copy the memory map. 63 * Pool memory is allocated to copy the memory map.
58 * The memory amp is copied and the map key is obtained. 64 * The memory amp is copied and the map key is obtained.
59 * The map key is used to exit the boot services. 65 * The map key is used to exit the boot services.
60 */ 66 */
61 void efi_st_exit_boot_services(void); 67 void efi_st_exit_boot_services(void);
62 68
63 /* 69 /*
64 * Print a pointer to an u16 string 70 * Print a colored message
65 * 71 *
66 * @pointer: pointer 72 * @color color, see constants in efi_api.h, use -1 for no color
67 * @buf: pointer to buffer address 73 * @fmt printf format
68 * on return position of terminating zero word 74 * @... arguments to be printed
75 * on return position of terminating zero word
69 */ 76 */
70 void efi_st_printf(const char *fmt, ...) 77 void efi_st_printc(int color, const char *fmt, ...)
71 __attribute__ ((format (__printf__, 1, 2))); 78 __attribute__ ((format (__printf__, 2, 3)));
72 79
73 /* 80 /*
74 * Compare memory. 81 * Compare memory.
75 * We cannot use lib/string.c due to different CFLAGS values. 82 * We cannot use lib/string.c due to different CFLAGS values.
76 * 83 *
77 * @buf1: first buffer 84 * @buf1: first buffer
78 * @buf2: second buffer 85 * @buf2: second buffer
79 * @length: number of bytes to compare 86 * @length: number of bytes to compare
80 * @return: 0 if both buffers contain the same bytes 87 * @return: 0 if both buffers contain the same bytes
81 */ 88 */
82 int efi_st_memcmp(const void *buf1, const void *buf2, size_t length); 89 int efi_st_memcmp(const void *buf1, const void *buf2, size_t length);
83 90
84 /* 91 /*
85 * Compare an u16 string to a char string. 92 * Compare an u16 string to a char string.
86 * 93 *
87 * @buf1: u16 string 94 * @buf1: u16 string
88 * @buf2: char string 95 * @buf2: char string
89 * @return: 0 if both buffers contain the same bytes 96 * @return: 0 if both buffers contain the same bytes
90 */ 97 */
91 int efi_st_strcmp_16_8(const u16 *buf1, const char *buf2); 98 int efi_st_strcmp_16_8(const u16 *buf1, const char *buf2);
92 99
93 /* 100 /*
94 * Reads an Unicode character from the input device. 101 * Reads an Unicode character from the input device.
95 * 102 *
96 * @return: Unicode character 103 * @return: Unicode character
97 */ 104 */
98 u16 efi_st_get_key(void); 105 u16 efi_st_get_key(void);
99 106
100 /** 107 /**
101 * struct efi_unit_test - EFI unit test 108 * struct efi_unit_test - EFI unit test
102 * 109 *
103 * An efi_unit_test provides a interface to an EFI unit test. 110 * An efi_unit_test provides a interface to an EFI unit test.
104 * 111 *
105 * @name: name of unit test 112 * @name: name of unit test
106 * @phase: specifies when setup and execute are executed 113 * @phase: specifies when setup and execute are executed
107 * @setup: set up the unit test 114 * @setup: set up the unit test
108 * @teardown: tear down the unit test 115 * @teardown: tear down the unit test
109 * @execute: execute the unit test 116 * @execute: execute the unit test
110 * @on_request: test is only executed on request 117 * @on_request: test is only executed on request
111 */ 118 */
112 struct efi_unit_test { 119 struct efi_unit_test {
113 const char *name; 120 const char *name;
114 const enum efi_test_phase phase; 121 const enum efi_test_phase phase;
115 int (*setup)(const efi_handle_t handle, 122 int (*setup)(const efi_handle_t handle,
116 const struct efi_system_table *systable); 123 const struct efi_system_table *systable);
117 int (*execute)(void); 124 int (*execute)(void);
118 int (*teardown)(void); 125 int (*teardown)(void);
119 bool on_request; 126 bool on_request;
120 }; 127 };
121 128
122 /* Declare a new EFI unit test */ 129 /* Declare a new EFI unit test */
123 #define EFI_UNIT_TEST(__name) \ 130 #define EFI_UNIT_TEST(__name) \
124 ll_entry_declare(struct efi_unit_test, __name, efi_unit_test) 131 ll_entry_declare(struct efi_unit_test, __name, efi_unit_test)
125 132
126 #endif /* _EFI_SELFTEST_H */ 133 #endif /* _EFI_SELFTEST_H */
127 134
lib/efi_selftest/efi_selftest.c
1 /* 1 /*
2 * EFI efi_selftest 2 * EFI efi_selftest
3 * 3 *
4 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> 4 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
5 * 5 *
6 * SPDX-License-Identifier: GPL-2.0+ 6 * SPDX-License-Identifier: GPL-2.0+
7 */ 7 */
8 8
9 #include <efi_selftest.h> 9 #include <efi_selftest.h>
10 #include <vsprintf.h> 10 #include <vsprintf.h>
11 11
12 /* 12 /*
13 * Constants for test step bitmap 13 * Constants for test step bitmap
14 */ 14 */
15 #define EFI_ST_SETUP 1 15 #define EFI_ST_SETUP 1
16 #define EFI_ST_EXECUTE 2 16 #define EFI_ST_EXECUTE 2
17 #define EFI_ST_TEARDOWN 4 17 #define EFI_ST_TEARDOWN 4
18 18
19 static const struct efi_system_table *systable; 19 static const struct efi_system_table *systable;
20 static const struct efi_boot_services *boottime; 20 static const struct efi_boot_services *boottime;
21 static const struct efi_runtime_services *runtime; 21 static const struct efi_runtime_services *runtime;
22 static efi_handle_t handle; 22 static efi_handle_t handle;
23 static u16 reset_message[] = L"Selftest completed"; 23 static u16 reset_message[] = L"Selftest completed";
24 24
25 /* 25 /*
26 * Exit the boot services. 26 * Exit the boot services.
27 * 27 *
28 * The size of the memory map is determined. 28 * The size of the memory map is determined.
29 * Pool memory is allocated to copy the memory map. 29 * Pool memory is allocated to copy the memory map.
30 * The memory amp is copied and the map key is obtained. 30 * The memory amp is copied and the map key is obtained.
31 * The map key is used to exit the boot services. 31 * The map key is used to exit the boot services.
32 */ 32 */
33 void efi_st_exit_boot_services(void) 33 void efi_st_exit_boot_services(void)
34 { 34 {
35 efi_uintn_t map_size = 0; 35 efi_uintn_t map_size = 0;
36 efi_uintn_t map_key; 36 efi_uintn_t map_key;
37 efi_uintn_t desc_size; 37 efi_uintn_t desc_size;
38 u32 desc_version; 38 u32 desc_version;
39 efi_status_t ret; 39 efi_status_t ret;
40 struct efi_mem_desc *memory_map; 40 struct efi_mem_desc *memory_map;
41 41
42 ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size, 42 ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
43 &desc_version); 43 &desc_version);
44 if (ret != EFI_BUFFER_TOO_SMALL) { 44 if (ret != EFI_BUFFER_TOO_SMALL) {
45 efi_st_error( 45 efi_st_error(
46 "GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n"); 46 "GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n");
47 return; 47 return;
48 } 48 }
49 /* Allocate extra space for newly allocated memory */ 49 /* Allocate extra space for newly allocated memory */
50 map_size += sizeof(struct efi_mem_desc); 50 map_size += sizeof(struct efi_mem_desc);
51 ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size, 51 ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size,
52 (void **)&memory_map); 52 (void **)&memory_map);
53 if (ret != EFI_SUCCESS) { 53 if (ret != EFI_SUCCESS) {
54 efi_st_error("AllocatePool did not return EFI_SUCCESS\n"); 54 efi_st_error("AllocatePool did not return EFI_SUCCESS\n");
55 return; 55 return;
56 } 56 }
57 ret = boottime->get_memory_map(&map_size, memory_map, &map_key, 57 ret = boottime->get_memory_map(&map_size, memory_map, &map_key,
58 &desc_size, &desc_version); 58 &desc_size, &desc_version);
59 if (ret != EFI_SUCCESS) { 59 if (ret != EFI_SUCCESS) {
60 efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n"); 60 efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n");
61 return; 61 return;
62 } 62 }
63 ret = boottime->exit_boot_services(handle, map_key); 63 ret = boottime->exit_boot_services(handle, map_key);
64 if (ret != EFI_SUCCESS) { 64 if (ret != EFI_SUCCESS) {
65 efi_st_error("ExitBootServices did not return EFI_SUCCESS\n"); 65 efi_st_error("ExitBootServices did not return EFI_SUCCESS\n");
66 return; 66 return;
67 } 67 }
68 efi_st_printf("\nBoot services terminated\n"); 68 efi_st_printc(EFI_WHITE, "\nBoot services terminated\n");
69 } 69 }
70 70
71 /* 71 /*
72 * Set up a test. 72 * Set up a test.
73 * 73 *
74 * @test the test to be executed 74 * @test the test to be executed
75 * @failures counter that will be incremented if a failure occurs 75 * @failures counter that will be incremented if a failure occurs
76 * @return EFI_ST_SUCCESS for success 76 * @return EFI_ST_SUCCESS for success
77 */ 77 */
78 static int setup(struct efi_unit_test *test, unsigned int *failures) 78 static int setup(struct efi_unit_test *test, unsigned int *failures)
79 { 79 {
80 int ret; 80 int ret;
81 81
82 if (!test->setup) 82 if (!test->setup)
83 return EFI_ST_SUCCESS; 83 return EFI_ST_SUCCESS;
84 efi_st_printf("\nSetting up '%s'\n", test->name); 84 efi_st_printc(EFI_LIGHTBLUE, "\nSetting up '%s'\n", test->name);
85 ret = test->setup(handle, systable); 85 ret = test->setup(handle, systable);
86 if (ret != EFI_ST_SUCCESS) { 86 if (ret != EFI_ST_SUCCESS) {
87 efi_st_error("Setting up '%s' failed\n", test->name); 87 efi_st_error("Setting up '%s' failed\n", test->name);
88 ++*failures; 88 ++*failures;
89 } else { 89 } else {
90 efi_st_printf("Setting up '%s' succeeded\n", test->name); 90 efi_st_printc(EFI_LIGHTGREEN,
91 "Setting up '%s' succeeded\n", test->name);
91 } 92 }
92 return ret; 93 return ret;
93 } 94 }
94 95
95 /* 96 /*
96 * Execute a test. 97 * Execute a test.
97 * 98 *
98 * @test the test to be executed 99 * @test the test to be executed
99 * @failures counter that will be incremented if a failure occurs 100 * @failures counter that will be incremented if a failure occurs
100 * @return EFI_ST_SUCCESS for success 101 * @return EFI_ST_SUCCESS for success
101 */ 102 */
102 static int execute(struct efi_unit_test *test, unsigned int *failures) 103 static int execute(struct efi_unit_test *test, unsigned int *failures)
103 { 104 {
104 int ret; 105 int ret;
105 106
106 if (!test->execute) 107 if (!test->execute)
107 return EFI_ST_SUCCESS; 108 return EFI_ST_SUCCESS;
108 efi_st_printf("\nExecuting '%s'\n", test->name); 109 efi_st_printc(EFI_LIGHTBLUE, "\nExecuting '%s'\n", test->name);
109 ret = test->execute(); 110 ret = test->execute();
110 if (ret != EFI_ST_SUCCESS) { 111 if (ret != EFI_ST_SUCCESS) {
111 efi_st_error("Executing '%s' failed\n", test->name); 112 efi_st_error("Executing '%s' failed\n", test->name);
112 ++*failures; 113 ++*failures;
113 } else { 114 } else {
114 efi_st_printf("Executing '%s' succeeded\n", test->name); 115 efi_st_printc(EFI_LIGHTGREEN,
116 "Executing '%s' succeeded\n", test->name);
115 } 117 }
116 return ret; 118 return ret;
117 } 119 }
118 120
119 /* 121 /*
120 * Tear down a test. 122 * Tear down a test.
121 * 123 *
122 * @test the test to be torn down 124 * @test the test to be torn down
123 * @failures counter that will be incremented if a failure occurs 125 * @failures counter that will be incremented if a failure occurs
124 * @return EFI_ST_SUCCESS for success 126 * @return EFI_ST_SUCCESS for success
125 */ 127 */
126 static int teardown(struct efi_unit_test *test, unsigned int *failures) 128 static int teardown(struct efi_unit_test *test, unsigned int *failures)
127 { 129 {
128 int ret; 130 int ret;
129 131
130 if (!test->teardown) 132 if (!test->teardown)
131 return EFI_ST_SUCCESS; 133 return EFI_ST_SUCCESS;
132 efi_st_printf("\nTearing down '%s'\n", test->name); 134 efi_st_printc(EFI_LIGHTBLUE, "\nTearing down '%s'\n", test->name);
133 ret = test->teardown(); 135 ret = test->teardown();
134 if (ret != EFI_ST_SUCCESS) { 136 if (ret != EFI_ST_SUCCESS) {
135 efi_st_error("Tearing down '%s' failed\n", test->name); 137 efi_st_error("Tearing down '%s' failed\n", test->name);
136 ++*failures; 138 ++*failures;
137 } else { 139 } else {
138 efi_st_printf("Tearing down '%s' succeeded\n", test->name); 140 efi_st_printc(EFI_LIGHTGREEN,
141 "Tearing down '%s' succeeded\n", test->name);
139 } 142 }
140 return ret; 143 return ret;
141 } 144 }
142 145
143 /* 146 /*
144 * Check that a test exists. 147 * Check that a test exists.
145 * 148 *
146 * @testname: name of the test 149 * @testname: name of the test
147 * @return: test 150 * @return: test
148 */ 151 */
149 static struct efi_unit_test *find_test(const u16 *testname) 152 static struct efi_unit_test *find_test(const u16 *testname)
150 { 153 {
151 struct efi_unit_test *test; 154 struct efi_unit_test *test;
152 155
153 for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); 156 for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
154 test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { 157 test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
155 if (!efi_st_strcmp_16_8(testname, test->name)) 158 if (!efi_st_strcmp_16_8(testname, test->name))
156 return test; 159 return test;
157 } 160 }
158 efi_st_printf("\nTest '%ps' not found\n", testname); 161 efi_st_printf("\nTest '%ps' not found\n", testname);
159 return NULL; 162 return NULL;
160 } 163 }
161 164
162 /* 165 /*
163 * List all available tests. 166 * List all available tests.
164 */ 167 */
165 static void list_all_tests(void) 168 static void list_all_tests(void)
166 { 169 {
167 struct efi_unit_test *test; 170 struct efi_unit_test *test;
168 171
169 /* List all tests */ 172 /* List all tests */
170 efi_st_printf("\nAvailable tests:\n"); 173 efi_st_printf("\nAvailable tests:\n");
171 for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); 174 for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
172 test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { 175 test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
173 efi_st_printf("'%s'%s\n", test->name, 176 efi_st_printf("'%s'%s\n", test->name,
174 test->on_request ? " - on request" : ""); 177 test->on_request ? " - on request" : "");
175 } 178 }
176 } 179 }
177 180
178 /* 181 /*
179 * Execute test steps of one phase. 182 * Execute test steps of one phase.
180 * 183 *
181 * @testname name of a single selected test or NULL 184 * @testname name of a single selected test or NULL
182 * @phase test phase 185 * @phase test phase
183 * @steps steps to execute 186 * @steps steps to execute
184 * failures returns EFI_ST_SUCCESS if all test steps succeeded 187 * failures returns EFI_ST_SUCCESS if all test steps succeeded
185 */ 188 */
186 void efi_st_do_tests(const u16 *testname, unsigned int phase, 189 void efi_st_do_tests(const u16 *testname, unsigned int phase,
187 unsigned int steps, unsigned int *failures) 190 unsigned int steps, unsigned int *failures)
188 { 191 {
189 struct efi_unit_test *test; 192 struct efi_unit_test *test;
190 193
191 for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); 194 for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
192 test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { 195 test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
193 if (testname ? 196 if (testname ?
194 efi_st_strcmp_16_8(testname, test->name) : test->on_request) 197 efi_st_strcmp_16_8(testname, test->name) : test->on_request)
195 continue; 198 continue;
196 if (test->phase != phase) 199 if (test->phase != phase)
197 continue; 200 continue;
198 if (steps & EFI_ST_SETUP) 201 if (steps & EFI_ST_SETUP)
199 setup(test, failures); 202 setup(test, failures);
200 if (steps & EFI_ST_EXECUTE) 203 if (steps & EFI_ST_EXECUTE)
201 execute(test, failures); 204 execute(test, failures);
202 if (steps & EFI_ST_TEARDOWN) 205 if (steps & EFI_ST_TEARDOWN)
203 teardown(test, failures); 206 teardown(test, failures);
204 } 207 }
205 } 208 }
206 209
207 /* 210 /*
208 * Execute selftest of the EFI API 211 * Execute selftest of the EFI API
209 * 212 *
210 * This is the main entry point of the EFI selftest application. 213 * This is the main entry point of the EFI selftest application.
211 * 214 *
212 * All tests use a driver model and are run in three phases: 215 * All tests use a driver model and are run in three phases:
213 * setup, execute, teardown. 216 * setup, execute, teardown.
214 * 217 *
215 * A test may be setup and executed at boottime, 218 * A test may be setup and executed at boottime,
216 * it may be setup at boottime and executed at runtime, 219 * it may be setup at boottime and executed at runtime,
217 * or it may be setup and executed at runtime. 220 * or it may be setup and executed at runtime.
218 * 221 *
219 * After executing all tests the system is reset. 222 * After executing all tests the system is reset.
220 * 223 *
221 * @image_handle: handle of the loaded EFI image 224 * @image_handle: handle of the loaded EFI image
222 * @systab: EFI system table 225 * @systab: EFI system table
223 */ 226 */
224 efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, 227 efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,
225 struct efi_system_table *systab) 228 struct efi_system_table *systab)
226 { 229 {
227 unsigned int failures = 0; 230 unsigned int failures = 0;
228 const u16 *testname = NULL; 231 const u16 *testname = NULL;
229 struct efi_loaded_image *loaded_image; 232 struct efi_loaded_image *loaded_image;
230 efi_status_t ret; 233 efi_status_t ret;
231 234
232 systable = systab; 235 systable = systab;
233 boottime = systable->boottime; 236 boottime = systable->boottime;
234 runtime = systable->runtime; 237 runtime = systable->runtime;
235 handle = image_handle; 238 handle = image_handle;
236 con_out = systable->con_out; 239 con_out = systable->con_out;
237 con_in = systable->con_in; 240 con_in = systable->con_in;
238 241
239 ret = boottime->handle_protocol(image_handle, &efi_guid_loaded_image, 242 ret = boottime->handle_protocol(image_handle, &efi_guid_loaded_image,
240 (void **)&loaded_image); 243 (void **)&loaded_image);
241 if (ret != EFI_SUCCESS) { 244 if (ret != EFI_SUCCESS) {
242 efi_st_error("Cannot open loaded image protocol\n"); 245 efi_st_error("Cannot open loaded image protocol\n");
243 return ret; 246 return ret;
244 } 247 }
245 248
246 if (loaded_image->load_options) 249 if (loaded_image->load_options)
247 testname = (u16 *)loaded_image->load_options; 250 testname = (u16 *)loaded_image->load_options;
248 251
249 if (testname) { 252 if (testname) {
250 if (!efi_st_strcmp_16_8(testname, "list") || 253 if (!efi_st_strcmp_16_8(testname, "list") ||
251 !find_test(testname)) { 254 !find_test(testname)) {
252 list_all_tests(); 255 list_all_tests();
253 /* 256 /*
254 * TODO: 257 * TODO:
255 * Once the Exit boottime service is correctly 258 * Once the Exit boottime service is correctly
256 * implemented we should call 259 * implemented we should call
257 * boottime->exit(image_handle, EFI_SUCCESS, 0, NULL); 260 * boottime->exit(image_handle, EFI_SUCCESS, 0, NULL);
258 * here, cf. 261 * here, cf.
259 * https://lists.denx.de/pipermail/u-boot/2017-October/308720.html 262 * https://lists.denx.de/pipermail/u-boot/2017-October/308720.html
260 */ 263 */
261 return EFI_SUCCESS; 264 return EFI_SUCCESS;
262 } 265 }
263 } 266 }
264 267
265 efi_st_printf("\nTesting EFI API implementation\n"); 268 efi_st_printc(EFI_WHITE, "\nTesting EFI API implementation\n");
266 269
267 if (testname) 270 if (testname)
268 efi_st_printf("\nSelected test: '%ps'\n", testname); 271 efi_st_printc(EFI_WHITE, "\nSelected test: '%ps'\n", testname);
269 else 272 else
270 efi_st_printf("\nNumber of tests to execute: %u\n", 273 efi_st_printc(EFI_WHITE, "\nNumber of tests to execute: %u\n",
271 ll_entry_count(struct efi_unit_test, 274 ll_entry_count(struct efi_unit_test,
272 efi_unit_test)); 275 efi_unit_test));
273 276
274 /* Execute boottime tests */ 277 /* Execute boottime tests */
275 efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 278 efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
276 EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, 279 EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN,
277 &failures); 280 &failures);
278 281
279 /* Execute mixed tests */ 282 /* Execute mixed tests */
280 efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT, 283 efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT,
281 EFI_ST_SETUP, &failures); 284 EFI_ST_SETUP, &failures);
282 285
283 efi_st_exit_boot_services(); 286 efi_st_exit_boot_services();
284 287
285 efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT, 288 efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT,
286 EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures); 289 EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures);
287 290
288 /* Execute runtime tests */ 291 /* Execute runtime tests */
289 efi_st_do_tests(testname, EFI_SETUP_AFTER_BOOTTIME_EXIT, 292 efi_st_do_tests(testname, EFI_SETUP_AFTER_BOOTTIME_EXIT,
290 EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, 293 EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN,
291 &failures); 294 &failures);
292 295
293 /* Give feedback */ 296 /* Give feedback */
294 efi_st_printf("\nSummary: %u failures\n\n", failures); 297 efi_st_printc(EFI_WHITE, "\nSummary: %u failures\n\n", failures);
295 298
296 /* Reset system */ 299 /* Reset system */
297 efi_st_printf("Preparing for reset. Press any key.\n"); 300 efi_st_printf("Preparing for reset. Press any key.\n");
298 efi_st_get_key(); 301 efi_st_get_key();
299 runtime->reset_system(EFI_RESET_WARM, EFI_NOT_READY, 302 runtime->reset_system(EFI_RESET_WARM, EFI_NOT_READY,
300 sizeof(reset_message), reset_message); 303 sizeof(reset_message), reset_message);
301 efi_st_printf("\n"); 304 efi_st_printf("\n");
302 efi_st_error("Reset failed.\n"); 305 efi_st_error("Reset failed.\n");
303 306
304 return EFI_UNSUPPORTED; 307 return EFI_UNSUPPORTED;
305 } 308 }
306 309
lib/efi_selftest/efi_selftest_console.c
1 /* 1 /*
2 * EFI efi_selftest 2 * EFI efi_selftest
3 * 3 *
4 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> 4 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
5 * 5 *
6 * SPDX-License-Identifier: GPL-2.0+ 6 * SPDX-License-Identifier: GPL-2.0+
7 */ 7 */
8 8
9 #include <efi_selftest.h> 9 #include <efi_selftest.h>
10 #include <vsprintf.h> 10 #include <vsprintf.h>
11 11
12 struct efi_simple_text_output_protocol *con_out; 12 struct efi_simple_text_output_protocol *con_out;
13 struct efi_simple_input_interface *con_in; 13 struct efi_simple_input_interface *con_in;
14 14
15 /* 15 /*
16 * Print a MAC address to an u16 string 16 * Print a MAC address to an u16 string
17 * 17 *
18 * @pointer: mac address 18 * @pointer: mac address
19 * @buf: pointer to buffer address 19 * @buf: pointer to buffer address
20 * on return position of terminating zero word 20 * on return position of terminating zero word
21 */ 21 */
22 static void mac(void *pointer, u16 **buf) 22 static void mac(void *pointer, u16 **buf)
23 { 23 {
24 int i, j; 24 int i, j;
25 u16 c; 25 u16 c;
26 u8 *p = (u8 *)pointer; 26 u8 *p = (u8 *)pointer;
27 u8 byte; 27 u8 byte;
28 u16 *pos = *buf; 28 u16 *pos = *buf;
29 29
30 for (i = 0; i < ARP_HLEN; ++i) { 30 for (i = 0; i < ARP_HLEN; ++i) {
31 if (i) 31 if (i)
32 *pos++ = ':'; 32 *pos++ = ':';
33 byte = p[i]; 33 byte = p[i];
34 for (j = 4; j >= 0; j -= 4) { 34 for (j = 4; j >= 0; j -= 4) {
35 c = (byte >> j) & 0x0f; 35 c = (byte >> j) & 0x0f;
36 c += '0'; 36 c += '0';
37 if (c > '9') 37 if (c > '9')
38 c += 'a' - '9' - 1; 38 c += 'a' - '9' - 1;
39 *pos++ = c; 39 *pos++ = c;
40 } 40 }
41 } 41 }
42 *pos = 0; 42 *pos = 0;
43 *buf = pos; 43 *buf = pos;
44 } 44 }
45 45
46 /* 46 /*
47 * Print a pointer to an u16 string 47 * Print a pointer to an u16 string
48 * 48 *
49 * @pointer: pointer 49 * @pointer: pointer
50 * @buf: pointer to buffer address 50 * @buf: pointer to buffer address
51 * on return position of terminating zero word 51 * on return position of terminating zero word
52 */ 52 */
53 static void pointer(void *pointer, u16 **buf) 53 static void pointer(void *pointer, u16 **buf)
54 { 54 {
55 int i; 55 int i;
56 u16 c; 56 u16 c;
57 uintptr_t p = (uintptr_t)pointer; 57 uintptr_t p = (uintptr_t)pointer;
58 u16 *pos = *buf; 58 u16 *pos = *buf;
59 59
60 for (i = 8 * sizeof(p) - 4; i >= 0; i -= 4) { 60 for (i = 8 * sizeof(p) - 4; i >= 0; i -= 4) {
61 c = (p >> i) & 0x0f; 61 c = (p >> i) & 0x0f;
62 c += '0'; 62 c += '0';
63 if (c > '9') 63 if (c > '9')
64 c += 'a' - '9' - 1; 64 c += 'a' - '9' - 1;
65 *pos++ = c; 65 *pos++ = c;
66 } 66 }
67 *pos = 0; 67 *pos = 0;
68 *buf = pos; 68 *buf = pos;
69 } 69 }
70 70
71 /* 71 /*
72 * Print an unsigned 32bit value as decimal number to an u16 string 72 * Print an unsigned 32bit value as decimal number to an u16 string
73 * 73 *
74 * @value: value to be printed 74 * @value: value to be printed
75 * @buf: pointer to buffer address 75 * @buf: pointer to buffer address
76 * on return position of terminating zero word 76 * on return position of terminating zero word
77 */ 77 */
78 static void uint2dec(u32 value, u16 **buf) 78 static void uint2dec(u32 value, u16 **buf)
79 { 79 {
80 u16 *pos = *buf; 80 u16 *pos = *buf;
81 int i; 81 int i;
82 u16 c; 82 u16 c;
83 u64 f; 83 u64 f;
84 84
85 /* 85 /*
86 * Increment by .5 and multiply with 86 * Increment by .5 and multiply with
87 * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC 87 * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC
88 * to move the first digit to bit 60-63. 88 * to move the first digit to bit 60-63.
89 */ 89 */
90 f = 0x225C17D0; 90 f = 0x225C17D0;
91 f += (0x9B5A52DULL * value) >> 28; 91 f += (0x9B5A52DULL * value) >> 28;
92 f += 0x44B82FA0ULL * value; 92 f += 0x44B82FA0ULL * value;
93 93
94 for (i = 0; i < 10; ++i) { 94 for (i = 0; i < 10; ++i) {
95 /* Write current digit */ 95 /* Write current digit */
96 c = f >> 60; 96 c = f >> 60;
97 if (c || pos != *buf) 97 if (c || pos != *buf)
98 *pos++ = c + '0'; 98 *pos++ = c + '0';
99 /* Eliminate current digit */ 99 /* Eliminate current digit */
100 f &= 0xfffffffffffffff; 100 f &= 0xfffffffffffffff;
101 /* Get next digit */ 101 /* Get next digit */
102 f *= 0xaULL; 102 f *= 0xaULL;
103 } 103 }
104 if (pos == *buf) 104 if (pos == *buf)
105 *pos++ = '0'; 105 *pos++ = '0';
106 *pos = 0; 106 *pos = 0;
107 *buf = pos; 107 *buf = pos;
108 } 108 }
109 109
110 /* 110 /*
111 * Print a signed 32bit value as decimal number to an u16 string 111 * Print a signed 32bit value as decimal number to an u16 string
112 * 112 *
113 * @value: value to be printed 113 * @value: value to be printed
114 * @buf: pointer to buffer address 114 * @buf: pointer to buffer address
115 * on return position of terminating zero word 115 * on return position of terminating zero word
116 */ 116 */
117 static void int2dec(s32 value, u16 **buf) 117 static void int2dec(s32 value, u16 **buf)
118 { 118 {
119 u32 u; 119 u32 u;
120 u16 *pos = *buf; 120 u16 *pos = *buf;
121 121
122 if (value < 0) { 122 if (value < 0) {
123 *pos++ = '-'; 123 *pos++ = '-';
124 u = -value; 124 u = -value;
125 } else { 125 } else {
126 u = value; 126 u = value;
127 } 127 }
128 uint2dec(u, &pos); 128 uint2dec(u, &pos);
129 *buf = pos; 129 *buf = pos;
130 } 130 }
131 131
132 /* 132 /*
133 * Print a formatted string to the EFI console 133 * Print a colored formatted string to the EFI console
134 * 134 *
135 * @fmt: format string 135 * @color color, see constants in efi_api.h, use -1 for no color
136 * @...: optional arguments 136 * @fmt format string
137 * @... optional arguments
137 */ 138 */
138 void efi_st_printf(const char *fmt, ...) 139 void efi_st_printc(int color, const char *fmt, ...)
139 { 140 {
140 va_list args; 141 va_list args;
141 u16 buf[160]; 142 u16 buf[160];
142 const char *c; 143 const char *c;
143 u16 *pos = buf; 144 u16 *pos = buf;
144 const char *s; 145 const char *s;
145 u16 *u; 146 u16 *u;
146 147
147 va_start(args, fmt); 148 va_start(args, fmt);
148 149
150 if (color >= 0)
151 con_out->set_attribute(con_out, (unsigned long)color);
149 c = fmt; 152 c = fmt;
150 for (; *c; ++c) { 153 for (; *c; ++c) {
151 switch (*c) { 154 switch (*c) {
152 case '\\': 155 case '\\':
153 ++c; 156 ++c;
154 switch (*c) { 157 switch (*c) {
155 case '\0': 158 case '\0':
156 --c; 159 --c;
157 break; 160 break;
158 case 'n': 161 case 'n':
159 *pos++ = '\n'; 162 *pos++ = '\n';
160 break; 163 break;
161 case 'r': 164 case 'r':
162 *pos++ = '\r'; 165 *pos++ = '\r';
163 break; 166 break;
164 case 't': 167 case 't':
165 *pos++ = '\t'; 168 *pos++ = '\t';
166 break; 169 break;
167 default: 170 default:
168 *pos++ = *c; 171 *pos++ = *c;
169 } 172 }
170 break; 173 break;
171 case '%': 174 case '%':
172 ++c; 175 ++c;
173 switch (*c) { 176 switch (*c) {
174 case '\0': 177 case '\0':
175 --c; 178 --c;
176 break; 179 break;
177 case 'd': 180 case 'd':
178 int2dec(va_arg(args, s32), &pos); 181 int2dec(va_arg(args, s32), &pos);
179 break; 182 break;
180 case 'p': 183 case 'p':
181 ++c; 184 ++c;
182 switch (*c) { 185 switch (*c) {
183 /* MAC address */ 186 /* MAC address */
184 case 'm': 187 case 'm':
185 mac(va_arg(args, void*), &pos); 188 mac(va_arg(args, void*), &pos);
186 break; 189 break;
187 190
188 /* u16 string */ 191 /* u16 string */
189 case 's': 192 case 's':
190 u = va_arg(args, u16*); 193 u = va_arg(args, u16*);
191 if (pos > buf) { 194 if (pos > buf) {
192 *pos = 0; 195 *pos = 0;
193 con_out->output_string(con_out, 196 con_out->output_string(con_out,
194 buf); 197 buf);
195 } 198 }
196 con_out->output_string(con_out, u); 199 con_out->output_string(con_out, u);
197 pos = buf; 200 pos = buf;
198 break; 201 break;
199 default: 202 default:
200 --c; 203 --c;
201 pointer(va_arg(args, void*), &pos); 204 pointer(va_arg(args, void*), &pos);
202 } 205 }
203 break; 206 break;
204 case 's': 207 case 's':
205 s = va_arg(args, const char *); 208 s = va_arg(args, const char *);
206 for (; *s; ++s) 209 for (; *s; ++s)
207 *pos++ = *s; 210 *pos++ = *s;
208 break; 211 break;
209 case 'u': 212 case 'u':
210 uint2dec(va_arg(args, u32), &pos); 213 uint2dec(va_arg(args, u32), &pos);
211 break; 214 break;
212 default: 215 default:
213 break; 216 break;
214 } 217 }
215 break; 218 break;
216 default: 219 default:
217 *pos++ = *c; 220 *pos++ = *c;
218 } 221 }
219 } 222 }
220 va_end(args); 223 va_end(args);
221 *pos = 0; 224 *pos = 0;
222 con_out->output_string(con_out, buf); 225 con_out->output_string(con_out, buf);
226 if (color >= 0)
227 con_out->set_attribute(con_out, EFI_LIGHTGRAY);
223 } 228 }
224 229
225 /* 230 /*
226 * Reads an Unicode character from the input device. 231 * Reads an Unicode character from the input device.
227 * 232 *
228 * @return: Unicode character 233 * @return: Unicode character
229 */ 234 */
230 u16 efi_st_get_key(void) 235 u16 efi_st_get_key(void)
231 { 236 {
232 struct efi_input_key input_key; 237 struct efi_input_key input_key;
233 efi_status_t ret; 238 efi_status_t ret;
234 239
235 /* Wait for next key */ 240 /* Wait for next key */
236 do { 241 do {
237 ret = con_in->read_key_stroke(con_in, &input_key); 242 ret = con_in->read_key_stroke(con_in, &input_key);
238 } while (ret == EFI_NOT_READY); 243 } while (ret == EFI_NOT_READY);
239 return input_key.unicode_char; 244 return input_key.unicode_char;
240 } 245 }
241 246