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