xref: /haiku/src/system/boot/platform/bios_ia32/debug.cpp (revision 68d37cfb3a755a7270d772b505ee15c8b18aa5e0)
128a2172cSIngo Weinhold /*
228a2172cSIngo Weinhold  * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de.
328a2172cSIngo Weinhold  * Distributed under the terms of the MIT License.
428a2172cSIngo Weinhold  */
528a2172cSIngo Weinhold 
628a2172cSIngo Weinhold 
728a2172cSIngo Weinhold #include "debug.h"
828a2172cSIngo Weinhold 
9*68d37cfbSAdrien Destugues #include <limits.h>
1028a2172cSIngo Weinhold #include <string.h>
1128a2172cSIngo Weinhold 
1228a2172cSIngo Weinhold #include <boot/platform.h>
1328a2172cSIngo Weinhold #include <boot/stage2.h>
1428a2172cSIngo Weinhold #include <boot/stdio.h>
1528a2172cSIngo Weinhold #include <kernel.h>
1628a2172cSIngo Weinhold #include <util/ring_buffer.h>
1728a2172cSIngo Weinhold 
1828a2172cSIngo Weinhold #include "keyboard.h"
1928a2172cSIngo Weinhold #include "mmu.h"
2028a2172cSIngo Weinhold #include "serial.h"
2128a2172cSIngo Weinhold 
2228a2172cSIngo Weinhold 
2333def425SIngo Weinhold //#define PRINT_TIME_STAMPS
2433def425SIngo Weinhold 	// Define to print a TSC timestamp before each line of output.
2533def425SIngo Weinhold 
2633def425SIngo Weinhold 
2728a2172cSIngo Weinhold static const char* const kDebugSyslogSignature = "Haiku syslog";
2828a2172cSIngo Weinhold 
2928a2172cSIngo Weinhold static char sBuffer[16384];
3028a2172cSIngo Weinhold static uint32 sBufferPosition;
3128a2172cSIngo Weinhold 
3228a2172cSIngo Weinhold static ring_buffer* sDebugSyslogBuffer = NULL;
332e8aa19cSIngo Weinhold static bool sPostCleanup = false;
342e8aa19cSIngo Weinhold 
352e8aa19cSIngo Weinhold 
362e8aa19cSIngo Weinhold static void
syslog_write(const char * buffer,size_t length)3733def425SIngo Weinhold syslog_write(const char* buffer, size_t length)
382e8aa19cSIngo Weinhold {
392e8aa19cSIngo Weinhold 	if (sPostCleanup && sDebugSyslogBuffer != NULL) {
402e8aa19cSIngo Weinhold 		ring_buffer_write(sDebugSyslogBuffer, (const uint8*)buffer, length);
412e8aa19cSIngo Weinhold 	} else if (sBufferPosition + length < sizeof(sBuffer)) {
422e8aa19cSIngo Weinhold 		memcpy(sBuffer + sBufferPosition, buffer, length);
432e8aa19cSIngo Weinhold 		sBufferPosition += length;
442e8aa19cSIngo Weinhold 	}
4533def425SIngo Weinhold }
462e8aa19cSIngo Weinhold 
4733def425SIngo Weinhold 
4833def425SIngo Weinhold static void
dprintf_args(const char * format,va_list args)4933def425SIngo Weinhold dprintf_args(const char *format, va_list args)
5033def425SIngo Weinhold {
5133def425SIngo Weinhold 	char buffer[512];
5233def425SIngo Weinhold 	int length = vsnprintf(buffer, sizeof(buffer), format, args);
5333def425SIngo Weinhold 	if (length == 0)
5433def425SIngo Weinhold 		return;
5533def425SIngo Weinhold 
5633def425SIngo Weinhold 	if (length >= (int)sizeof(buffer))
5733def425SIngo Weinhold 		length = sizeof(buffer) - 1;
5833def425SIngo Weinhold 
5933def425SIngo Weinhold #ifdef PRINT_TIME_STAMPS
6033def425SIngo Weinhold 	static bool sNewLine = true;
6133def425SIngo Weinhold 
6233def425SIngo Weinhold 	if (sNewLine) {
6333def425SIngo Weinhold 		char timeBuffer[32];
642d697067SAdrien Destugues 		snprintf(timeBuffer, sizeof(timeBuffer), "[%" B_PRIu64 "] ", __rdtsc());
6533def425SIngo Weinhold 		syslog_write(timeBuffer, strlen(timeBuffer));
6633def425SIngo Weinhold 		serial_puts(timeBuffer, strlen(timeBuffer));
6733def425SIngo Weinhold 	}
6833def425SIngo Weinhold 
6933def425SIngo Weinhold 	sNewLine = buffer[length - 1] == '\n';
7033def425SIngo Weinhold #endif	// PRINT_TIME_STAMPS
7133def425SIngo Weinhold 
7233def425SIngo Weinhold 	syslog_write(buffer, length);
732e8aa19cSIngo Weinhold 	serial_puts(buffer, length);
742e8aa19cSIngo Weinhold 
752e8aa19cSIngo Weinhold 	if (platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT)
762e8aa19cSIngo Weinhold 		fprintf(stderr, "%s", buffer);
772e8aa19cSIngo Weinhold }
782e8aa19cSIngo Weinhold 
792e8aa19cSIngo Weinhold 
802e8aa19cSIngo Weinhold // #pragma mark -
8128a2172cSIngo Weinhold 
8228a2172cSIngo Weinhold 
8328a2172cSIngo Weinhold /*!	This works only after console_init() was called.
8428a2172cSIngo Weinhold */
8528a2172cSIngo Weinhold void
panic(const char * format,...)8628a2172cSIngo Weinhold panic(const char *format, ...)
8728a2172cSIngo Weinhold {
8828a2172cSIngo Weinhold 	va_list list;
8928a2172cSIngo Weinhold 
9028a2172cSIngo Weinhold 	platform_switch_to_text_mode();
9128a2172cSIngo Weinhold 
9228a2172cSIngo Weinhold 	puts("*** PANIC ***");
9328a2172cSIngo Weinhold 
9428a2172cSIngo Weinhold 	va_start(list, format);
9528a2172cSIngo Weinhold 	vprintf(format, list);
9628a2172cSIngo Weinhold 	va_end(list);
9728a2172cSIngo Weinhold 
9828a2172cSIngo Weinhold 	puts("\nPress key to reboot.");
9928a2172cSIngo Weinhold 
10028a2172cSIngo Weinhold 	clear_key_buffer();
10128a2172cSIngo Weinhold 	wait_for_key();
10228a2172cSIngo Weinhold 	platform_exit();
10328a2172cSIngo Weinhold }
10428a2172cSIngo Weinhold 
10528a2172cSIngo Weinhold 
10628a2172cSIngo Weinhold void
dprintf(const char * format,...)10728a2172cSIngo Weinhold dprintf(const char *format, ...)
10828a2172cSIngo Weinhold {
1092e8aa19cSIngo Weinhold 	va_list args;
11028a2172cSIngo Weinhold 
1112e8aa19cSIngo Weinhold 	va_start(args, format);
1122e8aa19cSIngo Weinhold 	dprintf_args(format, args);
1132e8aa19cSIngo Weinhold 	va_end(args);
11428a2172cSIngo Weinhold }
11528a2172cSIngo Weinhold 
11628a2172cSIngo Weinhold 
1172e8aa19cSIngo Weinhold void
kprintf(const char * format,...)1182e8aa19cSIngo Weinhold kprintf(const char *format, ...)
1192e8aa19cSIngo Weinhold {
1202e8aa19cSIngo Weinhold 	va_list args;
1212e8aa19cSIngo Weinhold 
1222e8aa19cSIngo Weinhold 	va_start(args, format);
1232e8aa19cSIngo Weinhold 
1242e8aa19cSIngo Weinhold 	// print to console, if available
1252e8aa19cSIngo Weinhold 	if (stdout != NULL)
1262e8aa19cSIngo Weinhold 		vfprintf(stdout, format, args);
1272e8aa19cSIngo Weinhold 
1282e8aa19cSIngo Weinhold 	// always print to serial line
1292e8aa19cSIngo Weinhold 	dprintf_args(format, args);
1302e8aa19cSIngo Weinhold 
1312e8aa19cSIngo Weinhold 	va_end(args);
13228a2172cSIngo Weinhold }
13328a2172cSIngo Weinhold 
13428a2172cSIngo Weinhold 
13528a2172cSIngo Weinhold // #pragma mark -
13628a2172cSIngo Weinhold 
13728a2172cSIngo Weinhold 
13828a2172cSIngo Weinhold void
debug_init_post_mmu(void)13928a2172cSIngo Weinhold debug_init_post_mmu(void)
14028a2172cSIngo Weinhold {
1418d25a30cSIngo Weinhold 	// allocate 1 MB memory at 63 MB
1428d25a30cSIngo Weinhold 	addr_t base = 63 * 1024 * 1024;
14328a2172cSIngo Weinhold 	size_t size = 1024 * 1024;
14428a2172cSIngo Weinhold 	if (!mmu_allocate_physical(base, size))
14528a2172cSIngo Weinhold 		return;
14628a2172cSIngo Weinhold 
14728a2172cSIngo Weinhold 	void* buffer = (void*)mmu_map_physical_memory(base, size,
14828a2172cSIngo Weinhold 		kDefaultPageFlags);
14928a2172cSIngo Weinhold 	if (buffer == NULL)
15028a2172cSIngo Weinhold 		return;
15128a2172cSIngo Weinhold 
15228a2172cSIngo Weinhold 	// check whether there's a previous syslog we can recover
15328a2172cSIngo Weinhold 	size_t signatureLength = strlen(kDebugSyslogSignature);
15428a2172cSIngo Weinhold 	bool recover = memcmp(buffer, kDebugSyslogSignature, signatureLength) == 0;
15528a2172cSIngo Weinhold 
15628a2172cSIngo Weinhold 	size -= signatureLength;
15728a2172cSIngo Weinhold 	buffer = (uint8*)buffer + ROUNDUP(signatureLength, sizeof(void*));
15828a2172cSIngo Weinhold 
15928a2172cSIngo Weinhold 	sDebugSyslogBuffer = create_ring_buffer_etc(buffer, size,
16028a2172cSIngo Weinhold 		recover ? RING_BUFFER_INIT_FROM_BUFFER : 0);
16128a2172cSIngo Weinhold 
16228a2172cSIngo Weinhold 	gKernelArgs.debug_output = sDebugSyslogBuffer;
16328a2172cSIngo Weinhold 	gKernelArgs.debug_size = sDebugSyslogBuffer->size;
16428a2172cSIngo Weinhold }
16528a2172cSIngo Weinhold 
16628a2172cSIngo Weinhold 
16728a2172cSIngo Weinhold void
debug_cleanup(void)16828a2172cSIngo Weinhold debug_cleanup(void)
16928a2172cSIngo Weinhold {
1706b110c63SIngo Weinhold 	if (sDebugSyslogBuffer != NULL) {
1718540ec24SIngo Weinhold 		// If desired, store the debug syslog data from the previous session for
1728540ec24SIngo Weinhold 		// the kernel.
1738540ec24SIngo Weinhold 		size_t bytesReadable = 0;
1748540ec24SIngo Weinhold 		if (gKernelArgs.previous_debug_size != 0) {
1758540ec24SIngo Weinhold 			bytesReadable = ring_buffer_readable(sDebugSyslogBuffer);
1768540ec24SIngo Weinhold 			gKernelArgs.previous_debug_size = bytesReadable;
1778540ec24SIngo Weinhold 		}
1788540ec24SIngo Weinhold 
1798540ec24SIngo Weinhold 		if (bytesReadable != 0) {
1808540ec24SIngo Weinhold 			if (uint8* buffer = (uint8*)kernel_args_malloc(bytesReadable)) {
1818540ec24SIngo Weinhold 				ring_buffer_read(sDebugSyslogBuffer, buffer, bytesReadable);
1828540ec24SIngo Weinhold 				gKernelArgs.previous_debug_output = buffer;
1838540ec24SIngo Weinhold 			} else
1848540ec24SIngo Weinhold 				gKernelArgs.previous_debug_size = 0;
1858540ec24SIngo Weinhold 		}
1868540ec24SIngo Weinhold 
1878540ec24SIngo Weinhold 		// Prepare the debug syslog buffer for this session.
1886b110c63SIngo Weinhold 		size_t signatureLength = strlen(kDebugSyslogSignature);
1896b110c63SIngo Weinhold 		void* buffer
1906b110c63SIngo Weinhold 			= (void*)ROUNDDOWN((addr_t)sDebugSyslogBuffer, B_PAGE_SIZE);
1916b110c63SIngo Weinhold 
1926b110c63SIngo Weinhold 		if (gKernelArgs.keep_debug_output_buffer) {
19328a2172cSIngo Weinhold 			// copy the output gathered so far into the ring buffer
19428a2172cSIngo Weinhold 			ring_buffer_clear(sDebugSyslogBuffer);
1952e8aa19cSIngo Weinhold 			ring_buffer_write(sDebugSyslogBuffer, (uint8*)sBuffer,
1962e8aa19cSIngo Weinhold 				sBufferPosition);
19728a2172cSIngo Weinhold 
1986b110c63SIngo Weinhold 			memcpy(buffer, kDebugSyslogSignature, signatureLength);
19928a2172cSIngo Weinhold 		} else {
2006b110c63SIngo Weinhold 			// clear the signature
2016b110c63SIngo Weinhold 			memset(buffer, 0, signatureLength);
2026b110c63SIngo Weinhold 		}
2036b110c63SIngo Weinhold 	} else
2046b110c63SIngo Weinhold 		gKernelArgs.keep_debug_output_buffer = false;
2056b110c63SIngo Weinhold 
2066b110c63SIngo Weinhold 	if (!gKernelArgs.keep_debug_output_buffer) {
20728a2172cSIngo Weinhold 		gKernelArgs.debug_output = kernel_args_malloc(sBufferPosition);
20828a2172cSIngo Weinhold 		if (gKernelArgs.debug_output != NULL) {
20928a2172cSIngo Weinhold 			memcpy(gKernelArgs.debug_output, sBuffer, sBufferPosition);
21028a2172cSIngo Weinhold 			gKernelArgs.debug_size = sBufferPosition;
21128a2172cSIngo Weinhold 		}
21228a2172cSIngo Weinhold 	}
2132e8aa19cSIngo Weinhold 
2142e8aa19cSIngo Weinhold 	sPostCleanup = true;
21528a2172cSIngo Weinhold }
2165e78920cSIngo Weinhold 
2175e78920cSIngo Weinhold 
2185e78920cSIngo Weinhold char*
platform_debug_get_log_buffer(size_t * _size)2195e78920cSIngo Weinhold platform_debug_get_log_buffer(size_t* _size)
2205e78920cSIngo Weinhold {
2215e78920cSIngo Weinhold 	if (_size != NULL)
2225e78920cSIngo Weinhold 		*_size = sizeof(sBuffer);
2235e78920cSIngo Weinhold 
2245e78920cSIngo Weinhold 	return sBuffer;
2255e78920cSIngo Weinhold }
226