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 | |
---|
11 | uint32_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 | |
---|
41 | void 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 | |
---|
66 | int32_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 | |
---|
102 | void 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 | |
---|
168 | int32_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 | |
---|
196 | void 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 | |
---|
223 | void 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 | |
---|
258 | void 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 | |
---|
271 | unsigned 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 | |
---|
287 | int 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 | |
---|
310 | void boot_puts(char* str) |
---|
311 | { |
---|
312 | boot_tty_write(str, boot_strlen(str)); |
---|
313 | |
---|
314 | } // boot_puts() |
---|
315 | |
---|
316 | /****************************************************************************/ |
---|
317 | |
---|
318 | void 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 | |
---|
333 | print_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 | |
---|
363 | print_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 | |
---|
523 | error: |
---|
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 | |
---|
538 | void 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 | |
---|
551 | unsigned 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 | |
---|
563 | unsigned 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 | |
---|
575 | void 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 | |
---|