Files
mkrtos-real/mkrtos_knl/knl/task.c

645 lines
17 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file task.c
* @author ATShining (1358745329@qq.com)
* @brief
* @version 0.1
* @date 2023-09-29
*
* @copyright Copyright (c) 2023
*
*/
#include "task.h"
#include "access.h"
#include "assert.h"
#include "factory.h"
#include "init.h"
#include "knl_misc.h"
#include "kobject.h"
#include "map.h"
#include "printk.h"
#include "spinlock.h"
#include "string.h"
#include "thread.h"
#include "thread_arch.h"
#include "thread_task_arch.h"
#if IS_ENABLED(CONFIG_MMU)
#include "arch.h"
#endif
/**
* @brief 任务的操作码
*
*/
enum task_op_code
{
TASK_OBJ_MAP, //!< 进行映射操作
TASK_OBJ_UNMAP, //!< 进行解除映射操作
TASK_ALLOC_RAM_BASE, //!< 分配task的基础内存
TASK_GET_RAM_INFO, //!< 获取task的ram信息
TASK_OBJ_VALID, //!< 判断一个对象是否有效
TASK_SET_PID, //!< 设置task的pid
TASK_GET_PID, //!< 获取task的pid
TASK_COPY_DATA, //!< 拷贝数据到task的数据区域
TASK_SET_OBJ_NAME, //!< 设置对象的名字
TASK_COPY_DATA_TO, //!< 从当前task拷贝数据到目的task
TASK_SET_COM_POINT, //!< 通信点
TASK_COM_UNLOCK, //!< 任务通信解锁
TASK_COM_LOCK, //!< 任务通信加锁
};
static bool_t task_put(kobject_t *kobj);
static void task_release_stage1(kobject_t *kobj);
static void task_release_stage2(kobject_t *kobj);
#if IS_ENABLED(CONFIG_BUDDY_SLAB)
#include <slab.h>
static slab_t *task_slab;
#endif
/**
* @brief 在系统初始化时调用初始化task的内存
*
*/
static void task_mem_init(void)
{
#if IS_ENABLED(CONFIG_BUDDY_SLAB)
task_slab = slab_create(sizeof(task_t), "task");
assert(task_slab);
#endif
}
INIT_KOBJ_MEM(task_mem_init);
#if !IS_ENABLED(CONFIG_MMU)
/**
* @brief 为task分配其可以使用的内存空间
*
* @param tk
* @param lim
* @param size
* @param mem_block 使用的内存块
* @return int
*/
int task_alloc_base_ram(task_t *tk, ram_limit_t *lim, size_t size, int mem_block)
{
if (tk->mm_space.mm_block)
{
return -EACCES;
}
// 申请init的ram内存
void *ram = mpu_ram_alloc(&tk->mm_space, lim, size + THREAD_MSG_BUG_LEN, mem_block);
if (!ram)
{
printk("Failed to request process memory.\n");
return -ENOMEM;
}
memset(ram, 0, size + THREAD_MSG_BUG_LEN);
mm_space_set_ram_block(&tk->mm_space, ram, size + THREAD_MSG_BUG_LEN);
printk("task alloc [0x%x - 0x%x]\n", ram, (umword_t)ram + size + THREAD_MSG_BUG_LEN - 1);
return 0;
}
#endif
/**
* @brief 获取线程绑定的task
*
* @param th
* @return task_t*
*/
task_t *thread_get_bind_task(thread_t *th)
{
return container_of(th->task, task_t, kobj);
}
/**
* @brief 同时解锁两个进程,防止死锁
*
* @param sp0
* @param sp1
* @param status0
* @param status1
*/
static void task_unlock_2(spinlock_t *sp0, spinlock_t *sp1, int status0, int status1)
{
if (sp0 < sp1)
{
spinlock_set(sp1, status1);
spinlock_set(sp0, status0);
}
else if (sp0 > sp1)
{
spinlock_set(sp0, status0);
spinlock_set(sp1, status1);
} else {
spinlock_set(sp0, status0);
}
}
/**
* @brief 同时加锁两个进程
*
* @param sp0
* @param sp1
* @param st0
* @param st1
* @return int
*/
static int task_lock_2(spinlock_t *sp0, spinlock_t *sp1, int *st0, int *st1)
{
int status0;
int status1;
if (sp0 < sp1)
{
status0 = spinlock_lock(sp0);
if (status0 < 0)
{
return FALSE;
}
status1 = spinlock_lock(sp1);
if (status1 < 0)
{
spinlock_set(sp0, status0);
return FALSE;
}
*st0 = status0;
*st1 = status1;
}
else if (sp0 > sp1)
{
status0 = spinlock_lock(sp1);
if (status0 < 0)
{
return FALSE;
}
status1 = spinlock_lock(sp0);
if (status1 < 0)
{
spinlock_set(sp1, status0);
return FALSE;
}
*st0 = status1;
*st1 = status0;
} else {
status0 = spinlock_lock(sp0);
if (status0 < 0)
{
return FALSE;
}
*st0 = status0;
*st1 = status0;
}
return TRUE;
}
/**
* @brief 设置进程的pid只有pid为0的进程才能够设置
*
* @param task 任务对象
* @param pid 任务的pid
* @return int
*/
int task_set_pid(task_t *task, pid_t pid)
{
task_t *cur_task = thread_get_current_task();
if (cur_task->pid == 0)
{
task->pid = pid;
return 0;
}
else
{
return -EACCES;
}
}
/**
* @brief 进程的系统调用函数
*
* @param kobj
* @param sys_p
* @param in_tag
* @param f
*/
static void task_syscall_func(kobject_t *kobj, syscall_prot_t sys_p, msg_tag_t in_tag, entry_frame_t *f)
{
task_t *cur_task = thread_get_current_task();
task_t *tag_task = container_of(kobj, task_t, kobj);
msg_tag_t tag = msg_tag_init4(0, 0, 0, -EINVAL);
if (sys_p.prot != TASK_PROT)
{
f->regs[0] = msg_tag_init4(0, 0, 0, -EINVAL).raw;
return;
}
switch (sys_p.op)
{
case TASK_SET_OBJ_NAME:
{
mword_t status = spinlock_lock(&tag_task->kobj.lock);
if (status < 0)
{
tag = msg_tag_init4(0, 0, 0, -EINVAL);
break;
}
kobject_t *source_kobj = obj_space_lookup_kobj(&cur_task->obj_space, f->regs[0]);
if (!source_kobj)
{
spinlock_set(&tag_task->kobj.lock, status);
tag = msg_tag_init4(0, 0, 0, -EINVAL);
break;
}
kobject_set_name(source_kobj, (char *)(&f->regs[1]));
spinlock_set(&tag_task->kobj.lock, status);
tag = msg_tag_init4(0, 0, 0, 1);
}
break;
case TASK_OBJ_VALID: //!< 查看某个obj在task中是否存在
{
mword_t status = spinlock_lock(&tag_task->kobj.lock);
if (status < 0)
{
tag = msg_tag_init4(0, 0, 0, -EINVAL);
break;
}
kobject_t *source_kobj = obj_space_lookup_kobj(&cur_task->obj_space, f->regs[1]);
if (!source_kobj)
{
spinlock_set(&tag_task->kobj.lock, status);
tag = msg_tag_init4(0, 0, 0, 0);
break;
}
f->regs[1] = source_kobj->kobj_type;
spinlock_set(&tag_task->kobj.lock, status);
tag = msg_tag_init4(0, 0, 0, 1);
}
break;
case TASK_OBJ_MAP: //!< 从一个task中映射一个对象到目标进程
{
kobj_del_list_t del;
int st0, st1;
kobj_del_list_init(&del);
int suc = task_lock_2(&tag_task->kobj.lock, &cur_task->kobj.lock, &st0, &st1);
if (!suc)
{
tag = msg_tag_init4(0, 0, 0, -EINVAL);
break;
}
int ret = obj_map_src_dst(&tag_task->obj_space, &cur_task->obj_space,
f->regs[2], f->regs[1],
tag_task->lim, f->regs[3], &del);
kobj_del_list_to_do(&del);
task_unlock_2(&tag_task->kobj.lock, &cur_task->kobj.lock, st0, st1);
tag = msg_tag_init4(0, 0, 0, ret);
}
break;
case TASK_OBJ_UNMAP: //!< 解除task中一个进程的创建
{
kobject_t *del_kobj;
kobj_del_list_t kobj_list;
mword_t status = spinlock_lock(&tag_task->kobj.lock);
if (status < 0)
{
tag = msg_tag_init4(0, 0, 0, -EINVAL);
break;
}
kobj_del_list_init(&kobj_list);
obj_unmap(&tag_task->obj_space, vpage_create_raw(f->regs[1]), &kobj_list);
spinlock_set(&tag_task->kobj.lock, status);
status = cpulock_lock();
kobj_del_list_to_do(&kobj_list);
cpulock_set(status);
tag = msg_tag_init4(0, 0, 0, 0);
}
break;
#if !IS_ENABLED(CONFIG_MMU)
case TASK_ALLOC_RAM_BASE: //!< 分配task所拥有的内存空间
{
mword_t status = spinlock_lock(&tag_task->kobj.lock);
if (status < 0)
{
tag = msg_tag_init4(0, 0, 0, -EINVAL);
break;
}
int ret = task_alloc_base_ram(tag_task, tag_task->lim, f->regs[1], f->regs[2]);
tag = msg_tag_init4(0, 0, 0, ret);
tag_task->text_addr = (void *)(f->regs[3]);
tag_task->text_size = (size_t)(f->regs[4]);
f->regs[1] = (umword_t)(tag_task->mm_space.mm_block);
spinlock_set(&tag_task->kobj.lock, status);
}
break;
case TASK_GET_RAM_INFO:
{
mword_t status = spinlock_lock(&tag_task->kobj.lock);
if (status < 0)
{
tag = msg_tag_init4(0, 0, 0, -EINVAL);
break;
}
mm_space_get_ram_block(&tag_task->mm_space, (void**)(&f->regs[1]), (size_t *)(&f->regs[2]));
spinlock_set(&tag_task->kobj.lock, status);
tag = msg_tag_init4(0, 0, 0, 0);
}
break;
#endif
case TASK_COPY_DATA: //!< 拷贝数据到task的内存区域
{
void *mem;
size_t size;
umword_t st_addr = f->regs[0];
size_t cp_size = f->regs[1];
if (cp_size > THREAD_MSG_BUG_LEN)
{
tag = msg_tag_init4(0, 0, 0, -EINVAL);
break;
}
if (!is_rw_access(tag_task, (void *)st_addr, cp_size, FALSE))
{
tag = msg_tag_init4(0, 0, 0, -EPERM);
break;
}
// printk("addr:0x%x %d.\n", st_addr, cp_size);
void *msg = thread_get_msg_buf(thread_get_current());
memcpy((void *)st_addr, msg, cp_size);
tag = msg_tag_init4(0, 0, 0, 0);
break;
}
case TASK_SET_PID: //!< 设置pid
{
tag = msg_tag_init4(0, 0, 0, task_set_pid(tag_task, f->regs[0]));
}
break;
case TASK_GET_PID: //!< 获取pid
{
f->regs[1] = tag_task->pid;
tag = msg_tag_init4(0, 0, 0, 0);
}
break;
case TASK_COPY_DATA_TO: //!< 从当前task拷贝到目的task
{
int st0, st1;
int ret = 0;
obj_handler_t dst_task_hd;
addr_t src_addr;
addr_t dst_addr;
size_t copy_len;
int suc;
dst_task_hd = f->regs[0];
src_addr = f->regs[1];
dst_addr = f->regs[2];
copy_len = f->regs[3];
kobject_t *source_kobj = obj_space_lookup_kobj_cmp_type(&cur_task->obj_space, dst_task_hd, TASK_TYPE);
if (!source_kobj)
{
ret = -EINVAL;
goto copy_data_to_end2;
}
task_t *dst_task_obj = container_of(source_kobj, task_t, kobj);
suc = task_lock_2(&tag_task->kobj.lock, &dst_task_obj->kobj.lock, &st0, &st1);
if (!suc)
{
tag = msg_tag_init4(0, 0, 0, -EINVAL);
break;
}
#if 0/*TODO: 需要检查动态申请的内存*/
if (!is_rw_access(tag_task, (void *)src_addr, copy_len, FALSE))
{
ret = -EPERM;
goto copy_data_to_end;
}
#endif
if (!is_rw_access(dst_task_obj, (void *)dst_addr, copy_len, FALSE))
{
ret = -EPERM;
goto copy_data_to_end;
}
paddr_t src_paddr = (paddr_t)task_get_currnt_paddr((vaddr_t)src_addr);
paddr_t dst_paddr = (paddr_t)task_get_currnt_paddr((vaddr_t)dst_addr);
memcpy((void *)dst_paddr, (void *)src_paddr, copy_len);
copy_data_to_end:
task_unlock_2(&tag_task->kobj.lock, &dst_task_obj->kobj.lock, st0, st1);
copy_data_to_end2:
tag = msg_tag_init4(0, 0, 0, ret);
}
break;
case TASK_SET_COM_POINT: //!< 设置通信点
{
if (!is_rw_access(tag_task, (void *)(f->regs[1]), f->regs[2], FALSE))
{
tag = msg_tag_init4(0, 0, 0, -EPERM);
break;
}
if (f->regs[4] >= WORD_BITS)
{
tag = msg_tag_init4(0, 0, 0, -EINVAL);
break;
}
if (!is_rw_access(tag_task, (void *)(f->regs[3]),
ROUND_UP(f->regs[4], 8), FALSE))
{
tag = msg_tag_init4(0, 0, 0, -EPERM);
break;
}
if (!is_rw_access(tag_task, (void *)(f->regs[5]),
THREAD_MSG_BUG_LEN + CONFIG_THREAD_MAP_BUF_LEN * WORD_BYTES, FALSE))
{
tag = msg_tag_init4(0, 0, 0, -EPERM);
break;
}
int stack_size = f->regs[2];
tag_task->notify_point = (void *)(f->regs[0]);
tag_task->nofity_stack = (addr_t)(f->regs[1] + stack_size);
tag_task->nofity_bitmap = (void *)(f->regs[3]);
tag_task->nofity_bitmap_len = (f->regs[4]);
tag_task->nofity_msg_buf = (addr_t)f->regs[5];
tag_task->nofity_map_buf = (umword_t *)((addr_t)f->regs[5] + THREAD_MSG_BUG_LEN);
sema_init(&tag_task->notify_sema, tag_task->nofity_bitmap_len, tag_task->nofity_bitmap_len);
tag = msg_tag_init4(0, 0, 0, 0);
}
break;
case TASK_COM_UNLOCK:
{
task_t *cur_task = thread_get_current_task();
mutex_unlock(&cur_task->nofity_lock);
tag = msg_tag_init4(0, 0, 0, 0);
}
break;
case TASK_COM_LOCK:
{
task_t *cur_task = thread_get_current_task();
mutex_lock(&cur_task->nofity_lock, 0);
tag = msg_tag_init4(0, 0, 0, 0);
}
break;
default:
break;
}
f->regs[0] = tag.raw;
}
void task_init(task_t *task, ram_limit_t *ram, int is_knl)
{
assert(task);
assert(ram);
kobject_init(&task->kobj, TASK_TYPE);
obj_space_init(&task->obj_space, ram);
mm_space_init(&task->mm_space, is_knl);
ref_counter_init(&task->ref_cn);
ref_counter_inc(&task->ref_cn);
slist_init(&task->del_node);
slist_init(&task->nofity_theads_head);
mutex_init(&task->nofity_lock);
task->pid = -1;
task->lim = ram;
task->kobj.invoke_func = task_syscall_func;
task->kobj.put_func = task_put;
task->kobj.stage_1_func = task_release_stage1;
task->kobj.stage_2_func = task_release_stage2;
#if IS_ENABLED(CONFIG_MMU)
knl_pdir_init(&task->mm_space.mem_dir, task->mm_space.mem_dir.dir, 3 /*TODO:*/);
#else
assert(task_vma_alloc(&task->mm_space.mem_vma, vma_addr_create(VPAGE_PROT_RO, 0, 0),
align_power_of_2(CONFIG_SYS_TEXT_SIZE), CONFIG_SYS_TEXT_ADDR, NULL) >= 0);
#endif
}
static bool_t task_put(kobject_t *kobj)
{
task_t *tk = container_of(kobj, task_t, kobj);
return ref_counter_dec(&tk->ref_cn) == 1;
}
static void task_release_stage1(kobject_t *kobj)
{
int ret;
task_t *tk = container_of(kobj, task_t, kobj);
kobj_del_list_t kobj_list;
kobject_invalidate(kobj);
kobj_del_list_init(&kobj_list);
obj_unmap_all(&tk->obj_space, &kobj_list);
kobj_del_list_to_do(&kobj_list);
thread_fast_ipc_com_t *restore_th_com;
thread_fast_ipc_item_t ipc_item;
slist_foreach(restore_th_com, &tk->nofity_theads_head, fast_ipc_node)
{
thread_t *restore_th = restore_th_com->th;
ret = thread_fast_ipc_pop(restore_th, &ipc_item); /*TODO:这里有问题*/
if (ret >= 0)
{
// 还原栈和usp TODO: arch相关的
restore_th->ipc_status = THREAD_NONE;
if (restore_th->status == THREAD_SUSPEND)
{
thread_ready(restore_th, TRUE);
}
restore_th->task = ipc_item.task_bk;
thread_user_pf_restore(restore_th, ipc_item.usp_backup);
pf_t *cur_pf = ((pf_t *)((char *)restore_th + CONFIG_THREAD_BLOCK_SIZE + 8)) - 1;
cur_pf->regs[5] = (umword_t)(thread_get_bind_task(restore_th)->mm_space.mm_block);
ref_counter_dec_and_release(&tk->ref_cn, &tk->kobj);
} else {
break;
}
}
task_vma_clean(&tk->mm_space.mem_vma);
}
static void task_release_stage2(kobject_t *kobj)
{
task_t *tk = container_of(kobj, task_t, kobj);
kobj_del_list_t kobj_list;
// task_t *cur_tk = thread_get_current_task();
obj_space_release(&tk->obj_space, tk->lim);
#if !IS_ENABLED(CONFIG_MMU)
if (tk->mm_space.mm_block)
{
#if CONFIG_MPU
mm_limit_free_align(tk->lim, tk->mm_space.mm_block, tk->mm_space.mm_block_size);
#else
mm_limit_free(tk->lim, tk->mm_space.mm_block);
#endif
}
#endif
#if IS_ENABLED(CONFIG_BUDDY_SLAB)
mm_limit_free_slab(task_slab, tk->lim, tk);
#else
mm_limit_free(tk->lim, tk);
#endif
// if (cur_tk == tk)
// {
thread_sched(TRUE);
// arch_to_sche();
// }
printk("release tk %x, name is:%s\n", tk, kobject_get_name(&tk->kobj));
}
void task_kill(task_t *tk)
{
kobj_del_list_t kobj_list;
kobj_del_list_init(&kobj_list);
obj_unmap(&tk->obj_space, vpage_create3(KOBJ_DELETE_RIGHT, 0, TASK_PROT), &kobj_list);
kobj_del_list_to_do(&kobj_list);
thread_sched(TRUE);
// arch_to_sche();
}
task_t *task_create(ram_limit_t *lim, int is_knl)
{
task_t *tk = NULL;
#if IS_ENABLED(CONFIG_BUDDY_SLAB)
tk = mm_limit_alloc_slab(task_slab, lim);
#else
tk = mm_limit_alloc(lim, sizeof(task_t));
#endif
if (!tk)
{
return NULL;
}
task_init(tk, lim, is_knl);
printk("create task is 0x%x\n", tk);
return tk;
}
/**
* @brief 该函数创建一个工厂对象
*
* @param lim
* @param arg0
* @param arg1
* @param arg2
* @param arg3
* @return kobject_t*
*/
static kobject_t *task_create_func(ram_limit_t *lim, umword_t arg0, umword_t arg1,
umword_t arg2, umword_t arg3)
{
task_t *tk = task_create(lim, FALSE);
return &tk->kobj;
}
/**
* @brief 工厂注册函数
*
*/
void task_factory_register(void)
{
factory_register(task_create_func, TASK_PROT);
}
INIT_KOBJ(task_factory_register);