* Copyright 2004-2007, Axel DΓΆrfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#include "debug.h"
#include <limits.h>
#include <string.h>
#include <boot/platform.h>
#include <boot/stage2.h>
#include <boot/stdio.h>
#include <kernel.h>
#include <util/ring_buffer.h>
#include "keyboard.h"
#include "mmu.h"
#include "serial.h"
static const char* const kDebugSyslogSignature = "Haiku syslog";
static char sBuffer[16384];
static uint32 sBufferPosition;
static ring_buffer* sDebugSyslogBuffer = NULL;
static bool sPostCleanup = false;
static void
syslog_write(const char* buffer, size_t length)
{
if (sPostCleanup && sDebugSyslogBuffer != NULL) {
ring_buffer_write(sDebugSyslogBuffer, (const uint8*)buffer, length);
} else if (sBufferPosition + length < sizeof(sBuffer)) {
memcpy(sBuffer + sBufferPosition, buffer, length);
sBufferPosition += length;
}
}
static void
dprintf_args(const char *format, va_list args)
{
char buffer[512];
int length = vsnprintf(buffer, sizeof(buffer), format, args);
if (length == 0)
return;
if (length >= (int)sizeof(buffer))
length = sizeof(buffer) - 1;
#ifdef PRINT_TIME_STAMPS
static bool sNewLine = true;
if (sNewLine) {
char timeBuffer[32];
snprintf(timeBuffer, sizeof(timeBuffer), "[%" B_PRIu64 "] ", __rdtsc());
syslog_write(timeBuffer, strlen(timeBuffer));
serial_puts(timeBuffer, strlen(timeBuffer));
}
sNewLine = buffer[length - 1] == '\n';
#endif
syslog_write(buffer, length);
serial_puts(buffer, length);
if (platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT)
fprintf(stderr, "%s", buffer);
}
*/
void
panic(const char *format, ...)
{
va_list list;
platform_switch_to_text_mode();
puts("*** PANIC ***");
va_start(list, format);
vprintf(format, list);
va_end(list);
puts("\nPress key to reboot.");
clear_key_buffer();
wait_for_key();
platform_exit();
}
void
dprintf(const char *format, ...)
{
va_list args;
va_start(args, format);
dprintf_args(format, args);
va_end(args);
}
void
kprintf(const char *format, ...)
{
va_list args;
va_start(args, format);
if (stdout != NULL)
vfprintf(stdout, format, args);
dprintf_args(format, args);
va_end(args);
}
void
debug_init_post_mmu(void)
{
addr_t base = 63 * 1024 * 1024;
size_t size = 1024 * 1024;
if (!mmu_allocate_physical(base, size))
return;
void* buffer = (void*)mmu_map_physical_memory(base, size,
kDefaultPageFlags);
if (buffer == NULL)
return;
size_t signatureLength = strlen(kDebugSyslogSignature);
bool recover = memcmp(buffer, kDebugSyslogSignature, signatureLength) == 0;
size -= signatureLength;
buffer = (uint8*)buffer + ROUNDUP(signatureLength, sizeof(void*));
sDebugSyslogBuffer = create_ring_buffer_etc(buffer, size,
recover ? RING_BUFFER_INIT_FROM_BUFFER : 0);
gKernelArgs.debug_output = sDebugSyslogBuffer;
gKernelArgs.debug_size = sDebugSyslogBuffer->size;
}
void
debug_cleanup(void)
{
if (sDebugSyslogBuffer != NULL) {
size_t bytesReadable = 0;
if (gKernelArgs.previous_debug_size != 0) {
bytesReadable = ring_buffer_readable(sDebugSyslogBuffer);
gKernelArgs.previous_debug_size = bytesReadable;
}
if (bytesReadable != 0) {
if (uint8* buffer = (uint8*)kernel_args_malloc(bytesReadable)) {
ring_buffer_read(sDebugSyslogBuffer, buffer, bytesReadable);
gKernelArgs.previous_debug_output = buffer;
} else
gKernelArgs.previous_debug_size = 0;
}
size_t signatureLength = strlen(kDebugSyslogSignature);
void* buffer
= (void*)ROUNDDOWN((addr_t)sDebugSyslogBuffer, B_PAGE_SIZE);
if (gKernelArgs.keep_debug_output_buffer) {
ring_buffer_clear(sDebugSyslogBuffer);
ring_buffer_write(sDebugSyslogBuffer, (uint8*)sBuffer,
sBufferPosition);
memcpy(buffer, kDebugSyslogSignature, signatureLength);
} else {
memset(buffer, 0, signatureLength);
}
} else
gKernelArgs.keep_debug_output_buffer = false;
if (!gKernelArgs.keep_debug_output_buffer) {
gKernelArgs.debug_output = kernel_args_malloc(sBufferPosition);
if (gKernelArgs.debug_output != NULL) {
memcpy(gKernelArgs.debug_output, sBuffer, sBufferPosition);
gKernelArgs.debug_size = sBufferPosition;
}
}
sPostCleanup = true;
}
char*
platform_debug_get_log_buffer(size_t* _size)
{
if (_size != NULL)
*_size = sizeof(sBuffer);
return sBuffer;
}