1 /*
2 * Copyright (c) 2019, Google Inc. All rights reserved
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <assert.h>
25 #include <kernel/spinlock.h>
26 #include <lib/unittest/unittest.h>
27 #include <lk/init.h>
28 #include <stdio.h>
29 #include <string.h>
30 #if LK_LIBC_IMPLEMENTATION_IS_MUSL
31 #include <trusty/io_handle.h>
32 #endif
33
34 static size_t print_count;
35 static size_t print_bytes;
36 static size_t commit_count;
37
38 /*
39 * NOTE: we're just looking for a general sense these functions are being
40 * called. The kernel could be logging from other threads.
41 * TODO: modularize logging so it can be tested in isolation.
42 */
43
test_print_callback(print_callback_t * cb,const char * str,size_t len)44 static void test_print_callback(print_callback_t* cb,
45 const char* str,
46 size_t len) {
47 print_count += 1;
48 print_bytes += len;
49 }
50
test_commit_callback(print_callback_t * cb)51 static void test_commit_callback(print_callback_t* cb) {
52 commit_count += 1;
53 }
54
clear_stats(void)55 static void clear_stats(void) {
56 print_count = 0;
57 print_bytes = 0;
58 commit_count = 0;
59 }
60
61 /* Did we print something like "Hello, test!" ? */
check_standard_stats(void)62 static void check_standard_stats(void) {
63 EXPECT_LE(1, print_count);
64 EXPECT_LE(13, print_bytes);
65 EXPECT_LE(1, commit_count);
66 }
67
68 /*
69 * Most of these tests are smoke tests - making sure there are no trivial
70 * deadlocks or crashes.
71 */
72
TEST(consoletest,puts)73 TEST(consoletest, puts) {
74 clear_stats();
75
76 /* puts will have a slightly different code path than printf. */
77 puts("Hello, test!\n");
78
79 check_standard_stats();
80 }
81
TEST(consoletest,threading)82 TEST(consoletest, threading) {
83 clear_stats();
84
85 printf("Hello, %s!\n", "test");
86
87 check_standard_stats();
88 }
89
TEST(consoletest,irq_disabled)90 TEST(consoletest, irq_disabled) {
91 spin_lock_saved_state_t state;
92 clear_stats();
93
94 arch_interrupt_save(&state, SPIN_LOCK_FLAG_INTERRUPTS);
95 printf("Hello, %s!\n", "test");
96 arch_interrupt_restore(state, SPIN_LOCK_FLAG_INTERRUPTS);
97
98 check_standard_stats();
99 }
100
TEST(consoletest,steal_lock)101 TEST(consoletest, steal_lock) {
102 spin_lock_saved_state_t state;
103 clear_stats();
104
105 io_lock(file_io_handle(stdout));
106 arch_interrupt_save(&state, SPIN_LOCK_FLAG_INTERRUPTS);
107 printf("Hello, %s!\n", "test");
108 arch_interrupt_restore(state, SPIN_LOCK_FLAG_INTERRUPTS);
109 io_unlock(file_io_handle(stdout));
110
111 check_standard_stats();
112 }
113
run_console_test(struct unittest * test)114 static bool run_console_test(struct unittest* test) {
115 bool tests_passed;
116 print_callback_t cb;
117 /* Set a stub callback so all paths get exercised. */
118 memset(&cb, 0, sizeof(cb));
119 cb.print = test_print_callback;
120 cb.commit = test_commit_callback;
121 register_print_callback(&cb);
122 tests_passed = RUN_ALL_TESTS();
123 unregister_print_callback(&cb);
124 return tests_passed;
125 }
126
console_test_init(uint level)127 static void console_test_init(uint level) {
128 static struct unittest console_unittest = {
129 .port_name = "com.android.kernel.console-unittest",
130 .run_test = run_console_test,
131 };
132
133 unittest_add(&console_unittest);
134 }
135
136 LK_INIT_HOOK(console_test, console_test_init, LK_INIT_LEVEL_APPS);
137