1 /*
2  * Copyright (c) 2008-2015 Travis Geiselbrecht
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 <ctype.h>
25 #include <debug.h>
26 #include <err.h>
27 #include <stdlib.h>
28 #include <printf.h>
29 #include <stdio.h>
30 #include <lib/backtrace/backtrace.h>
31 #include <lib/io.h>
32 #include <list.h>
33 #include <arch/ops.h>
34 #include <platform.h>
35 #include <platform/debug.h>
36 #include <kernel/spinlock.h>
37 #include <kernel/thread.h>
38 #include <inttypes.h>
39 
spin(uint32_t usecs)40 void spin(uint32_t usecs)
41 {
42     lk_time_ns_t nsecs = usecs * 1000ULL;
43     lk_time_ns_t start = current_time_ns();
44 
45     while ((current_time_ns() - start) < nsecs)
46         ;
47 }
48 
49 /*
50  * This function relies on the "panic" macro decorating the format string so
51  * that the message can be output using a single print statement.
52  */
_panic(const char * fmt,...)53 void _panic(const char *fmt, ...)
54 {
55     va_list ap;
56     struct thread *curr = get_current_thread();
57 
58     if (thread_lock_held()) {
59         printf("panic called with thread lock held\n");
60         thread_unlock_ints_disabled();
61     }
62     dump_backtrace();
63 
64     if (curr && thread_get_flag_exit_on_panic(curr)) {
65         thread_exit_from_panic();
66     }
67 
68     va_start(ap, fmt);
69     vprintf(fmt, ap);
70     va_end(ap);
71 
72     platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC);
73 }
74 
75 #if !DISABLE_DEBUG_OUTPUT
76 
__panic_stdio_fgetc(void * ctx)77 static int __panic_stdio_fgetc(void *ctx)
78 {
79     char c;
80     int err;
81 
82     err = platform_pgetc(&c, false);
83     if (err < 0)
84         return err;
85     return (unsigned char)c;
86 }
87 
__panic_stdio_read(io_handle_t * io,char * s,size_t len)88 static ssize_t __panic_stdio_read(io_handle_t *io, char *s, size_t len)
89 {
90     if (len == 0)
91         return 0;
92 
93     int err = platform_pgetc(s, false);
94     if (err < 0)
95         return err;
96 
97     return 1;
98 }
99 
__panic_stdio_write(io_handle_t * io,const char * s,size_t len)100 static ssize_t __panic_stdio_write(io_handle_t *io, const char *s, size_t len)
101 {
102     for (size_t i = 0; i < len; i++) {
103         platform_pputc(s[i]);
104     }
105     return len;
106 }
107 
108 #if ENABLE_PANIC_SHELL
get_panic_fd(void)109 FILE *get_panic_fd(void)
110 {
111     static const io_handle_hooks_t panic_hooks = {
112         .write = __panic_stdio_write,
113         .read = __panic_stdio_read,
114     };
115     static io_handle_t panic_io = {
116         .magic = IO_HANDLE_MAGIC,
117         .hooks = &panic_hooks
118     };
119     static FILE panic_fd = {
120         .io = &panic_io
121     };
122 
123     return &panic_fd;
124 }
125 #endif
126 
hexdump(const void * ptr,size_t len)127 void hexdump(const void *ptr, size_t len)
128 {
129     addr_t address = (addr_t)ptr;
130     size_t count;
131 
132     for (count = 0 ; count < len; count += 16) {
133         union {
134             uint32_t buf[4];
135             uint8_t  cbuf[16];
136         } u;
137         size_t s = round_up(MIN(len - count, 16), 4);
138         size_t i;
139 
140         printf("0x%08" PRIxADDR ": ", address);
141         for (i = 0; i < s / 4; i++) {
142             u.buf[i] = ((const uint32_t *)address)[i];
143             printf("%08x ", u.buf[i]);
144         }
145         for (; i < 4; i++) {
146             printf("         ");
147         }
148         printf("|");
149 
150         for (i=0; i < 16; i++) {
151             unsigned char c = u.cbuf[i];
152             if (i < s && isprint(c)) {
153                 printf("%c", c);
154             } else {
155                 printf(".");
156             }
157         }
158         printf("|\n");
159         address += 16;
160     }
161 }
162 
hexdump8_ex(const void * ptr,size_t len,uint64_t disp_addr)163 void hexdump8_ex(const void *ptr, size_t len, uint64_t disp_addr)
164 {
165     addr_t address = (addr_t)ptr;
166     size_t count;
167     size_t i;
168     const char *addr_fmt = ((disp_addr + len) > 0xFFFFFFFF)
169                            ? "0x%016llx: "
170                            : "0x%08llx: ";
171 
172     for (count = 0 ; count < len; count += 16) {
173         printf(addr_fmt, disp_addr + count);
174 
175         for (i=0; i < MIN(len - count, 16); i++) {
176             printf("%02hhx ", *(const uint8_t *)(address + i));
177         }
178 
179         for (; i < 16; i++) {
180             printf("   ");
181         }
182 
183         printf("|");
184 
185         for (i=0; i < MIN(len - count, 16); i++) {
186             unsigned char c = ((const char *)address)[i];
187             printf("%c", isprint(c) ? c : '.');
188         }
189 
190         printf("\n");
191         address += 16;
192     }
193 }
194 
195 #endif // !DISABLE_DEBUG_OUTPUT
196