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 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 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 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 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 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 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 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* 219 platform_debug_get_log_buffer(size_t* _size) 220 { 221 if (_size != NULL) 222 *_size = sizeof(sBuffer); 223 224 return sBuffer; 225 } 226