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

Last change on this file since 1 was 1, checked in by alain, 5 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.