source: trunk/boot/tsar_mips32/boot_utils.c @ 641

Last change on this file since 641 was 525, checked in by viala@…, 6 years ago

[boot] Uniformisation of style on some prototypes.

File size: 19.6 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_kernel_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, const void * src, uint32_t size )
225{
226    uint32_t * wdst = dst;
227    const 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    const unsigned char * csrc = (const 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, const char * src)
285{
286    /* Copying the string. */
287    while ((*dest++ = *src++) != '\0');
288
289} // boot_strcpy()
290
291/////////////////////////////
292uint32_t boot_strlen( const char * s )
293{
294    uint32_t res = 0;   /* Length of the string (in bytes).             */
295    while (*s++ != '\0') {
296        res++;
297    }
298
299    return res;
300} // boot_strlen()
301
302///////////////////////////////////
303int boot_strcmp( const char * s1, const char * s2 )
304{
305    if (s1 == s2)
306        return 0;
307
308    while (1)
309    {
310        if (*s1 != *s2)
311            return 1;
312        if (*s1 == '\0')
313            break;
314        s1++;
315        s2++;
316    }
317
318    return 0;
319
320} // boot_strcmp()
321
322/****************************************************************************
323 *                             Display functions.                           *
324 ****************************************************************************/
325
326/////////////////////////
327void boot_puts( const char * str )
328{
329    boot_tty_write(str, boot_strlen(str));
330
331} // boot_puts()
332   
333///////////////////////////////////////
334void boot_printf( const char * format , ... )
335{
336    va_list args;
337    va_start( args , format );
338
339    // take the lock protecting TTY0
340    boot_remote_lock( XPTR( 0 , &tty0_lock ) );
341
342printf_text:
343
344    while ( *format ) 
345    {
346        uint32_t i;
347        for (i = 0 ; format[i] && (format[i] != '%') ; i++);
348        if (i) 
349        {
350            boot_tty_write( format , i );
351            format += i;
352        }
353        if (*format == '%') 
354        {
355            format++;
356            goto printf_arguments;
357        }
358    }
359
360    // release the lock
361    boot_remote_unlock( XPTR( 0 , &tty0_lock ) );
362
363    va_end( args );
364    return;
365
366printf_arguments:
367
368    {
369        char      buf[20];
370        char    * pbuf = NULL;
371        uint32_t  len  = 0;
372        static const char HexaTab[] = "0123456789ABCDEF";
373        uint32_t i;
374
375        switch (*format++) 
376        {
377            case ('c'):             /* char conversion */
378            {
379                int val = va_arg( args , int );
380                len = 1;
381                buf[0] = val;
382                pbuf = &buf[0];
383                break;
384            }
385            case ('d'):             /* 32 bits decimal signed  */
386            {
387                int val = va_arg( args , int );
388                if (val < 0) 
389                {
390                    val = -val;
391                    boot_tty_write( "-" , 1 );
392                }
393                for(i = 0; i < 10; i++) 
394                {
395                    buf[9 - i] = HexaTab[val % 10];
396                    if (!(val /= 10)) break;
397                }
398                len =  i + 1;
399                pbuf = &buf[9 - i];
400                break;
401            }
402            case ('u'):             /* 32 bits decimal unsigned  */
403            {
404                uint32_t val = va_arg( args , uint32_t );
405                for(i = 0; i < 10; i++) 
406                {
407                    buf[9 - i] = HexaTab[val % 10];
408                    if (!(val /= 10)) break;
409                }
410                len  = i + 1;
411                pbuf = &buf[9 - i];
412                break;
413            }
414            case ('x'):             /* 32 bits hexadecimal unsigned */
415            {
416                uint32_t val = va_arg( args , uint32_t );
417                boot_tty_write( "0x" , 2 );
418                for(i = 0; i < 8; i++) 
419                {
420                    buf[7 - i] = HexaTab[val & 0xF];
421                    if (!(val = (val>>4)))  break;
422                }
423                len =  i + 1;
424                pbuf = &buf[7 - i];
425                break;
426            }
427            case ('X'):             /* 32 bits hexadecimal unsigned  on 10 char */
428            {
429                uint32_t val = va_arg( args , uint32_t );
430                boot_tty_write( "0x" , 2 );
431                for(i = 0; i < 8; i++) 
432                {
433                    buf[7 - i] = HexaTab[val & 0xF];
434                    val = (val>>4);
435                }
436                len  = 8;
437                pbuf = buf;
438                break;
439            }
440            case ('l'):            /* 64 bits hexadecimal unsigned */
441            {
442                uint64_t val = va_arg( args , uint64_t );
443                boot_tty_write( "0x" , 2 );
444                for(i = 0; i < 16; i++) 
445                {
446                    buf[15 - i] = HexaTab[val & 0xF];
447                    if (!(val = (val>>4)))  break;
448                }
449                len  = i + 1;
450                pbuf = &buf[15 - i];
451                break;
452            }
453            case ('L'):           /* 64 bits hexadecimal unsigned on 18 char */ 
454            {
455                uint64_t val = va_arg( args , uint64_t );
456                boot_tty_write( "0x" , 2 );
457                for(i = 0; i < 16; i++) 
458                {
459                    buf[15 - i] = HexaTab[val & 0xF];
460                    val = (val>>4);
461                }
462                len  = 16;
463                pbuf = buf;
464                break;
465            }
466            case ('s'):             /* string */
467            {
468                char* str = va_arg( args , char* );
469                while (str[len]) 
470                {
471                    len++;
472                }
473                pbuf = str;
474                break;
475            }
476            default:
477            {
478                boot_tty_write( "\n[PANIC] in boot_printf() : illegal format\n", 43 );
479            }
480        }
481
482        if( pbuf != NULL ) boot_tty_write( pbuf, len );
483       
484        goto printf_text;
485    }
486}  // boot_printf()
487
488
489
490
491
492
493/****************************************************************************
494 *                              Misc. functions.                            *
495 ****************************************************************************/
496
497////////////////
498void boot_exit( void )
499{
500    boot_printf("\n[BOOT PANIC] core %x suicide at cycle %d...\n", 
501                boot_get_procid() , boot_get_proctime() );
502
503    while (1) asm volatile ("nop");
504
505} // boot_exit()
506
507////////////////////////////
508uint32_t boot_get_proctime( void )
509{
510    uint32_t res;       /* Value stored in the CP0_COUNT register.      */
511
512    asm volatile("mfc0 %0, $9" : "=r"(res));
513
514    return res;
515
516} // boot_get_proctime()
517
518
519//////////////////////////
520uint32_t boot_get_procid( void )
521{
522    uint32_t res;       /* Value stored in the CP0_PROCID register.     */
523
524    asm volatile("mfc0 %0, $15, 1" : "=r"(res));
525
526    return (res & 0xFFF);
527
528} // boot_get_procid()
529
530
531////////////////////////////////////////////////
532void boot_remote_barrier( xptr_t     xp_barrier, 
533                          uint32_t   count)
534{
535    boot_remote_barrier_t * ptr;
536    uint32_t                cxy;
537    uint32_t                expected;
538    uint32_t                current;
539
540    // Extract information from the extended pointer
541    ptr = (boot_remote_barrier_t*)GET_PTR(xp_barrier);
542    cxy = (uint32_t)              GET_CXY(xp_barrier);
543
544    // Explicitly test the barrier sense value because no initialization
545    if (boot_remote_lw(XPTR(cxy, &ptr->sense)) == 0) expected = 1;
546    else                                             expected = 0;
547   
548    // Atomically increment counter
549    current = boot_remote_atomic_add(XPTR(cxy, &ptr->current), 1);
550   
551    // The processor arrived last resets the barrier and toggles its sense
552    if (current == (count - 1))
553    {
554        boot_remote_sw(XPTR(cxy, &ptr->current), 0);
555        boot_remote_sw(XPTR(cxy, &ptr->sense), expected);
556    }
557    // Other processors poll the sense
558    else
559    {
560        while (boot_remote_lw(XPTR(cxy, &ptr->sense)) != expected);
561    }
562
563} // boot_barrier()
564
565////////////////////////////////////////
566void boot_remote_lock( xptr_t  lock_xp )
567
568{
569    // Extract information from the extended pointer
570    boot_remote_spinlock_t * ptr = (boot_remote_spinlock_t *)GET_PTR( lock_xp );
571    uint32_t                 cxy = GET_CXY( lock_xp );
572
573    // get next free ticket
574    uint32_t ticket = boot_remote_atomic_add( XPTR( cxy , &ptr->ticket ) , 1 );
575
576    // poll the current slot index
577    while ( boot_remote_lw( XPTR( cxy , &ptr->current ) ) != ticket )
578    {
579        asm volatile ("nop");
580    }
581
582}  // boot_remote_lock()
583
584/////////////////////////////////////////
585void boot_remote_unlock( xptr_t lock_xp )
586{
587    asm volatile ( "sync" );   // for consistency
588
589    // Extract information from the extended pointer
590    boot_remote_spinlock_t * ptr = (boot_remote_spinlock_t *)GET_PTR( lock_xp );
591    uint32_t                 cxy = GET_CXY( lock_xp );
592    xptr_t            current_xp = XPTR( cxy , &ptr->current );
593
594    // get current index value
595    uint32_t current = boot_remote_lw( current_xp );
596
597    // increment current index
598    boot_remote_sw( current_xp , current + 1 );
599
600}  // boot_remote_unlock()
601
602
Note: See TracBrowser for help on using the repository browser.