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

Last change on this file since 25 was 6, checked in by alain, 8 years ago

Modify the boot_info_t struct to describe external peripherals in all clusters.

File size: 19.7 KB
Line 
1/*
2 * boot_utils.c - TSAR bootloader utilities implementation.
3 *
4 * Authors :   Alain Greiner / Vu Son  (2016)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <stdarg.h>
25
26#include <boot_tty_driver.h>
27#include <hal_types.h>
28#include <boot_utils.h>
29
30
31/****************************************************************************
32 *                        Global variables                                  *
33 ****************************************************************************/
34
35extern boot_remote_spinlock_t  tty0_lock;   // allocated in boot.c
36
37/****************************************************************************
38 *                              Remote accesses.                            *
39 ****************************************************************************/
40
41//////////////////////////////////
42uint32_t boot_remote_lw(xptr_t xp)
43{
44    uint32_t res; 
45    uint32_t ptr; 
46    uint32_t cxy;
47
48    // Extracting information from the extended pointer
49    ptr = (uint32_t)GET_PTR(xp);
50    cxy = (uint32_t)GET_CXY(xp);
51
52    // Assembly instructions to get the work done.
53    asm volatile("mfc2  $15,    $24\n"  /* $15 <= CP2_DATA_PADDR_EXT        */
54                 "mtc2  %2,     $24\n"  /* CP2_DATA_PADDR_EXT <= cxy        */
55                 "lw    %0,   0(%1)\n"  /* *ptr <= data                     */
56                 "mtc2  $15,    $24\n"  /* CP2_DATA_PADDR_EXT <= $15        */
57                 "sync             \n"
58                 : "=&r"(res)           /* Temporary register so that it   
59                                           doesn't overlap the other inputs
60                                           or outputs.                      */
61                 : "r"(ptr), "r"(cxy)
62                 : "$15"
63                );
64
65    return res;
66
67} // boot_remote_lw()
68
69/////////////////////////////////////////////
70void boot_remote_sw(xptr_t xp, uint32_t data)
71{
72    uint32_t ptr;   /* Classic pointer to the distant memory location.      */
73    uint32_t cxy;   /* Identifier of the cluster containing the distant
74                       memory location.                                     */
75   
76    /* Extracting information from the extended pointers. */
77    ptr = (uint32_t)GET_PTR(xp);                                 
78    cxy = (uint32_t)GET_CXY(xp);
79
80    /* Assembly instructions to get the work done. */
81    asm volatile("mfc2  $15,    $24\n"  /* $15 <= CP2_DATA_PADDR_EXT        */
82                 "mtc2  %2,     $24\n"  /* CP2_DATA_PADDR_EXT <= cxy        */
83                 "sw    %0,   0(%1)\n"  /* *ptr <= data                     */
84                 "mtc2  $15,    $24\n"  /* CP2_DATA_PADDR_EXT <= $15        */
85                 "sync             \n"
86                 :
87                 : "r"(data), "r"(ptr), "r"(cxy)
88                 : "$15", "memory"
89                );
90
91} // boot_remote_sw()
92
93//////////////////////////////////////////////////////
94int32_t boot_remote_atomic_add(xptr_t xp, int32_t val)
95{
96    int32_t  res;   /* Value stored at the distant memory location before
97                       the atomic operation.                                */
98    uint32_t ptr;   /* Classic pointer to the distant memory location.      */
99    uint32_t cxy;   /* Identifier of the cluster containing the distant
100                       memory location.                                     */
101
102    /* Extracting information from the extended pointers. */
103    ptr = (uint32_t)GET_PTR(xp);
104    cxy = (uint32_t)GET_CXY(xp);
105
106    /* Assembly instructions to get the work done. */
107    asm volatile("mfc2  $15,    $24       \n" /* $15 <= CP2_DATA_PADDR_EXT  */ 
108                 "mtc2  %3,     $24       \n" /* CP2_DATA_PADDR_EXT <= cxy  */
109                 "1:                      \n"
110                 "ll    %0,   0(%1)       \n" /* res <= *ptr                */
111                 "addu  $3,     %0,     %2\n" /* $3 <= res + val            */
112                 "sc    $3,   0(%1)       \n" /* *ptr <= $3                 */
113                 "beq   $3,     $0,     1b\n" /* Retry until success.       */
114                 "nop                     \n" /* Delayed slot.              */
115                 "mtc2  $15,    $24       \n" /* CP2_DATA_PADDR_EXT <= $15  */
116                 "sync                    \n"
117                 : "=&r"(res)               /* Temporary register so that
118                                               it doesn't overlap the other
119                                               inputs or outputs.           */
120                 : "r"(ptr), "r"(val), "r"(cxy)
121                 : "$3", "$15", "memory"
122                );
123
124    return res;
125
126} // boot_remote_atomic_add()
127
128///////////////////////////////////////////////////////////////
129void boot_remote_memcpy(xptr_t dest, xptr_t src, uint32_t size)
130{
131    uint32_t words_nr;  /* Number of 32-bit words to be copied.             */
132    uint32_t dptr;      /* Classic pointer to the destination buffer.       */
133    uint32_t dcxy;      /* Identifier of the cluster containing the
134                           destination buffer.                              */
135    uint32_t sptr;      /* Classic pointer to the source buffer.            */
136    uint32_t scxy;      /* Identifier of the cluster containing the
137                           source buffer.                                   */
138    uint32_t i;         /* Iterator for memory copying loop.                */
139
140    /* Extracting information from the extended pointers. */
141    dptr = (uint32_t)GET_PTR(dest);
142    dcxy = (uint32_t)GET_CXY(dest);
143    sptr = (uint32_t)GET_PTR(src);
144    scxy = (uint32_t)GET_CXY(src);
145
146    /*
147     * Testing if we could perform word-by-word copy (if both addresses are
148     * word-aligned).
149     */
150    if ((dptr & 0x3) || (sptr & 0x3)) 
151        words_nr = 0;
152    else
153        words_nr = size >> 2;
154
155    /* Copying word-by-word. */
156    for (i = 0; i < words_nr; i++)
157    {
158        asm volatile("mfc2  $15,    $24\n"  /* $15 <= CP2_DATA_PADDR_EXT    */
159                     "mtc2  %0,     $24\n"  /* CP2_DATA_PADDR_EXT <= scxy   */
160                     "lw    $3,   0(%1)\n"  /* $3 <= *(sptr + 4*i)          */ 
161                     "mtc2  %2,     $24\n"  /* CP2_DATA_PADDR_EXT <= dcxy   */
162                     "sw    $3,   0(%3)\n"  /* *(dptr + 4*i) <= $3          */
163                     "mtc2  $15,    $24\n"  /* CP2_DATA_PADDR_EXT <= $15    */
164                     "sync             \n"
165                     :
166                     : "r"(scxy), "r"(sptr + (i << 2)), 
167                       "r"(dcxy), "r"(dptr + (i << 2))
168                     : "$3", "$15", "memory"
169                    );
170    }
171
172    /* Copying byte-by-byte if there is any left. */
173    for (i = words_nr << 2; i < size; i++)
174    {
175        asm volatile("mfc2  $15,    $24\n"  /* $15 <= CP2_DATA_PADDR_EXT    */
176                     "mtc2  %0,     $24\n"  /* CP2_DATA_PADDR_EXT <= scxy   */
177                     "lb    $3,   0(%1)\n"  /* $3 <= *(sptr + i)            */ 
178                     "mtc2  %2,     $24\n"  /* CP2_DATA_PADDR_EXT <= dcxy   */
179                     "sb    $3,   0(%3)\n"  /* *(dptr + i) <= $3            */
180                     "mtc2  $15,    $24\n"  /* CP2_DATA_PADDR_EXT <= $15    */
181                     "sync             \n"
182                     :
183                     : "r"(scxy), "r"(sptr + i), 
184                       "r"(dcxy), "r"(dptr + i)
185                     : "$3", "$15", "memory"
186                    );
187    }
188
189} // boot_remote_memcpy()
190
191/****************************************************************************
192 *                             Atomic operations.                           *
193 ****************************************************************************/
194
195int32_t boot_atomic_add(int32_t* ptr, int32_t val)
196{
197    int32_t res;    /* Value of the variable before the atomic operation.   */
198
199    asm volatile(".set noreorder          \n" 
200                 "1:                      \n"
201                 "ll    %0,   0(%1)       \n" /* res <= *ptr                */
202                 "addu  $3,     %0,     %2\n" /* $3 <= res + val            */
203                 "sc    $3,   0(%1)       \n" /* $ptr <= $3                 */
204                 "beq   $3,     $0,     1b\n" /* Retry until success.       */
205                 "nop                     \n"
206                 "sync                    \n"
207                 ".set reorder            \n"
208                 : "=&r"(res)               /* Temporary register so that it
209                                               doesn't overlap the other
210                                               inputs or outputs.           */
211                 : "r"(ptr), "r"(val)
212                 : "$3", "memory"
213                );
214
215    return res;
216
217} // boot_atomic_add()
218
219/****************************************************************************
220 *                             Memory functions.                            *
221 ****************************************************************************/
222
223///////////////////////////////////////////////////////
224void boot_memcpy(void * dst, void * src, uint32_t size)
225{
226    uint32_t * wdst = dst;
227    uint32_t * wsrc = src;
228
229    // word-by-word copy if both addresses are word-aligned
230    if ( (((uint32_t)dst & 0x3) == 0) && (((uint32_t)src & 0x3)  == 0) )
231    {
232        while (size > 3)
233        {
234            *wdst++ = *wsrc++;
235            size -= 4;
236        }
237    }
238
239    unsigned char * cdst = (unsigned char *)wdst;
240    unsigned char * csrc = (unsigned char *)wsrc;
241
242    // byte-by-byte copy if:
243    // - At least 1 of the 2 addresses is not word-aligned,
244    // - 'size' value is not a multiple of 4 bytes.
245    while (size)
246    {
247        *cdst++ = *csrc++;
248    }
249} // boot_memcpy()
250
251////////////////////////////////////////////////////
252void boot_memset(void * dst, int val, uint32_t size)
253{
254    val &= 0xFF;
255
256    // build a word-sized value
257    uint32_t   wval = (val << 24) | (val << 16) | (val << 8) | val;
258    uint32_t * wdst = (uint32_t *)dst; 
259
260    // word per word if address aligned
261    if (((uint32_t)dst & 0x3) == 0)
262    {
263        while (size > 3)
264        {
265            *wdst++ = wval;
266            size -= 4;
267        }
268    }
269   
270    char * cdst = (char *)wdst;
271
272    // byte per byte
273    while (size--)
274    {
275        *cdst++ = (char)val;
276    }
277} // boot_memset()
278
279/****************************************************************************
280 *                              String functions.                           *
281 ****************************************************************************/
282
283///////////////////////////////////////
284void boot_strcpy(char* dest, char* src)
285{
286    /* Checking if the arguments are correct. */
287    if ((dest == NULL) || (src == NULL))
288        return;
289
290    /* Copying the string. */
291    while ((*dest++ = *src++) != '\0');
292
293} // boot_strcpy()
294
295/////////////////////////////
296uint32_t boot_strlen(char* s)
297{
298    uint32_t res = 0;   /* Length of the string (in bytes).             */
299
300    if (s != NULL)
301    {
302        while (*s++ != '\0')
303            res++;
304    }
305
306    return res;
307
308} // boot_strlen()
309
310///////////////////////////////////
311int boot_strcmp(char* s1, char* s2)
312{
313    if ((s1 == NULL) || (s2 == NULL))
314        return 0;
315
316    while (1)
317    {
318        if (*s1 != *s2)
319            return 1;
320        if (*s1 == '\0')
321            break;
322        s1++;
323        s2++;
324    }
325
326    return 0;
327
328} // boot_strcmp()
329
330/****************************************************************************
331 *                             Display functions.                           *
332 ****************************************************************************/
333
334/////////////////////////
335void boot_puts(char* str)
336{
337    boot_tty_write(str, boot_strlen(str));
338
339} // boot_puts()
340   
341///////////////////////////////////////
342void boot_printf( char * format , ... )
343{
344    va_list args;
345    va_start( args , format );
346
347    // take the lock protecting TTY0
348    boot_remote_lock( XPTR( 0 , &tty0_lock ) );
349
350printf_text:
351
352    while ( *format ) 
353    {
354        uint32_t i;
355        for (i = 0 ; format[i] && (format[i] != '%') ; i++);
356        if (i) 
357        {
358            boot_tty_write( format , i );
359            format += i;
360        }
361        if (*format == '%') 
362        {
363            format++;
364            goto printf_arguments;
365        }
366    }
367
368    // release the lock
369    boot_remote_unlock( XPTR( 0 , &tty0_lock ) );
370
371    va_end( args );
372    return;
373
374printf_arguments:
375
376    {
377        char      buf[20];
378        char    * pbuf = NULL;
379        uint32_t  len  = 0;
380        static const char HexaTab[] = "0123456789ABCDEF";
381        uint32_t i;
382
383        switch (*format++) 
384        {
385            case ('c'):             /* char conversion */
386            {
387                int val = va_arg( args , int );
388                len = 1;
389                buf[0] = val;
390                pbuf = &buf[0];
391                break;
392            }
393            case ('d'):             /* 32 bits decimal signed  */
394            {
395                int val = va_arg( args , int );
396                if (val < 0) 
397                {
398                    val = -val;
399                    boot_tty_write( "-" , 1 );
400                }
401                for(i = 0; i < 10; i++) 
402                {
403                    buf[9 - i] = HexaTab[val % 10];
404                    if (!(val /= 10)) break;
405                }
406                len =  i + 1;
407                pbuf = &buf[9 - i];
408                break;
409            }
410            case ('u'):             /* 32 bits decimal unsigned  */
411            {
412                uint32_t val = va_arg( args , uint32_t );
413                for(i = 0; i < 10; i++) 
414                {
415                    buf[9 - i] = HexaTab[val % 10];
416                    if (!(val /= 10)) break;
417                }
418                len  = i + 1;
419                pbuf = &buf[9 - i];
420                break;
421            }
422            case ('x'):             /* 32 bits hexadecimal unsigned */
423            {
424                uint32_t val = va_arg( args , uint32_t );
425                boot_tty_write( "0x" , 2 );
426                for(i = 0; i < 8; i++) 
427                {
428                    buf[7 - i] = HexaTab[val & 0xF];
429                    if (!(val = (val>>4)))  break;
430                }
431                len =  i + 1;
432                pbuf = &buf[7 - i];
433                break;
434            }
435            case ('X'):             /* 32 bits hexadecimal unsigned  on 10 char */
436            {
437                uint32_t val = va_arg( args , uint32_t );
438                boot_tty_write( "0x" , 2 );
439                for(i = 0; i < 8; i++) 
440                {
441                    buf[7 - i] = HexaTab[val & 0xF];
442                    val = (val>>4);
443                }
444                len  = 8;
445                pbuf = buf;
446                break;
447            }
448            case ('l'):            /* 64 bits hexadecimal unsigned */
449            {
450                uint64_t val = va_arg( args , uint64_t );
451                boot_tty_write( "0x" , 2 );
452                for(i = 0; i < 16; i++) 
453                {
454                    buf[15 - i] = HexaTab[val & 0xF];
455                    if (!(val = (val>>4)))  break;
456                }
457                len  = i + 1;
458                pbuf = &buf[15 - i];
459                break;
460            }
461            case ('L'):           /* 64 bits hexadecimal unsigned on 18 char */ 
462            {
463                uint64_t val = va_arg( args , uint64_t );
464                boot_tty_write( "0x" , 2 );
465                for(i = 0; i < 16; i++) 
466                {
467                    buf[15 - i] = HexaTab[val & 0xF];
468                    val = (val>>4);
469                }
470                len  = 16;
471                pbuf = buf;
472                break;
473            }
474            case ('s'):             /* string */
475            {
476                char* str = va_arg( args , char* );
477                while (str[len]) 
478                {
479                    len++;
480                }
481                pbuf = str;
482                break;
483            }
484            default:
485            {
486                boot_tty_write( "\n[PANIC] in boot_printf() : illegal format\n", 43 );
487            }
488        }
489
490        if( pbuf != NULL ) boot_tty_write( pbuf, len );
491       
492        goto printf_text;
493    }
494}  // boot_printf()
495
496
497
498
499
500
501/****************************************************************************
502 *                              Misc. functions.                            *
503 ****************************************************************************/
504
505////////////////
506void boot_exit()
507{
508    boot_printf("\n[BOOT PANIC] core %x suicide at cycle %d...\n", 
509                boot_get_procid() , boot_get_proctime() );
510
511    while (1) asm volatile ("nop");
512
513} // boot_exit()
514
515////////////////////////////
516uint32_t boot_get_proctime()
517{
518    uint32_t res;       /* Value stored in the CP0_COUNT register.      */
519
520    asm volatile("mfc0 %0, $9" : "=r"(res));
521
522    return res;
523
524} // boot_get_proctime()
525
526
527//////////////////////////
528uint32_t boot_get_procid()
529{
530    uint32_t res;       /* Value stored in the CP0_PROCID register.     */
531
532    asm volatile("mfc0 %0, $15, 1" : "=r"(res));
533
534    return (res & 0xFFF);
535
536} // boot_get_procid()
537
538
539////////////////////////////////////////////////
540void boot_remote_barrier( xptr_t     xp_barrier, 
541                          uint32_t   count)
542{
543    boot_remote_barrier_t * ptr;
544    uint32_t                cxy;
545    uint32_t                expected;
546    uint32_t                current;
547
548    // Extract information from the extended pointer
549    ptr = (boot_remote_barrier_t*)GET_PTR(xp_barrier);
550    cxy = (uint32_t)              GET_CXY(xp_barrier);
551
552    // Explicitly test the barrier sense value because no initialization
553    if (boot_remote_lw(XPTR(cxy, &ptr->sense)) == 0) expected = 1;
554    else                                             expected = 0;
555   
556    // Atomically increment counter
557    current = boot_remote_atomic_add(XPTR(cxy, &ptr->current), 1);
558   
559    // The processor arrived last resets the barrier and toggles its sense
560    if (current == (count - 1))
561    {
562        boot_remote_sw(XPTR(cxy, &ptr->current), 0);
563        boot_remote_sw(XPTR(cxy, &ptr->sense), expected);
564    }
565    // Other processors poll the sense
566    else
567    {
568        while (boot_remote_lw(XPTR(cxy, &ptr->sense)) != expected);
569    }
570
571} // boot_barrier()
572
573////////////////////////////////////////
574void boot_remote_lock( xptr_t  lock_xp )
575
576{
577    // Extract information from the extended pointer
578    boot_remote_spinlock_t * ptr = (boot_remote_spinlock_t *)GET_PTR( lock_xp );
579    uint32_t                 cxy = GET_CXY( lock_xp );
580
581    // get next free ticket
582    uint32_t ticket = boot_remote_atomic_add( XPTR( cxy , &ptr->ticket ) , 1 );
583
584    // poll the current slot index
585    while ( boot_remote_lw( XPTR( cxy , &ptr->current ) ) != ticket )
586    {
587        asm volatile ("nop");
588    }
589
590}  // boot_remote_lock()
591
592/////////////////////////////////////////
593void boot_remote_unlock( xptr_t lock_xp )
594{
595    asm volatile ( "sync" );   // for consistency
596
597    // Extract information from the extended pointer
598    boot_remote_spinlock_t * ptr = (boot_remote_spinlock_t *)GET_PTR( lock_xp );
599    uint32_t                 cxy = GET_CXY( lock_xp );
600    xptr_t            current_xp = XPTR( cxy , &ptr->current );
601
602    // get current index value
603    uint32_t current = boot_remote_lw( current_xp );
604
605    // increment current index
606    boot_remote_sw( current_xp , current + 1 );
607
608}  // boot_remote_unlock()
609
610
Note: See TracBrowser for help on using the repository browser.