source: trunk/boot/tsar_mips32/boot_utils.c

Last change on this file was 525, checked in by viala@…, 8 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.