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