1 /*
2  * Copyright (c) 2014, Mentor Graphics Corporation
3  * Copyright (c) 2015 Xilinx, Inc.
4  * Copyright (c) 2016 Freescale Semiconductor, Inc.
5  * Copyright 2016-2023 NXP
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice,
12  *    this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16  * 3. Neither the name of the copyright holder nor the names of its
17  *    contributors may be used to endorse or promote products derived from this
18  *    software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /**************************************************************************
34  * FILE NAME
35  *
36  *       rpmsg_env_zephyr.c
37  *
38  *
39  * DESCRIPTION
40  *
41  *       This file is Zephyr RTOS Implementation of env layer for OpenAMP.
42  *
43  *
44  **************************************************************************/
45 
46 #include "rpmsg_compiler.h"
47 #include "rpmsg_env.h"
48 #include <zephyr/kernel.h>
49 #include <zephyr/sys_clock.h>
50 #include "rpmsg_platform.h"
51 #include "virtqueue.h"
52 
53 #include <stdlib.h>
54 #include <string.h>
55 
56 #if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
57 #error "This RPMsg-Lite port requires RL_USE_ENVIRONMENT_CONTEXT set to 0"
58 #endif
59 
60 /* RL_ENV_MAX_MUTEX_COUNT is an arbitrary count greater than 'count'
61    if the inital count is 1, this function behaves as a mutex
62    if it is greater than 1, it acts as a "resource allocator" with
63    the maximum of 'count' resources available.
64    Currently, only the first use-case is applicable/applied in RPMsg-Lite.
65  */
66 #define RL_ENV_MAX_MUTEX_COUNT (10)
67 
68 static int32_t env_init_counter = 0;
69 static struct k_sem env_sema    = {0};
70 static struct k_event env_event = {0};
71 
72 /* Max supported ISR counts */
73 #define ISR_COUNT (32U)
74 /*!
75  * Structure to keep track of registered ISR's.
76  */
77 struct isr_info
78 {
79     void *data;
80 };
81 static struct isr_info isr_table[ISR_COUNT];
82 
83 /*!
84  * env_in_isr
85  *
86  * @returns - true, if currently in ISR
87  *
88  */
env_in_isr(void)89 static int32_t env_in_isr(void)
90 {
91     return k_is_in_isr();
92 }
93 
94 /*!
95  * env_wait_for_link_up
96  *
97  * Wait until the link_state parameter of the rpmsg_lite_instance is set.
98  * Utilize events to avoid busy loop implementation.
99  *
100  */
env_wait_for_link_up(volatile uint32_t * link_state,uint32_t link_id,uint32_t timeout_ms)101 uint32_t env_wait_for_link_up(volatile uint32_t *link_state, uint32_t link_id, uint32_t timeout_ms)
102 {
103     if (*link_state != 1U)
104     {
105         if (env_in_isr() != 0)
106         {
107             timeout_ms = 0; /* force timeout == 0 when in ISR */
108         }
109 
110         if (0 != k_event_wait_all(&env_event, (1UL << link_id), false, K_MSEC(timeout_ms)))
111         {
112             return 1U;
113         }
114         return 0U;
115     }
116     else
117     {
118         return 1U;
119     }
120 }
121 
122 /*!
123  * env_tx_callback
124  *
125  * Set event to notify task waiting in env_wait_for_link_up().
126  *
127  */
env_tx_callback(uint32_t link_id)128 void env_tx_callback(uint32_t link_id)
129 {
130     k_event_post(&env_event, (1UL << link_id));
131 }
132 
133 /*!
134  * env_init
135  *
136  * Initializes OS/BM environment.
137  *
138  */
env_init(void)139 int32_t env_init(void)
140 {
141     int32_t retval;
142     k_sched_lock(); /* stop scheduler */
143     /* verify 'env_init_counter' */
144     RL_ASSERT(env_init_counter >= 0);
145     if (env_init_counter < 0)
146     {
147         k_sched_unlock(); /* re-enable scheduler */
148         return -1;
149     }
150     env_init_counter++;
151     /* multiple call of 'env_init' - return ok */
152     if (env_init_counter == 1)
153     {
154         /* first call */
155         k_sem_init(&env_sema, 0, 1);
156         k_event_init(&env_event);
157         (void)memset(isr_table, 0, sizeof(isr_table));
158         k_sched_unlock();
159         retval = platform_init();
160         k_sem_give(&env_sema);
161 
162         return retval;
163     }
164     else
165     {
166         k_sched_unlock();
167         /* Get the semaphore and then return it,
168          * this allows for platform_init() to block
169          * if needed and other tasks to wait for the
170          * blocking to be done.
171          * This is in ENV layer as this is ENV specific.*/
172         k_sem_take(&env_sema, K_FOREVER);
173         k_sem_give(&env_sema);
174         return 0;
175     }
176 }
177 
178 /*!
179  * env_deinit
180  *
181  * Uninitializes OS/BM environment.
182  *
183  * @returns - execution status
184  */
env_deinit(void)185 int32_t env_deinit(void)
186 {
187     int32_t retval;
188 
189     k_sched_lock(); /* stop scheduler */
190     /* verify 'env_init_counter' */
191     RL_ASSERT(env_init_counter > 0);
192     if (env_init_counter <= 0)
193     {
194         k_sched_unlock(); /* re-enable scheduler */
195         return -1;
196     }
197 
198     /* counter on zero - call platform deinit */
199     env_init_counter--;
200     /* multiple call of 'env_deinit' - return ok */
201     if (env_init_counter <= 0)
202     {
203         /* last call */
204         (void)memset(isr_table, 0, sizeof(isr_table));
205         retval = platform_deinit();
206         k_sem_reset(&env_sema);
207         k_sched_unlock();
208 
209         return retval;
210     }
211     else
212     {
213         k_sched_unlock();
214         return 0;
215     }
216 }
217 
218 /*!
219  * env_allocate_memory - implementation
220  *
221  * @param size
222  */
env_allocate_memory(uint32_t size)223 void *env_allocate_memory(uint32_t size)
224 {
225     return (k_malloc(size));
226 }
227 
228 /*!
229  * env_free_memory - implementation
230  *
231  * @param ptr
232  */
env_free_memory(void * ptr)233 void env_free_memory(void *ptr)
234 {
235     if (ptr != ((void *)0))
236     {
237         k_free(ptr);
238     }
239 }
240 
241 /*!
242  *
243  * env_memset - implementation
244  *
245  * @param ptr
246  * @param value
247  * @param size
248  */
env_memset(void * ptr,int32_t value,uint32_t size)249 void env_memset(void *ptr, int32_t value, uint32_t size)
250 {
251     (void)memset(ptr, value, size);
252 }
253 
254 /*!
255  *
256  * env_memcpy - implementation
257  *
258  * @param dst
259  * @param src
260  * @param len
261  */
env_memcpy(void * dst,void const * src,uint32_t len)262 void env_memcpy(void *dst, void const *src, uint32_t len)
263 {
264     (void)memcpy(dst, src, len);
265 }
266 
267 /*!
268  *
269  * env_strcmp - implementation
270  *
271  * @param dst
272  * @param src
273  */
274 
env_strcmp(const char * dst,const char * src)275 int32_t env_strcmp(const char *dst, const char *src)
276 {
277     return (strcmp(dst, src));
278 }
279 
280 /*!
281  *
282  * env_strncpy - implementation
283  *
284  * @param dest
285  * @param src
286  * @param len
287  */
env_strncpy(char * dest,const char * src,uint32_t len)288 void env_strncpy(char *dest, const char *src, uint32_t len)
289 {
290     (void)strncpy(dest, src, len);
291 }
292 
293 /*!
294  *
295  * env_strncmp - implementation
296  *
297  * @param dest
298  * @param src
299  * @param len
300  */
env_strncmp(char * dest,const char * src,uint32_t len)301 int32_t env_strncmp(char *dest, const char *src, uint32_t len)
302 {
303     return (strncmp(dest, src, len));
304 }
305 
306 /*!
307  *
308  * env_mb - implementation
309  *
310  */
env_mb(void)311 void env_mb(void)
312 {
313     MEM_BARRIER();
314 }
315 
316 /*!
317  * env_rmb - implementation
318  */
env_rmb(void)319 void env_rmb(void)
320 {
321     MEM_BARRIER();
322 }
323 
324 /*!
325  * env_wmb - implementation
326  */
env_wmb(void)327 void env_wmb(void)
328 {
329     MEM_BARRIER();
330 }
331 
332 /*!
333  * env_map_vatopa - implementation
334  *
335  * @param address
336  */
env_map_vatopa(void * address)337 uint32_t env_map_vatopa(void *address)
338 {
339     return platform_vatopa(address);
340 }
341 
342 /*!
343  * env_map_patova - implementation
344  *
345  * @param address
346  */
env_map_patova(uint32_t address)347 void *env_map_patova(uint32_t address)
348 {
349     return platform_patova(address);
350 }
351 
352 /*!
353  * env_create_mutex
354  *
355  * Creates a mutex with the given initial count.
356  *
357  */
358 #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
env_create_mutex(void ** lock,int32_t count,void * context)359 int32_t env_create_mutex(void **lock, int32_t count, void *context)
360 #else
361 int32_t env_create_mutex(void **lock, int32_t count)
362 #endif
363 {
364     struct k_sem *semaphore_ptr;
365 
366     if (count > RL_ENV_MAX_MUTEX_COUNT)
367     {
368         return -1;
369     }
370 
371 #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
372     semaphore_ptr = (struct k_sem *)context;
373 #else
374     semaphore_ptr = (struct k_sem *)env_allocate_memory(sizeof(struct k_sem));
375 #endif
376     if (semaphore_ptr == ((void *)0))
377     {
378         return -1;
379     }
380 
381     k_sem_init(semaphore_ptr, count, RL_ENV_MAX_MUTEX_COUNT);
382     /* Becasue k_sem_init() does not return any status, we do not know if all is OK or not.
383        If something would not be OK dynamically allocated memory has to be freed here. */
384 
385     *lock = (void *)semaphore_ptr;
386     return 0;
387 }
388 
389 /*!
390  * env_delete_mutex
391  *
392  * Deletes the given lock
393  *
394  */
env_delete_mutex(void * lock)395 void env_delete_mutex(void *lock)
396 {
397     k_sem_reset(lock);
398 #if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1))
399     env_free_memory(lock);
400 #endif
401 }
402 
403 /*!
404  * env_lock_mutex
405  *
406  * Tries to acquire the lock, if lock is not available then call to
407  * this function will suspend.
408  */
env_lock_mutex(void * lock)409 void env_lock_mutex(void *lock)
410 {
411     if (env_in_isr() == 0)
412     {
413         k_sem_take((struct k_sem *)lock, K_FOREVER);
414     }
415 }
416 
417 /*!
418  * env_unlock_mutex
419  *
420  * Releases the given lock.
421  */
env_unlock_mutex(void * lock)422 void env_unlock_mutex(void *lock)
423 {
424     if (env_in_isr() == 0)
425     {
426         k_sem_give((struct k_sem *)lock);
427     }
428 }
429 
430 /*!
431  * env_create_sync_lock
432  *
433  * Creates a synchronization lock primitive. It is used
434  * when signal has to be sent from the interrupt context to main
435  * thread context.
436  */
437 #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
env_create_sync_lock(void ** lock,int32_t state,void * context)438 int32_t env_create_sync_lock(void **lock, int32_t state, void *context)
439 {
440     return env_create_mutex(lock, state, context); /* state=1 .. initially free */
441 }
442 #else
env_create_sync_lock(void ** lock,int32_t state)443 int32_t env_create_sync_lock(void **lock, int32_t state)
444 {
445     return env_create_mutex(lock, state); /* state=1 .. initially free */
446 }
447 #endif
448 
449 /*!
450  * env_delete_sync_lock
451  *
452  * Deletes the given lock
453  *
454  */
env_delete_sync_lock(void * lock)455 void env_delete_sync_lock(void *lock)
456 {
457     if (lock != ((void *)0))
458     {
459         env_delete_mutex(lock);
460     }
461 }
462 
463 /*!
464  * env_acquire_sync_lock
465  *
466  * Tries to acquire the lock, if lock is not available then call to
467  * this function waits for lock to become available.
468  */
env_acquire_sync_lock(void * lock)469 void env_acquire_sync_lock(void *lock)
470 {
471     if (lock != ((void *)0))
472     {
473         env_lock_mutex(lock);
474     }
475 }
476 
477 /*!
478  * env_release_sync_lock
479  *
480  * Releases the given lock.
481  */
env_release_sync_lock(void * lock)482 void env_release_sync_lock(void *lock)
483 {
484     if (lock != ((void *)0))
485     {
486         env_unlock_mutex(lock);
487     }
488 }
489 
490 /*!
491  * env_sleep_msec
492  *
493  * Suspends the calling thread for given time , in msecs.
494  */
env_sleep_msec(uint32_t num_msec)495 void env_sleep_msec(uint32_t num_msec)
496 {
497     k_sleep(K_MSEC(num_msec));
498 }
499 
500 /*!
501  * env_register_isr
502  *
503  * Registers interrupt handler data for the given interrupt vector.
504  *
505  * @param vector_id - virtual interrupt vector number
506  * @param data      - interrupt handler data (virtqueue)
507  */
env_register_isr(uint32_t vector_id,void * data)508 void env_register_isr(uint32_t vector_id, void *data)
509 {
510     RL_ASSERT(vector_id < ISR_COUNT);
511     if (vector_id < ISR_COUNT)
512     {
513         isr_table[vector_id].data = data;
514     }
515 }
516 
517 /*!
518  * env_unregister_isr
519  *
520  * Unregisters interrupt handler data for the given interrupt vector.
521  *
522  * @param vector_id - virtual interrupt vector number
523  */
env_unregister_isr(uint32_t vector_id)524 void env_unregister_isr(uint32_t vector_id)
525 {
526     RL_ASSERT(vector_id < ISR_COUNT);
527     if (vector_id < ISR_COUNT)
528     {
529         isr_table[vector_id].data = ((void *)0);
530     }
531 }
532 
533 /*!
534  * env_enable_interrupt
535  *
536  * Enables the given interrupt
537  *
538  * @param vector_id   - virtual interrupt vector number
539  */
540 
env_enable_interrupt(uint32_t vector_id)541 void env_enable_interrupt(uint32_t vector_id)
542 {
543     (void)platform_interrupt_enable(vector_id);
544 }
545 
546 /*!
547  * env_disable_interrupt
548  *
549  * Disables the given interrupt
550  *
551  * @param vector_id   - virtual interrupt vector number
552  */
553 
env_disable_interrupt(uint32_t vector_id)554 void env_disable_interrupt(uint32_t vector_id)
555 {
556     (void)platform_interrupt_disable(vector_id);
557 }
558 
559 /*!
560  * env_map_memory
561  *
562  * Enables memory mapping for given memory region.
563  *
564  * @param pa   - physical address of memory
565  * @param va   - logical address of memory
566  * @param size - memory size
567  * param flags - flags for cache/uncached  and access type
568  */
569 
env_map_memory(uint32_t pa,uint32_t va,uint32_t size,uint32_t flags)570 void env_map_memory(uint32_t pa, uint32_t va, uint32_t size, uint32_t flags)
571 {
572     platform_map_mem_region(va, pa, size, flags);
573 }
574 
575 /*!
576  * env_disable_cache
577  *
578  * Disables system caches.
579  *
580  */
581 
env_disable_cache(void)582 void env_disable_cache(void)
583 {
584     platform_cache_all_flush_invalidate();
585     platform_cache_disable();
586 }
587 
588 /*========================================================= */
589 /* Util data / functions  */
590 
env_isr(uint32_t vector)591 void env_isr(uint32_t vector)
592 {
593     struct isr_info *info;
594     RL_ASSERT(vector < ISR_COUNT);
595     if (vector < ISR_COUNT)
596     {
597         info = &isr_table[vector];
598         virtqueue_notification((struct virtqueue *)info->data);
599     }
600 }
601 
602 /*
603  * env_create_queue
604  *
605  * Creates a message queue.
606  *
607  * @param queue -  pointer to created queue
608  * @param length -  maximum number of elements in the queue
609  * @param element_size - queue element size in bytes
610  * @param queue_static_storage - pointer to queue static storage buffer
611  * @param queue_static_context - pointer to queue static context
612  *
613  * @return - status of function execution
614  */
615 #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
env_create_queue(void ** queue,int32_t length,int32_t element_size,uint8_t * queue_static_storage,rpmsg_static_queue_ctxt * queue_static_context)616 int32_t env_create_queue(void **queue,
617                          int32_t length,
618                          int32_t element_size,
619                          uint8_t *queue_static_storage,
620                          rpmsg_static_queue_ctxt *queue_static_context)
621 #else
622 int32_t env_create_queue(void **queue, int32_t length, int32_t element_size)
623 #endif
624 {
625     struct k_msgq *queue_ptr = ((void *)0);
626     char *msgq_buffer_ptr    = ((void *)0);
627 
628 #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
629     queue_ptr       = (struct k_msgq *)queue_static_context;
630     msgq_buffer_ptr = (char *)queue_static_storage;
631 #else
632     queue_ptr       = (struct k_msgq *)env_allocate_memory(sizeof(struct k_msgq));
633     msgq_buffer_ptr = (char *)env_allocate_memory(length * element_size);
634 #endif
635     if ((queue_ptr == ((void *)0)) || (msgq_buffer_ptr == ((void *)0)))
636     {
637         return -1;
638     }
639     k_msgq_init(queue_ptr, msgq_buffer_ptr, element_size, length);
640     /* Becasue k_msgq_init() does not return any status, we do not know if all is OK or not.
641        If something would not be OK dynamically allocated memory has to be freed here. */
642 
643     *queue = (void *)queue_ptr;
644     return 0;
645 }
646 
647 /*!
648  * env_delete_queue
649  *
650  * Deletes the message queue.
651  *
652  * @param queue - queue to delete
653  */
654 
env_delete_queue(void * queue)655 void env_delete_queue(void *queue)
656 {
657     k_msgq_purge((struct k_msgq *)queue);
658 #if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1))
659     env_free_memory(((struct k_msgq *)queue)->buffer_start);
660     env_free_memory(queue);
661 #endif
662 }
663 
664 /*!
665  * env_put_queue
666  *
667  * Put an element in a queue.
668  *
669  * @param queue - queue to put element in
670  * @param msg - pointer to the message to be put into the queue
671  * @param timeout_ms - timeout in ms
672  *
673  * @return - status of function execution
674  */
675 
env_put_queue(void * queue,void * msg,uintptr_t timeout_ms)676 int32_t env_put_queue(void *queue, void *msg, uintptr_t timeout_ms)
677 {
678     if (env_in_isr() != 0)
679     {
680         timeout_ms = 0; /* force timeout == 0 when in ISR */
681     }
682 
683     if (0 == k_msgq_put((struct k_msgq *)queue, msg, K_MSEC(timeout_ms)))
684     {
685         return 1;
686     }
687     return 0;
688 }
689 
690 /*!
691  * env_get_queue
692  *
693  * Get an element out of a queue.
694  *
695  * @param queue - queue to get element from
696  * @param msg - pointer to a memory to save the message
697  * @param timeout_ms - timeout in ms
698  *
699  * @return - status of function execution
700  */
701 
env_get_queue(void * queue,void * msg,uintptr_t timeout_ms)702 int32_t env_get_queue(void *queue, void *msg, uintptr_t timeout_ms)
703 {
704     if (env_in_isr() != 0)
705     {
706         timeout_ms = 0; /* force timeout == 0 when in ISR */
707     }
708 
709     if (0 == k_msgq_get((struct k_msgq *)queue, msg, K_MSEC(timeout_ms)))
710     {
711         return 1;
712     }
713     return 0;
714 }
715 
716 /*!
717  * env_get_current_queue_size
718  *
719  * Get current queue size.
720  *
721  * @param queue - queue pointer
722  *
723  * @return - Number of queued items in the queue
724  */
725 
env_get_current_queue_size(void * queue)726 int32_t env_get_current_queue_size(void *queue)
727 {
728     return k_msgq_num_used_get((struct k_msgq *)queue);
729 }
730