source: soft/giet_vm/sys/common.c @ 226

Last change on this file since 226 was 221, checked in by meunier, 12 years ago

Ajout d'un "sync" avant de remettre à 0 un lock dans _release_lock()
Nécessaire pour l'architecture tsar du fait du modèle de consistence faible (multi write buffer)

File size: 15.9 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : common.c
3// Date     : 01/04/2012
4// Author   : alain greiner and joel porquet
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// The common.c and common.h files are part of the GIET nano-kernel.
8// They contains various utilities functions.
9///////////////////////////////////////////////////////////////////////////////////
10
11#include <sys_handler.h>
12#include <common.h>
13#include <ctx_handler.h>
14#include <drivers.h>
15#include <hwr_mapping.h>
16#include <stdarg.h>
17
18///////////////////////////////////////////////////////////////////////////////////
19//      Global variables
20///////////////////////////////////////////////////////////////////////////////////
21
22// current context cache TODO
23
24// SR save (used by _it_mask() / it_restore()
25unsigned int    _status_register_save;
26
27///////////////////////////////////////////////////////////////////////////////////
28//        _get_sched()
29// Access CP0 and returns scheduler physical address.
30///////////////////////////////////////////////////////////////////////////////////
31inline unsigned int _get_sched()
32{
33    unsigned int ret;
34    asm volatile (      "mfc0   %0,             $22" 
35                                        : "=r"(ret) );
36    return ret;
37}
38///////////////////////////////////////////////////////////////////////////////////
39//        _get_ptpr()
40// Access CP2 and returns PTPR register.
41///////////////////////////////////////////////////////////////////////////////////
42inline unsigned int _get_ptpr()
43{
44    unsigned int ret;
45    asm volatile (      "mfc2   %0,             $0" 
46                                        : "=r"(ret) );
47    return ret;
48}
49///////////////////////////////////////////////////////////////////////////////////
50//        _get_epc()
51// Access CP0 and returns EPC register.
52///////////////////////////////////////////////////////////////////////////////////
53inline unsigned int _get_epc()
54{
55    unsigned int ret;
56    asm volatile (      "mfc0   %0,             $14" 
57                                        : "=r"(ret) );
58    return ret;
59}
60///////////////////////////////////////////////////////////////////////////////////
61//        _get_bar()
62// Access CP0 and returns BAR register.
63///////////////////////////////////////////////////////////////////////////////////
64inline unsigned int _get_bvar()
65{
66    unsigned int ret;
67    asm volatile (      "mfc0   %0,             $8" 
68                                        : "=r"(ret) );
69    return ret;
70}
71///////////////////////////////////////////////////////////////////////////////////
72//        _get_cr()
73// Access CP0 and returns CR register.
74///////////////////////////////////////////////////////////////////////////////////
75inline unsigned int _get_cause()
76{
77    unsigned int ret;
78    asm volatile (      "mfc0   %0,             $13" 
79                                        : "=r"(ret) );
80    return ret;
81}
82///////////////////////////////////////////////////////////////////////////////////
83//        _get_sr()
84// Access CP0 and returns SR register.
85///////////////////////////////////////////////////////////////////////////////////
86inline unsigned int _get_sr()
87{
88    unsigned int ret;
89    asm volatile (      "mfc0   %0,             $12" 
90                                        : "=r"(ret) );
91    return ret;
92}
93///////////////////////////////////////////////////////////////////////////////////
94//    _it_mask()
95// Access CP0 and mask IRQs
96///////////////////////////////////////////////////////////////////////////////////
97inline void _it_mask()
98{
99    unsigned int        sr_value;
100    asm volatile(       "li             $3,             0xFFFFFFFE      \n"
101                                        "mfc0   %0,             $12                     \n"
102                                        "and    $3,             $3, %0          \n"
103                                        "mtc0   $3,             $12                     \n"
104                                        : "=r"(sr_value) : : "$3" );
105    _status_register_save = sr_value;
106}
107///////////////////////////////////////////////////////////////////////////////////
108//    _it_enable()
109// Access CP0 and enable IRQs
110///////////////////////////////////////////////////////////////////////////////////
111inline void _it_restore()
112{
113    unsigned int        sr_value = _status_register_save;
114    asm volatile(       "mtc0  %0,              $12                     \n"
115                                        : : "r"(sr_value) );
116}
117////////////////////////////////////////////////////////////////////////////
118//    _get_lock()
119// Takes a lock with an ll/sc atomic access.
120// A pseudo random delay is introduced before retry in case of miss
121// (delay average value = 100 cycles)
122////////////////////////////////////////////////////////////////////////////
123inline void _get_lock( unsigned int* plock )
124{
125    register unsigned int  delay = ( _proctime() ^ _procid()<<4 ) & 0xFF;
126
127    asm volatile (
128            "_lock_llsc:             \n"
129            "ll   $2,    0(%0)       \n" /* $2 <= _ioc_lock current value */
130            "bnez $2,    _lock_delay \n" /* delay if _ioc_lock already taken */
131            "li   $3,    1           \n" /* $3 <= argument for sc */
132            "sc   $3,    0(%0)       \n" /* try to set _ioc_lock */
133            "bnez $3,    _lock_ok    \n" /* exit if atomic */
134            "_lock_delay:            \n"
135            "move $4,    %1          \n" /* $4 <= delay */
136            "_lock_loop:             \n"
137            "addi $4,    $4,    -1   \n" /* $4 <= $4 - 1 */
138            "beqz $4,    _lock_loop  \n" /* test end delay */
139            "j           _lock_llsc  \n" /* retry */
140            "_lock_ok:               \n"
141            :
142            :"r"(plock), "r"(delay)
143            :"$2", "$3", "$4");
144}
145
146////////////////////////////////////////////////////////////////////////////
147// _release_lock()
148////////////////////////////////////////////////////////////////////////////
149inline void _release_lock( unsigned int* plock )
150{
151    asm volatile (
152          "sync\n" /* necessary because of the consistency model in tsar */
153    );
154    *plock = 0;
155}
156
157////////////////////////////////////////////////////////////////////////////
158//    _puts()
159// display a string on TTY0 / used for system code debug and log
160////////////////////////////////////////////////////////////////////////////
161void _puts(char* buffer) 
162{
163    unsigned int* tty_address = (unsigned int*) &seg_tty_base;
164    unsigned int n;
165
166    for ( n=0; n<100; n++)
167    {
168        if (buffer[n] == 0) break;
169        tty_address[TTY_WRITE] = (unsigned int)buffer[n];
170    }
171}
172////////////////////////////////////////////////////////////////////////////
173//    _putx()
174// display an int (hexa) on TTY0 / used for system code debug and log
175////////////////////////////////////////////////////////////////////////////
176void _putx(unsigned int val)
177{
178    static const char   HexaTab[] = "0123456789ABCDEF";
179    char                buf[11];
180    unsigned int        c;
181
182    buf[0]  = '0';
183    buf[1]  = 'x';
184    buf[10] = 0;
185
186    for ( c = 0 ; c < 8 ; c++ )
187    { 
188        buf[9-c] = HexaTab[val&0xF];
189        val = val >> 4;
190    }
191    _puts(buf);
192}
193////////////////////////////////////////////////////////////////////////////
194//    _putd()
195// display an int (decimal) on TTY0 / used for system code debug and log
196////////////////////////////////////////////////////////////////////////////
197void _putd(unsigned int val)
198{
199    static const char   DecTab[] = "0123456789";
200    char                                buf[11];
201    unsigned int                i;
202    unsigned int                first;
203
204    buf[10] = 0;
205
206    for (i = 0; i < 10; i++)
207    {
208        if ((val != 0) || (i == 0))
209        {
210            buf[9-i] = DecTab[val % 10];
211            first    = 9-i;
212        }
213        else
214        {
215            break;
216        }
217        val /= 10;
218    }
219    _puts( &buf[first] );
220}
221////////////////////////////////////////////////////////////////////////////
222//    _strncmp()
223// compare two strings s1 & s2 (no more than n characters)
224////////////////////////////////////////////////////////////////////////////
225unsigned int _strncmp(const char* s1, 
226                      const char* s2, 
227                      unsigned int n)
228{
229    unsigned int i;
230    for ( i=0 ; i<n ; i++)
231    {
232        if ( s1[i] != s2[i] ) return 1;
233        if ( s1[i] == 0 )     break;
234    }
235    return 0;
236}
237////////////////////////////////////////////////////////////////////////////
238//         _dcache_buf_invalidate()
239// Invalidate all data cache lines corresponding to a memory
240// buffer (identified by an address and a size).
241////////////////////////////////////////////////////////////////////////////
242void _dcache_buf_invalidate(const void *buffer, 
243                            unsigned int size)
244{
245    unsigned int i;
246    unsigned int tmp;
247    unsigned int line_size;
248
249    // compute data cache line size based on config register (bits 12:10)
250    asm volatile("mfc0 %0, $16, 1" : "=r"(tmp));
251    tmp = ((tmp>>10) & 0x7);
252    line_size = 2 << tmp;
253
254    // iterate on cache lines
255    for (i = 0; i < size; i += line_size)
256    {
257        asm volatile(
258                " cache %0, %1"
259                ::"i" (0x11), "R" (*((unsigned char*)buffer+i))
260                );
261    }
262}
263////////////////////////////////////////////////////////////////////////////
264//    _physical_read_access()
265// This function makes a physical read access to a 32 bits word in memory,
266// after a temporary DTLB desactivation.
267////////////////////////////////////////////////////////////////////////////
268unsigned int _physical_read_access(unsigned int* paddr)
269{
270    unsigned int value;
271
272    asm volatile(   "li     $3,     0xFFFFFFFE          \n"
273                    "mfc0   $2,     $12                         \n"             /* $2 <= SR        */
274                    "and    $3,     $3,         $2              \n"
275                    "mtc0   $3,     $12                         \n"             /* interrupt masked */
276                    "li         $3,             0xB                             \n"
277                    "mtc2       $3,             $1                              \n"             /* DTLB off                     */     
278
279                    "lw         %0,             0(%1)                   \n"             /* entry <= *pslot      */
280
281                    "li         $3,             0xF                             \n"
282                    "mtc2       $3,             $1                              \n"             /* DTLB on                      */     
283                    "mtc0       $2,             $12                             \n"             /* restore SR           */
284                    : "=r"(value)
285                    : "r"(paddr)
286                    : "$2", "$3" );
287    return value;
288}
289////////////////////////////////////////////////////////////////////////////
290//    _physical_write_access()
291// This function makes a physical write access to a 32 bits word in memory,
292// after a temporary DTLB desactivation.
293////////////////////////////////////////////////////////////////////////////
294void _physical_write_access(unsigned int* paddr, unsigned int value)
295{
296    asm volatile(   "li     $3,     0xFFFFFFFE          \n"
297                    "mfc0   $2,     $12                         \n"             /* $26 <= SR        */
298                    "and    $3,     $3,         $2              \n"
299                    "mtc0   $3,     $12                         \n"             /* interrupt masked */
300                    "li         $3,             0xB                             \n"
301                    "mtc2       $3,             $1                              \n"             /* DTLB off                     */
302       
303                    "sw         %0,             0(%1)                   \n"             /* entry <= *pslot      */
304
305                    "li         $3,             0xF                             \n"
306                    "mtc2       $3,             $1                              \n"             /* DTLB on                      */     
307                    "mtc0       $2,             $12                             \n"             /* restore SR           */
308                    :
309                    : "r"(value), "r"(paddr)
310                    : "$2", "$3" );
311}
312////////////////////////////////////////////////////////////////////////////
313//    _get_tasks_number()
314// This function returns the number of tasks allocated to processor.
315////////////////////////////////////////////////////////////////////////////
316unsigned int _get_tasks_number()
317{
318    static_scheduler_t*         psched = (static_scheduler_t*)_get_sched();
319    return _physical_read_access( &(psched->tasks) );
320}
321////////////////////////////////////////////////////////////////////////////
322//    _get_current_task_id()
323// This function returns the index of the currently running task.
324////////////////////////////////////////////////////////////////////////////
325unsigned int _get_current_task_id()
326{
327    static_scheduler_t*         psched = (static_scheduler_t*)_get_sched();
328    return _physical_read_access( &(psched->current) );
329}
330////////////////////////////////////////////////////////////////////////////
331//    _set_current_task_id()
332// This function returns the index of the currently running task.
333////////////////////////////////////////////////////////////////////////////
334void _set_current_task_id( unsigned int value )
335{
336    static_scheduler_t*         psched = (static_scheduler_t*)_get_sched();
337    _physical_write_access( &(psched->current), value );
338}
339///////////////////////////////////////////////////////////////////////////////
340//    _get_context_slot()
341// This function returns a slot content for the task defined by task_id.
342///////////////////////////////////////////////////////////////////////////////
343unsigned int _get_context_slot( unsigned int task_id,
344                                unsigned int slot_id )
345{
346    static_scheduler_t*         psched = (static_scheduler_t*)_get_sched();
347    return _physical_read_access( &(psched->context[task_id][slot_id]) );
348}
349///////////////////////////////////////////////////////////////////////////////
350//    _set_context_slot()
351// This function returns a slot content for the task defined by task_id.
352///////////////////////////////////////////////////////////////////////////////
353void _set_context_slot( unsigned int task_id,
354                        unsigned int slot_id,
355                        unsigned int value )
356{
357    static_scheduler_t*         psched = (static_scheduler_t*)_get_sched();
358    _physical_write_access( &(psched->context[task_id][slot_id]), value );
359}
360////////////////////////////////////////////////////////////////////////////////
361//    _get_interrupt_vector_entry()
362// This function returns the interrupt_vector entry defined by argument index.
363////////////////////////////////////////////////////////////////////////////////
364unsigned int _get_interrupt_vector_entry( unsigned int index )
365{
366    static_scheduler_t*         psched = (static_scheduler_t*)_get_sched();
367    return _physical_read_access( &(psched->interrupt_vector[index]) );
368}
369
370/////////////////////////////////////////////////////////////////////////////
371//      access functions to mapping_info data structure
372/////////////////////////////////////////////////////////////////////////////
373mapping_cluster_t* _get_cluster_base( mapping_header_t* header )
374{
375    return   (mapping_cluster_t*) ((char*)header +
376                                  MAPPING_HEADER_SIZE);
377}
378/////////////////////////////////////////////////////////////////////////////
379mapping_pseg_t* _get_pseg_base( mapping_header_t* header )
380{
381    return   (mapping_pseg_t*)    ((char*)header +
382                                  MAPPING_HEADER_SIZE +
383                                  MAPPING_CLUSTER_SIZE*header->clusters);
384}
385/////////////////////////////////////////////////////////////////////////////
386mapping_vspace_t* _get_vspace_base( mapping_header_t* header )
387{
388    return   (mapping_vspace_t*)  ((char*)header +
389                                  MAPPING_HEADER_SIZE +
390                                  MAPPING_CLUSTER_SIZE*header->clusters +
391                                  MAPPING_PSEG_SIZE*header->psegs);
392}
393/////////////////////////////////////////////////////////////////////////////
394mapping_vseg_t* _get_vseg_base( mapping_header_t* header )
395{
396    return   (mapping_vseg_t*)    ((char*)header +
397                                  MAPPING_HEADER_SIZE +
398                                  MAPPING_CLUSTER_SIZE*header->clusters +
399                                  MAPPING_PSEG_SIZE*header->psegs +
400                                  MAPPING_VSPACE_SIZE*header->vspaces);
401}
402/////////////////////////////////////////////////////////////////////////////
403mapping_vobj_t* _get_vobj_base( mapping_header_t* header )
404{
405    return   (mapping_vobj_t*)   ((char*)header +
406                                  MAPPING_HEADER_SIZE +
407                                  MAPPING_CLUSTER_SIZE*header->clusters +
408                                  MAPPING_PSEG_SIZE*header->psegs +
409                                  MAPPING_VSPACE_SIZE*header->vspaces +
410                                  MAPPING_VSEG_SIZE*header->vsegs );
411}
412/////////////////////////////////////////////////////////////////////////////
413mapping_task_t* _get_task_base( mapping_header_t* header )
414{
415    return   (mapping_task_t*)    ((char*)header +
416                                  MAPPING_HEADER_SIZE +
417                                  MAPPING_CLUSTER_SIZE*header->clusters +
418                                  MAPPING_PSEG_SIZE*header->psegs +
419                                  MAPPING_VSPACE_SIZE*header->vspaces +
420                                  MAPPING_VOBJ_SIZE*header->vobjs +
421                                  MAPPING_VSEG_SIZE*header->vsegs);
422}
423
Note: See TracBrowser for help on using the repository browser.