xref: /haiku/src/system/boot/platform/bios_ia32/debug.cpp (revision 68d37cfb3a755a7270d772b505ee15c8b18aa5e0)
1 /*
2  * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "debug.h"
8 
9 #include <limits.h>
10 #include <string.h>
11 
12 #include <boot/platform.h>
13 #include <boot/stage2.h>
14 #include <boot/stdio.h>
15 #include <kernel.h>
16 #include <util/ring_buffer.h>
17 
18 #include "keyboard.h"
19 #include "mmu.h"
20 #include "serial.h"
21 
22 
23 //#define PRINT_TIME_STAMPS
24 	// Define to print a TSC timestamp before each line of output.
25 
26 
27 static const char* const kDebugSyslogSignature = "Haiku syslog";
28 
29 static char sBuffer[16384];
30 static uint32 sBufferPosition;
31 
32 static ring_buffer* sDebugSyslogBuffer = NULL;
33 static bool sPostCleanup = false;
34 
35 
36 static void
syslog_write(const char * buffer,size_t length)37 syslog_write(const char* buffer, size_t length)
38 {
39 	if (sPostCleanup && sDebugSyslogBuffer != NULL) {
40 		ring_buffer_write(sDebugSyslogBuffer, (const uint8*)buffer, length);
41 	} else if (sBufferPosition + length < sizeof(sBuffer)) {
42 		memcpy(sBuffer + sBufferPosition, buffer, length);
43 		sBufferPosition += length;
44 	}
45 }
46 
47 
48 static void
dprintf_args(const char * format,va_list args)49 dprintf_args(const char *format, va_list args)
50 {
51 	char buffer[512];
52 	int length = vsnprintf(buffer, sizeof(buffer), format, args);
53 	if (length == 0)
54 		return;
55 
56 	if (length >= (int)sizeof(buffer))
57 		length = sizeof(buffer) - 1;
58 
59 #ifdef PRINT_TIME_STAMPS
60 	static bool sNewLine = true;
61 
62 	if (sNewLine) {
63 		char timeBuffer[32];
64 		snprintf(timeBuffer, sizeof(timeBuffer), "[%" B_PRIu64 "] ", __rdtsc());
65 		syslog_write(timeBuffer, strlen(timeBuffer));
66 		serial_puts(timeBuffer, strlen(timeBuffer));
67 	}
68 
69 	sNewLine = buffer[length - 1] == '\n';
70 #endif	// PRINT_TIME_STAMPS
71 
72 	syslog_write(buffer, length);
73 	serial_puts(buffer, length);
74 
75 	if (platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT)
76 		fprintf(stderr, "%s", buffer);
77 }
78 
79 
80 // #pragma mark -
81 
82 
83 /*!	This works only after console_init() was called.
84 */
85 void
panic(const char * format,...)86 panic(const char *format, ...)
87 {
88 	va_list list;
89 
90 	platform_switch_to_text_mode();
91 
92 	puts("*** PANIC ***");
93 
94 	va_start(list, format);
95 	vprintf(format, list);
96 	va_end(list);
97 
98 	puts("\nPress key to reboot.");
99 
100 	clear_key_buffer();
101 	wait_for_key();
102 	platform_exit();
103 }
104 
105 
106 void
dprintf(const char * format,...)107 dprintf(const char *format, ...)
108 {
109 	va_list args;
110 
111 	va_start(args, format);
112 	dprintf_args(format, args);
113 	va_end(args);
114 }
115 
116 
117 void
kprintf(const char * format,...)118 kprintf(const char *format, ...)
119 {
120 	va_list args;
121 
122 	va_start(args, format);
123 
124 	// print to console, if available
125 	if (stdout != NULL)
126 		vfprintf(stdout, format, args);
127 
128 	// always print to serial line
129 	dprintf_args(format, args);
130 
131 	va_end(args);
132 }
133 
134 
135 // #pragma mark -
136 
137 
138 void
debug_init_post_mmu(void)139 debug_init_post_mmu(void)
140 {
141 	// allocate 1 MB memory at 63 MB
142 	addr_t base = 63 * 1024 * 1024;
143 	size_t size = 1024 * 1024;
144 	if (!mmu_allocate_physical(base, size))
145 		return;
146 
147 	void* buffer = (void*)mmu_map_physical_memory(base, size,
148 		kDefaultPageFlags);
149 	if (buffer == NULL)
150 		return;
151 
152 	// check whether there's a previous syslog we can recover
153 	size_t signatureLength = strlen(kDebugSyslogSignature);
154 	bool recover = memcmp(buffer, kDebugSyslogSignature, signatureLength) == 0;
155 
156 	size -= signatureLength;
157 	buffer = (uint8*)buffer + ROUNDUP(signatureLength, sizeof(void*));
158 
159 	sDebugSyslogBuffer = create_ring_buffer_etc(buffer, size,
160 		recover ? RING_BUFFER_INIT_FROM_BUFFER : 0);
161 
162 	gKernelArgs.debug_output = sDebugSyslogBuffer;
163 	gKernelArgs.debug_size = sDebugSyslogBuffer->size;
164 }
165 
166 
167 void
debug_cleanup(void)168 debug_cleanup(void)
169 {
170 	if (sDebugSyslogBuffer != NULL) {
171 		// If desired, store the debug syslog data from the previous session for
172 		// the kernel.
173 		size_t bytesReadable = 0;
174 		if (gKernelArgs.previous_debug_size != 0) {
175 			bytesReadable = ring_buffer_readable(sDebugSyslogBuffer);
176 			gKernelArgs.previous_debug_size = bytesReadable;
177 		}
178 
179 		if (bytesReadable != 0) {
180 			if (uint8* buffer = (uint8*)kernel_args_malloc(bytesReadable)) {
181 				ring_buffer_read(sDebugSyslogBuffer, buffer, bytesReadable);
182 				gKernelArgs.previous_debug_output = buffer;
183 			} else
184 				gKernelArgs.previous_debug_size = 0;
185 		}
186 
187 		// Prepare the debug syslog buffer for this session.
188 		size_t signatureLength = strlen(kDebugSyslogSignature);
189 		void* buffer
190 			= (void*)ROUNDDOWN((addr_t)sDebugSyslogBuffer, B_PAGE_SIZE);
191 
192 		if (gKernelArgs.keep_debug_output_buffer) {
193 			// copy the output gathered so far into the ring buffer
194 			ring_buffer_clear(sDebugSyslogBuffer);
195 			ring_buffer_write(sDebugSyslogBuffer, (uint8*)sBuffer,
196 				sBufferPosition);
197 
198 			memcpy(buffer, kDebugSyslogSignature, signatureLength);
199 		} else {
200 			// clear the signature
201 			memset(buffer, 0, signatureLength);
202 		}
203 	} else
204 		gKernelArgs.keep_debug_output_buffer = false;
205 
206 	if (!gKernelArgs.keep_debug_output_buffer) {
207 		gKernelArgs.debug_output = kernel_args_malloc(sBufferPosition);
208 		if (gKernelArgs.debug_output != NULL) {
209 			memcpy(gKernelArgs.debug_output, sBuffer, sBufferPosition);
210 			gKernelArgs.debug_size = sBufferPosition;
211 		}
212 	}
213 
214 	sPostCleanup = true;
215 }
216 
217 
218 char*
platform_debug_get_log_buffer(size_t * _size)219 platform_debug_get_log_buffer(size_t* _size)
220 {
221 	if (_size != NULL)
222 		*_size = sizeof(sBuffer);
223 
224 	return sBuffer;
225 }
226