feat(kos): Added the os adaptation layer feature.

This commit is contained in:
MacRsh
2025-02-11 20:16:27 +08:00
parent 76e7efce33
commit 3a4d77588c
29 changed files with 1127 additions and 83 deletions

View File

@@ -14,4 +14,10 @@ menu "Kernel"
help
This option controls the size of the inline name of the kobject.
# KTHREAD
config MR_CFG_KTHREAD_IRES_SIZE
int "Kthread inline resource size"
default 256
help
This option controls the size of the inline resource of the kthread.
endmenu

View File

@@ -0,0 +1,89 @@
/**
* @copyright (c) 2024, MacRsh
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2024-09-06 MacRsh First version
*/
#ifndef __MR_KOS_H__
#define __MR_KOS_H__
#include <kernel/mr_kclock.h>
#include <kernel/mr_kobject.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* @addtogroup Kos
* @{
*/
/* Kthread operations type */
typedef struct mr_kthread_ops {
mr_err_t (*init)(void *, const char *, void *, void *, mr_size_t,
mr_uint32_t, mr_tick_t);
mr_err_t (*del)(void *);
mr_err_t (*startup)(void *);
mr_err_t (*resume)(void *);
mr_err_t (*yield)(void);
mr_err_t (*suspend)(void *);
mr_err_t (*sleep)(mr_tick_t tick);
mr_err_t (*exit)(void *);
void *(*self)(void);
} mr_kthread_ops_t;
/* Kthread-type type */
typedef struct mr_kthread_type {
mr_uint32_t priority_max;
mr_kthread_ops_t *ops;
mr_size_t size;
} mr_kthread_type_t;
/* Kos-type type */
typedef struct mr_kos_type {
mr_kthread_type_t *kth_type;
} mr_kos_type_t;
/* Kos type */
typedef struct mr_kos {
mr_kset_t parent;
mr_kos_type_t *type;
} mr_kos_t;
/**
* @brief This function registers kernel os.
*
* @return 0 on success, or a negative error code on failure.
*/
mr_err_t mr_kos_register(mr_kos_type_t *type);
/**
* @brief This function gets kernel os.
*
* @return The kernel os.
*/
mr_kos_t *mr_kos_get(void);
/**
* @brief This function puts kernel os.
*/
void mr_kos_put(void);
/**
* @brief This macro function gets the kthread operations of a kernel os.
*
* @param _kos The kernel os.
* @return The kthread operations of the kernel os.
*/
#define MR_KOS_KTH_OPS(_kos) ((_kos)->type->kth_type->ops)
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __MR_KOS_H__ */

View File

@@ -0,0 +1,177 @@
/**
* @copyright (c) 2024, MacRsh
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2024-09-06 MacRsh First version
*/
#ifndef __MR_KTHREAD_H__
#define __MR_KTHREAD_H__
#include <kernel/kos/mr_kos.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* @addtogroup Kthread
* @{
*/
/* Kthread type */
typedef struct mr_kthread {
mr_kobject_t parent;
const void *res;
#if !defined(MR_CFG_KTHREAD_IRES_SIZE)
#define MR_CFG_KTHREAD_IRES_SIZE (256)
#endif /* !defined(MR_CFG_KTHREAD_IRES_SIZE) */
mr_uint8_t ires[MR_CFG_KTHREAD_IRES_SIZE];
mr_uint32_t priority;
mr_tick_t tick;
mr_ptr_t entry;
mr_ptr_t args;
mr_kos_t *os;
} mr_kthread_t;
/**
* @brief This function initialize a kthread.
*
* @param kth The kthread.
* @param name The kthread name.
* @param entry The kthread entry.
* @param args The kthread arguments.
* @param stack The kthread stack.
* @param stack_size The kthread stack size.
* @param priority The kthread priority.
* @param tick The kthread time slice.
* @return 0 on success, or a negative error code on failure.
*/
mr_err_t mr_kthread_init(mr_kthread_t *kth, const char *name,
void (*entry)(mr_kthread_t *, void *), void *args,
void *stack, mr_size_t stack_size,
mr_uint32_t priority, mr_tick_t tick);
/**
* @brief This function create a kthread.
*
* @param name The kthread name.
* @param entry The kthread entry.
* @param args The kthread arguments.
* @param stack_size The kthread stack size.
* @param priority The kthread priority.
* @param tick The kthread time slice.
* @return The kthread on success, or NULL on failure.
*/
mr_kthread_t *mr_kthread_create(const char *name,
void (*entry)(mr_kthread_t *, void *),
void *args, mr_size_t stack_size,
mr_uint32_t priority, mr_tick_t tick);
/**
* @brief This function takeover a kthread.
*
* @param kth The kthread.
* @param name The kthread name.
* @param priority The kthread priority.
* @param tick The kthread time slice.
* @return 0 on success, or a negative error code on failure.
*/
mr_err_t mr_kthread_takeover(mr_kthread_t *kth, const char *name,
const void *res, mr_uint32_t priority,
mr_tick_t tick);
/**
* @brief This function delete a kthread.
*
* @param kth The kthread.
* @return 0 on success, or a negative error code on failure.
*/
mr_err_t mr_kthread_del(mr_kthread_t *kth);
/**
* @brief This function startup a kthread.
*
* @param kth The kthread.
* @return 0 on success, or a negative error code on failure.
*/
mr_err_t mr_kthread_startup(mr_kthread_t *kth);
/**
* @brief This function resume a kthread.
*
* @param kth The kthread.
* @return 0 on success, or a negative error code on failure.
*/
mr_err_t mr_kthread_resume(mr_kthread_t *kth);
/**
* @brief This function yield the current kthread.
*
* @return 0 on success, or a negative error code on failure.
*/
mr_err_t mr_kthread_yield(void);
/**
* @brief This function suspend a kthread.
*
* @param kth The kthread.
* @return 0 on success, or a negative error code on failure.
*/
mr_err_t mr_kthread_suspend(mr_kthread_t *kth);
/**
* @brief This function sleep a kthread.
*
* @param tick The sleep time slice.
* @return 0 on success, or a negative error code on failure.
*/
mr_err_t mr_kthread_sleep(mr_tick_t tick);
/**
* @brief This function exit a kthread.
*
* @param kth The kthread.
* @return 0 on success, or a negative error code on failure.
*/
mr_err_t mr_kthread_exit(mr_kthread_t *kth);
/**
* @brief This function get the current kthread.
*
* @return The current kthread.
*/
mr_kthread_t *mr_kthread_self(void);
/**
* @brief This function find a kthread.
*
* @param name The kthread name.
* @return The kthread on success, or MR_NULL on failure.
*/
mr_kthread_t *mr_kthread_find(const char *name);
/**
* @brief This function cleanup a kthread.
*
* @param kth The kthread.
*/
void mr_kthread_cleanup(mr_kthread_t *kth);
/**
* @brief This function is the kthread entry.
*
* @param kth The kthread.
*
* @note User does not need to call this function.
*/
void mr_kthread_entry(mr_kthread_t *kth);
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __MR_KTHREAD_H__ */

View File

@@ -9,7 +9,7 @@
#ifndef __MR_KHOOK_H__
#define __MR_KHOOK_H__
#include "mr_spinlock.h"
#include <kernel/mr_spinlock.h>
#include <libc/mr_errno.h>
#ifdef __cplusplus

View File

@@ -36,16 +36,16 @@ typedef struct mr_kname {
/* Ktype type */
typedef struct mr_ktype {
void (*release)(struct mr_kobject *kobj);
void (*release)(struct mr_kobject *);
} mr_ktype_t;
/* Kobject type */
typedef struct mr_kobject {
mr_uint32_t magic;
mr_kname_t name;
#ifndef MR_CFG_KOBJECT_INAME_SIZE
#if !defined(MR_CFG_KOBJECT_INAME_SIZE)
#define MR_CFG_KOBJECT_INAME_SIZE (16)
#endif /* !MR_CFG_KOBJECT_INAME_SIZE */
#endif /* !defined(MR_CFG_KOBJECT_INAME_SIZE) */
char iname[MR_CFG_KOBJECT_INAME_SIZE];
struct mr_kobject *parent;
mr_ktype_t *type;
@@ -65,7 +65,7 @@ typedef struct mr_kset {
* @param _release The release function.
*/
#define MR_KTYPE_INIT(_release) \
{ .release = _release }
{ .release = (_release) }
/**
* @brief This function initializes a ktype.
@@ -160,6 +160,16 @@ void mr_kobject_put(mr_kobject_t *kobj);
*/
#define MR_KOBJECT_NAME(_kobj) (((mr_kobject_t *)(_kobj))->name.str)
/**
* @brief This macro function gets the length of a kobject name.
*
* @param _kobj The kobject.
* @return The length of the kobject name.
*
* @note The name length includes the null terminator('\0').
*/
#define MR_KOBJECT_NAME_LEN(_kobj) (((mr_kobject_t *)(_kobj))->name.len)
/**
* @brief This macro function gets the parent of a kobject.
*

View File

@@ -9,7 +9,7 @@
#ifndef __MR_KPRINTF_H__
#define __MR_KPRINTF_H__
#include <libc/mr_stdio.h>
#include <libc/mr_printf.h>
#ifdef __cplusplus
extern "C" {

View File

@@ -20,8 +20,8 @@ extern "C" {
* @{
*/
/* Lockref type */
typedef mr_atomic_t mr_kref_t;
/* Kref type */
typedef mr_atomic_t mr_kref_t;
/**
* @brief This macro function initializes a kref.

View File

@@ -6,8 +6,8 @@
* @date 2024-09-06 MacRsh First version
*/
#ifndef __MR_SERVICE_H__
#define __MR_SERVICE_H__
#ifndef __MR_KSERVICE_H__
#define __MR_KSERVICE_H__
#ifdef __cplusplus
extern "C" {
@@ -35,7 +35,7 @@ extern "C" {
* @param _array The array.
* @return The size of the array.
*/
#define MR_ARRAY_SIZE(_array) (sizeof(_array) / sizeof(_array[0]))
#define MR_ARRAY_SIZE(_array) (sizeof(_array) / sizeof((_array)[0]))
/**
* @brief This macro function aligns a value upward.
@@ -112,4 +112,4 @@ extern "C" {
}
#endif /* __cplusplus */
#endif /* __MR_SERVICE_H__ */
#endif /* __MR_KSERVICE_H__ */

View File

@@ -6,8 +6,8 @@
* @date 2024-09-06 MacRsh First version
*/
#ifndef __MR_SLIST_H__
#define __MR_SLIST_H__
#ifndef __MR_KSLIST_H__
#define __MR_KSLIST_H__
#include <kernel/mr_kservice.h>
#include <libc/mr_compiler.h>
@@ -18,21 +18,21 @@ extern "C" {
#endif /* __cplusplus */
/**
* @addtogroup Slist
* @addtogroup Kslist
* @{
*/
/* Single list type */
typedef struct mr_slist {
struct mr_slist *next;
} mr_slist_t;
typedef struct mr_kslist {
struct mr_kslist *next;
} mr_kslist_t;
/**
* @brief This macro function initializes a single list.
*
* @param _slist The list to initialize.
* @param _kslist The list to initialize.
*/
#define MR_SLIST_INIT(_slist) \
#define MR_KSLIST_INIT(_kslist) \
{ .next = MR_NULL }
/**
@@ -40,7 +40,7 @@ typedef struct mr_slist {
*
* @param entry The element to initialize.
*/
MR_INLINE void mr_slist_init(mr_slist_t *entry) {
MR_INLINE void mr_kslist_init(mr_kslist_t *entry) {
entry->next = MR_NULL;
}
@@ -52,8 +52,8 @@ MR_INLINE void mr_slist_init(mr_slist_t *entry) {
*
* @note Adds to the end of the list.
*/
MR_INLINE void mr_slist_add(mr_slist_t *head, mr_slist_t *entry) {
mr_slist_t *p;
MR_INLINE void mr_kslist_add(mr_kslist_t *head, mr_kslist_t *entry) {
mr_kslist_t *p;
p = head;
while (!p->next) {
@@ -70,7 +70,7 @@ MR_INLINE void mr_slist_add(mr_slist_t *head, mr_slist_t *entry) {
*
* @note Inserts to the beginning of the list.
*/
MR_INLINE void mr_slist_insert(mr_slist_t *head, mr_slist_t *entry) {
MR_INLINE void mr_kslist_insert(mr_kslist_t *head, mr_kslist_t *entry) {
entry->next = head->next;
head->next = entry;
}
@@ -81,8 +81,8 @@ MR_INLINE void mr_slist_insert(mr_slist_t *head, mr_slist_t *entry) {
* @param head The list head.
* @param entry The element to remove.
*/
MR_INLINE void mr_slist_del(mr_slist_t *head, mr_slist_t *entry) {
mr_slist_t *p;
MR_INLINE void mr_kslist_del(mr_kslist_t *head, mr_kslist_t *entry) {
mr_kslist_t *p;
p = head;
while (!p->next) {
@@ -102,7 +102,7 @@ MR_INLINE void mr_slist_del(mr_slist_t *head, mr_slist_t *entry) {
* @param head The list head.
* @return MR_TRUE on empty, MR_FALSE otherwise.
*/
MR_INLINE mr_bool_t mr_slist_is_empty(mr_slist_t *head) {
MR_INLINE mr_bool_t mr_kslist_is_empty(mr_kslist_t *head) {
return (!head->next) ? MR_TRUE : MR_FALSE;
}
@@ -112,7 +112,7 @@ MR_INLINE mr_bool_t mr_slist_is_empty(mr_slist_t *head) {
* @param _pos The pointer to the element.
* @param _head The list head.
*/
#define MR_SLIST_FOR_EACH(_pos, _head) \
#define MR_KSLIST_FOR_EACH(_pos, _head) \
for ((_pos) = (_head)->next; (_pos) != MR_NULL; (_pos) = (_pos)->next)
/**
@@ -122,7 +122,7 @@ MR_INLINE mr_bool_t mr_slist_is_empty(mr_slist_t *head) {
* @param _n The pointer to the next element.
* @param _head The list head.
*/
#define MR_SLIST_FOR_EACH_SAFE(_pos, _n, _head) \
#define MR_KSLIST_FOR_EACH_SAFE(_pos, _n, _head) \
for ((_pos) = (_head)->next, (_n) = (_pos) ? (_pos)->next : MR_NULL; \
(_pos) != MR_NULL; \
(_pos) = (_n), (_n) = (_pos) ? (_pos)->next : MR_NULL)
@@ -133,4 +133,4 @@ MR_INLINE mr_bool_t mr_slist_is_empty(mr_slist_t *head) {
}
#endif /* __cplusplus */
#endif /* __MR_SLIST_H__ */
#endif /* __MR_KSLIST_H__ */

View File

@@ -74,7 +74,7 @@ menu "Libc"
prompt "Stdio"
default MR_USE_PRINTFK
config MR_USE_LIBC_STDIO
config MR_USE_LIBC_PRINTF
bool "Standard libc stdio"
help
Use the standard libc stdio for I/O operations.

View File

@@ -38,6 +38,7 @@ typedef int mr_err_t;
#define MR_EBUSY EBUSY
#define MR_EEXIST EEXIST
#define MR_EINVAL EINVAL
#define MR_ENOSYS ENOSYS
#define MR_ETIMEDOUT ETIMEDOUT
#elif defined(MR_USE_3PARTY_ERRNO)
/* In '3party/libc/mr_errno.h' */
@@ -50,6 +51,7 @@ typedef int mr_err_t;
#define MR_EBUSY 16
#define MR_EEXIST 17
#define MR_EINVAL 22
#define MR_ENOSYS 40
#define MR_ETIMEDOUT 116
#endif /* defined(MR_USE_LIBC_ERRNO) */

42
include/libc/mr_printf.h Normal file
View File

@@ -0,0 +1,42 @@
/**
* @copyright (c) 2024, MacRsh
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2024-09-06 MacRsh First version
*/
#ifndef __MR_PRINTF_H__
#define __MR_PRINTF_H__
#include <mr_config.h>
#if defined(MR_USE_LIBC_PRINTF)
#include <stdio.h>
#else
#include <libc/mr_types.h>
#endif /* defined(MR_USE_LIBC_PRINTF) */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* @addtogroup Stdio
* @{
*/
/* Stdio definition */
#if defined(MR_USE_LIBC_PRINTF)
#define mr_vprintf(_f, _a) vprintf(_f, _a)
#define mr_vsnprintf(_b, _s, _f, _a) vsnprintf(_b, _s, _f, _a)
#else
#endif /* defined(MR_USE_LIBC_PRINTF) */
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __MR_PRINTF_H__ */

View File

@@ -5,11 +5,6 @@
extern "C" {
#endif /* __cplusplus */
//#define MR_USE_THREAD
#define MR_USE_LIBC_MALLOC
#define MR_USE_ASSERT
#define MR_USE_LIBC_ASSERT
#define MR_USE_LIBC_STDIO
#ifdef __cplusplus
}

View File

@@ -7,50 +7,15 @@
*/
#include <kernel/mr_initcall.h>
#ifdef MR_USE_THREAD
#include <kernel/thread/mr_thread.h>
MR_INLINE void thread_main_entry(void *args) {
extern int main(void);
MR_UNUSED(args);
/* Run main */
main();
}
MR_INLINE void thread_main(void) {
#if !defined(MR_CFG_MAIN_THREAD_STACK_SIZE)
#define MR_CFG_MAIN_THREAD_STACK_SIZE (1024)
#endif /* !defined(MR_CFG_MAIN_THREAD_STACK_SIZE) */
static mr_uint8_t main_stack[MR_CFG_MAIN_THREAD_STACK_SIZE];
static mr_thread_t main_thread;
/* Init main thread */
#if !defined(MR_CFG_MAIN_THREAD_PRIORITY)
#define MR_CFG_MAIN_THREAD_PRIORITY (MR_CFG_THREAD_PRIORITY_MAX / 2)
#endif /* !defined(MR_CFG_MAIN_THREAD_PRIORITY) */
#if MR_CFG_MAIN_THREAD_PRIORITY >= MR_CFG_THREAD_PRIORITY_MAX
#error "Main thread priority must be less than thread priority max."
#endif /* MR_CFG_MAIN_THREAD_PRIORITY >= MR_CFG_THREAD_PRIORITY_MAX */
mr_thread_init(&main_thread, "main", thread_main_entry, MR_NULL, main_stack,
MR_CFG_MAIN_THREAD_STACK_SIZE, MR_CFG_MAIN_THREAD_PRIORITY,
10);
/* Startup main thread */
mr_thread_startup(&main_thread);
}
#endif /* MR_USE_THREAD */
MR_INLINE void entry(void) {
extern int main(void);
/* Run autoinit(kernel) */
mr_autoinit_kernel();
/* Run main */
#ifdef MR_USE_THREAD
thread_main();
#else
extern int main(void);
main();
#endif /* MR_USE_THREAD */
}
/* MR-X entry point */

View File

@@ -44,7 +44,7 @@ mr_uint32_t mr_kfifo_in(mr_kfifo_t *kfifo, const void *buf, mr_uint32_t size) {
mr_memcpy(kfifo->buf + (kfifo->in & (kfifo->size - 1)), buf, s);
/* In start of kfifo */
mr_memcpy(kfifo->buf, buf + s, size - s);
mr_memcpy(kfifo->buf, (mr_uint8_t *)buf + s, size - s);
/* Update in index */
kfifo->in += size;
@@ -95,6 +95,6 @@ mr_uint32_t mr_kfifo_peek(mr_kfifo_t *kfifo, void *buf, mr_uint32_t size) {
mr_memcpy(buf, kfifo->buf + (kfifo->out & (kfifo->size - 1)), s);
/* Out start of kfifo */
mr_memcpy(buf + s, kfifo->buf, size - s);
mr_memcpy((mr_uint8_t *)buf + s, kfifo->buf, size - s);
return size;
}

View File

@@ -23,7 +23,6 @@ void mr_khook_init(mr_khook_t *khook, mr_ptr_t *entry, mr_size_t size) {
mr_err_t mr_khook_add(mr_khook_t *khook, mr_ptr_t entry) {
mr_err_t ret;
mr_size_t i;
int mask;
/* Check arguments */

View File

@@ -9,7 +9,7 @@
#include <kernel/mr_kobject.h>
#include <kernel/mr_spinlock.h>
#include <libc/mr_malloc.h>
#include <libc/mr_stdio.h>
#include <libc/mr_printf.h>
#include <libc/mr_string.h>
/* Last-word definition */
@@ -188,9 +188,9 @@ MR_INLINE mr_err_t kobject_name_alloc(mr_kobject_t *kobj, const char *name) {
s = kobj->iname;
} else {
s = mr_malloc(size + 1);
}
if (!s) {
return -MR_ENOMEM;
if (!s) {
return -MR_ENOMEM;
}
}
/* Copy name */

48
kernel/kos/kos.c Normal file
View File

@@ -0,0 +1,48 @@
/**
* @copyright (c) 2024, MacRsh
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2024-09-06 MacRsh First version
*/
#include <kernel/kos/mr_kos.h>
static mr_kos_t kos;
MR_INLINE void kos_init(mr_kos_t *os, mr_kos_type_t *type) {
/* Init kos */
os->type = type;
}
MR_INLINE mr_err_t kos_init_register(mr_kos_t *os, const char *name,
mr_kos_type_t *type) {
/* Init kos */
kos_init(os, type);
/* Init kset */
mr_kset_init((mr_kset_t *)os, MR_NULL);
/* Register kset */
return mr_kset_register((mr_kset_t *)os, name);
}
mr_err_t mr_kos_register(mr_kos_type_t *type) {
/* Check arguments */
if (MR_KOBJECT_IS_INITED(&kos) || (!type)) {
return -MR_EINVAL;
}
/* Init and register kos */
return kos_init_register(&kos, "os", type);
}
mr_kos_t *mr_kos_get(void) {
/* Get kos */
return (mr_kos_t *)mr_kobject_get((mr_kobject_t *)&kos);
}
void mr_kos_put(void) {
/* Put kos */
mr_kobject_put((mr_kobject_t *)&kos);
}

400
kernel/kos/kthread.c Normal file
View File

@@ -0,0 +1,400 @@
/**
* @copyright (c) 2024, MacRsh
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2024-09-06 MacRsh First version
*/
#include <kernel/kos/mr_kthread.h>
#include <kernel/mr_initcall.h>
#include <libc/mr_malloc.h>
#include <libc/mr_string.h>
static mr_ktype_t ktype1, ktype2;
static mr_kset_t kroot = MR_KSET_INIT(&kroot, MR_NULL);
MR_INLINE mr_err_t kthread_res_alloc(mr_kthread_t *kth, mr_size_t size) {
void *res;
/* Alloc resource */
if (size <= sizeof(kth->ires)) {
/* Use inline resource if possible */
res = kth->ires;
} else {
res = mr_malloc(size);
if (!res) {
return -MR_ENOMEM;
}
}
/* Init resource */
mr_memset(res, 0, size);
kth->res = res;
return 0;
}
MR_INLINE mr_err_t kthread_init(mr_kthread_t *kth, const char *name,
mr_ptr_t entry, mr_ptr_t args, void *stack,
mr_size_t stack_size, mr_uint32_t priority,
mr_tick_t tick, mr_kos_t *kos) {
mr_kthread_type_t *type;
mr_err_t ret;
/* Get kthread kth_type and check priority */
type = kos->type->kth_type;
if ((!type) || (priority >= type->priority_max)) {
return -MR_EINVAL;
}
/* Init kthread */
kth->priority = priority;
kth->tick = tick;
kth->entry = entry;
kth->args = args;
kth->os = kos;
/* Takeover kthread resources not need init. */
if (!kth->entry) {
return 0;
}
/* Alloc resource */
ret = kthread_res_alloc(kth, type->size);
if (ret != 0) {
return ret;
}
/* Init kthread resource */
return MR_KOS_KTH_OPS(kth->os)->init((void *)kth->res, name, kth, stack,
stack_size, priority, tick);
}
MR_INLINE mr_err_t kthread_del(mr_kthread_t *kth) {
/* Delete kthread resource */
return MR_KOS_KTH_OPS(kth->os)->del((void *)kth->res);
}
MR_INLINE mr_err_t kthread_init_add(mr_kthread_t *kth, mr_ktype_t *ktype,
const char *name, mr_ptr_t entry,
mr_ptr_t args, void *stack,
mr_size_t stack_size, mr_uint32_t priority,
mr_tick_t tick) {
mr_kos_t *kos;
mr_err_t ret;
/* Get kos */
kos = mr_kos_get();
if (!kos) {
return -MR_ENOSYS;
}
/* Init kthread */
ret = kthread_init(kth, name, entry, args, stack, stack_size, priority,
tick, kos);
if (ret != 0) {
goto _exit;
}
/* Init kobject */
mr_kobject_init((mr_kobject_t *)kth, ktype);
/* Add kobject to kroot */
ret = mr_kobject_add((mr_kobject_t *)kth, (mr_kobject_t *)&kroot, name);
if (ret != 0) {
kthread_del(kth);
goto _exit;
}
_exit:
/* Put kos */
mr_kos_put();
return ret;
}
mr_err_t mr_kthread_init(mr_kthread_t *kth, const char *name,
void (*entry)(mr_kthread_t *, void *), void *args,
void *stack, mr_size_t stack_size,
mr_uint32_t priority, mr_tick_t tick) {
/* Check arguments */
if ((!kth) || (MR_KOBJECT_IS_INITED(kth)) || (!name) || (!entry) || (!stack)
|| (!tick)) {
return -MR_EINVAL;
}
/* Init and add kthread */
return kthread_init_add(kth, &ktype1, name, (mr_ptr_t)entry, args, stack,
stack_size, priority, tick);
}
mr_kthread_t *mr_kthread_create(const char *name,
void (*entry)(mr_kthread_t *, void *),
void *args, mr_size_t stack_size,
mr_uint32_t priority, mr_tick_t tick) {
mr_kthread_t *kth;
mr_uint8_t *stack;
mr_err_t ret;
/* Check arguments */
if ((!name) || (!entry) || (!tick)) {
return MR_NULL;
}
/* Create kthread */
kth = mr_malloc(sizeof(mr_kthread_t) + stack_size);
if (!kth) {
return MR_NULL;
}
/* Init and add kthread */
stack = (mr_uint8_t *)kth + sizeof(mr_kthread_t);
ret = kthread_init_add(kth, &ktype2, name, (mr_ptr_t)entry, args, stack,
stack_size, priority, tick);
if (ret != 0) {
mr_free(kth);
return MR_NULL;
}
return kth;
}
MR_INLINE mr_err_t kthread_takeover(mr_kthread_t *kth, const char *name,
const void *res, mr_uint32_t priority,
mr_tick_t tick) {
/* Takeover kthread resource */
kth->res = res;
/* Init and add kthread */
return kthread_init_add(kth, &ktype1, name, MR_NULL, MR_NULL, MR_NULL, 0,
priority, tick);
}
mr_err_t mr_kthread_takeover(mr_kthread_t *kth, const char *name,
const void *res, mr_uint32_t priority,
mr_tick_t tick) {
/* Check arguments */
if ((!kth) || (MR_KOBJECT_IS_INITED(kth)) || (!name) || (!res)) {
return -MR_EINVAL;
}
/* Takeover kthread */
return kthread_takeover(kth, name, res, priority, tick);
}
mr_err_t mr_kthread_del(mr_kthread_t *kth) {
mr_err_t ret;
/* Check arguments */
if ((!kth) || (!MR_KOBJECT_IS_INITED(kth))) {
return -MR_EINVAL;
}
/* Delete kthread */
ret = kthread_del(kth);
if (ret != 0) {
return ret;
}
/* Delete kobject */
mr_kobject_del((mr_kobject_t *)kth);
return 0;
}
MR_INLINE mr_err_t kthread_startup(mr_kthread_t *kth) {
/* Get kobject */
mr_kobject_get((mr_kobject_t *)kth);
/* Startup kthread resource */
return MR_KOS_KTH_OPS(kth->os)->startup((void *)kth->res);
}
mr_err_t mr_kthread_startup(mr_kthread_t *kth) {
/* Check arguments */
if ((!kth) || (!MR_KOBJECT_IS_INITED(kth))) {
return -MR_EINVAL;
}
/* Start kthread */
return kthread_startup(kth);
}
MR_INLINE mr_err_t kthread_resume(mr_kthread_t *kth) {
/* Resume kthread resource */
return MR_KOS_KTH_OPS(kth->os)->resume((void *)kth->res);
}
mr_err_t mr_kthread_resume(mr_kthread_t *kth) {
/* Check arguments */
if ((!kth) || (!MR_KOBJECT_IS_INITED(kth))) {
return -MR_EINVAL;
}
/* Resume kthread */
return kthread_resume(kth);
}
MR_INLINE mr_err_t kthread_yield(void) {
mr_kos_t *kos;
mr_err_t ret;
/* Get kos */
kos = mr_kos_get();
if (!kos) {
return -MR_ENOSYS;
}
/* Yield kthread resource */
ret = MR_KOS_KTH_OPS(kos)->yield();
/* Put kos */
mr_kos_put();
return ret;
}
mr_err_t mr_kthread_yield(void) {
/* Yield kthread */
return kthread_yield();
}
MR_INLINE mr_err_t kthread_suspend(mr_kthread_t *kth) {
/* Suspend kthread resource */
return MR_KOS_KTH_OPS(kth->os)->suspend((void *)kth->res);
}
mr_err_t mr_kthread_suspend(mr_kthread_t *kth) {
/* Check arguments */
if ((!kth) || (!MR_KOBJECT_IS_INITED(kth))) {
return -MR_EINVAL;
}
/* Suspend kthread */
return kthread_suspend(kth);
}
MR_INLINE mr_err_t kthread_sleep(mr_tick_t tick) {
mr_kos_t *kos;
mr_err_t ret;
/* Get kos */
kos = mr_kos_get();
if (!kos) {
return -MR_ENOSYS;
}
/* Sleep kthread resource */
ret = MR_KOS_KTH_OPS(kos)->sleep(tick);
/* Put kos */
mr_kos_put();
return ret;
}
mr_err_t mr_kthread_sleep(mr_tick_t tick) {
/* Sleep kthread */
return kthread_sleep(tick);
}
MR_INLINE mr_err_t kthread_exit(mr_kthread_t *kth) {
/* Exit kthread resource */
return MR_KOS_KTH_OPS(kth->os)->exit((void *)kth->res);
}
mr_err_t mr_kthread_exit(mr_kthread_t *kth) {
/* Check arguments */
if ((!kth) || (!MR_KOBJECT_IS_INITED(kth))) {
return -MR_EINVAL;
}
/* Exit kthread */
return kthread_exit(kth);
}
MR_INLINE mr_kthread_t *kthread_self(void) {
mr_kthread_t *ret;
mr_kos_t *kos;
/* Get kos */
kos = mr_kos_get();
if (!kos) {
return MR_NULL;
}
/* Get kthread self */
ret = MR_KOS_KTH_OPS(mr_kos_get())->self();
/* Put kos */
mr_kos_put();
return ret;
}
mr_kthread_t *mr_kthread_self(void) {
/* Get kthread self */
return kthread_self();
}
mr_kthread_t *mr_kthread_find(const char *name) {
/* Lookup kthread in kroot */
return (mr_kthread_t *)mr_kobject_lookup((mr_kobject_t *)&kroot, name);
}
void mr_kthread_cleanup(mr_kthread_t *kth) {
/* Check arguments */
if ((!kth) || (!MR_KOBJECT_IS_INITED(kth))) {
return;
}
/* Cleanup kthread */
mr_kobject_put((mr_kobject_t *)kth);
}
void mr_kthread_entry(mr_kthread_t *kth) {
/* Check entry */
if (!kth->entry) {
return;
}
/* Call kthread entry */
((void (*)(mr_kthread_t *, void *))kth->entry)(kth, kth->args);
}
MR_INLINE mr_kthread_t *kthread_release_kobj(mr_kobject_t *kobj) {
mr_kthread_t *kth;
const void *res;
/* Get kthread */
kth = MR_CONTAINER_OF(kobj, mr_kthread_t, parent);
/* If resource is inline or takeover, not need to free */
res = ((kth->res != kth->ires) && (kth->entry)) ? kth->res : MR_NULL;
if (res) {
mr_free((void *)res);
}
/* Put kos */
mr_kos_put();
return kth;
}
MR_INLINE void kthread_release1_kobj(mr_kobject_t *kobj) {
/* Release kthread */
kthread_release_kobj(kobj);
}
MR_INLINE void kthread_release2_kobj(mr_kobject_t *kobj) {
mr_kthread_t *kth;
/* Release kobject */
kth = kthread_release_kobj(kobj);
/* Free kthread */
mr_free(kth);
}
MR_INLINE void mr_kthread_kset_init(void) {
/* Register kset */
mr_kset_register(&kroot, "thread");
/* Init ktype */
mr_ktype_init(&ktype1, kthread_release1_kobj);
mr_ktype_init(&ktype2, kthread_release2_kobj);
}
MR_INIT_EXPORT(mr_kthread_kset_init, MR_INIT_LEVEL_KERNEL);

View File

@@ -72,7 +72,6 @@ mr_ktimer_t *mr_ktimer_create(const char *name,
/* Init and add ktimer */
ret = ktimer_init_add(ktimer, &ktype2, name, (mr_ptr_t)entry, args, tick);
if (ret != 0) {
/* Free ktimer */
mr_free(ktimer);
return MR_NULL;
}
@@ -246,13 +245,13 @@ MR_INLINE void ktimer_timeout_check(void) {
mr_klist_move(&ktimer->list, &list);
/* Unlock */
mr_spinlock_unlock(&klock);
mr_spinlock_unlock_irqrestore(&klock, mask);
/* Call ktimer entry */
((void (*)(mr_ktimer_t *, void *))ktimer->entry)(ktimer, ktimer->args);
/* Lock */
mr_spinlock_lock(&klock);
mask = mr_spinlock_lock_irqsave(&klock);
/* Check that the ktimer has not been moved */
if (mr_klist_is_empty(&list)) {

View File

@@ -0,0 +1 @@
from .builder import Builder

41
tools/builder/builder.py Normal file
View File

@@ -0,0 +1,41 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@copyright (c) 2024, MacRsh
@license SPDX-License-Identifier: Apache-2.0
@date 2024-09-06 MacRsh First version
"""
from pathlib import Path
from .parsers import BaseParser
class Builder:
def __init__(self, projdir: Path):
# Choose suitable parser
self.__parser = self._get_parser(projdir)
if self.__parser is None:
raise ValueError("Suitable parser not found.")
self.projdir = projdir
self.incdirs = []
self.srcfiles = []
@staticmethod
def _get_parser(projdir: Path) -> BaseParser | None:
for parser_cls in BaseParser.__subclasses__():
parser = parser_cls(projdir)
if parser.can_handle(projdir):
return parser
return None
def add_include_dir(self, incdir: Path):
self.incdirs.append(incdir)
def add_source_file(self, srcfile: Path):
self.srcfiles.append(srcfile)
def build(self):
self.__parser.build(self.incdirs, self.srcfiles)

View File

@@ -0,0 +1,2 @@
from .base import BaseParser
from .mdk import MdkParser

View File

@@ -0,0 +1,39 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@copyright (c) 2024, MacRsh
@license SPDX-License-Identifier: Apache-2.0
@date 2024-09-06 MacRsh First version
"""
from pathlib import Path
class BaseParser:
def __init__(self, projdir: Path):
self.projdir = projdir
def can_handle(self, projdir: Path) -> bool:
"""
Determines whether the parser can handle the given project directory.
Args:
projdir (Path): The project directory to be checked.
Returns:
bool: True if the parser can handle the project directory, False otherwise.
"""
pass
def build(self, incdirs: list[Path], srcfiles: list[Path]):
"""
Builds the project using the given include directories and source files.
Args:
incdirs (list[Path]): The list of include directories.
srcfiles (list[Path]): The list of source files.
"""
pass

View File

@@ -0,0 +1,85 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@copyright (c) 2024, MacRsh
@license SPDX-License-Identifier: Apache-2.0
@date 2024-09-06 MacRsh First version
"""
import os
from lxml import etree
from pathlib import Path
from .base import BaseParser
class MdkParser(BaseParser):
def __init__(self, projdir: Path):
super().__init__(projdir)
self.projfile: Path | None = None
self.tree: etree.ElementTree = None
def can_handle(self, projdir: Path) -> bool:
# Look for ".uvprojx" files that can be parsed properly
for file in projdir.rglob('*.uvprojx'):
try:
self.projfile = file
self.tree = etree.parse(file)
return True
except:
continue
return False
def build(self, incdirs: list[Path], srcfiles: list[Path]):
self._add_incdirs(incdirs)
self._add_srcfiles(srcfiles)
self._save()
def _add_incdirs(self, incdirs: list[Path]):
projdir = self.projfile.parent
mdk_incdirs = self.tree.xpath("//Cads/VariousControls/IncludePath")
for incdir in incdirs:
incdir = Path(os.path.relpath(incdir, projdir)).as_posix()
if incdir not in mdk_incdirs[0].text.split(';'):
mdk_incdirs[0].text += f";{incdir}"
def _add_srcfiles(self, srcfiles: list[Path]):
projdir = self.projfile.parent
for srcfile in srcfiles:
gid = Path(
os.path.relpath(Path(srcfile).parent, projdir)).relative_to(
"..").as_posix()
file = Path(os.path.relpath(srcfile, projdir))
# Add gid if it doesn't exist
groups_node = self.tree.find('.//Groups')
group_node = groups_node.find(f"./Group[GroupName='{gid}']")
if group_node is None:
group_node = etree.SubElement(groups_node, "Group")
group_name_node = etree.SubElement(group_node, "GroupName")
group_name_node.text = gid
etree.SubElement(group_node, "Files")
# Add file if it doesn't exist
files_node = group_node.find("Files")
file_node = files_node.find(f"./File[FilePath='{file.as_posix()}']")
if file_node is None:
file_node = etree.SubElement(files_node, "File")
file_path_node = file_node.find("FilePath")
if file_path_node is None:
file_path_node = etree.SubElement(file_node, "FilePath")
file_name_node = file_node.find("FileName")
if file_name_node is None:
file_name_node = etree.SubElement(file_node, "FileName")
file_type_node = file_node.find("FileType")
if file_type_node is None:
file_type_node = etree.SubElement(file_node, "FileType")
file_path_node.text = file.as_posix()
file_name_node.text = file.name
file_type_node.text = '1'
def _save(self):
self.tree.write(self.projfile, pretty_print=True, encoding="utf-8",
xml_declaration=True)

0
tools/config/__init__.py Normal file
View File

51
tools/config/kconfig.py Normal file
View File

@@ -0,0 +1,51 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@copyright (c) 2023-2024, MR Development Team
@license SPDX-License-Identifier: Apache-2.0
@date 2023-12-17 MacRsh First version
"""
import re
from pathlib import Path
from kconfiglib import Kconfig
def generate_config(configfile: Path):
kconf = Kconfig("Kconfig", warn=False, warn_to_stderr=False)
# Load config file
kconf.load_config(".config")
kconf.write_config(".config")
kconf.write_autoconf(configfile)
with open(configfile, 'r+') as file:
content = file.read()
file.truncate(0)
file.seek(0)
# Writes file header
file.write("#ifndef __MR_CONFIG_H__\n")
file.write("#define __MR_CONFIG_H__\n\n")
# Writes cplusplus header
file.write("#ifdef __cplusplus\n")
file.write("extern \"C\" {\n")
file.write("#endif /* __cplusplus */\n\n")
# Writes the formatted context
content = content.replace("#define CONFIG_", "#define ")
content = re.sub(r'#define MR_USE_(\w+) (\d+)', r'#define MR_USE_\1',
content)
file.write(content)
# Writes cplusplus footer
file.write("\n#ifdef __cplusplus\n")
file.write("}\n")
file.write("#endif /* __cplusplus */\n\n")
# Writes file footer
file.write("#endif /* __MR_CONFIG_H__ */\n")

3
tools/requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
kconfiglib==14.1.0
lxml==5.2.2
windows-curses==2.3.3

90
tools/tool.py Normal file
View File

@@ -0,0 +1,90 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@copyright (c) 2023-2024, MR Development Team
@license SPDX-License-Identifier: Apache-2.0
@date 2024-07-26 MacRsh First version
"""
import sys
import logging
import argparse
import subprocess
from pathlib import Path
from builder import Builder
from config import kconfig
logging.basicConfig(level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
def _check_python_version():
if sys.version_info < (3, 10):
logging.error(f'Python version must be >= 3.10(current: {sys.version})')
exit(1)
def _find_mrlib() -> Path | None:
for dir in Path(__file__).parents:
if dir.name == 'mr-library':
return dir
return None
def _build(projdir: Path, incdirs: list[Path], srcfiles: list[Path]):
try:
builder = Builder(projdir)
for incdir in incdirs:
builder.add_include_dir(incdir)
for srcfile in srcfiles:
builder.add_source_file(srcfile)
builder.build()
logging.info("Build succeeded")
except Exception as e:
logging.error(f"Error during build: {e}")
exit(1)
def _run_menuconfig(configfile: Path):
try:
subprocess.run(['menuconfig'], stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
kconfig.generate_config(configfile)
logging.info("Menuconfig succeeded")
except Exception as e:
logging.error(f"Error during menuconfig: {e}")
def main():
# Check Python version
_check_python_version()
# Find "mr-library"
mrlib = _find_mrlib()
if mrlib is None:
logging.error('mr-library not found')
return
# Parse arguments
parser = argparse.ArgumentParser()
parser.add_argument('-b', '--build', action='store_true',
help='Build the project')
parser.add_argument('-m', '--menuconfig', action='store_true',
help='Run menuconfig')
args = parser.parse_args()
# Build the project
if args.build:
_build(mrlib.parent, [mrlib], list(mrlib.rglob('*.c')))
# Run menuconfig
if args.menuconfig:
_run_menuconfig(mrlib / 'include' / 'mr_config.h')
if __name__ == '__main__':
main()