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