1 #include <stdio.h> 2 #include <stdint.h> 3 #include <stdarg.h> 4 #include <gpxe/io.h> 5 #include <console.h> 6 7 void pause ( void ) { 8 printf ( "\nPress a key" ); 9 getchar(); 10 printf ( "\r \r" ); 11 } 12 13 void more ( void ) { 14 printf ( "---more---" ); 15 getchar(); 16 printf ( "\r \r" ); 17 } 18 19 /** 20 * Print row of a hex dump with specified display address 21 * 22 * @v dispaddr Display address 23 * @v data Data to print 24 * @v len Length of data 25 * @v offset Starting offset within data 26 */ 27 static void dbg_hex_dump_da_row ( unsigned long dispaddr, const void *data, 28 unsigned long len, unsigned int offset ) { 29 const uint8_t *bytes = data; 30 unsigned int i; 31 uint8_t byte; 32 33 printf ( "%08lx :", ( dispaddr + offset ) ); 34 for ( i = offset ; i < ( offset + 16 ) ; i++ ) { 35 if ( i >= len ) { 36 printf ( " " ); 37 continue; 38 } 39 printf ( "%c%02x", 40 ( ( ( i % 16 ) == 8 ) ? '-' : ' ' ), bytes[i] ); 41 } 42 printf ( " : " ); 43 for ( i = offset ; i < ( offset + 16 ) ; i++ ) { 44 if ( i >= len ) { 45 printf ( " " ); 46 continue; 47 } 48 byte = bytes[i]; 49 if ( ( byte < 0x20 ) || ( byte >= 0x7f ) ) 50 byte = '.'; 51 printf ( "%c", byte ); 52 } 53 printf ( "\n" ); 54 } 55 56 /** 57 * Print hex dump with specified display address 58 * 59 * @v dispaddr Display address 60 * @v data Data to print 61 * @v len Length of data 62 */ 63 void dbg_hex_dump_da ( unsigned long dispaddr, const void *data, 64 unsigned long len ) { 65 unsigned int offset; 66 67 for ( offset = 0 ; offset < len ; offset += 16 ) { 68 dbg_hex_dump_da_row ( dispaddr, data, len, offset ); 69 } 70 } 71 72 #define GUARD_SYMBOL ( ( 'M' << 24 ) | ( 'I' << 16 ) | ( 'N' << 8 ) | 'E' ) 73 /* Fill a region with guard markers. We use a 4-byte pattern to make 74 * it less likely that check_region will find spurious 1-byte regions 75 * of non-corruption. 76 */ 77 void guard_region ( void *region, size_t len ) { 78 uint32_t offset = 0; 79 80 len &= ~0x03; 81 for ( offset = 0; offset < len ; offset += 4 ) { 82 *((uint32_t *)(region + offset)) = GUARD_SYMBOL; 83 } 84 } 85 86 /* Check a region that has been guarded with guard_region() for 87 * corruption. 88 */ 89 int check_region ( void *region, size_t len ) { 90 uint8_t corrupted = 0; 91 uint8_t in_corruption = 0; 92 uint32_t offset = 0; 93 uint32_t test = 0; 94 95 len &= ~0x03; 96 for ( offset = 0; offset < len ; offset += 4 ) { 97 test = *((uint32_t *)(region + offset)) = GUARD_SYMBOL; 98 if ( ( in_corruption == 0 ) && 99 ( test != GUARD_SYMBOL ) ) { 100 /* Start of corruption */ 101 if ( corrupted == 0 ) { 102 corrupted = 1; 103 printf ( "Region %p-%p (physical %#lx-%#lx) " 104 "corrupted\n", 105 region, region + len, 106 virt_to_phys ( region ), 107 virt_to_phys ( region + len ) ); 108 } 109 in_corruption = 1; 110 printf ( "--- offset %#x ", offset ); 111 } else if ( ( in_corruption != 0 ) && 112 ( test == GUARD_SYMBOL ) ) { 113 /* End of corruption */ 114 in_corruption = 0; 115 printf ( "to offset %#x", offset ); 116 } 117 118 } 119 if ( in_corruption != 0 ) { 120 printf ( "to offset %#zx (end of region)\n", len-1 ); 121 } 122 return corrupted; 123 } 124 125 /** 126 * Maximum number of separately coloured message streams 127 * 128 * Six is the realistic maximum; there are 8 basic ANSI colours, one 129 * of which will be the terminal default and one of which will be 130 * invisible on the terminal because it matches the background colour. 131 */ 132 #define NUM_AUTO_COLOURS 6 133 134 /** A colour assigned to an autocolourised debug message stream */ 135 struct autocolour { 136 /** Message stream ID */ 137 unsigned long stream; 138 /** Last recorded usage */ 139 unsigned long last_used; 140 }; 141 142 /** 143 * Choose colour index for debug autocolourisation 144 * 145 * @v stream Message stream ID 146 * @ret colour Colour ID 147 */ 148 static int dbg_autocolour ( unsigned long stream ) { 149 static struct autocolour acs[NUM_AUTO_COLOURS]; 150 static unsigned long use; 151 unsigned int i; 152 unsigned int oldest; 153 unsigned int oldest_last_used; 154 155 /* Increment usage iteration counter */ 156 use++; 157 158 /* Scan through list for a currently assigned colour */ 159 for ( i = 0 ; i < ( sizeof ( acs ) / sizeof ( acs[0] ) ) ; i++ ) { 160 if ( acs[i].stream == stream ) { 161 acs[i].last_used = use; 162 return i; 163 } 164 } 165 166 /* No colour found; evict the oldest from the list */ 167 oldest = 0; 168 oldest_last_used = use; 169 for ( i = 0 ; i < ( sizeof ( acs ) / sizeof ( acs[0] ) ) ; i++ ) { 170 if ( acs[i].last_used < oldest_last_used ) { 171 oldest_last_used = acs[i].last_used; 172 oldest = i; 173 } 174 } 175 acs[oldest].stream = stream; 176 acs[oldest].last_used = use; 177 return oldest; 178 } 179 180 /** 181 * Select automatic colour for debug messages 182 * 183 * @v stream Message stream ID 184 */ 185 void dbg_autocolourise ( unsigned long stream ) { 186 printf ( "\033[%dm", 187 ( stream ? ( 31 + dbg_autocolour ( stream ) ) : 0 ) ); 188 } 189 190 /** 191 * Revert to normal colour 192 * 193 */ 194 void dbg_decolourise ( void ) { 195 printf ( "\033[0m" ); 196 } 197