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