/* syscall * * Copyright (C) 2025 Advanced Micro Devices, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * */ #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE #include "FreeRTOS.h" #include "syscall.h" #include "task.h" #include "queue.h" #include "trap.h" #include "timers.h" #include "x86_64.h" #include "freertos_serial.h" #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE #define MAX_SYSCALLS 128 /* Alse file syscall.asm these constants are also defined there */ #define SYSCALL_NUM_writec 0 #define SYSCALL_NUM_xTaskGetTickCount 1 #define SYSCALL_NUM_xTaskDelayUntil 2 #define SYSCALL_NUM_xQueueGenericSend 3 #define SYSCALL_NUM_xQueueReceive 4 #define SYSCALL_NUM_xTimerGenericCommandFromTask 5 #define SYSCALL_NUM_eTaskGetState 6 #define SYSCALL_NUM_pcQueueGetName 7 #define SYSCALL_NUM_pcTimerGetName 8 #define SYSCALL_NUM_pvTimerGetTimerID 9 #define SYSCALL_NUM_ulTaskGenericNotifyTake 10 #define SYSCALL_NUM_ulTaskGenericNotifyValueClear 11 #define SYSCALL_NUM_uxQueueMessagesWaiting 12 #define SYSCALL_NUM_uxQueueSpacesAvailable 13 #define SYSCALL_NUM_uxTaskGetNumberOfTasks 14 #define SYSCALL_NUM_uxTaskGetSystemState 15 #define SYSCALL_NUM_uxTaskPriorityGet 16 #define SYSCALL_NUM_uxTimerGetReloadMode 17 #define SYSCALL_NUM_vQueueAddToRegistry 18 #define SYSCALL_NUM_vQueueUnregisterQueue 19 #define SYSCALL_NUM_vTaskDelay 20 #define SYSCALL_NUM_vTaskGetInfo 21 #define SYSCALL_NUM_vTaskResume 22 #define SYSCALL_NUM_vTaskSetTimeOutState 23 #define SYSCALL_NUM_vTaskSuspend 24 #define SYSCALL_NUM_vTaskSuspendAll 25 #define SYSCALL_NUM_vTimerSetReloadMode 26 #define SYSCALL_NUM_vTimerSetTimerID 27 #define SYSCALL_NUM_xQueueAddToSet 28 #define SYSCALL_NUM_xQueueGiveMutexRecursive 29 #define SYSCALL_NUM_xQueuePeek 30 #define SYSCALL_NUM_xQueueRemoveFromSet 31 #define SYSCALL_NUM_xQueueSelectFromSet 32 #define SYSCALL_NUM_xQueueSemaphoreTake 33 #define SYSCALL_NUM_xQueueTakeMutexRecursive 34 #define SYSCALL_NUM_xTaskCheckForTimeOut 35 #define SYSCALL_NUM_xTaskGenericNotify 36 #define SYSCALL_NUM_xTaskGenericNotifyStateClear 37 #define SYSCALL_NUM_xTaskGenericNotifyWait 38 #define SYSCALL_NUM_xTaskGetCurrentTaskHandle 39 #define SYSCALL_NUM_xTaskGetSchedulerState 40 #define SYSCALL_NUM_xTimerGetExpiryTime 41 #define SYSCALL_NUM_xTimerGetPeriod 42 #define SYSCALL_NUM_xTimerGetTimerDaemonTaskHandle 43 #define SYSCALL_NUM_xTimerIsTimerActive 44 #define SYSCALL_NUM_xTaskAbortDelay 45 #define SYSCALL_NUM_xTaskGetHandle 46 #define SYSCALL_NUM_xEventGroupCreate 47 #define SYSCALL_NUM_xEventGroupWaitBits 48 #define SYSCALL_NUM_vEventGroupDelete 49 #define SYSCALL_NUM_xStreamBufferGenericCreate 50 #define SYSCALL_NUM_xStreamBufferReceive 51 #define SYSCALL_NUM_vStreamBufferDelete 52 #define SYSCALL_NUM_xQueueGetMutexHolder 53 #define SYSCALL_NUM_xEventGroupSync 54 #define SYSCALL_NUM_xEventGroupSetBits 55 #define SYSCALL_NUM_xEventGroupClearBits 56 #define SYSCALL_NUM_xStreamBufferSend 57 #define SYSCALL_NUM_xStreamBufferIsEmpty 58 #define SYSCALL_NUM_xStreamBufferNextMessageLengthBytes 59 #define SYSCALL_NUM_xStreamBufferIsFull 60 #define SYSCALL_NUM_xStreamBufferSpacesAvailable 61 #define SYSCALL_NUM_xStreamBufferReset 62 #define SYSCALL_NUM_xStreamBufferBytesAvailable 64 static SYSTEMCALL system_calls[MAX_SYSCALLS]; static uint64_t *getpgd() { extern StackType_t *pxCurrentTCB; xMPU_SETTINGS * xMPUSettings = (xMPU_SETTINGS *) (pxCurrentTCB+1); return (uint64_t *) xMPUSettings->pgd; } /* Check that a user space address is mapped */ int check_address_valid(uint64_t target_address) { uint64_t *pml4=getpgd(); uint64_t addr = target_address; if (target_address < USER_VA_START) { return 0; } uint32_t pml4_index=0; uint32_t pml3_index=0; uint32_t pml2_index=0; uint32_t pml1_index=0; uint64_t *pml3, *pml2,*pml1; pml4_index = (addr >> 39) & 0x1ff; pml3=(uint64_t *)(pml4[pml4_index]&0xfffffffff000); if (!pml3){ return 0; } pml3_index = (addr >> 30) & 0x1ff; pml2=(uint64_t *)(pml3[pml3_index]&0xfffffffff000); if (!pml2){ return 0; } pml2_index = (addr >> 21) & 0x1ff; pml1=(uint64_t *)(pml2[pml2_index]&0xfffffffff000); if (!pml1){ return 0; } pml1_index = (addr >> 12) & 0x1ff; uint64_t phyaddr = pml1[pml1_index]&0xfffffffff000; if (!phyaddr){ return 0; } return 1; } #define CHECK_USER_PARAM(x) \ if (!check_address_valid(argptr[x])) \ return -1 uint64_t sys_writec(uint64_t *argptr) { serial_send((char) argptr[0]&0xff); return (uint64_t) 0; } uint64_t sys_xTaskGetTickCount(uint64_t *argptr) { return (uint64_t) (BaseType_t) xTaskGetTickCount(); } uint64_t sys_xTaskDelayUntil(uint64_t *argptr) { CHECK_USER_PARAM(0); return (uint64_t) (BaseType_t) xTaskDelayUntil((TickType_t * const) argptr[0],( TickType_t) argptr[1]); } uint64_t sys_xQueueGenericSend(uint64_t *argptr) { CHECK_USER_PARAM(1); return (uint64_t) (BaseType_t) xQueueGenericSend((QueueHandle_t) argptr[0],( const void * const) argptr[1],(TickType_t) argptr[2],( BaseType_t) argptr[3]); } uint64_t sys_xQueueReceive(uint64_t *argptr) { CHECK_USER_PARAM(1); return (uint64_t) (BaseType_t) xQueueReceive((QueueHandle_t) argptr[0],(void * const) argptr[1],(TickType_t) argptr[2]); } uint64_t sys_xTimerGenericCommandFromTask(uint64_t *argptr) { CHECK_USER_PARAM(3); return (uint64_t) (BaseType_t) xTimerGenericCommandFromTask((TimerHandle_t) argptr[0],(const BaseType_t) argptr[1],( const TickType_t) argptr[2],( BaseType_t * const) argptr[3],( const TickType_t) argptr[4]); } uint64_t sys_vTaskDelay(uint64_t *argptr) { vTaskDelay((TickType_t) argptr[0]); return (uint64_t) 0; } uint64_t sys_uxTaskPriorityGet(uint64_t *argptr) { return (uint64_t) (UBaseType_t) uxTaskPriorityGet((const TaskHandle_t) argptr[0]); } uint64_t sys_vTaskPrioritySet(uint64_t *argptr) { vTaskPrioritySet((TaskHandle_t) argptr[0],( UBaseType_t) argptr[1]); return (uint64_t) 0; } uint64_t sys_eTaskGetState(uint64_t *argptr) { return (uint64_t) (eTaskState) eTaskGetState((TaskHandle_t) argptr[0]); } uint64_t sys_vTaskGetInfo(uint64_t *argptr) { CHECK_USER_PARAM(1); vTaskGetInfo((TaskHandle_t) argptr[0],( TaskStatus_t * ) argptr[1],( BaseType_t) argptr[2],( eTaskState) argptr[3]); return (uint64_t) 0; } uint64_t sys_vTaskSuspend(uint64_t *argptr) { vTaskSuspend((TaskHandle_t) argptr[0]); return (uint64_t) 0; } uint64_t sys_vTaskResume(uint64_t *argptr) { vTaskResume((TaskHandle_t) argptr[0]); return (uint64_t) 0; } uint64_t sys_vTaskSuspendAll(uint64_t *argptr) { vTaskSuspendAll(); return (uint64_t) 0; } uint64_t sys_uxTaskGetNumberOfTasks(uint64_t *argptr) { return (uint64_t) (UBaseType_t) uxTaskGetNumberOfTasks(); } uint64_t sys_uxTaskGetSystemState(uint64_t *argptr) { CHECK_USER_PARAM(0); CHECK_USER_PARAM(2); return (uint64_t) (UBaseType_t) uxTaskGetSystemState((TaskStatus_t *) argptr[0],( UBaseType_t) argptr[1],( configRUN_TIME_COUNTER_TYPE *) argptr[2]); } uint64_t sys_xTaskGetCurrentTaskHandle(uint64_t *argptr) { return (uint64_t) (TaskHandle_t) xTaskGetCurrentTaskHandle(); } uint64_t sys_xTaskGetSchedulerState(uint64_t *argptr) { return (uint64_t) (BaseType_t) xTaskGetSchedulerState(); } uint64_t sys_vTaskSetTimeOutState(uint64_t *argptr) { CHECK_USER_PARAM(0); vTaskSetTimeOutState((TimeOut_t * const) argptr[0]); return (uint64_t) 0; } uint64_t sys_xTaskCheckForTimeOut(uint64_t *argptr) { CHECK_USER_PARAM(0); CHECK_USER_PARAM(1); return (uint64_t) (BaseType_t) xTaskCheckForTimeOut((TimeOut_t * const) argptr[0],( TickType_t * const) argptr[1]); } uint64_t sys_xTaskGenericNotify(uint64_t *argptr) { CHECK_USER_PARAM(4); return (uint64_t) (BaseType_t) xTaskGenericNotify((TaskHandle_t) argptr[0],( UBaseType_t) argptr[1],( uint32_t) argptr[2],( eNotifyAction) argptr[3],( uint32_t *) argptr[4]); } uint64_t sys_xTaskGenericNotifyWait(uint64_t *argptr) { return (uint64_t) (BaseType_t) xTaskGenericNotifyWait((UBaseType_t) argptr[0],( uint32_t) argptr[1],( uint32_t) argptr[2],( uint32_t *) argptr[3],( TickType_t) argptr[4]); } uint64_t sys_ulTaskGenericNotifyTake(uint64_t *argptr) { return (uint64_t) (uint32_t) ulTaskGenericNotifyTake((UBaseType_t) argptr[0],( BaseType_t) argptr[1],( TickType_t) argptr[2]); } uint64_t sys_xTaskGenericNotifyStateClear(uint64_t *argptr) { return (uint64_t) (BaseType_t) xTaskGenericNotifyStateClear((TaskHandle_t) argptr[0],( UBaseType_t) argptr[1]); } uint64_t sys_ulTaskGenericNotifyValueClear(uint64_t *argptr) { return (uint64_t) (uint32_t) ulTaskGenericNotifyValueClear((TaskHandle_t) argptr[0],( UBaseType_t) argptr[1],( uint32_t) argptr[2]); } uint64_t sys_xQueueGenericReset(uint64_t *argptr) { return (uint64_t) (BaseType_t) xQueueGenericReset((QueueHandle_t) argptr[0],( BaseType_t) argptr[1]); } uint64_t sys_uxQueueMessagesWaiting(uint64_t *argptr) { return (uint64_t) (UBaseType_t) uxQueueMessagesWaiting((const QueueHandle_t) argptr[0]); } uint64_t sys_uxQueueSpacesAvailable(uint64_t *argptr) { return (uint64_t) (UBaseType_t) uxQueueSpacesAvailable((const QueueHandle_t) argptr[0]); } uint64_t sys_xQueuePeek(uint64_t *argptr) { CHECK_USER_PARAM(1); return (uint64_t) (BaseType_t) xQueuePeek((QueueHandle_t) argptr[0],( void * const) argptr[1],( TickType_t) argptr[2]); } uint64_t sys_xQueueSemaphoreTake(uint64_t *argptr) { return (uint64_t) (BaseType_t) xQueueSemaphoreTake((QueueHandle_t) argptr[0],( TickType_t) argptr[1]); } uint64_t sys_xQueueCreateMutex(uint64_t *argptr) { return (uint64_t) (QueueHandle_t) xQueueCreateMutex((const uint8_t) argptr[0]); } uint64_t sys_xQueueCreateCountingSemaphore(uint64_t *argptr) { return (uint64_t) (QueueHandle_t) xQueueCreateCountingSemaphore((UBaseType_t) argptr[0],( UBaseType_t) argptr[1]); } uint64_t sys_xQueueTakeMutexRecursive(uint64_t *argptr) { return (uint64_t) (BaseType_t) xQueueTakeMutexRecursive((QueueHandle_t) argptr[0],( TickType_t) argptr[1]); } uint64_t sys_xQueueGiveMutexRecursive(uint64_t *argptr) { return (uint64_t) (BaseType_t) xQueueGiveMutexRecursive((QueueHandle_t) argptr[0]); } uint64_t sys_xQueueCreateSet(uint64_t *argptr) { return (uint64_t) (QueueSetHandle_t) xQueueCreateSet((UBaseType_t) argptr[0]); } uint64_t sys_xQueueSelectFromSet(uint64_t *argptr) { return (uint64_t) (QueueSetMemberHandle_t) xQueueSelectFromSet((QueueSetHandle_t) argptr[0],( TickType_t) argptr[1]); } uint64_t sys_xQueueAddToSet(uint64_t *argptr) { return (uint64_t) (BaseType_t) xQueueAddToSet((QueueSetMemberHandle_t) argptr[0],( QueueSetHandle_t) argptr[1]); } uint64_t sys_xQueueRemoveFromSet(uint64_t *argptr) { return (uint64_t) (BaseType_t) xQueueRemoveFromSet((QueueSetMemberHandle_t) argptr[0],( QueueSetHandle_t) argptr[1]); } uint64_t sys_vQueueAddToRegistry(uint64_t *argptr) { CHECK_USER_PARAM(1); vQueueAddToRegistry((QueueHandle_t) argptr[0],( const char *) argptr[1]); return (uint64_t) 0; } uint64_t sys_vQueueUnregisterQueue(uint64_t *argptr) { vQueueUnregisterQueue((QueueHandle_t) argptr[0]); return (uint64_t) 0; } uint64_t sys_pcQueueGetName(uint64_t *argptr) { return (uint64_t) (const char *) pcQueueGetName((QueueHandle_t) argptr[0]); } uint64_t sys_vQueueDelete(uint64_t *argptr) { vQueueDelete((QueueHandle_t) argptr[0]); return (uint64_t) 0; } uint64_t sys_pvTimerGetTimerID(uint64_t *argptr) { return (uint64_t) (void *) pvTimerGetTimerID((const TimerHandle_t) argptr[0]); } uint64_t sys_vTimerSetTimerID(uint64_t *argptr) { CHECK_USER_PARAM(1); vTimerSetTimerID((TimerHandle_t) argptr[0],( void *) argptr[1]); return (uint64_t) 0; } uint64_t sys_xTimerIsTimerActive(uint64_t *argptr) { return (uint64_t) (BaseType_t) xTimerIsTimerActive((TimerHandle_t) argptr[0]); } uint64_t sys_xTimerGetTimerDaemonTaskHandle(uint64_t *argptr) { return (uint64_t) (TaskHandle_t) xTimerGetTimerDaemonTaskHandle(); } uint64_t sys_vTimerSetReloadMode(uint64_t *argptr) { vTimerSetReloadMode((TimerHandle_t) argptr[0],( const BaseType_t) argptr[1]); return (uint64_t) 0; } uint64_t sys_uxTimerGetReloadMode(uint64_t *argptr) { return (uint64_t) (UBaseType_t) uxTimerGetReloadMode((TimerHandle_t) argptr[0]); } uint64_t sys_pcTimerGetName(uint64_t *argptr) { // Return a pointer. return (uint64_t) (const char *) pcTimerGetName((TimerHandle_t) argptr[0]); } uint64_t sys_xTimerGetPeriod(uint64_t *argptr) { return (uint64_t) (TickType_t) xTimerGetPeriod((TimerHandle_t) argptr[0]); } uint64_t sys_xTimerGetExpiryTime(uint64_t *argptr) { return (uint64_t) (TickType_t) xTimerGetExpiryTime((TimerHandle_t) argptr[0]); } uint64_t sys_xTaskAbortDelay(uint64_t *argptr) { return (uint64_t) (BaseType_t) xTaskAbortDelay((TaskHandle_t) argptr[0]); } uint64_t sys_xTaskGetHandle(uint64_t *argptr) { return (uint64_t) (TaskHandle_t) xTaskGetHandle((const char *) argptr[0]); } uint64_t sys_xEventGroupCreate(uint64_t *argptr) { return (uint64_t) (EventGroupHandle_t) xEventGroupCreate(); } uint64_t sys_xEventGroupWaitBits(uint64_t *argptr) { return (uint64_t) (EventBits_t) xEventGroupWaitBits((EventGroupHandle_t) argptr[0], (const EventBits_t) argptr[1], (const BaseType_t) argptr[2], (const BaseType_t)argptr[3], (TickType_t)argptr[4]); } uint64_t sys_vEventGroupDelete(uint64_t *argptr) { CHECK_USER_PARAM(0); vEventGroupDelete((EventGroupHandle_t) argptr[0]); return (uint64_t) 0; } uint64_t sys_xStreamBufferGenericCreate(uint64_t *argptr) { return (uint64_t) (StreamBufferHandle_t) xStreamBufferGenericCreate((size_t) argptr[0], (size_t) argptr[1], (BaseType_t) argptr[2], (StreamBufferCallbackFunction_t )argptr[3], (StreamBufferCallbackFunction_t)argptr[4]); } uint64_t sys_xStreamBufferReceive(uint64_t *argptr) { return (uint64_t) (size_t) xStreamBufferReceive((StreamBufferHandle_t) argptr[0], (void *) argptr[1], (size_t) argptr[2], (TickType_t)argptr[3]); } uint64_t sys_vStreamBufferDelete(uint64_t *argptr) { CHECK_USER_PARAM(0); vStreamBufferDelete((StreamBufferHandle_t) argptr[0]); return (uint64_t) 0; } uint64_t sys_xQueueGetMutexHolder(uint64_t *argptr) { CHECK_USER_PARAM(1); return (uint64_t) (TaskHandle_t) xQueueGetMutexHolder((QueueHandle_t) argptr[0]); } uint64_t sys_xEventGroupSync(uint64_t *argptr) { return (uint64_t) (EventBits_t) xEventGroupSync((EventGroupHandle_t) argptr[0], (const EventBits_t) argptr[1], (const EventBits_t ) argptr[2], (TickType_t )argptr[3]); } uint64_t sys_xEventGroupSetBits(uint64_t *argptr) { return (uint64_t) ( EventBits_t) xEventGroupSetBits((EventGroupHandle_t) argptr[0], (const EventBits_t) argptr[1]); } uint64_t sys_xEventGroupClearBits(uint64_t *argptr) { return (uint64_t) ( EventBits_t) xEventGroupClearBits((EventGroupHandle_t) argptr[0], (const EventBits_t) argptr[1]); } uint64_t sys_xStreamBufferSend(uint64_t *argptr) { return (uint64_t) (size_t) xStreamBufferSend((StreamBufferHandle_t) argptr[0], (const void *) argptr[1], (size_t) argptr[2], (TickType_t)argptr[3]); } uint64_t sys_xStreamBufferIsEmpty(uint64_t *argptr) { return (uint64_t) ( size_t ) xStreamBufferIsEmpty((StreamBufferHandle_t) argptr[0]); } uint64_t sys_xStreamBufferNextMessageLengthBytes(uint64_t *argptr) { return (uint64_t) ( size_t ) xStreamBufferNextMessageLengthBytes((StreamBufferHandle_t) argptr[0]); } uint64_t sys_xStreamBufferIsFull(uint64_t *argptr) { return (uint64_t) (BaseType_t) xStreamBufferIsFull((StreamBufferHandle_t) argptr[0]); } uint64_t sys_xStreamBufferSpacesAvailable(uint64_t *argptr) { return (uint64_t) (size_t) xStreamBufferSpacesAvailable((StreamBufferHandle_t) argptr[0]); } uint64_t sys_xStreamBufferReset(uint64_t *argptr) { return (uint64_t) (size_t) xStreamBufferReset((StreamBufferHandle_t) argptr[0]); } uint64_t sys_xStreamBufferBytesAvailable(uint64_t *argptr) { return (uint64_t) (size_t) xStreamBufferBytesAvailable((StreamBufferHandle_t) argptr[0]); } extern StackType_t *pxCurrentTCB; void vInitSystemCall(void) { int i=0; for (i=0;irax; int64_t param_count = tf->rdi; int64_t *argptr = (int64_t*)tf->rsi; if (param_count < 0 || i >= MAX_SYSCALLS || i < 0) { tf->rax = -1; return; } if (system_calls[i]){ tf->rax = system_calls[i](argptr); } else{ tf->rax = -1; } }