diff --git a/docs/doc/kernel/int.md b/docs/doc/kernel/int.md index 37624b2..25c09f7 100644 --- a/docs/doc/kernel/int.md +++ b/docs/doc/kernel/int.md @@ -191,8 +191,8 @@ CPU 响应中断并进行处理,通常经历以下过程:保存当前线程 ## 中断函数接口 ```c -typedef void *xs_handler_x(int irq_num, void *arg); -xs_int32 xs_RegisterHwIrq(xs_uint32 irq_num, xs_handler_x handler, void *arg, const char *name); +typedef void (*IsrHandlerType)(int vector, void *param); +int32 RegisterHwIrq(uint32 irq_num, IsrHandlerType handler, void *arg); ``` 该函数用于注册一个中断,当产生中断时,将调用该硬件中断号相应的回调函数进行执行 。 | 参数 | 描述 | @@ -200,9 +200,8 @@ xs_int32 xs_RegisterHwIrq(xs_uint32 irq_num, xs_handler_x handler, void *arg, co | irq_num | 硬件中断号 | | handler | 中断处理回调函数 | | arg | 中断处理回调函数的参数 | -| name | 中断名称 | ```c -xs_int32 xs_FreeHwIrq(xs_uint32 irq_num); +int32 FreeHwIrq(uint32 irq_num); ``` 该函数用于释放一个中断。 | 参数 | 描述 | @@ -210,14 +209,14 @@ xs_int32 xs_FreeHwIrq(xs_uint32 irq_num); | irq_num | 硬件中断号 | ```c -xs_int32 xs_DisableHwIrq(xs_uint32 irq_num); +int32 DisableHwIrq(uint32 irq_num); ``` 该函数用于屏蔽一个中断。 | 参数 | 描述 | | --- | --- | | irq_num | 硬件中断号 | ```c -xs_int32 xs_EnableHwIrq(xs_uint32 irq_num); +int32 EnableHwIrq(uint32 irq_num); ``` 该函数用于注使能一个中断。 | 参数 | 描述 | @@ -259,33 +258,112 @@ xs_int32 xs_EnableHwIrq(xs_uint32 irq_num); #### 编程代码清单 ```c -#include -#include -#include -#include -#include + +static BusType pin; #define GPIO_C2 17 #define GPIO_C13 7 -void pin_irqisr(void *args){ +void PinIrqIsr(void *args){ *(volatile *)0x40020818 = 0x2000; /////< GPIO_C13 set high *(volatile *)0x4002081a = 0x2000; /////< GPIO_C13 set low } -int realtime_irq_test() +int RealtimeIrqTest() { - int val = 0; + int ret = 0; + struct PinParam output_pin; + struct PinStat output_pin_stat; + struct PinParam input_pin; - xs_PinMode(GPIO_C13, PIN_MODE_OUTPUT); - xs_PinMode(GPIO_C2, PIN_MODE_INPUT); + struct BusConfigureInfo configure_info; + struct BusConfigureInfo configure_info_2; + struct BusBlockWriteParam write_param; - xs_PinWrite(GPIO_C13, PIN_LOW); + configure_info.configure_cmd = OPE_CFG; + configure_info.private_data = (void *)&output_pin; + write_param.buffer = (void *)&output_pin_stat; - xs_PinAttachIrq(GPIO_C2, PIN_IRQ_MODE_RISING, pin_irqisr, XS_NULL); - xs_PinIrqEnable(GPIO_C2, PIN_IRQ_ENABLE); + configure_info_2.configure_cmd = OPE_CFG; + configure_info_2.private_data = (void *)&input_pin; - return 0; + KPrintf("%s irq test\n",__func__); + /* config test pin 1 as output*/ + output_pin.cmd = GPIO_CONFIG_MODE; + output_pin.pin = GPIO_C13; + output_pin.mode = GPIO_CFG_OUTPUT; + + ret = BusDrvConfigure(pin->owner_driver, &configure_info); + if (ret != EOK) { + KPrintf("config output_pin %d failed!\n", GPIO_C13); + return -ERROR; + } + + /* set test pin 1 as high*/ + output_pin_stat.pin = GPIO_C13; + output_pin_stat.val = GPIO_LOW; + BusDevWriteData(pin->owner_haldev, &write_param); + + /* config test pin 2 as input*/ + input_pin.cmd = GPIO_CONFIG_MODE; + input_pin.pin = GPIO_C2; + input_pin.mode = GPIO_CFG_INPUT; + + ret = BusDrvConfigure(pin->owner_driver, &configure_info_2); + if (ret != EOK) { + KPrintf("config input_pin %d input failed!\n", input_pin.pin); + return -ERROR; + } + + input_pin.cmd = GPIO_IRQ_REGISTER; + input_pin.pin = GPIO_C2; + input_pin.irq_set.irq_mode = GPIO_IRQ_EDGE_BOTH; + input_pin.irq_set.hdr = PinIrqIsr; + input_pin.irq_set.args = NONE; + + ret = BusDrvConfigure(pin->owner_driver, &configure_info_2); + if (ret != EOK) { + KPrintf("register input_pin %d irq failed!\n", input_pin.pin); + return -ERROR; + } + + input_pin.cmd = GPIO_IRQ_ENABLE; + input_pin.pin = GPIO_C2; + + ret = BusDrvConfigure(pin->owner_driver, &configure_info_2); + if (ret != EOK) { + KPrintf("enable input_pin %d irq failed!\n", input_pin.pin); + return -ERROR; + } + KPrintf("%s irq test\n",__func__); + + return 0; +} + +int TestRealtime(int argc, char * argv[]) +{ + int ret = 0; + struct BusConfigureInfo configure_info; + + pin = BusFind(PIN_BUS_NAME); + if (!pin) { + KPrintf("find %s failed!\n", PIN_BUS_NAME); + return -ERROR; + } + + pin->owner_driver = BusFindDriver(pin, PIN_DRIVER_NAME); + pin->owner_haldev = BusFindDevice(pin, PIN_DEVICE_NAME); + + configure_info.configure_cmd = OPE_INT; + ret = BusDrvConfigure(pin->owner_driver, &configure_info); + if (ret != EOK) { + KPrintf("initialize %s failed!\n", PIN_BUS_NAME); + return -ERROR; + } + + RealtimeIrqTest(); + + return 0; } ``` @@ -347,31 +425,86 @@ int realtime_irq_test() #### 编程代码清单 ```c +static BusType pin; #define GPIO_18 18 #define GPIO_19 19 -void pin_irqisr(void *args){ +void PinIrqIsr(void *args){ *(volatile *)0x3800100c |= 0x5; usleep(100); *(volatile *)0x3800100c &= ~0x5; } int realtime_irq_test() { - xs_PinMode(GPIO_18, PIN_MODE_OUTPUT); - xs_PinMode(GPIO_19, PIN_MODE_INPUT); - xs_PinWrite(GPIO_18, PIN_LOW); - xs_PinAttachIrq(GPIO_19, PIN_MODE_RISING, pin_irqisr, XS_NULL); - xs_PinIrqEnable(GPIO_19, PIN_IRQ_ENABLE); + struct PinParam output_pin; + struct PinStat output_pin_stat; + struct PinParam input_pin; + + struct BusConfigureInfo configure_info; + struct BusConfigureInfo configure_info_2; + struct BusBlockWriteParam write_param; + + configure_info.configure_cmd = OPE_CFG; + configure_info.private_data = (void *)&output_pin; + write_param.buffer = (void *)&output_pin_stat; + + configure_info_2.configure_cmd = OPE_CFG; + configure_info_2.private_data = (void *)&input_pin; + + /* config GPIO18 as output and set as low */ + output_pin.cmd = GPIO_CONFIG_MODE; + output_pin.pin = GPIO_18; + output_pin.mode = GPIO_CFG_OUTPUT; + BusDrvConfigure(pin->owner_driver, &configure_info); + + output_pin_stat.pin = GPIO_18; + output_pin_stat.val = GPIO_LOW; + BusDevWriteData(pin->owner_haldev, &write_param); + + /* config GPIO18 as input */ + input_pin.cmd = GPIO_CONFIG_MODE; + input_pin.pin = GPIO_19; + input_pin.mode = GPIO_CFG_INPUT; + BusDrvConfigure(pin->owner_driver, &configure_info_2); + + input_pin.cmd = GPIO_IRQ_REGISTER; + input_pin.pin = GPIO_19; + input_pin.irq_set.irq_mode = GPIO_IRQ_EDGE_RISING; + input_pin.irq_set.hdr = PinIrqIsr; + input_pin.irq_set.args = NONE; + BusDrvConfigure(pin->owner_driver, &configure_info_2); + + input_pin.cmd = GPIO_IRQ_ENABLE; + input_pin.pin = GPIO_19; + BusDrvConfigure(pin->owner_driver, &configure_info_2); + return 0; } -void realtime_taskswitch_test() +int TestRealtime(int argc, char * argv[]) { - xs_PinMode(GPIO_18, PIN_MODE_OUTPUT); - xs_PinWrite(GPIO_18, PIN_LOW); - while(1){ - xs_DelayKThread(1); + int ret = 0; + struct BusConfigureInfo configure_info; + + pin = BusFind(PIN_BUS_NAME); + if (!pin) { + KPrintf("find %s failed!\n", PIN_BUS_NAME); + return -ERROR; } + + pin->owner_driver = BusFindDriver(pin, PIN_DRIVER_NAME); + pin->owner_haldev = BusFindDevice(pin, PIN_DEVICE_NAME); + + configure_info.configure_cmd = OPE_INT; + ret = BusDrvConfigure(pin->owner_driver, &configure_info); + if (ret != EOK) { + KPrintf("initialize %s failed!\n", PIN_BUS_NAME); + return -ERROR; + } + + RealtimeIrqTest(); + + return 0; } ``` diff --git a/docs/doc/kernel/mm.md b/docs/doc/kernel/mm.md index 77fce58..0b951fc 100644 --- a/docs/doc/kernel/mm.md +++ b/docs/doc/kernel/mm.md @@ -174,7 +174,7 @@ XiUOS 操作系统提供了独特的内存管理分配算法进行内存管理 #### 内存初始化 ```C -void xs_SystemHeapInit(void *start_phy_address, void *end_phy_address); +void InitBoardMemory(void *start_phy_address, void *end_phy_address); ``` 这个函数用来初始化静态和动态内存。 @@ -188,7 +188,7 @@ void xs_SystemHeapInit(void *start_phy_address, void *end_phy_address); #### 分配和释放内存 ```C -void *xs_malloc(xs_size_t size); +void *x_malloc(xs_size_t size); ``` 这个函数用来分配一块合适大小的内存,如果分配成功,则返回分配内存的首地址;否则返回NULL。 @@ -199,7 +199,7 @@ void *xs_malloc(xs_size_t size);
```C -void *xs_realloc(void *pointer, xs_size_t size); +void *x_realloc(void *pointer, xs_size_t size); ``` 这个函数用来重新分配一块内存,将原内存块中的数据保存到新的内存中去,并将原内存块释放。如果分配成功,则返回分配内存的首地址;否则返回NULL。 @@ -211,7 +211,7 @@ void *xs_realloc(void *pointer, xs_size_t size);
```C -void *xs_calloc(xs_size_t count, xs_size_t size); +void *x_calloc(xs_size_t count, xs_size_t size); ``` 这个函数会分配多个内存块并将内存块中的数据初始化为0。 @@ -224,7 +224,7 @@ void *xs_calloc(xs_size_t count, xs_size_t size); ```C -void xs_free(void *pointer); +void x_free(void *pointer); ``` 这个函数用来释放内存。 @@ -234,32 +234,10 @@ void xs_free(void *pointer); | pointer | 指向需要被释放的内存 |
-#### 内存钩子函数 -```C -void xs_MallocSetHook(void (*MallocHook)(void *pointer, xs_size_t size)); -``` -这个函数设置了一个 MallocHook 函数,MallocHook 函数会在动态内存分配之前调用。 - - -| 参数 | 描述 | -| :------ | :------ | -| MallocHook | MallocHook 函数指针 | -
- -```C -void xs_FreeSetHook(void (*FreeHook)(void *pointer)); -``` -这个函数设置了一个FreeHook 函数, FreeHook 函数会在内存块被释放回动态内存区时调用。 - - -| 参数 | 描述 | -| :------ | :------ | -| FreeHook | FreeHook 函数指针 | -
#### 其他函数 ```C -void xs_MemoryInfo(xs_uint32 *total_memory, xs_uint32 *used_memory, xs_uint32 *max_used_memory) +void MemoryInfo(uint32 *total_memory, uint32 *used_memory, uint32 *max_used_memory); ``` 这个函数用于获取内存的统计信息。 @@ -272,14 +250,14 @@ void xs_MemoryInfo(xs_uint32 *total_memory, xs_uint32 *used_memory, xs_uint32 *m
```C -void list_mem(void) +void ShowMemory(void); ``` 打印内存信息。
```C -void list_buddy(void) +void ListBuddy(void); ``` 打印动态内存中的空闲节点信息。 @@ -289,7 +267,7 @@ void list_buddy(void) #### 创建内存池 ```C -xs_gm_t xs_CreateMemGather(const char *gm_name, xs_size_t block_number, xs_size_t one_block_size); +GatherMemType CreateMemGather(const char *gm_name, x_size_t block_number, x_size_t one_block_size); ``` 创建一个内存池。如果创建成功,返回第一个内存块的地址,否则返回XS_NULL。 @@ -301,7 +279,7 @@ xs_gm_t xs_CreateMemGather(const char *gm_name, xs_size_t block_number, xs_size
```C -xs_err_t xs_InitMemGather(struct xs_MemGather *gm_handler, const char *gm_name, void *begin_address, xs_size_t gm_size, xs_size_t one_block_size); +x_err_t InitMemGather(struct MemGather *gm_handler, const char *gm_name, void *begin_address, x_size_t gm_size, x_size_t one_block_size); ``` 初始化内存池,用于静态内存管理模式。 @@ -316,7 +294,7 @@ xs_err_t xs_InitMemGather(struct xs_MemGather *gm_handler, const char *gm_name, #### 删除内存池 ```C -xs_err_t xs_DeleteMemGather(xs_gm_t gm_handler); +x_err_t DeleteMemGather(GatherMemType gm_handler); ``` 删除由xs_CreateMemGather创建的内存池。 @@ -327,7 +305,7 @@ xs_err_t xs_DeleteMemGather(xs_gm_t gm_handler);
```C -xs_err_t xs_RemoveMemGather(struct xs_MemGather *gm_handler); +x_err_t RemoveMemGather(struct MemGather *gm_handler); ``` 删除由xs_MemGatherInit创建的内存池。 @@ -339,7 +317,7 @@ xs_err_t xs_RemoveMemGather(struct xs_MemGather *gm_handler); #### 分配内存块 ```C -void *xs_AllocBlockMemGather(xs_gm_t gm_handler, xs_int32 wait_time); +void *AllocBlockMemGather(GatherMemType gm_handler, int32 msec); ``` 该函数将从指定的内存池中分配一个内存块。如果内存池中有可用的内存块,则从内存池的空闲块链表上取下一个内存块,将空闲内存块数目减1并返回这个内存块;如果内存池中已经没有空闲内存块,则判断超时时间设置:若超时时间设置为零,则立刻返回空内存块;如果等待时间大于零,则把当前线程挂起在该内存池对象上,直到内存池中有可用的自由内存块,或等待时间到达。 @@ -353,7 +331,7 @@ void *xs_AllocBlockMemGather(xs_gm_t gm_handler, xs_int32 wait_time); #### 释放内存块 ```C -void xs_FreeBlockMemGather(void *data_block); +void FreeBlockMemGather(void *data_block); ``` 这个函数用于释放指定的内存块,然后增加内存池对象的可用内存块数目,并把该被释放的内存块加入空闲内存块链表上。接着判断该内存池对象上是否有挂起的线程,如果有则唤醒挂起线程链表上的首线程。 @@ -363,29 +341,8 @@ void xs_FreeBlockMemGather(void *data_block);
-#### 内存池钩子函数 -```C -void xs_GmSetAllocHook(void (*gm_allocation_hook)(struct xs_MemGather *gm, void *date_ptr)); -``` -该钩子函数会在内存池分配之前调用。 -| 参数 | 描述 | -| :------ | :------ | -| MallocHook | 钩子函数指针 | -
- -```C -void xs_GmSetFreeHook(void (*gm_release_hook)(struct xs_MemGather *gm, void *date_ptr)); -``` -该钩子函数会在内存池被删除后调用。 - - -| 参数 | 描述 | -| :------ | :------ | -| gm_release_hook | 钩子函数指针 | -
- ## 应用场景 diff --git a/docs/doc/kernel/task.md b/docs/doc/kernel/task.md index b1a8c27..41e73bd 100644 --- a/docs/doc/kernel/task.md +++ b/docs/doc/kernel/task.md @@ -54,92 +54,85 @@ XiUOS 中的任务在任意时刻都处于就绪(ready)、运行(running ### 任务结构定义 -每一个任务在内核中都有一个task_descriptor描述符,其结构体定义如下: +每一个任务在内核中都有一个TaskDescriptor描述符,其结构体定义如下: ```c -struct task_descriptor +struct TaskDescriptor { void *stack_point; - TaskDyncSchedMember_x Task_DyncSchedMember; - TaskBaseInfo_x Task_BaseInfo; + TaskDyncSchedMembeType task_dync_sched_member; + TaskBaseInfoType task_base_info; -#ifdef XS_CONFIG_SMP - TaskSmpInfo_t Task_SmpInfo; +#ifdef ARCH_SMP + TaskSmpInfoType task_smp_info; #endif -#if defined(XS_USING_EVENT) - xs_uint32 event_trigger:29; - xs_uint32 event_mode:3; -#if defined(XS_CONFIG_TASK_ISOLATION) - xs_uint32 *Recved_event; -#endif -#endif - -#if defined(XS_CONFIG_MESSAGEQUEUE) && defined(XS_CONFIG_TASK_ISOLATION) - void *mq_buf; +#if defined(KERNEL_EVENT) + uint32 event_id_trigger:29; + uint32 event_mode:3; #endif - xs_err_t exstatus; - XS_DOUBLE_LINKLIST link; - struct xs_IdNode id; + x_err_t exstatus; + DoubleLinklistType link; + struct IdNode id; + struct KTaskDone *Done; }; ``` -其中,stack_point 指向任务堆栈的起始地址,Task_DyncSchedMember 包含与任务调度相关的信息,Task_BaseInfo 记录任务的基本信息,Task_SmpInfo 统计与多处理器相关的信息,event_trigger / event_mode 用于实现事件集机制(详见[任务通信](#communication)),exstatus为任务调用内核接口时最近的错误码,即用户线程在使用内核接口时可能会执行失败,此时内核接口返回-1,具体的错误码被保存在exstatus成员中,且在下一次调用内核接口失败时被覆盖,link 用于组织内核中所有的任务。各复合成员的详细定义如下。 +其中,stack_point 指向任务堆栈的起始地址,task_dync_sched_member 包含与任务调度相关的信息,task_base_info 记录任务的基本信息,task_smp_info 统计与多处理器相关的信息,event_id_trigger / event_mode 用于实现事件集机制(详见[任务通信](#communication)),exstatus为任务调用内核接口时最近的错误码,即用户线程在使用内核接口时可能会执行失败,此时内核接口返回-1,具体的错误码被保存在exstatus成员中,且在下一次调用内核接口失败时被覆盖,link 用于组织内核中所有的任务。id 用于表示一个线程,Done提供所有的线程的操作函数,各复合成员的详细定义如下。 * struct TaskDyncSchedMember ```c struct TaskDyncSchedMember { - xs_uint8 stat; - xs_uint8 advance_cnt; - xs_uint8 cur_prio; - xs_ubase origin_timeslice; - xs_ubase rest_timeslice; + uint8 stat; + uint8 advance_cnt; + uint8 cur_prio; + ubase origin_timeslice; + ubase rest_timeslice; -#ifdef XS_USING_TASK_ISOLATION - xs_uint8 isolation_flag; - void *isolation; - xs_uint8 isolation_status; +#ifdef SEPARATE_COMPILE + uint8 isolation_flag; + void *isolation; + uint8 isolation_status; #endif union { - XS_DOUBLE_LINKLIST sched_link; - XS_AVL sched_avl; + DoubleLinklistType sched_link; + AvlNodeType sched_avl; }; -#if XS_KTASK_PRIORITY_MAX > 32 - xs_uint8 bitmap_offset; - xs_uint8 bitmap_row; +#if KTASK_PRIORITY_MAX > 32 + uint8 bitmap_offset; + uint8 bitmap_row; #endif - xs_uint32 bitmap_column; - struct xs_Timer task_timer; + uint32 bitmap_column; + delay_t delay; }; -#define XS_SUSPEND ((1) << (0)) -#define XS_READY ((1) << (1)) -#define XS_RUNNING ((1) << (2)) -#define XS_QUIT ((1) << (3)) +#define KTASK_INIT 0x00 +#define KTASK_READY 0x01 +#define KTASK_SUSPEND 0x02 +#define KTASK_RUNNING 0x03 +#define KTASK_CLOSE 0x04 ``` -struct TaskDyncSchedMember结构用于记录与调度相关的信息。stat记录任务的当前状态,可以为挂起(XS_SUSPEND)、就绪(XS_READY)、运行(XS_RUNNING)或退出(XS_QUIT)。advance_cnt表示在配置成短作业预先调度时优先处理的时间片周期个数。cur_prio表示任务当前的优先级,用于优先级反转,该优先级可以高于任务创建时配置的优先级。origin_timeslice表示在时间片轮转调度时,任务每次运行的时间片。isolation_flag变量和指针isolation支持地址空间隔离。sched_link和sched_avl构成的联合体为就绪队列节点,XiUOS中就绪队列可以组织为双链表(sched_link)或平衡二叉树(sched_avl)。task_timer为任务睡眠的计数器。 +struct TaskDyncSchedMember结构用于记录与调度相关的信息。stat记录任务的当前状态,可以为初始化(KTASK_INIT)挂起(KTASK_SUSPEND)、就绪(KTASK_READY)、运行(KTASK_RUNNING)或退出(KTASK_CLOSE)。advance_cnt表示在配置成短作业预先调度时优先处理的时间片周期个数。cur_prio表示任务当前的优先级,用于优先级反转,该优先级可以高于任务创建时配置的优先级。origin_timeslice表示在时间片轮转调度时,任务每次运行的时间片。isolation_flag变量和指针isolation支持地址空间隔离,isolation_status用于标志内核服务的过程(1表示进入内核服务上下文)。sched_link和sched_avl构成的联合体为就绪队列节点,XiUOS中就绪队列可以组织为双链表(sched_link)或平衡二叉树(sched_avl)。task_timer为任务睡眠的计数器。 * struct TaskBaseInfo ```c struct TaskBaseInfo { - char name[XS_NAME_MAX]; + char name[NAME_NUM_MAX]; void *func_entry; void *func_param; - xs_uint8 origin_prio; - xs_uint32 stack_size; - void *stack_addr; + uint8 origin_prio; + uint32 stack_depth; + void *stack_start; }; ``` -struct TaskBaseInfo结构记录了任务的基本属性,包括任务的名称(name)、入口函数(func_entry)和参数(func_param)、栈大小(stack_size)、初始优先级(origin_prio)。 +struct TaskBaseInfo结构记录了任务的基本属性,包括任务的名称(name)、入口函数(func_entry)和参数(func_param)、栈大小(stack_depth)、初始优先级(origin_prio)。 * struct TaskSmpInfo ```c struct TaskSmpInfo { - xs_uint8 combined_coreid; - xs_uint8 running_coreid; - xs_uint16 sched_lock_cnt; - xs_uint16 cpus_lock_cnt; - xs_uint16 critical_lock_cnt; + uint8 combined_coreid; + uint8 running_coreid; + uint16 critical_lock_cnt; }; ``` struct TaskSmpInfo结构包含多处理器相关的信息,其成员分别表示该任务绑定的CPU ID与正在运行的CPU ID。 @@ -148,40 +141,50 @@ struct TaskSmpInfo结构包含多处理器相关的信息,其成员分别表 ### 任务函数接口 ```c -struct xs_utask +struct utask { - char name[XS_NAME_MAX]; + char name[NAME_NUM_MAX]; void *func_entry; void *func_param; - xs_uint32 stack_size; - xs_uint8 prio; + uint32 stack_size; + uint8 prio; }; -typedef struct xs_utask xs_utask_x; +typedef struct utask UtaskType; -struct task_descriptor* xs_UserTaskCreate(xs_utask_x task); +int32_t UserTaskCreate(UtaskType task); ``` -该函数用于用户态的任务创建。任务的各个属性由struct xs_utask结构表示,包括任务的名称、入口函数及参数、栈大小和优先级,在调用该函数时需要传入该结构的实例用于配置任务属性。任务创建成功后,内核会为其分配指定大小的栈及其他结构(如struct task_descriptor),并返回任务描述符指针。 +该函数用于用户态的任务创建。任务的各个属性由struct utask结构表示,包括任务的名称、入口函数及参数、栈大小和优先级,在调用该函数时需要传入该结构的实例用于配置任务属性。任务创建成功后,内核会为其分配指定大小的栈及其他结构(如struct TaskDescriptor),并返回任务id。 | 参数 | 描述 | | --- | --- | | task | 任务配置属性 | ```c -xs_err_t xs_UserTaskDelete(xs_int32 id); +x_err_t UserTaskStartup(int32_t id); ``` -该函数用于删除一个任务,强制其进入退出状态。若删除成功则返回XS_EOK,否则返回-XS_ERROR。 +该函数用于就绪一个任务,交由调度器开始调度执行。 + +| 参数 | 描述 | +| --- | --- | +| id | 待就绪的任务ID | + +```c +x_err_t UserTaskDelete(int32_t id); +``` + +该函数用于删除一个任务,强制其进入退出状态。若删除成功则返回EOK,否则返回-ERROR。 | 参数 | 描述 | | --- | --- | | id | 待删除的任务ID | ```c -xs_err_t xs_UserTaskCoreCombine(xs_int32 id,xs_uint8 core_id); +x_err_t UserTaskCoreCombine(int32_t id,uint8_t core_id); ``` -该函数用于将任务绑定至指定的处理器上。若绑定成功则返回XS_EOK,否则返回-XS_ERROR。 +该函数用于将任务绑定至指定的处理器上。若绑定成功则返回EOK,否则返回-ERROR。 | 参数 | 描述 | | --- | --- | @@ -189,17 +192,17 @@ xs_err_t xs_UserTaskCoreCombine(xs_int32 id,xs_uint8 core_id); | core_id | 待绑定的处理器ID | ```c -xs_err_t xs_UserTaskCoreUncombine(xs_int32 id); +x_err_t UserTaskCoreUnCombine(int32_t id); ``` -该函数用于解除任务与处理器的绑定。若解除成功则返回XS_EOK,否则返回-XS_ERROR。 +该函数用于解除任务与处理器的绑定。若解除成功则返回EOK,否则返回-ERROR。 | 参数 | 描述 | | --- | --- | | id | 待解除绑定的任务ID | ```c -xs_err_t xs_UserTaskDelay(xs_int32 ms); +x_err_t UserTaskDelay(int32_t ms); ``` 该函数用于将当前任务挂起一定时间,单位为tick。挂起时间结束后,任务会进入就绪状态,等待系统调用。 @@ -222,20 +225,19 @@ XiUOS 提供多种任务间通信机制,包括消息队列、信号量、互 #### 消息队列结构定义 ```c -struct xs_MsgQueue +struct MsgQueue { - xs_uint16 id; - + struct IdNode id; void *msg_buf; - xs_uint16 index; - xs_uint16 num_msgs; - xs_uint16 each_len; - xs_uint16 max_msgs; + uint16 index; + uint16 num_msgs; + uint16 each_len; + uint16 max_msgs; - XS_DOUBLE_LINKLIST send_pend_list; - XS_DOUBLE_LINKLIST recv_pend_list; - XS_DOUBLE_LINKLIST link; - struct xs_MsgQueue_Ops *ops; + DoubleLinklistType send_pend_list; + DoubleLinklistType recv_pend_list; + DoubleLinklistType link; + struct MsgQueueDone *Done; }; ``` @@ -255,7 +257,7 @@ struct xs_MsgQueue #### 消息队列函数接口 ```c -xs_int32 xs_UserMsgQueueCreate(xs_uint16 msg_size, xs_uint16 max_msgs); +int32_t UserMsgQueueCreate(size_t msg_size, size_t max_msgs); ``` 该函数用于创建一个消息队列。创建成功后,新的消息队列会被加入内核的消息队列管理链表,并返回该消息队列的ID,ID默认范围0-255,可配置。 @@ -266,50 +268,74 @@ xs_int32 xs_UserMsgQueueCreate(xs_uint16 msg_size, xs_uint16 max_msgs); | max_msgs | 缓冲区中最多存放的消息数量 | ```c -void xs_UserMsgQueueDelete(xs_uint16 id); +x_err_t UserMsgQueueDelete(int32_t mq); ``` 该函数用于删除一个已创建的消息队列。 | 参数 | 描述 | | --- | --- | -| id | 待删除的消息队列ID | +| mq | 待删除的消息队列ID | ```c -xs_int32 xs_UserMsgQueueSend(xs_uint16 id, const void *msg, xs_uint16 size, xs_ticks_x wait_time); +x_err_t UserMsgQueueSendwait(int32_t mq, const void *buffer, size_t size, int32_t wait_time); ``` -该函数用于向消息队列发送一个消息。若消息发送成功则返回XS_EOK,若不成功(等待超时)则返回-XS_ETIMEOUT。 +该函数用于向消息队列发送一个消息。若消息发送成功则返回EOK,若不成功(等待超时)则返回-ETIMEOUT。 | 参数 | 描述 | | --- | --- | -| id | 目标消息队列ID | -| msg | 消息数据首地址 | +| mq | 目标消息队列ID | +| buffer | 消息数据首地址 | | size | 消息长度 | -| wait_time | 等待时间上限,单位ticks;若为0,则不等待 | +| wait_time | 等待时间上限,单位ms;若为0,则不等待 | ```c -xs_int32 xs_UserMsgQueueRecv(xs_uint16 id, void *buf, xs_uint16 size, xs_ticks_x wait_time); +x_err_t UserMsgQueueSend(int32_t mq, const void *buffer, size_t size); ``` -该函数用于从消息队列接收一个消息。若消息接收成功则返回XS_EOK,若不成功(等待超时)则返回-XS_ETIMEOUT。 +该函数用于向消息队列发送一个消息。若消息发送成功则返回EOK,若不成功(等待超时)则返回-ETIMEOUT。 | 参数 | 描述 | | --- | --- | -| id | 来源消息队列ID | -| buf | 用于接收消息数据的缓冲区 | -| size | 缓冲区大小 | -| wait_time | 等待时间上限,单位ticks;若为0,则不等待 | +| mq | 目标消息队列ID | +| buffer | 消息数据首地址 | +| size | 消息长度 | ```c -xs_int32 xs_UserMsgQueueReinit(xs_uint16 id); +x_err_t UserMsgQueueUrgentSend(int32_t mq, const void *buffer, size_t size); +``` + +该函数用于向消息队列y优先发送一个消息。若消息发送成功则返回EOK,若不成功(等待超时)则返回-ETIMEOUT。 + +| 参数 | 描述 | +| --- | --- | +| mq | 目标消息队列ID | +| buffer | 消息数据首地址 | +| size | 消息长度 | + +```c +x_err_t UserMsgQueueRecv(int32_t mq, void *buffer, size_t size,int32_t wait_time); +``` + +该函数用于从消息队列接收一个消息。若消息接收成功则返回EOK,若不成功(等待超时)则返回-ETIMEOUT。 + +| 参数 | 描述 | +| --- | --- | +| mq | 来源消息队列ID | +| buffer | 用于接收消息数据的缓冲区 | +| size | 缓冲区大小 | +| wait_time | 等待时间上限,单位ms;若为0,则不等待 | + +```c +x_err_t UserMsgQueueReinit(int32_t mq); ``` 该函数用于将一个消息队列复位。 | 参数 | 描述 | | --- | --- | -| id | 消息队列ID | +| mq | 消息队列ID | ### 信号量 @@ -319,13 +345,13 @@ xs_int32 xs_UserMsgQueueReinit(xs_uint16 id); #### 信号量结构定义 ```c -struct xs_Semaphore +struct Semaphore { - struct xs_IdNode id; - xs_uint16 value; + struct IdNode id; + uint16 value; - XS_DOUBLE_LINKLIST pend_list; - XS_DOUBLE_LINKLIST link; + DoubleLinklistType pend_list; + DoubleLinklistType link; }; ``` @@ -339,7 +365,7 @@ struct xs_Semaphore #### 信号量函数接口 ```c -xs_int32 xs_UserSemaphoreCreate(xs_uint16 val); +sem_t UserSemaphoreCreate(uint16_t val); ``` 该函数用于创建一个信号量。创建成功后,新的信号量会被加入内核的信号量管理链表,并返回该信号量的ID,ID默认范围0-255,可配置。 @@ -349,45 +375,45 @@ xs_int32 xs_UserSemaphoreCreate(xs_uint16 val); | val | 信号量的初值| ```c -void xs_UserSemaphoreDelete(xs_uint16 id); +x_err_t UserSemaphoreDelete(sem_t sem); ``` 该函数用于删除一个已创建的信号量。 | 参数 | 描述 | | --- | --- | -| id | 待删除的信号量ID | +| sem | 待删除的信号量ID | ```c -xs_int32 xs_UserSemaphoreObtain(xs_uint16 id, xs_ticks_x wait_time); +x_err_t UserSemaphoreObtain(sem_t sem, int32_t wait_time); ``` -该函数用于获取一个信号量。若获取成功则返回XS_EOK,若不成功(等待超时)则返回-XS_ETIMEOUT。 +该函数用于获取一个信号量。若获取成功则返回EOK,若不成功(等待超时)则返回-ETIMEOUT。 | 参数 | 描述 | | --- | --- | -| id | 欲获取的信号量ID | -| wait_time | 等待时间上限,单位ticks;若为0,则不等待 | +| sem | 欲获取的信号量ID | +| wait_time | 等待时间上限,单位ms;若为0,则不等待 | ```c -xs_int32 xs_UserSemaphoreAbandon(xs_uint16 id); +x_err_t UserSemaphoreAbandon(sem_t sem); ``` 该函数用于释放一个信号量。 | 参数 | 描述 | | --- | --- | -| id | 待释放的信号量ID | +| sem | 待释放的信号量ID | ```c -xs_int32 xs_UserSemaphoreSetValue(xs_uint16 id, xs_uint16 val); +x_err_t UserSemaphoreSetValue(sem_t sem, uint16_t val); ``` 该函数用于将一个信号量的值进行重置。 | 参数 | 描述 | | --- | --- | -| id | 来源消息队列ID | +| sem | 来源消息队列ID | | val | 重置的信号量的值 | @@ -398,18 +424,15 @@ xs_int32 xs_UserSemaphoreSetValue(xs_uint16 id, xs_uint16 val); #### 互斥量结构定义 ```c -struct xs_Mutex +struct Mutex { - struct xs_IdNode id; - - xs_uint16 val; - xs_uint8 origin_prio; - xs_uint8 recursive_cnt; - - struct task_descriptor *holder; - - XS_DOUBLE_LINKLIST pend_list; - XS_DOUBLE_LINKLIST link; + struct IdNode id; + uint16 val; + uint8 recursive_cnt; + uint8 origin_prio; + struct TaskDescriptor *holder; + DoubleLinklistType pend_list; + DoubleLinklistType link; }; ``` | 成员 | 描述 | @@ -425,41 +448,41 @@ struct xs_Mutex #### 互斥量函数接口 ```c -xs_int32 xs_UserMutexCreate(void); +int32_t UserMutexCreate(); ``` 该函数用于创建一个互斥量。创建成功后,新的互斥量会被加入内核的互斥量管理链表,并返回该互斥量的ID,ID默认范围0-255,可配置。 ```c -void xs_UserMutexDelete(xs_uint16 id); +void UserMutexDelete(int32_t mutex); ``` 该函数用于删除一个已创建的互斥量。 | 参数 | 描述 | | --- | --- | -| id | 待删除的互斥量的ID | +| mutex | 待删除的互斥量的ID | ```c -xs_int32 xs_UserMutexObtain(xs_uint16 id, xs_ticks_x wait_time); +int32_t UserMutexObtain(int32_t mutex, int32_t wait_time); ``` -该函数用于获取一个互斥量。若获取成功则返回XS_EOK,若不成功(等待超时)则返回-XS_ETIMEOUT。 +该函数用于获取一个互斥量。若获取成功则返回EOK,若不成功(等待超时)则返回-ETIMEOUT。 | 参数 | 描述 | | --- | --- | -| id | 欲获取的互斥量的ID | -| wait_time | 等待时间上限,单位ticks;若为0,则不等待 | +| mutex | 欲获取的互斥量的ID | +| wait_time | 等待时间上限,单位ms;若为0,则不等待 | ```c -xs_int32 xs_UserMutexAbandon(xs_uint16 id); +int32_t UserMutexAbandon(int32_t mutex); ``` 该函数用于释放一个互斥量。 | 参数 | 描述 | | --- | --- | -| id | 待释放的互斥量的ID | +| mutex | 待释放的互斥量的ID | ### 事件集 @@ -469,92 +492,85 @@ xs_int32 xs_UserMutexAbandon(xs_uint16 id); #### 事件集结构定义 ```c -#define XS_EVENT_AND (1 << 29) -#define XS_EVENT_OR (1 << 30) -#define XS_EVENT_AUTOCLEAN (1 << 31) -#define XS_EVENTS(x) (1 << x) +#define EVENT_AND (1 << 0) +#define EVENT_OR (1 << 1) +#define EVENT_AUTOCLEAN (1 << 2) +#define EVENTS(x) (1 << x) -struct xs_event +struct Event { - xs_uint16 id; - xs_uint32 trigger_way; - - XS_DOUBLE_LINKLIST pend_list; - XS_DOUBLE_LINKLIST link; + struct IdNode id; + uint32 options : 3; + uint32 events : 29; + + DoubleLinklistType pend_list; + DoubleLinklistType link; }; ``` | 成员 | 描述 | | --- | --- | | id | 事件集ID,用于唯一标识一个事件集 | -| trigger_way | 高3位用于记录事件集属性(等待触发条件、是否自动清空),低29位用于表示至多29个事件 | +| options | 高3位用于记录事件集属性(等待触发条件、是否自动清空) | +| events | 低29位用于表示至多29个事件 | | pend_list | 等待任务链表 | | link | 系统中所有事件集构成的链表 | #### 事件集函数接口 ```c -xs_int32 xs_UserEventCreate(xs_uint32 options); +EventIdType UserEventCreate(uint8_t flag); ``` -该函数用于创建一个事件集。options参数用于配置事件集的属性。可配置的属性有等待触发方式(XS_EVENT_AND 或 XS_EVENT_OR)及等待触发后是否自动清空其他已触发的事件(XS_EVENT_AUTOCLEAN)。创建成功后,新的事件集会被加入内核的事件集管理链表,并返回该事件集的ID,ID默认范围0-255,可配置。 +该函数用于创建一个事件集。flag参数用于配置事件集的属性。可配置的属性有等待触发方式(EVENT_AND 或 EVENT_OR)及等待触发后是否自动清空其他已触发的事件(EVENT_AUTOCLEAN)。创建成功后,新的事件集会被加入内核的事件集管理链表,并返回该事件集的ID,ID默认范围0-255,可配置。 | 参数 | 描述 | | --- | --- | -| options | 事件集配置选项,须在 XS_EVENT_AND 及 XS_EVENT_OR 中指定其一,并可以按位或上 XS_EVENT_AUTOCLEAN | +| flag | 事件集配置选项,须在 EVENT_AND 及 EVENT_OR 中指定其一,并可以按位或上 EVENT_AUTOCLEAN | ```c -void xs_UserEventDelete(xs_uint16 id); +void UserEventDelete(EventIdType event); ``` 该函数用于删除一个已创建的事件集。 | 参数 | 描述 | | --- | --- | -| id | 待删除的事件集的ID | +| event | 待删除的事件集的ID | ```c -xs_int32 xs_UserEventTrigger(xs_uint16 id, xs_uint32 events); +x_err_t UserEventTrigger(EventIdType event, uint32_t set); ``` 该函数用于触发事件集中的一组事件。 | 参数 | 描述 | | --- | --- | -| id | 事件集ID | -| events | 欲触发的事件,其中被置1的位标识被触发的事件 ,可以使用 XS_EVENTS 宏按位或发送事件类型| +| event | 事件集ID | +| set | 欲触发的事件,其中被置1的位标识被触发的事件 ,可以使用 EVENTS 宏按位或发送事件类型| ```c -xs_int32 xs_UserEventProcess(xs_uint16 id, xs_uint32 events, xs_ticks_x wait_time); +x_err_t UserEventProcess(EventIdType event, uint32_t set, uint8_t option, int32_t wait_time, uint32_t *Recved); ``` -该函数用于等待事件集中的一组事件。若等待成功则返回 XS_EOK,此时若 XS_EVENT_AUTOCLEAN 被打开则事件集中所有已触发事件会被清空;若等待失败(超时)则返回 -XS_ETIMEOUT。 +该函数用于等待事件集中的一组事件。若等待成功则返回 EOK,此时若 EVENT_AUTOCLEAN 被打开则事件集中所有已触发事件会被清空;若等待失败(超时)则返回 -ETIMEOUT。 | 参数 | 描述 | | --- | --- | -| id | 事件集ID | -| events | 欲等待的事件,其中被置1的位标识被等待的事件,可以使用XS_EVENTS宏按位或接收事件类型| -| wait_time | 等待时间上限,单位ticks;若为0,则不等待 | +| event | 事件集ID | +| set | 欲等待的事件,其中被置1的位标识被等待的事件,可以使用EVENTS宏按位或接收事件类型| +| options | 用于记录事件集属性(等待触发条件、是否自动清空) | +| wait_time | 等待时间上限,单位 ms;若为0,则不等待 | +| Recved | 用于记录已经被处理完成的事件 | ```c -xs_int32 xs_UserEventConfig(xs_uint16 id, xs_uint32 options); -``` - -该函数用于配置事件集中的一种事件类型。若配置成功则返回 XS_EOK,options 参数用于配置事件集的属性。可配置的属性有等待触发方式(XS_EVENT_AND 或 XS_EVENT_OR)及等待触发后是否自动清空其他已触发的事件(XS_EVENT_AUTOCLEAN)。 - -| 参数 | 描述 | -| --- | --- | -| id | 事件集ID | -| options | 事件集配置选项,须在 XS_EVENT_AND 及 XS_EVENT_OR 中指定其一,并可以按位或上 XS_EVENT_AUTOCLEAN | - -```c -xs_int32 xs_UserEventReinit(xs_uint16 id); +x_err_t UserEventReinit(EventIdType event); ``` 该函数用于将一个事件的值进行重置。 | 参数 | 描述 | | --- | --- | -| id | 来源消息队列ID | +| event | 来源消息队列ID | @@ -581,22 +597,23 @@ ARM 和 RISC-V 在体系架构上支持机器在特权模式和非特权模式 ### 任务隔离表 -在 XiUOS 中,任务描述符 task_descriptor 管理系统的任务,其中包含了任务优先级、任务名称、任务状态等信息。为了管理任务可访问的内存空间,task_descriptor 描述符在 dync_sched_member 子结构中增加任务隔离标志位 isolation_flag 和任务隔离表 isolation_table, 其定义如下: +在 XiUOS 中,任务描述符 TaskDescriptor 管理系统的任务,其中包含了任务优先级、任务名称、任务状态等信息。为了管理任务可访问的内存空间,TaskDescriptor 描述符在 TaskDyncSchedMember 子结构中增加任务隔离标志位 isolation_flag 和任务隔离成员isolation、isolation_status, 其定义如下: ```c -struct dync_sched_member +struct TaskDyncSchedMember { … - #ifdef XS_USING_TASK_ISOLATION - xs_uint8 isolation_flag; - void *isolation_table; - #endif +#ifdef SEPARATE_COMPILE + uint8 isolation_flag; + void *isolation; + uint8 isolation_status; +#endif … }; ``` 用户程序运行在非信任地址空间,默认开启隔离机制。在用户程序对应的任务被创建时,任务隔离标志位 isolation_flag 被置为1,其允许访问的地址空间范围由 isolation_table 指针所指定。isolation_table 包含了任务可访问的多个内存地址空间,每个内存地址空间用一个 isolation_region 数据结构来描述,这个数据结构包括一段连续的地址空间范围和访问权限,其具体结构取决于体系架构提供的内存保护功能,如 ARM 提供的 MPU 和 RISC-V 提供的 PMP 功能。isolation_region 的定义如下: ```c -#if defined(XS_USING_TASK_ISOLATION) +#if defined(TASK_ISOLATION) typedef struct isolation_region { #ifdefined (XS_RISCV32) @@ -618,7 +635,7 @@ typedef struct isolation_region ### 隔离机制 1. 任务内存结构分布及 isolation_region -XiUOS 中的任务在编译链接后形成Linux通用的ELF文件结构,其中包括.code、.data、.bss等段。在任务加载过程中,.code、.data、.bss会被加载到对应的内存段中。在创建任务时,先判断任务类型,xs_UserTaskCreate用于创建任务,其中 isolation_flag 标志位会被置为1。当为任务分配好栈空间后,isolation_table 中为.code、.data、.bss 等段分别创建一个 isolation_region,并设置对应的地址范围和访问权限,如.code段对应的 isolation_region 为读和执行权限,.data 段对应的 isolation_region 为只读权限,.bss 段和栈对应的 isolation_region 为读写权限。 +XiUOS 中的任务在编译链接后形成Linux通用的ELF文件结构,其中包括.code、.data、.bss等段。在任务加载过程中,.code、.data、.bss会被加载到对应的内存段中。在创建任务时,先判断任务类型,UserTaskCreate用于创建任务,其中 isolation_flag 标志位会被置为1。当为任务分配好栈空间后,isolation_table 中为.code、.data、.bss 等段分别创建一个 isolation_region,并设置对应的地址范围和访问权限,如.code段对应的 isolation_region 为读和执行权限,.data 段对应的 isolation_region 为只读权限,.bss 段和栈对应的 isolation_region 为读写权限。 2. 任务切换时的隔离 在 XiUOS 中,多个任务共享有限个 CPU 核,采用优先级加时间片的调度方式,当一个任务时间片耗尽或者主动让出 CPU 的使用权时,内核调度程序负责保存当前任务的上下文信息,并从等待队列中挑选下一个就绪任务,恢复其上下文信息,并允许其获取 CPU 的使用权。为了保证每个任务只能访问自己的内存空间,内核调度程序在恢复任务上下文时,会先根据 isolation_flag 标志判断该任务是否为用户程序,如果为用户程序,则当前 CPU 核在运行该任务时,只允许访问本任务 isolation_table 中定义的内存区域,对于其它区域没有访问权限。 3. 动态申请/释放内存时的隔离 @@ -696,61 +713,122 @@ MPU_load(isolation_region *isolation_table, xs_uint8 coreid); -XiUOS的任务切换函数为xs_SwitchKthreadContext,在SwitchKthreadContext函数入口位置将C13管脚置为高电平,出口位置置为低电平;则C13管脚保持高电平的时间即切换时间。 +XiUOS的任务切换函数为宏定义DO_KTASK_ASSIGN,在SwitchKtaskContext函数入口位置将C13管脚置为高电平,出口位置置为低电平;则C13管脚保持高电平的时间即切换时间。 #### 编程代码清单
```c -void realtime_taskswitch_test() +static BusType pin; +void RealtimeTaskSwitchTest() { - xs_PinMode(GPIO_C13, PIN_MODE_OUTPUT); - xs_PinWrite(GPIO_C13, PIN_LOW); + struct PinParam test_pin; + struct PinStat test_pin_stat; + int ret = 0; + + struct BusConfigureInfo configure_info; + struct BusBlockWriteParam write_param; + + configure_info.configure_cmd = OPE_CFG; + configure_info.private_data = (void *)&test_pin; + write_param.buffer = (void *)&test_pin_stat; + + /* config test pin as output*/ + test_pin.cmd = GPIO_CONFIG_MODE; + test_pin.pin = GPIO_C13; + test_pin.mode = GPIO_CFG_OUTPUT; + + ret = BusDrvConfigure(pin->owner_driver, &configure_info); + if (ret != EOK) { + KPrintf("config test_pin %d failed!\n", GPIO_C13); + return ; + } + + /* set test pin as low*/ + test_pin_stat.pin = GPIO_C13; + test_pin_stat.val = GPIO_LOW; + BusDevWriteData(pin->owner_haldev, &write_param); while(1){ - xs_DelayKThread(1); + DelayKTask(1); } } +int TestRealtime(int argc, char * argv[]) +{ + int ret = 0; + struct BusConfigureInfo configure_info; + + pin = BusFind(PIN_BUS_NAME); + if (!pin) { + KPrintf("find %s failed!\n", PIN_BUS_NAME); + return -ERROR; + } + + pin->owner_driver = BusFindDriver(pin, PIN_DRIVER_NAME); + pin->owner_haldev = BusFindDevice(pin, PIN_DEVICE_NAME); + + configure_info.configure_cmd = OPE_INT; + ret = BusDrvConfigure(pin->owner_driver, &configure_info); + if (ret != EOK) { + KPrintf("initialize %s failed!\n", PIN_BUS_NAME); + return -ERROR; + } + + RealtimeTaskSwitchTest(); + + return 0; +} + ```
因为测试单板为cortex-m4单板,该系列单板的线程切换是基于pendSV CPU异常进行线程切换,因此下面基于该特点区分测试场景: -* 测量pendSV异常切换,在SwitchKthreadContext函数入口处将C13管脚置为高电平,在pendSV异常处理过程,保存现场之后,切换到目标任务之前将C13管脚置为低电平。得出的管脚电平时间即为带pendSV异常的的任务切换时间。 -* 只测了SwitchKthreadContext,在SwitchKthreadContext函数入口处将C13管脚置为高电平,在出口位置,将C13管脚置为低电平。得出的管脚电平时间即为不计算pendSV异常的的任务切换时间。 +* 测量pendSV异常切换,在SwitchKtaskContext函数入口处将C13管脚置为高电平,在pendSV异常处理过程,保存现场之后,切换到目标任务之前将C13管脚置为低电平。得出的管脚电平时间即为带pendSV异常的的任务切换时间。 +* 只测了SwitchKtaskContext,在SwitchKtaskContext函数入口处将C13管脚置为高电平,在出口位置,将C13管脚置为低电平。得出的管脚电平时间即为不计算pendSV异常的的任务切换时间。 ```c -xs_SwitchKthreadContext: +void __attribute__((naked)) HwInterruptcontextSwitch(x_ubase from, x_ubase to, struct TaskDescriptor *to_task, void *context) +{ /* 将GPIO C13置为高电平 */ - LDR r2, =0x40020818 // 测试代码 - MOV r3, #0x2000 // 测试代码 - STR r3, [r2] // 测试代码 - LDR r2, =xs_KthreadSwitchInterruptFlag - LDR r3, [r2] - CMP r3, #1 - BEQ _reswitch - MOV r3, #1 - STR r3, [r2] + asm volatile("LDR r2, =0x40020818"); // 测试代码 + asm volatile("MOV r3, #0x2000"); // 测试代码 + asm volatile("STR r3, [r2]"); // 测试代码 - LDR r2, =xs_InterruptFromKthread - STR r0, [r2] + asm volatile ("LDR r4, =KtaskSwitchInterruptFlag"); + asm volatile ("LDR r5, [r4]"); + asm volatile ("CMP r5, #1"); + asm volatile ("BEQ Arm32SwitchReswitch"); + asm volatile ("MOV r5, #1"); + asm volatile ("STR r5, [r4]"); + asm volatile ("LDR r4, =InterruptFromKtask"); + asm volatile ("STR r0, [r4]"); + asm volatile ("B Arm32SwitchReswitch"); +} -_reswitch: - LDR r2, =xs_InterruptToKthread - STR r1, [r2] +void __attribute__((naked)) Arm32SwitchReswitch() +{ + asm volatile ("LDR r4, =InterruptToKtask"); + asm volatile ("STR r1, [r4]"); + asm volatile ("LDR r4, =InterruptToKtaskDescriptor"); + asm volatile ("STR r2, [r4]"); + asm volatile ("LDR r0, =" NVIC_INT_CTRL); + asm volatile ("LDR r1, =" NVIC_PENDSVSET); + asm volatile ("STR r1, [r0]"); - LDR r0, =NVIC_INT_CTRL - LDR r2, =NVIC_PENDSVSET - STR r1, [r0] + /* 将GPIO C13置为低电平 */ + asm volatile("LDR r2, =0x4002081a"); // 测试代码 + asm volatile("MOV r3, #0x2000"); // 测试代码 + asm volatile("STR r3, [r2]"); // 测试代码 - /* 将GPIO C13置为低电平 */ - LDR r2, =0x4002081a // 测试代码 - MOV r3, #0x2000 // 测试代码 - STR r3, [r2] // 测试代码 - - BX LR + asm volatile ("BX LR"); +} +void __attribute__((naked)) SwitchKtaskContext(x_ubase from, x_ubase to, struct TaskDescriptor *to_task) +{ + asm volatile("B HwInterruptcontextSwitch"); +} ``` @@ -761,16 +839,16 @@ PendSV_Handler: MRS r2, PRIMASK CPSID I - LDR r0, =xs_KthreadSwitchInterruptFlag + LDR r0, =KtaskSwitchInterruptFlag LDR r1, [r0] CBZ r1, pendsv_exit MOV r1, #0x00 STR r1, [r0] - LDR r0, =xs_InterruptFromKthread + LDR r0, =InterruptFromKtask LDR r1, [r0] - CBZ r1, switch_to_thread + CBZ r1, switch_to_task MRS r1, psp @@ -788,7 +866,7 @@ PendSV_Handler: LDR r0, [r0] STR r1, [r0] -switch_to_thread: +switch_to_task: /* 将GPIO C13置为低电平 */ LDR r2, =0x4002081a // 测试代码 MOV r3, #0x2000 // 测试代码 @@ -823,14 +901,14 @@ switch_to_thread: -从示波器测试结果上来看,单独测试 SwitchKthreadContext 的执行时间是1.26us。 +从示波器测试结果上来看,单独测试 SwitchKtaskContext 的执行时间是1.26us。
![RISCV TEST CONNECT](./imagesrc/arm_test_result1.png)
-从示波器测试结果上来看,测试 SwitchKthreadContext 加上 pendSV 异常的的执行时间是17us。 +从示波器测试结果上来看,测试 SwitchKtaskContext 加上 pendSV 异常的的执行时间是17us。 @@ -848,64 +926,145 @@ switch_to_thread: -XiUOS的任务切换函数为 xs_SwitchKthreadContext,在 SwitchKthreadContext 函数入口位置将 GPIO18 管脚置为高电平,出口位置置为低电平;则GPIO18管脚保持高电平的时间即切换时间。 +XiUOS的任务切换函数为宏定义DO_KTASK_ASSIGN,在 SwitchKtaskContext 函数入口位置将 GPIO18 管脚置为高电平,出口位置SaveMpie置为低电平;则GPIO18管脚保持高电平的时间即切换时间。 #### 编程代码清单 ```c -void realtime_taskswitch_test() +static BusType pin; + +void RealtimeTaskSwitchTest() { - xs_PinMode(GPIO_18, PIN_MODE_OUTPUT); - xs_PinWrite(GPIO_18, PIN_LOW); - while(1){ - xs_DelayKThread(1); + struct PinParam test_pin; + struct PinStat test_pin_stat; + + struct BusConfigureInfo configure_info; + struct BusBlockWriteParam write_param; + + configure_info.configure_cmd = OPE_CFG; + configure_info.private_data = (void *)&test_pin; + write_param.buffer = (void *)&test_pin_stat; + + test_pin.cmd = GPIO_CONFIG_MODE; + test_pin.pin = GPIO_18; + test_pin.mode = GPIO_CFG_OUTPUT; + BusDrvConfigure(pin->owner_driver, &configure_info); + + test_pin_stat.pin = GPIO_18; + test_pin_stat.val = GPIO_LOW; + BusDevWriteData(pin->owner_haldev, &write_param); + + while (1) { + DelayKTask(10); } } + +int TestRealtime(int argc, char * argv[]) +{ + int ret = 0; + struct BusConfigureInfo configure_info; + + pin = BusFind(PIN_BUS_NAME); + if (!pin) { + KPrintf("find %s failed!\n", PIN_BUS_NAME); + return -ERROR; + } + + pin->owner_driver = BusFindDriver(pin, PIN_DRIVER_NAME); + pin->owner_haldev = BusFindDevice(pin, PIN_DEVICE_NAME); + + configure_info.configure_cmd = OPE_INT; + ret = BusDrvConfigure(pin->owner_driver, &configure_info); + if (ret != EOK) { + KPrintf("initialize %s failed!\n", PIN_BUS_NAME); + return -ERROR; + } + + RealtimeTaskSwitchTest(); + + return 0; +} ``` 初始化GPIO18为输出模式,并初始化为低电平;在while(1)当中调用delay函数,每隔1个时间片发生一次调度。在下面的switch函数入口和出口位置操作GPIO。 ```c -.global xs_SwitchKthreadContext -xs_SwitchKthreadContext: - /* 将 GPIO18 置为高电平 */ - lui a5, 0x38001 // 测试代码 - addi a5, a5, 12 // 测试代码 - lw a5, 0(a5) // 测试代码 - sext.w a4, a5 // 测试代码 - lui a5, 0x38001 // 测试代码 - addi a5, a5, 12 // 测试代码 - ori a4, a4, 5 // 测试代码 - sext.w a4, a4 // 测试代码 - sw a4, 0(a5) // 测试代码 +void __attribute__((naked)) SwitchKtaskContext(x_ubase from, x_ubase to, struct TaskDescriptor *to_task) +{ + /* 将 GPIO18 置为高电平 */ + asm volatile ("lui a5, 0x38001"); // 测试代码 + asm volatile ("addi a5, a5, 12"); // 测试代码 + asm volatile ("lw a5, 0(a5)"); // 测试代码 + asm volatile ("sext.w a4, a5"); // 测试代码 + asm volatile ("lui a5, 0x38001"); // 测试代码 + asm volatile ("addi a5, a5, 12"); // 测试代码 + asm volatile ("ori a4, a4, 5"); // 测试代码 + asm volatile ("sext.w a4, a4"); // 测试代码 + asm volatile ("sw a4, 0(a5)"); // 测试代码 - addi sp, sp, -32 * REGBYTES - STORE sp, (a0) + asm volatile ("addi sp, sp, -32 * " RegLengthS); + asm volatile (StoreDS " sp, (a0)"); + asm volatile (StoreDS " x1, 0 * " RegLengthS "(sp)"); + asm volatile (StoreDS " x1, 1 * " RegLengthS "(sp)"); + asm volatile ("csrr a0, mstatus"); +#ifndef TASK_ISOLATION + asm volatile ("andi a0, a0, 8"); + asm volatile ("beqz a0, SaveMpie"); + asm volatile ("li a0, 0x80"); +#endif + asm volatile ("j SaveMpie"); +} - STORE x1, 0 * REGBYTES(sp) - STORE x1, 1 * REGBYTES(sp) +void __attribute__((naked)) SaveMpie() +{ + asm volatile (StoreDS " a0, 2 * " RegLengthS "(sp)"); + asm volatile (StoreDS " tp, 4 * " RegLengthS "(sp)"); + asm volatile (StoreDS " t0, 5 * " RegLengthS "(sp)"); + asm volatile (StoreDS " t1, 6 * " RegLengthS "(sp)"); + asm volatile (StoreDS " t2, 7 * " RegLengthS "(sp)"); + asm volatile (StoreDS " s0, 8 * " RegLengthS "(sp)"); + asm volatile (StoreDS " s1, 9 * " RegLengthS "(sp)"); + asm volatile (StoreDS " a0, 10 * " RegLengthS "(sp)"); + asm volatile (StoreDS " a1, 11 * " RegLengthS "(sp)"); + asm volatile (StoreDS " a2, 12 * " RegLengthS "(sp)"); + asm volatile (StoreDS " a3, 13 * " RegLengthS "(sp)"); + asm volatile (StoreDS " a4, 14 * " RegLengthS "(sp)"); + asm volatile (StoreDS " a5, 15 * " RegLengthS "(sp)"); + asm volatile (StoreDS " a6, 16 * " RegLengthS "(sp)"); + asm volatile (StoreDS " a7, 17 * " RegLengthS "(sp)"); + asm volatile (StoreDS " s2, 18 * " RegLengthS "(sp)"); + asm volatile (StoreDS " s3, 19 * " RegLengthS "(sp)"); + asm volatile (StoreDS " s4, 20 * " RegLengthS "(sp)"); + asm volatile (StoreDS " s5, 21 * " RegLengthS "(sp)"); + asm volatile (StoreDS " s6, 22 * " RegLengthS "(sp)"); + asm volatile (StoreDS " s7, 23 * " RegLengthS "(sp)"); + asm volatile (StoreDS " s8, 24 * " RegLengthS "(sp)"); + asm volatile (StoreDS " s9, 25 * " RegLengthS "(sp)"); + asm volatile (StoreDS " s10, 26 * " RegLengthS "(sp)"); + asm volatile (StoreDS " s11, 27 * " RegLengthS "(sp)"); + asm volatile (StoreDS " t3, 28 * " RegLengthS "(sp)"); + asm volatile (StoreDS " t4, 29 * " RegLengthS "(sp)"); + asm volatile (StoreDS " t5, 30 * " RegLengthS "(sp)"); + asm volatile (StoreDS " t6, 31 * " RegLengthS "(sp)"); + asm volatile (LoadDS " sp, (a1)"); + asm volatile ("mv a0, a2"); + asm volatile ("jal RestoreCpusLockStatus"); - csrr a0, mstatus - andi a0, a0, 8 - beqz a0, save_mpie - li a0, 0x80 -> save_mpie: ... - -> #ifdef XS_USING_SMP ... - #endif /* 将GPIO18 置为低电平 */ - lui a5, 0x38001 // 测试代码 - addi a5, a5, 12 // 测试代码 - lw a5, 0(a5) // 测试代码 - sext.w a4, a5 // 测试代码 - lui a5, 0x38001 // 测试代码 - addi a5, a5, 12 // 测试代码 - addi a4, a4, -6 // 测试代码 - sext.w a4, a4 // 测试代码 - sw a4, 0(a5) // 测试代码 + asm volatile ("lui a5, 0x38001"); // 测试代码 + asm volatile ("addi a5, a5, 12"); // 测试代码 + asm volatile ("lw a5, 0(a5)"); // 测试代码 + asm volatile ("sext.w a4, a5"); // 测试代码 + asm volatile ("lui a5, 0x38001"); // 测试代码 + asm volatile ("addi a5, a5, 12"); // 测试代码 + asm volatile ("addi a4, a4, -6"); // 测试代码 + asm volatile ("sext.w a4, a4"); // 测试代码 + asm volatile ("sw a4, 0(a5)"); // 测试代码 + + asm volatile ("j SwitchKTaskContextExit"); +} - j xs_switch_kthread_context_exit ``` ### 示波器测试选项设置 @@ -937,7 +1096,7 @@ xs_SwitchKthreadContext: -从示波器测试结果上来看,测试 SwitchKthreadContext 的执行时间是160ns。 +从示波器测试结果上来看,测试 SwitchKtaskContext 的执行时间是160ns。 diff --git a/docs/doc/kernel/tmr.md b/docs/doc/kernel/tmr.md index a7cf2db..12e1df5 100644 --- a/docs/doc/kernel/tmr.md +++ b/docs/doc/kernel/tmr.md @@ -16,7 +16,7 @@ XiUOS的“心跳”通过芯片提供的硬件定时器产生的周期性中断 -界面中的数值将配置给变量 XS_TICK_PER_SECOND,该变量解释为每秒钟支持的节拍数(tick)。当 XS_TICK_PER_SECOND +界面中的数值将配置给变量 TICK_PER_SECOND,该变量解释为每秒钟支持的节拍数(tick)。当 TICK_PER_SECOND 配置为100,则tick节拍表示10毫秒,即一个时间片(timeslice)为10毫秒。 在节拍配置成功后,系统支持的调度算法、软件定时器等依赖于该时钟周期服务的事件就可以正常工作了。例如,在XiUOS支持的时间片轮转算法当中,每进行的一次线程切换为10个tick。 @@ -31,15 +31,15 @@ XiUOS的“心跳”通过芯片提供的硬件定时器产生的周期性中断 ## 函数接口 ```c -xs_ticks_x xs_CalculteTickFromTimeMs(xs_uint32 time_ms); +x_ticks_t CalculteTickFromTimeMs(uint32 ms); ``` 该函数用于获取毫秒时间转化成节拍数。 | 参数 | 描述 | | --- | --- | -| time_ms | 毫秒时间 | +| ms | 毫秒时间 | ```c -xs_uint32 xs_CalculteTimeMsFromTick(xs_ticks_x ticks); +uint32 CalculteTimeMsFromTick(x_ticks_t ticks); ``` 该函数用于获取节拍数转换成毫秒时间。 @@ -47,7 +47,7 @@ xs_uint32 xs_CalculteTimeMsFromTick(xs_ticks_x ticks); | --- | --- | | ticks | 节拍数 | ```c -xs_uint32 xs_CurrentTicksGain(void); +x_ticks_t CurrentTicksGain(void); ``` 该函数用于获取当前的时钟节拍数。 @@ -62,23 +62,27 @@ xs_uint32 xs_CurrentTicksGain(void); ### 内核软件定时器结构定义 ```c -struct xs_Timer +struct Timer { - xs_uint32 id; - xs_uint8 active_status; - xs_uint8 trigger_mode; + struct IdNode id_node; + char name[NAME_NUM_MAX]; + uint8 active_status; + uint8 trigger_mode; void (*func_callback)(void *param); - void *param; - xs_ticks_x origin_timeslice; - xs_ticks_x deadline_timeslice; - XS_DOUBLE_LINKLIST link; - XS_DOUBLE_LINKLIST sortlist; + void *param; + x_ticks_t origin_timeslice; + x_ticks_t deadline_timeslice; + DoubleLinklistType link; + DoubleLinklistType sortlist; + uint8 prio; + struct Work *t_work; + struct TimerDone *done; }; -typedef struct xs_Timer *xs_timer_x; ``` | 成员 | 描述 | | --- | --- | -| id | 软件定时器ID,用于唯一标识一个软件定时器 | +| id_node | 软件定时器ID,用于唯一标识一个软件定时器 | +| name | 软件定时器名称 | | active_status | 定时器的激活状态 | | trigger_mode | 定时器的触发模式,包含单次触发和周期触发两种方式 | | func_callback | 定时器超时回调函数 | @@ -87,6 +91,9 @@ typedef struct xs_Timer *xs_timer_x; | deadline_timeslice | 截止时间 | | link | 系统中所有定时器构成的链表 | | sortlist | 处于激活态的定时器链表,并按时间排序 | +| prio | 记录使用定时器处理回调的线程优先级 | +| t_work | 定时器所用到的工作队列 | +| done | 定时器的函数操作集 | @@ -97,51 +104,52 @@ typedef struct xs_Timer *xs_timer_x; #define TIMER_TRIGGER_ONCE (1 << 0) #define TIMER_TRIGGER_PERIODIC (1 << 1) -xs_timer_t xs_KCreateTimer(const char *name, void (*timeout)(void *parameter), void *parameter, xs_ticks_x time, xs_uint8 trigger_mode); +int32 KCreateTimer(const char *name, void (*timeout)(void *parameter), void *parameter, x_ticks_t time, uint8 trigger_mode); ``` 该函数用于创建一个内核软件定时器,并返回创建成功的软件定时器的ID,ID默认范围0-255,可配置。 | 参数 | 描述 | | --- | --- | -| trigge_way | 触发方式,可以配置为宏TRIGGE_WAY_ONCE和TRIGGE_WAY_PERIODIC | -| func_callback | 软件定时器回调函数 | -| func_param | 软件定时器回调函数参数 | -| ticks | 配置需要等待的超时时间 | +| name | 定时器名称 | +| timeout | 软件定时器回调函数 | +| parameter | 软件定时器回调函数参数 | +| time | 配置需要等待的超时时间,单位tick | +| trigger_mode | 触发方式,可以配置为宏TRIGGE_WAY_ONCE和TRIGGE_WAY_PERIODIC | ```c -void xs_KTimerDelete(xs_uint16 id); +void KTimerDelete(int32 timer_id); ``` 该函数用于删除一个软件定时器。 | 参数 | 描述 | | --- | --- | -| id | 待删除的软件定时器ID | +| timer_id | 待删除的软件定时器ID | ```c -xs_int32 xs_KTimerStartRun(xs_uint16 id); +x_err_t KTimerStartRun(int32 timer_id); ``` 该函数用于启动一个软件定时器。 | 参数 | 描述 | | --- | --- | -| id | 已创建且待运行的软件定时器ID | +| timer_id | 已创建且待运行的软件定时器ID | ```c -xs_int32 xs_KTimerQuitRun(xs_uint16 id); +x_err_t KTimerQuitRun(int32 timer_id); ``` 该函数用于停止一个软件定时器。 | 参数 | 描述 | | --- | --- | -| id | 待停止运行的软件定时器ID | +| timer_id | 待停止运行的软件定时器ID | ```c -xs_int32 xs_KTimerModify(xs_uint16 id, xs_tick_x ticks); +x_err_t KTimerModify(int32 timer_id, x_tick_t ticks); ``` 该函数用于修改一个软件定时器的超时时间。 | 参数 | 描述 | | --- | --- | -| id | 待修改超时时间的软件定时器ID | +| timer_id | 待修改超时时间的软件定时器ID | | ticks | 超时时间 |