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