source: trunk/tools/bootloader_tsar/boot_utils.c@ 1

Last change on this file since 1 was 1, checked in by alain, 10 years ago

First import

File size: 20.8 KB
Line 
1#include <stdarg.h>
2
3#include <boot_tty_driver.h>
4#include <hal_types.h>
5#include <boot_utils.h>
6
7/****************************************************************************
8 * Remote accesses. *
9 ****************************************************************************/
10
11uint32_t boot_remote_lw(xptr_t xp)
12{
13 uint32_t res; /* Value to be read, stored at the remote address. */
14 uint32_t ptr; /* Classic pointer to the distant memory location. */
15 uint32_t cxy; /* Identifier of the cluster containing the distant
16 memory location. */
17
18 /* Extracting information from the extended pointer. */
19 ptr = (uint32_t)GET_PTR(xp);
20 cxy = (uint32_t)GET_CXY(xp);
21
22 /* Assembly instructions to get the work done. */
23 asm volatile("mfc2 $15, $24\n" /* $15 <= CP2_DATA_PADDR_EXT */
24 "mtc2 %2, $24\n" /* CP2_DATA_PADDR_EXT <= cxy */
25 "lw %0, 0(%1)\n" /* *ptr <= data */
26 "mtc2 $15, $24\n" /* CP2_DATA_PADDR_EXT <= $15 */
27 "sync \n"
28 : "=&r"(res) /* Temporary register so that it
29 doesn't overlap the other inputs
30 or outputs. */
31 : "r"(ptr), "r"(cxy)
32 : "$15"
33 );
34
35 return res;
36
37} // boot_remote_lw()
38
39/****************************************************************************/
40
41void boot_remote_sw(xptr_t xp, uint32_t data)
42{
43 uint32_t ptr; /* Classic pointer to the distant memory location. */
44 uint32_t cxy; /* Identifier of the cluster containing the distant
45 memory location. */
46
47 /* Extracting information from the extended pointers. */
48 ptr = (uint32_t)GET_PTR(xp);
49 cxy = (uint32_t)GET_CXY(xp);
50
51 /* Assembly instructions to get the work done. */
52 asm volatile("mfc2 $15, $24\n" /* $15 <= CP2_DATA_PADDR_EXT */
53 "mtc2 %2, $24\n" /* CP2_DATA_PADDR_EXT <= cxy */
54 "sw %0, 0(%1)\n" /* *ptr <= data */
55 "mtc2 $15, $24\n" /* CP2_DATA_PADDR_EXT <= $15 */
56 "sync \n"
57 :
58 : "r"(data), "r"(ptr), "r"(cxy)
59 : "$15", "memory"
60 );
61
62} // boot_remote_sw()
63
64/****************************************************************************/
65
66int32_t boot_remote_atomic_add(xptr_t xp, int32_t val)
67{
68 int32_t res; /* Value stored at the distant memory location before
69 the atomic operation. */
70 uint32_t ptr; /* Classic pointer to the distant memory location. */
71 uint32_t cxy; /* Identifier of the cluster containing the distant
72 memory location. */
73
74 /* Extracting information from the extended pointers. */
75 ptr = (uint32_t)GET_PTR(xp);
76 cxy = (uint32_t)GET_CXY(xp);
77
78 /* Assembly instructions to get the work done. */
79 asm volatile("mfc2 $15, $24 \n" /* $15 <= CP2_DATA_PADDR_EXT */
80 "mtc2 %3, $24 \n" /* CP2_DATA_PADDR_EXT <= cxy */
81 "1: \n"
82 "ll %0, 0(%1) \n" /* res <= *ptr */
83 "addu $3, %0, %2\n" /* $3 <= res + val */
84 "sc $3, 0(%1) \n" /* *ptr <= $3 */
85 "beq $3, $0, 1b\n" /* Retry until success. */
86 "nop \n" /* Delayed slot. */
87 "mtc2 $15, $24 \n" /* CP2_DATA_PADDR_EXT <= $15 */
88 "sync \n"
89 : "=&r"(res) /* Temporary register so that
90 it doesn't overlap the other
91 inputs or outputs. */
92 : "r"(ptr), "r"(val), "r"(cxy)
93 : "$3", "$15", "memory"
94 );
95
96 return res;
97
98} // boot_remote_atomic_add()
99
100/****************************************************************************/
101
102void boot_remote_memcpy(xptr_t dest, xptr_t src, unsigned int size)
103{
104 uint32_t words_nr; /* Number of 32-bit words to be copied. */
105 uint32_t dptr; /* Classic pointer to the destination buffer. */
106 uint32_t dcxy; /* Identifier of the cluster containing the
107 destination buffer. */
108 uint32_t sptr; /* Classic pointer to the source buffer. */
109 uint32_t scxy; /* Identifier of the cluster containing the
110 source buffer. */
111 uint32_t i; /* Iterator for memory copying loop. */
112
113 /* Extracting information from the extended pointers. */
114 dptr = (uint32_t)GET_PTR(dest);
115 dcxy = (uint32_t)GET_CXY(dest);
116 sptr = (uint32_t)GET_PTR(src);
117 scxy = (uint32_t)GET_CXY(src);
118
119 /*
120 * Testing if we could perform word-by-word copy (if both addresses are
121 * word-aligned).
122 */
123 if ((dptr & 0x3) || (sptr & 0x3))
124 words_nr = 0;
125 else
126 words_nr = size >> 2;
127
128 /* Copying word-by-word. */
129 for (i = 0; i < words_nr; i++)
130 {
131 asm volatile("mfc2 $15, $24\n" /* $15 <= CP2_DATA_PADDR_EXT */
132 "mtc2 %0, $24\n" /* CP2_DATA_PADDR_EXT <= scxy */
133 "lw $3, 0(%1)\n" /* $3 <= *(sptr + 4*i) */
134 "mtc2 %2, $24\n" /* CP2_DATA_PADDR_EXT <= dcxy */
135 "sw $3, 0(%3)\n" /* *(dptr + 4*i) <= $3 */
136 "mtc2 $15, $24\n" /* CP2_DATA_PADDR_EXT <= $15 */
137 "sync \n"
138 :
139 : "r"(scxy), "r"(sptr + (i << 2)),
140 "r"(dcxy), "r"(dptr + (i << 2))
141 : "$3", "$15", "memory"
142 );
143 }
144
145 /* Copying byte-by-byte if there is any left. */
146 for (i = words_nr << 2; i < size; i++)
147 {
148 asm volatile("mfc2 $15, $24\n" /* $15 <= CP2_DATA_PADDR_EXT */
149 "mtc2 %0, $24\n" /* CP2_DATA_PADDR_EXT <= scxy */
150 "lb $3, 0(%1)\n" /* $3 <= *(sptr + i) */
151 "mtc2 %2, $24\n" /* CP2_DATA_PADDR_EXT <= dcxy */
152 "sb $3, 0(%3)\n" /* *(dptr + i) <= $3 */
153 "mtc2 $15, $24\n" /* CP2_DATA_PADDR_EXT <= $15 */
154 "sync \n"
155 :
156 : "r"(scxy), "r"(sptr + i),
157 "r"(dcxy), "r"(dptr + i)
158 : "$3", "$15", "memory"
159 );
160 }
161
162} // boot_remote_memcpy()
163
164/****************************************************************************
165 * Atomic operations. *
166 ****************************************************************************/
167
168int32_t boot_atomic_add(int32_t* ptr, int32_t val)
169{
170 int32_t res; /* Value of the variable before the atomic operation. */
171
172 asm volatile(".set noreorder \n"
173 "1: \n"
174 "ll %0, 0(%1) \n" /* res <= *ptr */
175 "addu $3, %0, %2\n" /* $3 <= res + val */
176 "sc $3, 0(%1) \n" /* $ptr <= $3 */
177 "beq $3, $0, 1b\n" /* Retry until success. */
178 "nop \n"
179 "sync \n"
180 ".set reorder \n"
181 : "=&r"(res) /* Temporary register so that it
182 doesn't overlap the other
183 inputs or outputs. */
184 : "r"(ptr), "r"(val)
185 : "$3", "memory"
186 );
187
188 return res;
189
190} // boot_atomic_add()
191
192/****************************************************************************
193 * Memory functions. *
194 ****************************************************************************/
195
196void boot_memcpy(void* dest, void* src, unsigned int size)
197{
198 /* Word-by-word copy if both addresses are word-aligned. */
199 if ((((unsigned int)dest & 0x3) == 0) &&
200 (((unsigned int)src & 0x3) == 0))
201 {
202 // 'size' might not be a multiple of 4 bytes, we have to copy a few
203 // bytes left (at most 3) byte-by-byte later.
204 while (size > 3)
205 {
206 *(unsigned int*)dest++ = *(unsigned int*)src++;
207 size -= 4;
208 }
209 }
210
211 /*
212 * Byte-by-byte copy if:
213 * - At least 1 of the 2 addresses is not word-aligned,
214 * - 'size' value is not a multiple of 4 bytes.
215 */
216 while (size)
217 *(unsigned char*)dest++ = *(unsigned char*)src++;
218
219} // boot_memcpy()
220
221/****************************************************************************/
222
223void boot_memset(void* base, int val, unsigned int size)
224{
225 unsigned int wval; /* Word-sized value to word-by-word filling. */
226
227 /* Word-by-word filling if the base address is word-aligned. */
228 // Extracting the first 2 bytes of 'val'.
229 val &= 0xFF;
230 // Making it word-sized.
231 wval = (val << 24) | (val << 16) | (val << 8) | val;
232
233 if (((unsigned int)base & 0x3) == 0)
234 {
235 // 'size' might not be a multiple of 4 bytes, we have to fill a
236 // few bytes left (at most 3) byte-by-byte later.
237 while (size > 3)
238 {
239 *(unsigned int*)base++ = wval;
240 size -= 4;
241 }
242 }
243
244 /*
245 * Byte-by-byte filling if:
246 * - The base address is not word-aligned,
247 * - 'size' value is not a multiple of 4 bytes.
248 */
249 while (size--)
250 *(unsigned char*)base++ = val;
251
252} // boot_memset()
253
254/****************************************************************************
255 * String functions. *
256 ****************************************************************************/
257
258void boot_strcpy(char* dest, char* src)
259{
260 /* Checking if the arguments are correct. */
261 if ((dest == NULL) || (src == NULL))
262 return;
263
264 /* Copying the string. */
265 while ((*dest++ = *src++) != '\0');
266
267} // boot_strcpy()
268
269/****************************************************************************/
270
271unsigned int boot_strlen(char* s)
272{
273 unsigned int res = 0; /* Length of the string (in bytes). */
274
275 if (s != NULL)
276 {
277 while (*s++ != '\0')
278 res++;
279 }
280
281 return res;
282
283} // boot_strlen()
284
285/****************************************************************************/
286
287int boot_strcmp(char* s1, char* s2)
288{
289 if ((s1 == NULL) || (s2 == NULL))
290 return 0;
291
292 while (1)
293 {
294 if (*s1 != *s2)
295 return 1;
296 if (*s1 == '\0')
297 break;
298 s1++;
299 s2++;
300 }
301
302 return 0;
303
304} // boot_strcmp()
305
306/****************************************************************************
307 * Display functions. *
308 ****************************************************************************/
309
310void boot_puts(char* str)
311{
312 boot_tty_write(str, boot_strlen(str));
313
314} // boot_puts()
315
316/****************************************************************************/
317
318void boot_printf(char* format, ...)
319{
320 va_list arg; /* Used to iterate arguments list. */
321 char buf[16]; /* Buffer for argument conversion. */
322 char* print_pt; /* String pointer for argument printing. */
323 int arg_val; /* Raw value of the argument. */
324 unsigned int arg_len; /* Length of a argument (in bytes). */
325 unsigned int nb_printed; /* Iterator for text printing loop. */
326 unsigned int conv_index; /* Index for argument conversion loop. */
327
328 const char conv_tab[] = "0123456789ABCDEF";
329
330 /* Starting the arguments iterating process with a va_list. */
331 va_start(arg, format);
332
333print_text:
334
335 while (*format)
336 {
337 /* Counting the number of ordinary characters. */
338 for (nb_printed = 0;
339 (format[nb_printed] != '\0') && (format[nb_printed] != '%');
340 nb_printed++);
341
342 /* Copying them unchanged to the boot TTY terminal. */
343 if (nb_printed > 0)
344 {
345 if (boot_tty_write(format, nb_printed))
346 goto error;
347 format += nb_printed;
348 }
349
350 /* Skipping the '%' character. */
351 if (*format == '%')
352 {
353 format++;
354 goto print_argument;
355 }
356 }
357
358 /* Freeing the va_list. */
359 va_end(arg);
360
361 return;
362
363print_argument:
364
365 /* Analyzing the conversion specifier. */
366 switch (*format++)
367 {
368 // A character.
369 case ('c'):
370 {
371 // Retrieving the argument.
372 arg_val = va_arg(arg, int);
373
374 // Preparing for the printing.
375 arg_len = 1;
376 buf[0] = arg_val;
377 print_pt = &buf[0];
378 break;
379 }
380
381 // A 32-bit signed decimal notation of an integer.
382 case ('d'):
383 {
384 // Retrieving the argument.
385 arg_val = va_arg(arg, int);
386
387 // Printing the minus sign if needed.
388 if (arg_val < 0)
389 {
390 arg_val = -arg_val;
391 if (boot_tty_write("-", 1))
392 goto error;
393 }
394
395 // Converting the argument raw value to a character string.
396 // Note that the maximum value for this type is 2.147.483.647
397 // (2^31 - 1), a 10-digit number.
398 for (conv_index = 0; conv_index < 10; conv_index++)
399 {
400 // Writing to the buffer, starting from the least significant
401 // digit.
402 buf[9 - conv_index] = conv_tab[arg_val % 10];
403
404 // Getting to the next digit, stop when no more digit.
405 if ((arg_val /= 10) == 0)
406 break;
407 }
408
409 // Preparing for the printing.
410 arg_len = conv_index + 1;
411 print_pt = &buf[9 - conv_index];
412 break;
413 }
414
415 // A 32-bit unsigned decimal notation of an integer.
416 case ('u'):
417 {
418 // Retrieving the argument.
419 arg_val = va_arg(arg, unsigned int);
420
421 // Converting the argument raw value to a character string.
422 // Note that the maximum value for this type is 4.294.967.295
423 // (2^32 - 1), also a 10-digit number.
424 for (conv_index = 0; conv_index < 10; conv_index++)
425 {
426 // Writing to the buffer, starting from the least significant
427 // digit.
428 buf[9 - conv_index] = conv_tab[arg_val % 10];
429
430 // Getting to the next digit, stop when no more digit.
431 if ((arg_val /= 10) == 0)
432 break;
433 }
434
435 // Preparing for the printing.
436 arg_len = conv_index + 1;
437 print_pt = &buf[9 - conv_index];
438 break;
439 }
440
441 // A 32-bit unsigned hexadecimal notation of an integer.
442 case ('x'):
443 {
444 // Retrieving the argument.
445 arg_val = va_arg(arg, unsigned int);
446
447 // Printing the hexadecimal prefix.
448 if (boot_tty_write("0x", 2))
449 goto error;
450
451 // Converting the argument raw value to a character string.
452 // Note that the maximum value for this type is 0xFFFFFFFF
453 // (2^32 - 1), a 8-digit hexadecimal number.
454 for (conv_index = 0; conv_index < 8; conv_index++)
455 {
456 // Writing to the buffer, starting from the least significant
457 // digit.
458 buf[7 - conv_index] = conv_tab[arg_val % 16];
459
460 // Getting to the next digit, stop when no more digit.
461 if ((arg_val >>= 4) == 0)
462 break;
463 }
464
465 // Preparing for the printing.
466 arg_len = conv_index + 1;
467 print_pt = &buf[7 - conv_index];
468 break;
469 }
470
471 // A 64-bit unsigned hexadecimal notation of an integer.
472 case ('l'):
473 {
474 // Retrieving the argument.
475 arg_val = va_arg(arg, unsigned long long);
476
477 // Printing the hexadecimal prefix.
478 if (boot_tty_write("0x", 2))
479 goto error;
480
481 // Converting the argument raw value to a character string.
482 // Note that the maximum value for this type is 0xFFFFFFFFFFFFFFFF
483 // (2^64 - 1), a 16-digit hexadecimal number.
484 for (conv_index = 0; conv_index < 16; conv_index++)
485 {
486 // Writing to the buffer, starting from the least significant
487 // digit.
488 buf[15 - conv_index] = conv_tab[arg_val % 16];
489
490 // Getting to the next digit, stop when no more digit.
491 if ((arg_val >>= 4) == 0)
492 break;
493 }
494
495 // Preparing for the printing.
496 arg_len = conv_index + 1;
497 print_pt = &buf[15 - conv_index];
498 break;
499 }
500
501 // A NUL terminated string.
502 case ('s'):
503 {
504 // Retrieving the argument.
505 print_pt = va_arg(arg, char*);
506
507 // Preparing for the printing.
508 arg_len = boot_strlen(print_pt);
509 break;
510 }
511
512 default:
513 goto error;
514
515 }
516
517 /* Printing the converted argument. */
518 if (boot_tty_write(print_pt, arg_len))
519 goto error;
520
521 goto print_text;
522
523error:
524
525 /* Trying to print an error message then exit. */
526 boot_puts("\n[BOOT ERROR] boot_printf(): "
527 "Cannot print the whole message\n"
528 );
529
530 boot_exit();
531
532} // boot_printf()
533
534/****************************************************************************
535 * Misc. functions. *
536 ****************************************************************************/
537
538void boot_exit()
539{
540 boot_printf("\n[BOOT PANIC] Suiciding at cycle %d...\n",
541 boot_get_proctime()
542 );
543
544 while (1)
545 asm volatile ("nop");
546
547} // boot_exit()
548
549/****************************************************************************/
550
551unsigned int boot_get_proctime()
552{
553 unsigned int res; /* Value stored in the CP0_COUNT register. */
554
555 asm volatile("mfc0 %0, $9" : "=r"(res));
556
557 return res;
558
559} // boot_get_proctime()
560
561/****************************************************************************/
562
563unsigned int boot_get_procid()
564{
565 unsigned int res; /* Value stored in the CP0_PROCID register. */
566
567 asm volatile("mfc0 %0, $15, 1" : "=r"(res));
568
569 return (res & 0xFFF);
570
571} // boot_get_procid()
572
573/****************************************************************************/
574
575void boot_barrier(xptr_t xp_barrier, uint32_t count)
576{
577 boot_barrier_t* ptr; /* Classic pointer to the toggling
578 barrier. */
579 uint32_t cxy; /* Identifier of the cluster containing
580 the toggling barrier. */
581 uint32_t expected; /* Expected barrier state after reset. */
582 uint32_t current; /* Number of processors reached the
583 barrier. */
584
585 /* Extracting information from the extended pointer. */
586 ptr = (boot_barrier_t*)GET_PTR(xp_barrier);
587 cxy = (uint32_t) GET_CXY(xp_barrier);
588
589 /*
590 * Explicitly testing the barrier sense value because no initialization
591 * has been previously done.
592 */
593 if (boot_remote_lw(XPTR(cxy, &ptr->sense)) == 0)
594 expected = 1;
595 else
596 expected = 0;
597
598 /* Incrementing the counter. */
599 current = boot_remote_atomic_add(XPTR(cxy, &ptr->current), 1);
600
601 /* The processor arrived last resets the barrier and toggles its sense. */
602 if (current == (count - 1))
603 {
604 boot_remote_sw(XPTR(cxy, &ptr->current), 0);
605 boot_remote_sw(XPTR(cxy, &ptr->sense), expected);
606 }
607 /* Other processors poll the sense. */
608 else
609 {
610 while (boot_remote_lw(XPTR(cxy, &ptr->sense)) != expected);
611 }
612
613} // boot_barrier()
614
Note: See TracBrowser for help on using the repository browser.