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