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