Merge branch 'smp' of https://gitlink.org.cn/tuyuyang/xiuos into smp
This commit is contained in:
@@ -31,32 +31,14 @@ Modification:
|
||||
|
||||
context_switch:
|
||||
# store original context to stack
|
||||
str lr, [r13, #-4]!
|
||||
str r12, [r13, #-4]!
|
||||
str r11, [r13, #-4]!
|
||||
str r10, [r13, #-4]!
|
||||
str r9, [r13, #-4]!
|
||||
str r8, [r13, #-4]!
|
||||
str r7, [r13, #-4]!
|
||||
str r6, [r13, #-4]!
|
||||
str r5, [r13, #-4]!
|
||||
str r4, [r13, #-4]!
|
||||
stmfd r13!, {r4-r12, lr}
|
||||
|
||||
# switch the stack
|
||||
str r13, [r0] // save current sp to the old PCB (**old)
|
||||
mov r13, r1 // load the next stack
|
||||
|
||||
# restore context from stack
|
||||
ldr r4, [r13], #4
|
||||
ldr r5, [r13], #4
|
||||
ldr r6, [r13], #4
|
||||
ldr r7, [r13], #4
|
||||
ldr r8, [r13], #4
|
||||
ldr r9, [r13], #4
|
||||
ldr r10, [r13], #4
|
||||
ldr r11, [r13], #4
|
||||
ldr r12, [r13], #4
|
||||
ldr lr, [r13], #4
|
||||
ldmfd r13!, {r4-r12, lr}
|
||||
|
||||
# return to the caller
|
||||
bx lr
|
||||
|
||||
@@ -76,7 +76,7 @@ Modification:
|
||||
|
||||
#define NR_CPU 4
|
||||
|
||||
__attribute__((always_inline)) static inline uint32_t user_mode()
|
||||
__attribute__((always_inline, optimize("O0"))) static inline uint32_t user_mode()
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
@@ -92,6 +92,16 @@ __attribute__((always_inline)) static inline uint32_t user_mode()
|
||||
return val;
|
||||
}
|
||||
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void cpu_into_low_power()
|
||||
{
|
||||
WFE();
|
||||
}
|
||||
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void cpu_leave_low_power()
|
||||
{
|
||||
SEV();
|
||||
}
|
||||
|
||||
struct context {
|
||||
uint32_t r4;
|
||||
uint32_t r5;
|
||||
@@ -103,12 +113,12 @@ struct context {
|
||||
uint32_t r11;
|
||||
uint32_t r12;
|
||||
uint32_t lr;
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
/// @brief init task context, set return address to trap return
|
||||
/// @param
|
||||
extern void task_prepare_enter();
|
||||
__attribute__((__always_inline__)) static inline void arch_init_context(struct context* ctx)
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void arch_init_context(struct context* ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->lr = (uint32_t)(task_prepare_enter + 4);
|
||||
@@ -133,13 +143,13 @@ struct trapframe {
|
||||
uint32_t r11;
|
||||
uint32_t r12;
|
||||
uint32_t pc;
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
/// @brief init task trapframe (*especially the user mode cpsr)
|
||||
/// @param tf
|
||||
/// @param sp
|
||||
/// @param pc
|
||||
__attribute__((__always_inline__)) static inline void arch_init_trapframe(struct trapframe* tf, uintptr_t sp, uintptr_t pc)
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void arch_init_trapframe(struct trapframe* tf, uintptr_t sp, uintptr_t pc)
|
||||
{
|
||||
memset(tf, 0, sizeof(*tf));
|
||||
tf->spsr = user_mode();
|
||||
@@ -153,7 +163,7 @@ __attribute__((__always_inline__)) static inline void arch_init_trapframe(struct
|
||||
/// @param tf
|
||||
/// @param sp
|
||||
/// @param pc
|
||||
__attribute__((__always_inline__)) static inline void arch_trapframe_set_sp_pc(struct trapframe* tf, uintptr_t sp, uintptr_t pc)
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void arch_trapframe_set_sp_pc(struct trapframe* tf, uintptr_t sp, uintptr_t pc)
|
||||
{
|
||||
tf->sp_usr = sp;
|
||||
tf->pc = pc;
|
||||
@@ -163,7 +173,7 @@ __attribute__((__always_inline__)) static inline void arch_trapframe_set_sp_pc(s
|
||||
/// @param tf
|
||||
/// @param argc
|
||||
/// @param argv
|
||||
__attribute__((__always_inline__)) static inline void arch_set_main_params(struct trapframe* tf, int argc, uintptr_t argv)
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void arch_set_main_params(struct trapframe* tf, int argc, uintptr_t argv)
|
||||
{
|
||||
tf->r0 = (uint32_t)argc;
|
||||
tf->r1 = (uint32_t)argv;
|
||||
@@ -178,7 +188,7 @@ __attribute__((__always_inline__)) static inline void arch_set_main_params(struc
|
||||
/// @param param5
|
||||
/// @return
|
||||
extern int syscall(int sys_num, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4);
|
||||
__attribute__((__always_inline__)) static inline int arch_syscall(struct trapframe* tf, int* syscall_num)
|
||||
__attribute__((always_inline, optimize("O0"))) static inline int arch_syscall(struct trapframe* tf, int* syscall_num)
|
||||
{
|
||||
// call syscall
|
||||
*syscall_num = tf->r0;
|
||||
@@ -188,7 +198,7 @@ __attribute__((__always_inline__)) static inline int arch_syscall(struct trapfra
|
||||
/// @brief set return reg to trapframe
|
||||
/// @param tf
|
||||
/// @param ret
|
||||
__attribute__((__always_inline__)) static inline void arch_set_return(struct trapframe* tf, int ret)
|
||||
__attribute__((always_inline, optimize("O0"))) static inline void arch_set_return(struct trapframe* tf, int ret)
|
||||
{
|
||||
tf->r0 = (uint32_t)ret;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export CROSS_COMPILE ?= arm-none-eabi-
|
||||
export DEVICE = -march=armv7-a -mtune=cortex-a9 -mfpu=vfpv3-d16 -ftree-vectorize -ffast-math -mfloat-abi=softfp
|
||||
export CFLAGS := $(DEVICE) -Wall -O0 -g -gdwarf-2
|
||||
export CFLAGS := $(DEVICE) -Wall -O2 -g -gdwarf-2 -Wnull-dereference -Waddress -Warray-bounds -Wchar-subscripts -Wimplicit-int -Wimplicit-function-declaration -Wcomment -Wformat -Wmissing-braces -Wnonnull -Wparentheses -Wpointer-sign -Wreturn-type -Wsequence-point -Wstrict-aliasing -Wstrict-overflow=1 -Wswitch -Wtrigraphs -Wuninitialized -Wunknown-pragmas -Wunused-function -Wunused-label -Wunused-value -Wunused-variable -Wunused-function
|
||||
export AFLAGS := -c $(DEVICE) -x assembler-with-cpp -D__ASSEMBLY__ -gdwarf-2
|
||||
# export LFLAGS := $(DEVICE) -Wl,-Map=XiZi-imx6q-sabrelite.map,-cref,-u,_boot_start -T $(KERNEL_ROOT)/hardkernel/arch/arm/armv7-a/cortex-a9/preboot_for_imx6q-sabrelite/nxp_imx6q_sabrelite.lds
|
||||
export LFLAGS := $(DEVICE) --specs=nosys.specs -Wl,-Map=XiZi-imx6q-sabrelite.map,-cref,-u,_boot_start -T $(KERNEL_ROOT)/hardkernel/arch/arm/armv7-a/cortex-a9/preboot_for_imx6q-sabrelite/nxp_imx6q_sabrelite.lds
|
||||
|
||||
@@ -77,6 +77,10 @@ BOOT_STACK_SIZE = 0x4000;
|
||||
RAM_VECTORS_SIZE = 72;
|
||||
|
||||
/* Specify the memory areas */
|
||||
/*
|
||||
ddr3: physical area: [0x10000000, 0x50000000);
|
||||
virt_ddr3: virt area exclude boot(start_sec), that will be [0x90000000 + 0x11000, 0xD0000000)
|
||||
*/
|
||||
MEMORY
|
||||
{
|
||||
ocram (rwx) : ORIGIN = 0x00900000, LENGTH = 256K
|
||||
@@ -154,7 +158,7 @@ SECTIONS
|
||||
PROVIDE(boot_end_addr = .);
|
||||
} > ddr3
|
||||
|
||||
/* Other Kernel code is placed over 0x80000000 + 128KB. */
|
||||
/* Other Kernel code is placed over 0x10011000(phy) and 0x90011000(virt). */
|
||||
.text : AT(0x10011000) {
|
||||
*(.vectors)
|
||||
. = ALIGN(0x1000);
|
||||
|
||||
@@ -40,24 +40,8 @@ static void _sys_clock_init()
|
||||
{
|
||||
uint32_t freq = get_main_clock(IPG_CLK);
|
||||
gpt_init(CLKSRC_IPG_CLK, freq / 1000000, RESTART_MODE, WAIT_MODE_EN | STOP_MODE_EN);
|
||||
switch (cur_cpuid()) {
|
||||
case 0:
|
||||
gpt_set_compare_event(kGPTOutputCompare1, OUTPUT_CMP_DISABLE, 1000);
|
||||
gpt_counter_enable(kGPTOutputCompare1);
|
||||
break;
|
||||
case 1:
|
||||
gpt_set_compare_event(kGPTOutputCompare2, OUTPUT_CMP_DISABLE, 1000);
|
||||
gpt_counter_enable(kGPTOutputCompare2);
|
||||
break;
|
||||
case 2:
|
||||
gpt_set_compare_event(kGPTOutputCompare3, OUTPUT_CMP_DISABLE, 1000);
|
||||
gpt_counter_enable(kGPTOutputCompare3);
|
||||
break;
|
||||
case 3:
|
||||
gpt_set_compare_event(kGPTOutputCompare1, OUTPUT_CMP_DISABLE, 1000);
|
||||
gpt_counter_enable(kGPTOutputCompare1);
|
||||
break;
|
||||
}
|
||||
gpt_set_compare_event(kGPTOutputCompare1, OUTPUT_CMP_DISABLE, 1000);
|
||||
gpt_counter_enable(kGPTOutputCompare1);
|
||||
}
|
||||
|
||||
static uint32_t _get_clock_int()
|
||||
|
||||
@@ -218,10 +218,7 @@ bool secondary_cpu_hardkernel_init(int cpu_id, struct TraceTag* _hardkernel_tag)
|
||||
// cache
|
||||
p_icache_driver->enable();
|
||||
p_dcache_driver->enable();
|
||||
// p_icache_driver->disable();
|
||||
// p_dcache_driver->disable();
|
||||
// clock
|
||||
// p_clock_driver->sys_clock_init();
|
||||
p_intr_driver->single_irq_enable(p_clock_driver->get_clock_int(), cpu_id, 0);
|
||||
// mmu
|
||||
secondary_cpu_load_kern_pgdir(&init_mmu_tag, &init_intr_tag);
|
||||
|
||||
@@ -41,32 +41,18 @@ Modification:
|
||||
*************************************************/
|
||||
#include "core.h"
|
||||
#include "memlayout.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "multicores.h"
|
||||
#include "spinlock.h"
|
||||
#include "syscall.h"
|
||||
#include "trap_common.h"
|
||||
|
||||
__attribute__((always_inline)) static inline void _abort_reason(uint32_t fault_status)
|
||||
{
|
||||
if ((fault_status & 0xd) == 0x1) // Alignment failure
|
||||
KPrintf("reason: alignment\n");
|
||||
else if ((fault_status & 0xd) == 0x5) // External abort "on translation"
|
||||
KPrintf("reason: ext. abort on trnslt.\n");
|
||||
else if ((fault_status & 0xd) == 0x5) // Translation
|
||||
KPrintf("reason: sect. translation\n");
|
||||
else if ((fault_status & 0xd) == 0x9) // Domain
|
||||
KPrintf("reason: sect. domain\n");
|
||||
else if ((fault_status & 0xd) == 0xd) // Permission
|
||||
KPrintf("reason: sect. permission\n");
|
||||
else if ((fault_status & 0xd) == 0x8) // External abort
|
||||
KPrintf("reason: ext. abort\n");
|
||||
else
|
||||
KPrintf("reason: unknown???\n");
|
||||
}
|
||||
#include "assert.h"
|
||||
#include "multicores.h"
|
||||
#include "syscall.h"
|
||||
#include "task.h"
|
||||
|
||||
void dump_tf(struct trapframe* tf)
|
||||
{
|
||||
KPrintf("sp_usr: 0x%x\n", tf->sp_usr);
|
||||
KPrintf("lr_usr: 0x%x\n", tf->lr_usr);
|
||||
KPrintf("lr_svc: 0x%x\n", tf->lr_svc);
|
||||
KPrintf(" spsr: 0x%x\n", tf->spsr);
|
||||
KPrintf(" r0: 0x%x\n", tf->r0);
|
||||
@@ -85,64 +71,76 @@ void dump_tf(struct trapframe* tf)
|
||||
KPrintf(" pc: 0x%x\n", tf->pc);
|
||||
}
|
||||
|
||||
void dabort_reason(struct trapframe* r)
|
||||
{
|
||||
uint32_t fault_status, dfa;
|
||||
__asm__ __volatile__("mrc p15, 0, %0, c5, c0, 0" : "=r"(fault_status)::);
|
||||
__asm__ __volatile__("mrc p15, 0, %0, c6, c0, 0" : "=r"(dfa)::);
|
||||
LOG("program counter: 0x%x caused\n", r->pc);
|
||||
LOG("data abort at 0x%x, status 0x%x\n", dfa, fault_status);
|
||||
|
||||
if ((fault_status & 0xd) == 0x1) // Alignment failure
|
||||
KPrintf("reason: alignment\n");
|
||||
else if ((fault_status & 0xd) == 0x5) // External abort "on translation"
|
||||
KPrintf("reason: ext. abort on trnslt.\n");
|
||||
else if ((fault_status & 0xd) == 0x5) // Translation
|
||||
KPrintf("reason: sect. translation\n");
|
||||
else if ((fault_status & 0xd) == 0x9) // Domain
|
||||
KPrintf("reason: sect. domain\n");
|
||||
else if ((fault_status & 0xd) == 0xd) // Permission
|
||||
KPrintf("reason: sect. permission\n");
|
||||
else if ((fault_status & 0xd) == 0x8) // External abort
|
||||
KPrintf("reason: ext. abort\n");
|
||||
else
|
||||
KPrintf("reason: unknown???\n");
|
||||
|
||||
dump_tf(r);
|
||||
}
|
||||
|
||||
void iabort_reason(struct trapframe* r)
|
||||
{
|
||||
uint32_t fault_status, ifa;
|
||||
__asm__ __volatile__("mrc p15, 0, %0, c5, c0, 1" : "=r"(fault_status)::);
|
||||
__asm__ __volatile__("mrc p15, 0, %0, c6, c0, 2" : "=r"(ifa)::);
|
||||
LOG("prefetch abort at 0x%x, status 0x%x\n", ifa, fault_status);
|
||||
|
||||
if ((fault_status & 0xd) == 0x1) // Alignment failure
|
||||
KPrintf("reason: alignment\n");
|
||||
else if ((fault_status & 0xd) == 0x5) // External abort "on translation"
|
||||
KPrintf("reason: ext. abort on trnslt.\n");
|
||||
else if ((fault_status & 0xd) == 0x5) // Translation
|
||||
KPrintf("reason: sect. translation\n");
|
||||
else if ((fault_status & 0xd) == 0x9) // Domain
|
||||
KPrintf("reason: sect. domain\n");
|
||||
else if ((fault_status & 0xd) == 0xd) // Permission
|
||||
KPrintf("reason: sect. permission\n");
|
||||
else if ((fault_status & 0xd) == 0x8) // External abort
|
||||
KPrintf("reason: ext. abort\n");
|
||||
else
|
||||
KPrintf("reason: unknown???\n");
|
||||
|
||||
dump_tf(r);
|
||||
}
|
||||
|
||||
void handle_undefined_instruction(struct trapframe* tf)
|
||||
{
|
||||
// unimplemented trap handler
|
||||
KPrintf("undefined instruction at %x\n", tf->pc);
|
||||
ERROR("undefined instruction at %x\n", tf->pc);
|
||||
xizi_enter_kernel();
|
||||
panic("");
|
||||
}
|
||||
|
||||
extern void context_switch(struct context**, struct context*);
|
||||
void dabort_handler(struct trapframe* r)
|
||||
void handle_reserved(void)
|
||||
{
|
||||
if (!is_spinlock_locked(&whole_kernel_lock) || whole_kernel_lock.owner_cpu != cur_cpuid()) {
|
||||
spinlock_lock(&whole_kernel_lock);
|
||||
}
|
||||
uint32_t dfs, dfa;
|
||||
|
||||
__asm__ __volatile__("mrc p15, 0, %0, c5, c0, 0" : "=r"(dfs)::);
|
||||
__asm__ __volatile__("mrc p15, 0, %0, c6, c0, 0" : "=r"(dfa)::);
|
||||
|
||||
if (r->pc < KERN_MEM_BASE) { // Exception occured in User space: exit
|
||||
ERROR("dabort in user space: %s\n", cur_cpu()->task->name);
|
||||
LOG("program counter: 0x%x caused\n", r->pc);
|
||||
LOG("data abort at 0x%x, status 0x%x\n", dfa, dfs);
|
||||
_abort_reason(dfs);
|
||||
dump_tf(r);
|
||||
sys_exit(cur_cpu()->task);
|
||||
context_switch(&cur_cpu()->task->main_thread.context, cur_cpu()->scheduler);
|
||||
} else { // Exception occured in Kernel space: panic
|
||||
LOG("program counter: 0x%x caused\n", r->pc);
|
||||
LOG("data abort at 0x%x, status 0x%x\n", dfa, dfs);
|
||||
_abort_reason(dfs);
|
||||
dump_tf(r);
|
||||
panic("data abort exception\n");
|
||||
}
|
||||
// unimplemented trap handler
|
||||
ERROR("Unimplemented Reserved\n");
|
||||
xizi_enter_kernel();
|
||||
panic("");
|
||||
}
|
||||
|
||||
void iabort_handler(struct trapframe* r)
|
||||
void handle_fiq(void)
|
||||
{
|
||||
if (!is_spinlock_locked(&whole_kernel_lock) || whole_kernel_lock.owner_cpu != cur_cpuid()) {
|
||||
spinlock_lock(&whole_kernel_lock);
|
||||
}
|
||||
uint32_t ifs, ifa;
|
||||
|
||||
__asm__ __volatile__("mrc p15, 0, %0, c5, c0, 1" : "=r"(ifs)::);
|
||||
__asm__ __volatile__("mrc p15, 0, %0, c6, c0, 2" : "=r"(ifa)::);
|
||||
|
||||
if (r->pc < KERN_MEM_BASE) { // Exception occured in User space: exit
|
||||
ERROR("iabort in user space: %s\n", cur_cpu()->task->name);
|
||||
LOG("program counter: 0x%x(%s) caused\n", r->pc, cur_cpu()->task);
|
||||
LOG("prefetch abort at 0x%x, status 0x%x\n", ifa, ifs);
|
||||
_abort_reason(ifs);
|
||||
dump_tf(r);
|
||||
sys_exit(cur_cpu()->task);
|
||||
context_switch(&cur_cpu()->task->main_thread.context, cur_cpu()->scheduler);
|
||||
} else { // Exception occured in Kernel space: panic
|
||||
LOG("program counter: 0x%x(%s) caused\n", r->pc, cur_cpu()->task);
|
||||
LOG("prefetch abort at 0x%x, status 0x%x\n", ifa, ifs);
|
||||
_abort_reason(ifs);
|
||||
dump_tf(r);
|
||||
panic("prefetch abort exception\n");
|
||||
}
|
||||
}
|
||||
ERROR("Unimplemented FIQ\n");
|
||||
xizi_enter_kernel();
|
||||
panic("");
|
||||
}
|
||||
@@ -45,6 +45,8 @@ Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. take only gicd part of functions
|
||||
*************************************************/
|
||||
#include "string.h"
|
||||
|
||||
#include "gicv2_common_opa.h"
|
||||
#include "gicv2_registers.h"
|
||||
|
||||
@@ -139,7 +141,7 @@ void gic_send_sgi(uint32_t irqID, uint32_t target_list, uint32_t filter_list)
|
||||
|
||||
void gic_init(void)
|
||||
{
|
||||
gicd_t* gicd = gic_get_gicd();
|
||||
volatile gicd_t* gicd = gic_get_gicd();
|
||||
|
||||
// First disable the distributor.
|
||||
gic_enable(false);
|
||||
@@ -150,7 +152,9 @@ void gic_init(void)
|
||||
|
||||
for (uint32_t i = 0; i < 255; i++) {
|
||||
*(uint32_t*)(&gicd->IPRIORITYRn[i * sizeof(uint32_t)]) = (uint32_t)0x80808080;
|
||||
// memset((void*)&gicd->IPRIORITYRn[i * sizeof(uint32_t)], 0x80, sizeof(uint32_t));
|
||||
*(uint32_t*)(&gicd->ITARGETSRn[i * sizeof(uint32_t)]) = (uint32_t)0x01010101;
|
||||
// memset((void*)&gicd->IPRIORITYRn[i * sizeof(uint32_t)], 0x01, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// Init the GIC CPU interface.
|
||||
|
||||
@@ -42,13 +42,13 @@ extern void trap_iabort(void);
|
||||
extern void trap_dabort(void);
|
||||
extern void trap_irq_enter(void);
|
||||
extern void trap_undefined_instruction(void);
|
||||
extern void handle_reserved(void);
|
||||
extern void handle_fiq(void);
|
||||
|
||||
static struct XiziTrapDriver xizi_trap_driver;
|
||||
|
||||
void panic(char* s)
|
||||
{
|
||||
xizi_trap_driver.cpu_irq_disable();
|
||||
spinlock_unlock(&whole_kernel_lock);
|
||||
KPrintf("panic: %s\n", s);
|
||||
for (;;)
|
||||
;
|
||||
@@ -56,7 +56,6 @@ void panic(char* s)
|
||||
|
||||
/* stack for different mode*/
|
||||
static char mode_stack_pages[NR_CPU][NR_MODE_STACKS][MODE_STACK_SIZE];
|
||||
|
||||
extern uint32_t _vector_jumper;
|
||||
extern uint32_t _vector_start;
|
||||
extern uint32_t _vector_end;
|
||||
@@ -71,19 +70,6 @@ void init_cpu_mode_stacks(int cpu_id)
|
||||
}
|
||||
}
|
||||
|
||||
void handle_reserved(void)
|
||||
{
|
||||
// unimplemented trap handler
|
||||
LOG("Unimplemented Reserved\n");
|
||||
panic("");
|
||||
}
|
||||
|
||||
void handle_fiq(void)
|
||||
{
|
||||
LOG("Unimplemented FIQ\n");
|
||||
panic("");
|
||||
}
|
||||
|
||||
static void _sys_irq_init(int cpu_id)
|
||||
{
|
||||
/* load exception vectors */
|
||||
@@ -99,9 +85,10 @@ static void _sys_irq_init(int cpu_id)
|
||||
vector_base[5] = (uint32_t)handle_reserved; // Reserved
|
||||
vector_base[6] = (uint32_t)trap_irq_enter; // IRQ
|
||||
vector_base[7] = (uint32_t)handle_fiq; // FIQ
|
||||
|
||||
gic_init();
|
||||
}
|
||||
/* active hardware irq responser */
|
||||
gic_init();
|
||||
xizi_trap_driver.switch_hw_irqtbl((uint32_t*)&_vector_jumper);
|
||||
}
|
||||
|
||||
@@ -153,29 +140,6 @@ static void _bind_irq_handler(int irq, irq_handler_t handler)
|
||||
xizi_trap_driver.sw_irqtbl[irq].handler = handler;
|
||||
}
|
||||
|
||||
static bool _send_sgi(uint32_t irq, uint32_t bitmask, enum SgiFilterType type)
|
||||
{
|
||||
if (bitmask > (1 << NR_CPU) - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
enum _gicd_sgi_filter sgi_filter;
|
||||
switch (type) {
|
||||
case SgiFilter_TargetList:
|
||||
sgi_filter = kGicSgiFilter_UseTargetList;
|
||||
break;
|
||||
case SgiFilter_AllOtherCPUs:
|
||||
sgi_filter = kGicSgiFilter_AllOtherCPUs;
|
||||
break;
|
||||
default:
|
||||
sgi_filter = kGicSgiFilter_OnlyThisCPU;
|
||||
break;
|
||||
}
|
||||
gic_send_sgi(irq, bitmask, sgi_filter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t _hw_before_irq()
|
||||
{
|
||||
|
||||
@@ -192,29 +156,11 @@ static uint32_t _hw_cur_int_num(uint32_t int_info)
|
||||
return int_info & 0x1FF;
|
||||
}
|
||||
|
||||
static uint32_t _hw_cur_int_cpu(uint32_t int_info)
|
||||
{
|
||||
return (int_info >> 10) & 0x7;
|
||||
}
|
||||
|
||||
static void _hw_after_irq(uint32_t int_info)
|
||||
{
|
||||
gic_write_end_of_irq(int_info);
|
||||
}
|
||||
|
||||
static int _is_interruptable(void)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"mrs %0, cpsr"
|
||||
: "=r"(val)
|
||||
:
|
||||
:);
|
||||
|
||||
return !(val & DIS_INT);
|
||||
}
|
||||
|
||||
int _cur_cpu_id()
|
||||
{
|
||||
return cpu_get_current();
|
||||
@@ -231,12 +177,9 @@ static struct XiziTrapDriver xizi_trap_driver = {
|
||||
.switch_hw_irqtbl = _switch_hw_irqtbl,
|
||||
|
||||
.bind_irq_handler = _bind_irq_handler,
|
||||
.send_sgi = _send_sgi,
|
||||
|
||||
.is_interruptable = _is_interruptable,
|
||||
.hw_before_irq = _hw_before_irq,
|
||||
.hw_cur_int_num = _hw_cur_int_num,
|
||||
.hw_cur_int_cpu = _hw_cur_int_cpu,
|
||||
.hw_after_irq = _hw_after_irq,
|
||||
};
|
||||
|
||||
|
||||
@@ -47,43 +47,17 @@ trap_return:
|
||||
ldmfd r13!, {r14}
|
||||
ldmfd r13!, {r2}
|
||||
msr spsr_cxsf, r2
|
||||
ldr r0, [r13], #4
|
||||
ldr r1, [r13], #4
|
||||
ldr r2, [r13], #4
|
||||
ldr r3, [r13], #4
|
||||
ldr r4, [r13], #4
|
||||
ldr r5, [r13], #4
|
||||
ldr r6, [r13], #4
|
||||
ldr r7, [r13], #4
|
||||
ldr r8, [r13], #4
|
||||
ldr r9, [r13], #4
|
||||
ldr r10, [r13], #4
|
||||
ldr r11, [r13], #4
|
||||
ldr r12, [r13], #4
|
||||
ldm r13!, {pc}^
|
||||
ldmfd r13!, {r0-r12, pc}^ // restore context and return
|
||||
|
||||
user_trap_swi_enter:
|
||||
# save trapframe to swi stack
|
||||
sub sp, sp, #56
|
||||
str r14, [sp, #52]
|
||||
str r12, [sp, #48]
|
||||
str r11, [sp, #44]
|
||||
str r10, [sp, #40]
|
||||
str r9, [sp, #36]
|
||||
str r8, [sp, #32]
|
||||
str r7, [sp, #28]
|
||||
str r6, [sp, #24]
|
||||
str r5, [sp, #20]
|
||||
str r4, [sp, #16]
|
||||
str r3, [sp, #12]
|
||||
str r2, [sp, #8]
|
||||
str r1, [sp, #4]
|
||||
str r0, [sp]
|
||||
# save trapframe to swi stack
|
||||
cpsid i
|
||||
stmfd sp!, {r0-r12, r14} // save context
|
||||
mrs r2, spsr // copy spsr to r2
|
||||
stmfd r13!, {r2} // save r2(spsr) to the stack
|
||||
|
||||
mrs r2, spsr
|
||||
stmfd r13!, {r2}
|
||||
stmfd r13!, {r14}
|
||||
stmfd r13, {sp, lr}^
|
||||
stmfd r13!, {r14} // save r14 again to have one uniform trapframe
|
||||
stmfd r13, {sp, lr}^ // save user mode sp and lr
|
||||
sub r13, r13, #8
|
||||
|
||||
# call syscall handler
|
||||
@@ -92,17 +66,13 @@ user_trap_swi_enter:
|
||||
b trap_return
|
||||
|
||||
trap_irq_enter:
|
||||
# save context in irq stack
|
||||
sub r14, r14, #4
|
||||
sub sp, sp, #16
|
||||
str r14, [sp, #12]
|
||||
str r2, [sp, #8]
|
||||
str r1, [sp, #4]
|
||||
str r0, [sp]
|
||||
|
||||
mrs r1, spsr
|
||||
mov r0, r13 // irq stack stop
|
||||
add r13, r13, #16 // reset IRQ stack
|
||||
# save it on the stack as r14 is banked
|
||||
cpsid i
|
||||
sub r14, r14, #4 // r14 (lr) contains the interrupted PC
|
||||
stmfd r13!, {r0-r2, r14} //
|
||||
mrs r1, spsr // save spsr_irq
|
||||
mov r0, r13 // save stack stop (r13_irq)
|
||||
add r13, r13, #16 // reset the IRQ stack
|
||||
|
||||
# switch to the SVC mode
|
||||
mrs r2, cpsr
|
||||
@@ -111,134 +81,110 @@ trap_irq_enter:
|
||||
msr cpsr_cxsf, r2
|
||||
|
||||
# build the trap frame
|
||||
ldr r2, [r0, #12]
|
||||
ldr r2, [r0, #12] // read the r14_irq, then save it
|
||||
stmfd r13!, {r2}
|
||||
sub r13, r13, #40
|
||||
str r12, [r13, #36]
|
||||
str r11, [r13, #32]
|
||||
str r10, [r13, #28]
|
||||
str r9, [r13, #24]
|
||||
str r8, [r13, #20]
|
||||
str r7, [r13, #16]
|
||||
str r6, [r13, #12]
|
||||
str r5, [r13, #8]
|
||||
str r4, [r13, #4]
|
||||
str r3, [r13]
|
||||
|
||||
ldmfd r0, {r3-r5}
|
||||
stmfd r13!, {r3-r12} // r4-r12 are preserved (non-banked)
|
||||
ldmfd r0, {r3-r5} // copy r0-r2 over from irq stack
|
||||
stmfd r13!, {r3-r5}
|
||||
stmfd r13!, {r1}
|
||||
stmfd r13!, {lr}
|
||||
stmfd r13, {sp, lr}^
|
||||
stmfd r13!, {r1} // save spsr
|
||||
stmfd r13!, {lr} // save lr_svc
|
||||
|
||||
stmfd r13, {sp, lr}^ // save user mode sp and lr
|
||||
sub r13, r13, #8
|
||||
|
||||
mov r0, r13 // trapframe as parameters
|
||||
bl intr_irq_dispatch
|
||||
b trap_return
|
||||
|
||||
trap_reset_enter:
|
||||
mov r14, #0
|
||||
sub r13, r13, #56
|
||||
str r14, [r13, #52]
|
||||
str r12, [r13, #48]
|
||||
str r11, [r13, #44]
|
||||
str r10, [r13, #40]
|
||||
str r9, [r13, #36]
|
||||
str r8, [r13, #32]
|
||||
str r7, [r13, #28]
|
||||
str r6, [r13, #24]
|
||||
str r5, [r13, #20]
|
||||
str r4, [r13, #16]
|
||||
str r3, [r13, #12]
|
||||
str r2, [r13, #8]
|
||||
str r1, [r13, #4]
|
||||
str r0, [r13]
|
||||
|
||||
mrs r2, spsr
|
||||
stmfd r13!, {r2}
|
||||
stmfd r13!, {r14}
|
||||
stmfd r13, {sp, lr}^
|
||||
sub r13, r13, #8
|
||||
mov r0, r13
|
||||
bl _vector_jumper
|
||||
|
||||
trap_dabort:
|
||||
sub r14, r14, #8
|
||||
sub r13, r13, #56
|
||||
str r14, [r13, #52]
|
||||
str r12, [r13, #48]
|
||||
str r11, [r13, #44]
|
||||
str r10, [r13, #40]
|
||||
str r9, [r13, #36]
|
||||
str r8, [r13, #32]
|
||||
str r7, [r13, #28]
|
||||
str r6, [r13, #24]
|
||||
str r5, [r13, #20]
|
||||
str r4, [r13, #16]
|
||||
str r3, [r13, #12]
|
||||
str r2, [r13, #8]
|
||||
str r1, [r13, #4]
|
||||
str r0, [r13]
|
||||
# save it on the stack as r14 is banked
|
||||
cpsid i
|
||||
sub r14, r14, #8 // r14 (lr) contains the interrupted PC
|
||||
stmfd r13!, {r0-r2, r14} //
|
||||
mrs r1, spsr // save spsr_irq
|
||||
mov r0, r13 // save stack stop (r13_irq)
|
||||
add r13, r13, #16 // reset the IRQ stack
|
||||
|
||||
mrs r2, spsr
|
||||
stmfd r13!, {r2}
|
||||
stmfd r13!, {r14}
|
||||
stmfd r13, {sp, lr}^
|
||||
# switch to the SVC mode
|
||||
mrs r2, cpsr
|
||||
bic r2, r2, #ARM_CPSR_MODE_MASK
|
||||
orr r2, r2, #ARM_MODE_SVC
|
||||
msr cpsr_cxsf, r2
|
||||
|
||||
# build the trap frame
|
||||
ldr r2, [r0, #12] // read the r14_irq, then save it
|
||||
stmfd r13!, {r2}
|
||||
stmfd r13!, {r3-r12} // r4-r12 are preserved (non-banked)
|
||||
ldmfd r0, {r3-r5} // copy r0-r2 over from irq stack
|
||||
stmfd r13!, {r3-r5}
|
||||
stmfd r13!, {r1} // save spsr
|
||||
stmfd r13!, {lr} // save lr_svc
|
||||
|
||||
stmfd r13, {sp, lr}^ // save user mode sp and lr
|
||||
sub r13, r13, #8
|
||||
mov r0, r13
|
||||
|
||||
mov r0, r13 // trapframe as parameters
|
||||
bl dabort_handler
|
||||
|
||||
trap_iabort:
|
||||
sub r14, r14, #4
|
||||
sub r13, r13, #56
|
||||
str r14, [r13, #52]
|
||||
str r12, [r13, #48]
|
||||
str r11, [r13, #44]
|
||||
str r10, [r13, #40]
|
||||
str r9, [r13, #36]
|
||||
str r8, [r13, #32]
|
||||
str r7, [r13, #28]
|
||||
str r6, [r13, #24]
|
||||
str r5, [r13, #20]
|
||||
str r4, [r13, #16]
|
||||
str r3, [r13, #12]
|
||||
str r2, [r13, #8]
|
||||
str r1, [r13, #4]
|
||||
str r0, [r13]
|
||||
# save it on the stack as r14 is banked
|
||||
cpsid i
|
||||
sub r14, r14, #4 // r14 (lr) contains the interrupted PC
|
||||
stmfd r13!, {r0-r2, r14} //
|
||||
mrs r1, spsr // save spsr_irq
|
||||
mov r0, r13 // save stack stop (r13_irq)
|
||||
add r13, r13, #16 // reset the IRQ stack
|
||||
|
||||
mrs r2, spsr
|
||||
# switch to the SVC mode
|
||||
mrs r2, cpsr
|
||||
bic r2, r2, #ARM_CPSR_MODE_MASK
|
||||
orr r2, r2, #ARM_MODE_SVC
|
||||
msr cpsr_cxsf, r2
|
||||
|
||||
# build the trap frame
|
||||
ldr r2, [r0, #12] // read the r14_irq, then save it
|
||||
stmfd r13!, {r2}
|
||||
stmfd r13!, {r14}
|
||||
stmfd r13, {sp, lr}^
|
||||
stmfd r13!, {r3-r12} // r4-r12 are preserved (non-banked)
|
||||
ldmfd r0, {r3-r5} // copy r0-r2 over from irq stack
|
||||
stmfd r13!, {r3-r5}
|
||||
stmfd r13!, {r1} // save spsr
|
||||
stmfd r13!, {lr} // save lr_svc
|
||||
|
||||
stmfd r13, {sp, lr}^ // save user mode sp and lr
|
||||
sub r13, r13, #8
|
||||
mov r0, r13
|
||||
|
||||
mov r0, r13 // trapframe as parameters
|
||||
bl iabort_handler
|
||||
|
||||
trap_undefined_instruction:
|
||||
sub r13, r13, #56
|
||||
str r14, [r13, #52]
|
||||
str r12, [r13, #48]
|
||||
str r11, [r13, #44]
|
||||
str r10, [r13, #40]
|
||||
str r9, [r13, #36]
|
||||
str r8, [r13, #32]
|
||||
str r7, [r13, #28]
|
||||
str r6, [r13, #24]
|
||||
str r5, [r13, #20]
|
||||
str r4, [r13, #16]
|
||||
str r3, [r13, #12]
|
||||
str r2, [r13, #8]
|
||||
str r1, [r13, #4]
|
||||
str r0, [r13]
|
||||
# save it on the stack as r14 is banked
|
||||
cpsid i
|
||||
sub r14, r14, #4 // r14 (lr) contains the interrupted PC
|
||||
stmfd r13!, {r0-r2, r14} //
|
||||
mrs r1, spsr // save spsr_irq
|
||||
mov r0, r13 // save stack stop (r13_irq)
|
||||
add r13, r13, #16 // reset the IRQ stack
|
||||
|
||||
mrs r2, spsr
|
||||
# switch to the SVC mode
|
||||
mrs r2, cpsr
|
||||
bic r2, r2, #ARM_CPSR_MODE_MASK
|
||||
orr r2, r2, #ARM_MODE_SVC
|
||||
msr cpsr_cxsf, r2
|
||||
|
||||
# build the trap frame
|
||||
ldr r2, [r0, #12] // read the r14_irq, then save it
|
||||
stmfd r13!, {r2}
|
||||
stmfd r13!, {r14}
|
||||
stmfd r13, {sp, lr}^
|
||||
sub r13, r13, #8
|
||||
mov r0, r13
|
||||
bl handle_undefined_instruction
|
||||
stmfd r13!, {r3-r12} // r4-r12 are preserved (non-banked)
|
||||
ldmfd r0, {r3-r5} // copy r0-r2 over from irq stack
|
||||
stmfd r13!, {r3-r5}
|
||||
stmfd r13!, {r1} // save spsr
|
||||
stmfd r13!, {lr} // save lr_svc
|
||||
|
||||
stmfd r13, {sp, lr}^ // save user mode sp and lr
|
||||
sub r13, r13, #8
|
||||
|
||||
mov r0, r13 // trapframe as parameters
|
||||
bl handle_undefined_instruction
|
||||
|
||||
init_stack:
|
||||
# set the stack for Other mode
|
||||
|
||||
@@ -42,12 +42,13 @@ extern void trap_iabort(void);
|
||||
extern void trap_dabort(void);
|
||||
extern void trap_irq_enter(void);
|
||||
extern void trap_undefined_instruction(void);
|
||||
extern void handle_reserved(void);
|
||||
extern void handle_fiq(void);
|
||||
|
||||
static struct XiziTrapDriver xizi_trap_driver;
|
||||
|
||||
void panic(char* s)
|
||||
{
|
||||
xizi_trap_driver.cpu_irq_disable();
|
||||
KPrintf("panic: %s\n", s);
|
||||
for (;;)
|
||||
;
|
||||
@@ -55,7 +56,6 @@ void panic(char* s)
|
||||
|
||||
/* stack for different mode*/
|
||||
static char mode_stack_pages[NR_CPU][NR_MODE_STACKS][MODE_STACK_SIZE];
|
||||
|
||||
extern uint32_t _vector_jumper;
|
||||
extern uint32_t _vector_start;
|
||||
extern uint32_t _vector_end;
|
||||
@@ -72,19 +72,6 @@ void init_cpu_mode_stacks(int cpu_id)
|
||||
}
|
||||
}
|
||||
|
||||
void handle_reserved(void)
|
||||
{
|
||||
// unimplemented trap handler
|
||||
LOG("Unimplemented Reserved\n");
|
||||
panic("");
|
||||
}
|
||||
|
||||
void handle_fiq(void)
|
||||
{
|
||||
LOG("Unimplemented FIQ\n");
|
||||
panic("");
|
||||
}
|
||||
|
||||
static void _sys_irq_init(int cpu_id)
|
||||
{
|
||||
|
||||
@@ -101,18 +88,18 @@ static void _sys_irq_init(int cpu_id)
|
||||
vector_base[5] = (uint32_t)handle_reserved; // Reserved
|
||||
vector_base[6] = (uint32_t)trap_irq_enter; // IRQ
|
||||
vector_base[7] = (uint32_t)handle_fiq; // FIQ
|
||||
}
|
||||
|
||||
/* active hardware irq responser */
|
||||
XScuGic_Config* gic_config = XScuGic_LookupConfig(XPAR_PS7_SCUGIC_0_DEVICE_ID);
|
||||
if (NULL == gic_config) {
|
||||
ERROR("Error while looking up gic config\n");
|
||||
return;
|
||||
}
|
||||
int gic_init_status = XScuGic_CfgInitialize(&IntcInstance, gic_config, gic_config->CpuBaseAddress);
|
||||
if (gic_init_status != XST_SUCCESS) {
|
||||
ERROR("Error initializing gic\n");
|
||||
return;
|
||||
/* active hardware irq responser */
|
||||
XScuGic_Config* gic_config = XScuGic_LookupConfig(XPAR_PS7_SCUGIC_0_DEVICE_ID);
|
||||
if (NULL == gic_config) {
|
||||
ERROR("Error while looking up gic config\n");
|
||||
return;
|
||||
}
|
||||
int gic_init_status = XScuGic_CfgInitialize(&IntcInstance, gic_config, gic_config->CpuBaseAddress);
|
||||
if (gic_init_status != XST_SUCCESS) {
|
||||
ERROR("Error initializing gic\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
xizi_trap_driver.switch_hw_irqtbl((uint32_t*)&_vector_jumper);
|
||||
@@ -164,24 +151,6 @@ static void _bind_irq_handler(int irq, irq_handler_t handler)
|
||||
xizi_trap_driver.sw_irqtbl[irq].handler = handler;
|
||||
}
|
||||
|
||||
static bool _send_sgi(uint32_t irq, uint32_t bitmask, enum SgiFilterType type)
|
||||
{
|
||||
if (bitmask > (1 << NR_CPU) - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int cpu_id = 0;
|
||||
while (bitmask != 0) {
|
||||
if ((bitmask & 0x1) != 0) {
|
||||
XScuGic_SoftwareIntr(&IntcInstance, irq, cpu_id);
|
||||
}
|
||||
cpu_id++;
|
||||
bitmask >>= 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t _hw_before_irq()
|
||||
{
|
||||
|
||||
@@ -194,29 +163,11 @@ static uint32_t _hw_cur_int_num(uint32_t int_info)
|
||||
return int_info & XSCUGIC_ACK_INTID_MASK;
|
||||
}
|
||||
|
||||
static uint32_t _hw_cur_int_cpu(uint32_t int_info)
|
||||
{
|
||||
return (int_info >> 5) & 0x3;
|
||||
}
|
||||
|
||||
static void _hw_after_irq(uint32_t int_info)
|
||||
{
|
||||
XScuGic_CPUWriteReg(&IntcInstance, XSCUGIC_EOI_OFFSET, int_info);
|
||||
}
|
||||
|
||||
static int _is_interruptable(void)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"mrs %0, cpsr"
|
||||
: "=r"(val)
|
||||
:
|
||||
:);
|
||||
|
||||
return !(val & DIS_INT);
|
||||
}
|
||||
|
||||
int _cur_cpu_id()
|
||||
{
|
||||
return cpu_get_current();
|
||||
@@ -233,18 +184,15 @@ static struct XiziTrapDriver xizi_trap_driver = {
|
||||
.switch_hw_irqtbl = _switch_hw_irqtbl,
|
||||
|
||||
.bind_irq_handler = _bind_irq_handler,
|
||||
.send_sgi = _send_sgi,
|
||||
|
||||
.is_interruptable = _is_interruptable,
|
||||
.hw_before_irq = _hw_before_irq,
|
||||
.hw_cur_int_num = _hw_cur_int_num,
|
||||
.hw_cur_int_cpu = _hw_cur_int_cpu,
|
||||
.hw_after_irq = _hw_after_irq,
|
||||
};
|
||||
|
||||
struct XiziTrapDriver* hardkernel_intr_init(struct TraceTag* hardkernel_tag)
|
||||
{
|
||||
xizi_trap_driver.sys_irq_init(0);
|
||||
xizi_trap_driver.cpu_irq_enable();
|
||||
xizi_trap_driver.cpu_irq_disable();
|
||||
return &xizi_trap_driver;
|
||||
}
|
||||
@@ -27,8 +27,8 @@
|
||||
#include "multicores.h"
|
||||
|
||||
struct lock_node {
|
||||
int cpu_id;
|
||||
struct double_list_node node;
|
||||
int cpu_id;
|
||||
};
|
||||
|
||||
static struct double_list_node lock_request_guard;
|
||||
@@ -52,7 +52,7 @@ enum {
|
||||
SPINLOCK_LOCK_WAITFOREVER = 0xFFFFFFFF,
|
||||
};
|
||||
|
||||
void spinlock_init(struct spinlock* lock, char* name)
|
||||
__attribute__((optimize("O0"))) void spinlock_init(struct spinlock* lock, char* name)
|
||||
{
|
||||
lock->owner_cpu = SPINLOCK_STATE_UNLOCK;
|
||||
strncpy(lock->name, name, 24);
|
||||
@@ -61,33 +61,59 @@ void spinlock_init(struct spinlock* lock, char* name)
|
||||
extern int _spinlock_lock(struct spinlock* lock, uint32_t timeout);
|
||||
void _spinlock_unlock(struct spinlock* lock);
|
||||
|
||||
void spinlock_lock(struct spinlock* lock)
|
||||
__attribute__((optimize("O0"))) void spinlock_lock(struct spinlock* lock)
|
||||
{
|
||||
if (lock->owner_cpu != SPINLOCK_STATE_UNLOCK && lock->owner_cpu == cur_cpuid()) {
|
||||
int cur_cpu_id = cur_cpuid();
|
||||
if (lock->owner_cpu != SPINLOCK_STATE_UNLOCK && lock->owner_cpu == cur_cpu_id) {
|
||||
ERROR("spinlock %s lock double locked by core %d\n", lock->name, lock->owner_cpu);
|
||||
panic("");
|
||||
}
|
||||
|
||||
struct double_list_node* p_lock_node = &core_lock_request[cur_cpu_id].node;
|
||||
_spinlock_lock(&request_lock, SPINLOCK_LOCK_WAITFOREVER);
|
||||
doubleListAddOnBack(&core_lock_request[cur_cpuid()].node, &lock_request_guard);
|
||||
doubleListAddOnBack(p_lock_node, &lock_request_guard);
|
||||
_spinlock_unlock(&request_lock);
|
||||
|
||||
while (lock_request_guard.next != &core_lock_request[cur_cpuid()].node)
|
||||
while (lock_request_guard.next != p_lock_node)
|
||||
;
|
||||
|
||||
_spinlock_lock(lock, SPINLOCK_LOCK_WAITFOREVER);
|
||||
}
|
||||
|
||||
void spinlock_unlock(struct spinlock* lock)
|
||||
__attribute__((optimize("O0"))) void spinlock_unlock(struct spinlock* lock)
|
||||
{
|
||||
assert(lock_request_guard.next == &core_lock_request[cur_cpuid()].node);
|
||||
struct double_list_node* p_lock_node = &core_lock_request[cur_cpuid()].node;
|
||||
assert(lock_request_guard.next == p_lock_node);
|
||||
_spinlock_lock(&request_lock, SPINLOCK_LOCK_WAITFOREVER);
|
||||
_double_list_del(core_lock_request[cur_cpuid()].node.prev, core_lock_request[cur_cpuid()].node.next);
|
||||
_double_list_del(p_lock_node->prev, p_lock_node->next);
|
||||
_spinlock_unlock(&request_lock);
|
||||
|
||||
_spinlock_unlock(lock);
|
||||
}
|
||||
|
||||
bool is_spinlock_locked(struct spinlock* lock)
|
||||
__attribute__((optimize("O0"))) bool spinlock_try_lock(struct spinlock* lock)
|
||||
{
|
||||
return lock->owner_cpu != SPINLOCK_STATE_UNLOCK;
|
||||
int cur_cpu_id = cur_cpuid();
|
||||
if (lock->owner_cpu != SPINLOCK_STATE_UNLOCK && lock->owner_cpu == cur_cpu_id) {
|
||||
ERROR("spinlock %s lock double locked by core %d\n", lock->name, lock->owner_cpu);
|
||||
panic("");
|
||||
}
|
||||
|
||||
struct double_list_node* p_lock_node = &core_lock_request[cur_cpu_id].node;
|
||||
_spinlock_lock(&request_lock, SPINLOCK_LOCK_WAITFOREVER);
|
||||
doubleListAddOnBack(p_lock_node, &lock_request_guard);
|
||||
if (lock_request_guard.next != p_lock_node) {
|
||||
_double_list_del(p_lock_node->prev, p_lock_node->next);
|
||||
_spinlock_unlock(&request_lock);
|
||||
return false;
|
||||
}
|
||||
_spinlock_unlock(&request_lock);
|
||||
_spinlock_lock(lock, SPINLOCK_LOCK_WAITFOREVER);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_spinlock_hold_by_current_cpu(struct spinlock* lock)
|
||||
{
|
||||
return lock->owner_cpu;
|
||||
}
|
||||
@@ -34,7 +34,7 @@ Modification:
|
||||
#define STACK_DEPTH 32
|
||||
|
||||
struct spinlock { // Mutex.
|
||||
uint32_t owner_cpu; // 1 for locked, 0 for unlocked
|
||||
volatile uint32_t owner_cpu; // 1 for locked, 0 for unlocked
|
||||
char name[28]; // The call stack (an array of program counters)
|
||||
} __attribute__((aligned(32)));
|
||||
|
||||
@@ -42,4 +42,5 @@ bool module_spinlock_use_intr_init(void);
|
||||
void spinlock_init(struct spinlock* lock, char* name);
|
||||
void spinlock_lock(struct spinlock* lock);
|
||||
void spinlock_unlock(struct spinlock* lock);
|
||||
bool is_spinlock_locked(struct spinlock* lock);
|
||||
bool spinlock_try_lock(struct spinlock* lock);
|
||||
bool is_spinlock_hold_by_current_cpu(struct spinlock* lock);
|
||||
@@ -56,8 +56,6 @@ struct irq_table_entry {
|
||||
struct XiziTrapDriver {
|
||||
/* irq number table*/
|
||||
struct irq_table_entry sw_irqtbl[NR_IRQS];
|
||||
/* current irq number happening in cpu*/
|
||||
uint32_t curr_int[NR_CPU];
|
||||
|
||||
void (*sys_irq_init)(int);
|
||||
int (*cur_cpu_id)();
|
||||
@@ -66,17 +64,14 @@ struct XiziTrapDriver {
|
||||
void (*cpu_irq_disable)();
|
||||
void (*single_irq_enable)(int irq, int cpu, int prio);
|
||||
void (*single_irq_disable)(int irq, int cpu);
|
||||
uint32_t* (*switch_hw_irqtbl)(uint32_t*);
|
||||
|
||||
bool (*send_sgi)(uint32_t, uint32_t, enum SgiFilterType);
|
||||
uint32_t* (*switch_hw_irqtbl)(uint32_t*);
|
||||
void (*bind_irq_handler)(int, irq_handler_t);
|
||||
|
||||
/* check if no if interruptable */
|
||||
int (*is_interruptable)();
|
||||
/* code runs before irq handling */
|
||||
uint32_t (*hw_before_irq)();
|
||||
uint32_t (*hw_cur_int_num)(uint32_t int_info);
|
||||
uint32_t (*hw_cur_int_cpu)(uint32_t int_info);
|
||||
/* code runs after irq handling */
|
||||
void (*hw_after_irq)(uint32_t int_info);
|
||||
};
|
||||
@@ -101,4 +96,7 @@ void panic(char* s);
|
||||
bool intr_distributer_init(struct IrqDispatcherRightGroup*);
|
||||
void intr_irq_dispatch(struct trapframe* tf);
|
||||
bool swi_distributer_init(struct SwiDispatcherRightGroup*);
|
||||
void software_irq_dispatch(struct trapframe* tf);
|
||||
void software_irq_dispatch(struct trapframe* tf);
|
||||
|
||||
void dabort_reason(struct trapframe* r);
|
||||
void iabort_reason(struct trapframe* r);
|
||||
@@ -56,10 +56,11 @@ Modification:
|
||||
#define MAX_NR_FREE_PAGES ((PHY_MEM_STOP - PHY_MEM_BASE) >> LEVEL4_PTE_SHIFT)
|
||||
|
||||
/* User memory layout */
|
||||
#define USER_STACK_SIZE PAGE_SIZE
|
||||
#define USER_STACK_SIZE MODE_STACK_SIZE
|
||||
#define USER_MEM_BASE (0x00000000)
|
||||
#define USER_MEM_TOP DEV_VRTMEM_BASE
|
||||
#define USER_IPC_SPACE_BASE (0x70000000)
|
||||
#define USER_IPC_USE_ALLOCATOR_WATERMARK (0x70010000)
|
||||
#define USER_IPC_SPACE_TOP (USER_MEM_TOP - USER_STACK_SIZE)
|
||||
|
||||
/* Deivce memory layout */
|
||||
|
||||
@@ -38,24 +38,6 @@ Modification:
|
||||
// extern struct MmuCommonDone mmu_common_done;
|
||||
static struct MmuDriverRightGroup right_group;
|
||||
|
||||
void load_pgdir_critical(uintptr_t pgdir_paddr, struct TraceTag* intr_driver_tag)
|
||||
{
|
||||
|
||||
/* get cache driver */
|
||||
struct ICacheDone* p_icache_done = AchieveResource(&right_group.icache_driver_tag);
|
||||
struct DCacheDone* p_dcache_done = AchieveResource(&right_group.dcache_driver_tag);
|
||||
|
||||
/* get intr driver */
|
||||
struct XiziTrapDriver* p_intr_driver = AchieveResource(intr_driver_tag);
|
||||
|
||||
p_intr_driver->cpu_irq_disable();
|
||||
TTBR0_W((uint32_t)pgdir_paddr);
|
||||
CLEARTLB(0);
|
||||
p_icache_done->invalidateall();
|
||||
p_dcache_done->flushall();
|
||||
p_intr_driver->cpu_irq_enable();
|
||||
}
|
||||
|
||||
void load_pgdir(uintptr_t pgdir_paddr)
|
||||
{
|
||||
/* get cache driver */
|
||||
@@ -94,7 +76,6 @@ static struct MmuCommonDone mmu_common_done = {
|
||||
.MmuUsrDevPteAttr = GetUsrDevPteAttr,
|
||||
.MmuKernPteAttr = GetKernPteAttr,
|
||||
|
||||
.LoadPgdirCrit = load_pgdir_critical,
|
||||
.LoadPgdir = load_pgdir,
|
||||
.TlbFlushAll = tlb_flush_all,
|
||||
.TlbFlush = tlb_flush_range,
|
||||
|
||||
@@ -53,13 +53,14 @@ Modification:
|
||||
#define NUM_TOPLEVEL_PDE NUM_LEVEL3_PDE
|
||||
|
||||
#define PAGE_SIZE LEVEL4_PTE_SIZE
|
||||
#define MAX_NR_FREE_PAGES ((PHY_MEM_STOP - PHY_MEM_BASE) >> LEVEL4_PTE_SHIFT)
|
||||
#define MAX_NR_FREE_PAGES ((PHY_USER_FREEMEM_BASE - PHY_MEM_BASE) >> LEVEL4_PTE_SHIFT)
|
||||
|
||||
/* User memory layout */
|
||||
#define USER_STACK_SIZE PAGE_SIZE
|
||||
#define USER_STACK_SIZE MODE_STACK_SIZE
|
||||
#define USER_MEM_BASE (0x00000000)
|
||||
#define USER_MEM_TOP DEV_VRTMEM_BASE
|
||||
#define USER_IPC_SPACE_BASE (0x70000000)
|
||||
#define USER_IPC_USE_ALLOCATOR_WATERMARK (0x70010000)
|
||||
#define USER_IPC_SPACE_TOP (USER_MEM_TOP - USER_STACK_SIZE)
|
||||
|
||||
/* Deivce memory layout */
|
||||
|
||||
@@ -27,7 +27,6 @@ struct MmuCommonDone
|
||||
void (*MmuUsrDevPteAttr)(uintptr_t* attr);
|
||||
void (*MmuKernPteAttr)(uintptr_t* attr);
|
||||
|
||||
void (*LoadPgdirCrit)(uintptr_t pgdir_paddr, struct TraceTag*);
|
||||
void (*LoadPgdir)(uintptr_t pgdir_paddr);
|
||||
void (*TlbFlushAll)();
|
||||
void (*TlbFlush)(uintptr_t vaddr, int len);
|
||||
|
||||
102
Ubiquitous/XiZi_AIoT/hardkernel/uart/printf.h
Normal file
102
Ubiquitous/XiZi_AIoT/hardkernel/uart/printf.h
Normal file
@@ -0,0 +1,102 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2019, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \license The MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
|
||||
// embedded systems with a very limited resources.
|
||||
// Use this instead of bloated standard/newlib printf.
|
||||
// These routines are thread safe and reentrant.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _PRINTF_H_
|
||||
#define _PRINTF_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Tiny printf implementation
|
||||
* You have to implement _putchar if you use printf()
|
||||
* To avoid conflicts with the regular printf() API it is overridden by macro defines
|
||||
* and internal underscore-appended functions like printf_() are used
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are written into the array, not counting the terminating null character
|
||||
*/
|
||||
#define KPrintf printf_
|
||||
#define printf printf_
|
||||
int printf_(const char* format, ...);
|
||||
|
||||
/**
|
||||
* Tiny sprintf implementation
|
||||
* Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
|
||||
* \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||
*/
|
||||
#define sprintf sprintf_
|
||||
int sprintf_(char* buffer, const char* format, ...);
|
||||
|
||||
/**
|
||||
* Tiny snprintf/vsnprintf implementation
|
||||
* \param buffer A pointer to the buffer where to store the formatted string
|
||||
* \param count The maximum number of characters to store in the buffer, including a terminating null character
|
||||
* \param format A string that specifies the format of the output
|
||||
* \param va A value identifying a variable arguments list
|
||||
* \return The number of characters that COULD have been written into the buffer, not counting the terminating
|
||||
* null character. A value equal or larger than count indicates truncation. Only when the returned value
|
||||
* is non-negative and less than count, the string has been completely written.
|
||||
*/
|
||||
#define snprintf snprintf_
|
||||
#define vsnprintf vsnprintf_
|
||||
int snprintf_(char* buffer, size_t count, const char* format, ...);
|
||||
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
|
||||
|
||||
/**
|
||||
* Tiny vprintf implementation
|
||||
* \param format A string that specifies the format of the output
|
||||
* \param va A value identifying a variable arguments list
|
||||
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||
*/
|
||||
#define vprintf vprintf_
|
||||
int vprintf_(const char* format, va_list va);
|
||||
|
||||
/**
|
||||
* printf with output function
|
||||
* You may use this as dynamic alternative to printf() with its fixed _putchar() output
|
||||
* \param out An output function which takes one character and an argument pointer
|
||||
* \param arg An argument pointer for user data passed to output function
|
||||
* \param format A string that specifies the format of the output
|
||||
* \return The number of characters that are sent to the output function, not counting the terminating null character
|
||||
*/
|
||||
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _PRINTF_H_
|
||||
@@ -1,15 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// \author (c) Marco Paland (info@paland.com)
|
||||
// 2014-2019, PALANDesign Hannover, Germany
|
||||
//
|
||||
// \license The MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
|
||||
// embedded systems with a very limited resources. These routines are thread
|
||||
// safe and reentrant!
|
||||
// Use this instead of the bloated standard/newlib printf cause these use
|
||||
// malloc for printf (and may not be thread safe).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* @file uart_common_ope.c
|
||||
* @brief support uart common operation
|
||||
@@ -17,8 +36,10 @@
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.11.20
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "uart_common_ope.h"
|
||||
#include "assert.h"
|
||||
|
||||
struct PrintProxy {
|
||||
struct TraceTag uart_driver_tag;
|
||||
@@ -38,85 +59,840 @@ int serial_init(struct TraceTag* uart_driver_tag)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void PrintInt(int xx, int base, int sign)
|
||||
// 'ntoa' conversion buffer size, this must be big enough to hold one converted
|
||||
// numeric number including padded zeros (dynamically created on stack)
|
||||
// default: 32 byte
|
||||
#define PRINTF_NTOA_BUFFER_SIZE 32U
|
||||
|
||||
#define PRINTF_FTOA_BUFFER_SIZE 32U
|
||||
|
||||
// support for the floating point type (%f)
|
||||
// default: activated
|
||||
#define PRINTF_SUPPORT_FLOAT
|
||||
|
||||
// support for exponential floating point notation (%e/%g)
|
||||
// default: activated
|
||||
#define PRINTF_SUPPORT_EXPONENTIAL
|
||||
|
||||
// define the default floating point precision
|
||||
// default: 6 digits
|
||||
#define PRINTF_DEFAULT_FLOAT_PRECISION 6U
|
||||
|
||||
// define the largest float suitable to print with %f
|
||||
// default: 1e9
|
||||
#define PRINTF_MAX_FLOAT 1e9
|
||||
|
||||
// support for the long long types (%llu or %p)
|
||||
// default: activated
|
||||
#define PRINTF_SUPPORT_LONG_LONG
|
||||
|
||||
// support for the ptrdiff_t type (%t)
|
||||
// ptrdiff_t is normally defined in <stddef.h> as long or long long type
|
||||
// default: activated
|
||||
#define PRINTF_SUPPORT_PTRDIFF_T
|
||||
|
||||
#define _putchar proxy()->serial->putc
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// internal flag definitions
|
||||
#define FLAGS_ZEROPAD (1U << 0U)
|
||||
#define FLAGS_LEFT (1U << 1U)
|
||||
#define FLAGS_PLUS (1U << 2U)
|
||||
#define FLAGS_SPACE (1U << 3U)
|
||||
#define FLAGS_HASH (1U << 4U)
|
||||
#define FLAGS_UPPERCASE (1U << 5U)
|
||||
#define FLAGS_CHAR (1U << 6U)
|
||||
#define FLAGS_SHORT (1U << 7U)
|
||||
#define FLAGS_LONG (1U << 8U)
|
||||
#define FLAGS_LONG_LONG (1U << 9U)
|
||||
#define FLAGS_PRECISION (1U << 10U)
|
||||
#define FLAGS_ADAPT_EXP (1U << 11U)
|
||||
|
||||
// import float.h for DBL_MAX
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
// output function type
|
||||
typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
|
||||
|
||||
// wrapper (used as buffer) for output function type
|
||||
typedef struct {
|
||||
void (*fct)(char character, void* arg);
|
||||
void* arg;
|
||||
} out_fct_wrap_type;
|
||||
|
||||
// internal buffer output
|
||||
static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
static char digits[] = "0123456789ABCDEF";
|
||||
char buf[16];
|
||||
int i;
|
||||
uint32_t x;
|
||||
|
||||
if (sign && (sign = xx < 0)) {
|
||||
x = -xx;
|
||||
} else {
|
||||
x = xx;
|
||||
if (idx < maxlen) {
|
||||
((char*)buffer)[idx] = character;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
||||
do {
|
||||
buf[i++] = digits[x % base];
|
||||
} while ((x /= base) != 0);
|
||||
|
||||
if (sign)
|
||||
buf[i++] = '-';
|
||||
|
||||
while (--i >= 0)
|
||||
proxy()->serial->putc(buf[i]);
|
||||
}
|
||||
|
||||
void KPrintf(char* fmt, ...)
|
||||
// internal null output
|
||||
static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
int i, c;
|
||||
uint32_t* argp;
|
||||
char* s;
|
||||
(void)character;
|
||||
(void)buffer;
|
||||
(void)idx;
|
||||
(void)maxlen;
|
||||
}
|
||||
|
||||
if (fmt == 0) {
|
||||
KPrintf("null fmt");
|
||||
return;
|
||||
// internal _putchar wrapper
|
||||
static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
(void)buffer;
|
||||
(void)idx;
|
||||
(void)maxlen;
|
||||
if (character) {
|
||||
_putchar(character);
|
||||
}
|
||||
}
|
||||
|
||||
// internal output function wrapper
|
||||
static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen)
|
||||
{
|
||||
(void)idx;
|
||||
(void)maxlen;
|
||||
if (character) {
|
||||
// buffer is the output fct pointer
|
||||
((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg);
|
||||
}
|
||||
}
|
||||
|
||||
// internal secure strlen
|
||||
// \return The length of the string (excluding the terminating 0) limited by 'maxsize'
|
||||
static inline unsigned int _strnlen_s(const char* str, size_t maxsize)
|
||||
{
|
||||
const char* s;
|
||||
for (s = str; *s && maxsize--; ++s)
|
||||
;
|
||||
return (unsigned int)(s - str);
|
||||
}
|
||||
|
||||
// internal test if char is a digit (0-9)
|
||||
// \return true if char is a digit
|
||||
static inline bool _is_digit(char ch)
|
||||
{
|
||||
return (ch >= '0') && (ch <= '9');
|
||||
}
|
||||
|
||||
// internal ASCII string to unsigned int conversion
|
||||
static unsigned int _atoi(const char** str)
|
||||
{
|
||||
unsigned int i = 0U;
|
||||
while (_is_digit(**str)) {
|
||||
i = i * 10U + (unsigned int)(*((*str)++) - '0');
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
// output the specified string in reverse, taking care of any zero-padding
|
||||
static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags)
|
||||
{
|
||||
const size_t start_idx = idx;
|
||||
|
||||
// pad spaces up to given width
|
||||
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
|
||||
for (size_t i = len; i < width; i++) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
argp = (uint32_t*)(void*)(&fmt + 1);
|
||||
// reverse string
|
||||
while (len) {
|
||||
out(buf[--len], buffer, idx++, maxlen);
|
||||
}
|
||||
|
||||
for (i = 0; (c = fmt[i] & 0xff) != 0; i++) {
|
||||
if (c != '%') {
|
||||
proxy()->serial->putc(c);
|
||||
// append pad spaces up to given width
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (idx - start_idx < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
// internal itoa format
|
||||
static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
// pad leading zeros
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
// handle hash
|
||||
if (flags & FLAGS_HASH) {
|
||||
if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
|
||||
len--;
|
||||
if (len && (base == 16U)) {
|
||||
len--;
|
||||
}
|
||||
}
|
||||
if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'x';
|
||||
} else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'X';
|
||||
} else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'b';
|
||||
}
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||
}
|
||||
|
||||
// internal itoa for 'long' type
|
||||
static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) {
|
||||
flags &= ~FLAGS_HASH;
|
||||
}
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= base;
|
||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||
}
|
||||
|
||||
// internal itoa for 'long long' type
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) {
|
||||
flags &= ~FLAGS_HASH;
|
||||
}
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
value /= base;
|
||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||
}
|
||||
#endif // PRINTF_SUPPORT_LONG_LONG
|
||||
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
|
||||
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags);
|
||||
#endif
|
||||
|
||||
// internal ftoa for fixed decimal floating point
|
||||
static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
char buf[PRINTF_FTOA_BUFFER_SIZE];
|
||||
size_t len = 0U;
|
||||
double diff = 0.0;
|
||||
|
||||
// powers of 10
|
||||
static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
|
||||
// test for special values
|
||||
if (value != value)
|
||||
return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags);
|
||||
if (value < -DBL_MAX)
|
||||
return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags);
|
||||
if (value > DBL_MAX)
|
||||
return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
|
||||
|
||||
// test for very large values
|
||||
// standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
|
||||
if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
return _etoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||
#else
|
||||
return 0U;
|
||||
#endif
|
||||
}
|
||||
|
||||
// test for negative
|
||||
bool negative = false;
|
||||
if (value < 0) {
|
||||
negative = true;
|
||||
value = 0 - value;
|
||||
}
|
||||
|
||||
// set default precision, if not set explicitly
|
||||
if (!(flags & FLAGS_PRECISION)) {
|
||||
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
}
|
||||
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
|
||||
buf[len++] = '0';
|
||||
prec--;
|
||||
}
|
||||
|
||||
int whole = (int)value;
|
||||
double tmp = (value - whole) * pow10[prec];
|
||||
unsigned long frac = (unsigned long)tmp;
|
||||
diff = tmp - frac;
|
||||
|
||||
if (diff > 0.5) {
|
||||
++frac;
|
||||
// handle rollover, e.g. case 0.99 with prec 1 is 1.0
|
||||
if (frac >= pow10[prec]) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
} else if (diff < 0.5) {
|
||||
} else if ((frac == 0U) || (frac & 1U)) {
|
||||
// if halfway, round up if odd OR if last digit is 0
|
||||
++frac;
|
||||
}
|
||||
|
||||
if (prec == 0U) {
|
||||
diff = value - (double)whole;
|
||||
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
|
||||
// exactly 0.5 and ODD, then round up
|
||||
// 1.5 -> 2, but 2.5 -> 2
|
||||
++whole;
|
||||
}
|
||||
} else {
|
||||
unsigned int count = prec;
|
||||
// now do fractional part, as an unsigned number
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
--count;
|
||||
buf[len++] = (char)(48U + (frac % 10U));
|
||||
if (!(frac /= 10U)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// add extra 0s
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
// add decimal
|
||||
buf[len++] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
// do whole part, number is reversed
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
buf[len++] = (char)(48 + (whole % 10));
|
||||
if (!(whole /= 10)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// pad leading zeros
|
||||
if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
|
||||
if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||
}
|
||||
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
|
||||
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||
{
|
||||
// check for NaN and special values
|
||||
if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
|
||||
return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||
}
|
||||
|
||||
// determine the sign
|
||||
const bool negative = value < 0;
|
||||
if (negative) {
|
||||
value = -value;
|
||||
}
|
||||
|
||||
// default precision
|
||||
if (!(flags & FLAGS_PRECISION)) {
|
||||
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
}
|
||||
|
||||
// determine the decimal exponent
|
||||
// based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
|
||||
union {
|
||||
uint64_t U;
|
||||
double F;
|
||||
} conv;
|
||||
|
||||
conv.F = value;
|
||||
int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
|
||||
conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
|
||||
// now approximate log10 from the log2 integer part and an expansion of ln around 1.5
|
||||
int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
|
||||
// now we want to compute 10^expval but we want to be sure it won't overflow
|
||||
exp2 = (int)(expval * 3.321928094887362 + 0.5);
|
||||
const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
|
||||
const double z2 = z * z;
|
||||
conv.U = (uint64_t)(exp2 + 1023) << 52U;
|
||||
// compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
|
||||
conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
|
||||
// correct for rounding errors
|
||||
if (value < conv.F) {
|
||||
expval--;
|
||||
conv.F /= 10;
|
||||
}
|
||||
|
||||
// the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
|
||||
unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
|
||||
|
||||
// in "%g" mode, "prec" is the number of *significant figures* not decimals
|
||||
if (flags & FLAGS_ADAPT_EXP) {
|
||||
// do we want to fall-back to "%f" mode?
|
||||
if ((value >= 1e-4) && (value < 1e6)) {
|
||||
if ((int)prec > expval) {
|
||||
prec = (unsigned)((int)prec - expval - 1);
|
||||
} else {
|
||||
prec = 0;
|
||||
}
|
||||
flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
|
||||
// no characters in exponent
|
||||
minwidth = 0U;
|
||||
expval = 0;
|
||||
} else {
|
||||
// we use one sigfig for the whole part
|
||||
if ((prec > 0) && (flags & FLAGS_PRECISION)) {
|
||||
--prec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// will everything fit?
|
||||
unsigned int fwidth = width;
|
||||
if (width > minwidth) {
|
||||
// we didn't fall-back so subtract the characters required for the exponent
|
||||
fwidth -= minwidth;
|
||||
} else {
|
||||
// not enough characters, so go back to default sizing
|
||||
fwidth = 0U;
|
||||
}
|
||||
if ((flags & FLAGS_LEFT) && minwidth) {
|
||||
// if we're padding on the right, DON'T pad the floating part
|
||||
fwidth = 0U;
|
||||
}
|
||||
|
||||
// rescale the float value
|
||||
if (expval) {
|
||||
value /= conv.F;
|
||||
}
|
||||
|
||||
// output the floating part
|
||||
const size_t start_idx = idx;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP);
|
||||
|
||||
// output the exponent part
|
||||
if (minwidth) {
|
||||
// output the exponential symbol
|
||||
out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
|
||||
// output the exponent value
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth - 1, FLAGS_ZEROPAD | FLAGS_PLUS);
|
||||
// might need to right-pad spaces
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (idx - start_idx < width)
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
|
||||
// internal vsnprintf
|
||||
static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
|
||||
{
|
||||
unsigned int flags, width, precision, n;
|
||||
size_t idx = 0U;
|
||||
|
||||
if (!buffer) {
|
||||
// use null output function
|
||||
out = _out_null;
|
||||
}
|
||||
|
||||
while (*format) {
|
||||
// format specifier? %[flags][width][.precision][length]
|
||||
if (*format != '%') {
|
||||
// no
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
continue;
|
||||
} else {
|
||||
// yes, evaluate it
|
||||
format++;
|
||||
}
|
||||
|
||||
c = fmt[++i] & 0xff;
|
||||
// evaluate flags
|
||||
flags = 0U;
|
||||
do {
|
||||
switch (*format) {
|
||||
case '0':
|
||||
flags |= FLAGS_ZEROPAD;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case '-':
|
||||
flags |= FLAGS_LEFT;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case '+':
|
||||
flags |= FLAGS_PLUS;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case ' ':
|
||||
flags |= FLAGS_SPACE;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
case '#':
|
||||
flags |= FLAGS_HASH;
|
||||
format++;
|
||||
n = 1U;
|
||||
break;
|
||||
default:
|
||||
n = 0U;
|
||||
break;
|
||||
}
|
||||
} while (n);
|
||||
|
||||
if (!c)
|
||||
// evaluate width field
|
||||
width = 0U;
|
||||
if (_is_digit(*format)) {
|
||||
width = _atoi(&format);
|
||||
} else if (*format == '*') {
|
||||
const int w = va_arg(va, int);
|
||||
if (w < 0) {
|
||||
flags |= FLAGS_LEFT; // reverse padding
|
||||
width = (unsigned int)-w;
|
||||
} else {
|
||||
width = (unsigned int)w;
|
||||
}
|
||||
format++;
|
||||
}
|
||||
|
||||
// evaluate precision field
|
||||
precision = 0U;
|
||||
if (*format == '.') {
|
||||
flags |= FLAGS_PRECISION;
|
||||
format++;
|
||||
if (_is_digit(*format)) {
|
||||
precision = _atoi(&format);
|
||||
} else if (*format == '*') {
|
||||
const int prec = (int)va_arg(va, int);
|
||||
precision = prec > 0 ? (unsigned int)prec : 0U;
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate length field
|
||||
switch (*format) {
|
||||
case 'l':
|
||||
flags |= FLAGS_LONG;
|
||||
format++;
|
||||
if (*format == 'l') {
|
||||
flags |= FLAGS_LONG_LONG;
|
||||
format++;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
flags |= FLAGS_SHORT;
|
||||
format++;
|
||||
if (*format == 'h') {
|
||||
flags |= FLAGS_CHAR;
|
||||
format++;
|
||||
}
|
||||
break;
|
||||
#if defined(PRINTF_SUPPORT_PTRDIFF_T)
|
||||
case 't':
|
||||
flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
#endif
|
||||
case 'j':
|
||||
flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
case 'z':
|
||||
flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||
format++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
// evaluate specifier
|
||||
switch (*format) {
|
||||
case 'd':
|
||||
PrintInt(*argp++, 10, 1);
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'p':
|
||||
PrintInt(*argp++, 16, 0);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if ((s = (char*)*argp++) == 0) {
|
||||
s = "(null)";
|
||||
case 'X':
|
||||
case 'o':
|
||||
case 'b': {
|
||||
// set the base
|
||||
unsigned int base;
|
||||
if (*format == 'x' || *format == 'X') {
|
||||
base = 16U;
|
||||
} else if (*format == 'o') {
|
||||
base = 8U;
|
||||
} else if (*format == 'b') {
|
||||
base = 2U;
|
||||
} else {
|
||||
base = 10U;
|
||||
flags &= ~FLAGS_HASH; // no hash for dec format
|
||||
}
|
||||
// uppercase
|
||||
if (*format == 'X') {
|
||||
flags |= FLAGS_UPPERCASE;
|
||||
}
|
||||
|
||||
for (; *s; s++) {
|
||||
proxy()->serial->putc(*s);
|
||||
// no plus or space flag for u, x, X, o, b
|
||||
if ((*format != 'i') && (*format != 'd')) {
|
||||
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
|
||||
}
|
||||
|
||||
// ignore '0' flag when precision is given
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
flags &= ~FLAGS_ZEROPAD;
|
||||
}
|
||||
|
||||
// convert the integer
|
||||
if ((*format == 'i') || (*format == 'd')) {
|
||||
// signed
|
||||
if (flags & FLAGS_LONG_LONG) {
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
const long long value = va_arg(va, long long);
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
#endif
|
||||
} else if (flags & FLAGS_LONG) {
|
||||
const long value = va_arg(va, long);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
} else {
|
||||
const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int)
|
||||
: va_arg(va, int);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||
}
|
||||
} else {
|
||||
// unsigned
|
||||
if (flags & FLAGS_LONG_LONG) {
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags);
|
||||
#endif
|
||||
} else if (flags & FLAGS_LONG) {
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags);
|
||||
} else {
|
||||
const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int)
|
||||
: va_arg(va, unsigned int);
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||
case 'f':
|
||||
case 'F':
|
||||
if (*format == 'F')
|
||||
flags |= FLAGS_UPPERCASE;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||
format++;
|
||||
break;
|
||||
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
if ((*format == 'g') || (*format == 'G'))
|
||||
flags |= FLAGS_ADAPT_EXP;
|
||||
if ((*format == 'E') || (*format == 'G'))
|
||||
flags |= FLAGS_UPPERCASE;
|
||||
idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||
format++;
|
||||
break;
|
||||
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||
#endif // PRINTF_SUPPORT_FLOAT
|
||||
case 'c': {
|
||||
unsigned int l = 1U;
|
||||
// pre padding
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// char output
|
||||
out((char)va_arg(va, int), buffer, idx++, maxlen);
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 's': {
|
||||
const char* p = va_arg(va, char*);
|
||||
unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
|
||||
// pre padding
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
l = (l < precision ? l : precision);
|
||||
}
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
// string output
|
||||
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
|
||||
out(*(p++), buffer, idx++, maxlen);
|
||||
}
|
||||
// post padding
|
||||
if (flags & FLAGS_LEFT) {
|
||||
while (l++ < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p': {
|
||||
width = sizeof(void*) * 2U;
|
||||
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
|
||||
if (is_ll) {
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags);
|
||||
} else {
|
||||
#endif
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags);
|
||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||
}
|
||||
#endif
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case '%':
|
||||
proxy()->serial->putc('%');
|
||||
out('%', buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Print unknown % sequence to draw attention.
|
||||
proxy()->serial->putc('%');
|
||||
proxy()->serial->putc(c);
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// termination
|
||||
out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
|
||||
|
||||
// return written chars without terminating \0
|
||||
return (int)idx;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int printf_(const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
char buffer[1];
|
||||
const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sprintf_(char* buffer, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int snprintf_(char* buffer, size_t count, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vprintf_(const char* format, va_list va)
|
||||
{
|
||||
char buffer[1];
|
||||
return _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
|
||||
}
|
||||
|
||||
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va)
|
||||
{
|
||||
return _vsnprintf(_out_buffer, buffer, count, format, va);
|
||||
}
|
||||
|
||||
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const out_fct_wrap_type out_fct_wrap = { out, arg };
|
||||
const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "actracer.h"
|
||||
#include "printf.h"
|
||||
|
||||
struct XiziSerialDriver {
|
||||
void (*sys_serial_init)();
|
||||
@@ -33,8 +34,6 @@ struct XiziSerialDriver {
|
||||
void (*putc)(uint8_t);
|
||||
};
|
||||
|
||||
void KPrintf(char* fmt, ...);
|
||||
|
||||
struct XiziSerialDriver* hardkernel_uart_init(struct TraceTag* hardkernel_tag);
|
||||
|
||||
int serial_init(struct TraceTag* uart_driver_tag);
|
||||
|
||||
@@ -101,7 +101,7 @@ static bool dealloc_trace_meta(struct TraceMeta* meta)
|
||||
|
||||
static tracer_mem_chunk_idx_t trace_meta_map_mem_chunk(struct TraceMeta* const p_trace_meta, tracer_mem_chunk_idx_t mem_chunk_num)
|
||||
{
|
||||
tracer_mem_chunk_idx_t addr;
|
||||
tracer_mem_chunk_idx_t addr = 0;
|
||||
/* direct mapping */
|
||||
if (mem_chunk_num < TRACEMETA_NR_DIRECT) {
|
||||
if ((addr = p_trace_meta->addr[mem_chunk_num]) == 0) {
|
||||
@@ -367,8 +367,9 @@ static void trace_locate_inner(struct TraceTag* target, struct TraceTag* const p
|
||||
// p_trace_meta: TRACER_OWNER, VT_FS or other.
|
||||
// TRACER_OWNER: path: "", name: "dir name"
|
||||
// other: path: "", name: "file name"
|
||||
if (!p_trace_meta) {
|
||||
if (p_trace_meta == NULL) {
|
||||
DEBUG("trace_locate, not found\n");
|
||||
return;
|
||||
}
|
||||
target->type = p_trace_meta->type;
|
||||
target->meta = p_trace_meta;
|
||||
|
||||
@@ -105,6 +105,9 @@ static struct tracer_mem_chunk* tracer_get_mem_chunk_cache(uint32_t chunk_id)
|
||||
struct tracer_mem_chunk* tracer_mem_chunk_read(uint32_t chunk_id)
|
||||
{
|
||||
struct tracer_mem_chunk* b = tracer_get_mem_chunk_cache(chunk_id);
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (!(b->flag & TRACER_MEM_CHUNK_VALID)) {
|
||||
tracer_mem_chunk_sync(b);
|
||||
b->flag |= TRACER_MEM_CHUNK_VALID;
|
||||
@@ -137,6 +140,9 @@ static void tracer_mem_chunk_zero(uint32_t chunk_id)
|
||||
assert(chunk_id >= 0 && chunk_id < tracer_mem_chunk_syner.nr_mem_chunks);
|
||||
struct tracer_mem_chunk* tracer_mem_chunk = NULL;
|
||||
tracer_mem_chunk = tracer_mem_chunk_read(chunk_id);
|
||||
if (tracer_mem_chunk == NULL) {
|
||||
return;
|
||||
}
|
||||
memset(tracer_mem_chunk->data, 0, tracer_mem_chunk_syner.mem_chunk_size);
|
||||
tracer_mem_chunk_write(tracer_mem_chunk);
|
||||
tracer_mem_chunk_release(tracer_mem_chunk);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
ifeq ($(BOARD), imx6q-sabrelite)
|
||||
toolchain ?= arm-none-eabi-
|
||||
user_ldflags = --specs=nosys.specs -Wl,-Map=user.map,-cref -N
|
||||
cflags = -std=c11 -march=armv7-a -mtune=cortex-a9 -nostdlib -nodefaultlibs -mfloat-abi=soft -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -ggdb -Wno-unused -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pie -no-pie
|
||||
cflags = -std=c11 -O2 -march=armv7-a -mtune=cortex-a9 -nostdlib -nodefaultlibs -mfloat-abi=soft -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -ggdb -Wno-unused -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pie -no-pie
|
||||
endif
|
||||
ifeq ($(BOARD), zynq7000-zc702)
|
||||
toolchain ?= arm-xilinx-eabi-
|
||||
user_ldflags = -Wl,--start-group,-lgcc,-lc,--end-group -N
|
||||
cflags = -std=c11 -march=armv7-a -mtune=cortex-a9 -nostdlib -nodefaultlibs -mfloat-abi=soft -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -ggdb -Wno-unused -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pie
|
||||
cflags = -std=c11 -O2 -march=armv7-a -mtune=cortex-a9 -nostdlib -nodefaultlibs -mfloat-abi=soft -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -ggdb -Wno-unused -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pie
|
||||
board_specs = stub.o
|
||||
#cflags = -Wall -g -std=c11
|
||||
endif
|
||||
@@ -19,11 +19,17 @@ c_useropts = -O0
|
||||
INC_DIR = -I$(KERNEL_ROOT)/services/shell/letter-shell \
|
||||
-I$(KERNEL_ROOT)/services/lib/ipc \
|
||||
-I$(KERNEL_ROOT)/services/lib/memory \
|
||||
-I$(KERNEL_ROOT)/services/lib/serial \
|
||||
-I$(KERNEL_ROOT)/services/lib/usyscall \
|
||||
-I$(KERNEL_ROOT)/services/fs/libfs \
|
||||
-I$(KERNEL_ROOT)/services/boards/$(BOARD) \
|
||||
-I$(KERNEL_ROOT)/services/app
|
||||
|
||||
all: init test_fs simple_client simple_server shell fs_server test_priority readme.txt | bin
|
||||
ifeq ($(BOARD), imx6q-sabrelite)
|
||||
all: init test_fs simple_client simple_server shell fs_server test_irq_hdlr test_irq_block test_irq_send readme.txt | bin
|
||||
else
|
||||
all: init test_fs simple_client simple_server shell fs_server test_irq_hdlr readme.txt | bin
|
||||
endif
|
||||
../tools/mkfs/mkfs ./fs.img $^
|
||||
@mv $(filter-out readme.txt, $^) bin
|
||||
@mv *.o bin
|
||||
@@ -32,31 +38,45 @@ all: init test_fs simple_client simple_server shell fs_server test_priority read
|
||||
bin:
|
||||
@mkdir -p bin
|
||||
|
||||
shell: shell_port.o libserial.o shell_cmd_list.o shell.o shell_ext.o libfs_to_client.o libipc.o session.o usyscall.o libmem.o
|
||||
ifeq ($(BOARD), imx6q-sabrelite)
|
||||
test_irq_send: test_irq_sender.o usyscall.o arch_usyscall.o libserial.o
|
||||
@${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs}
|
||||
@${objdump} -S $@ > $@.asm
|
||||
endif
|
||||
|
||||
test_irq_block: test_irq_block.o libserial.o libipc.o session.o usyscall.o arch_usyscall.o libmem.o
|
||||
@${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs}
|
||||
@${objdump} -S $@ > $@.asm
|
||||
|
||||
test_irq_hdlr: test_irq_handler.o libserial.o libipc.o session.o usyscall.o arch_usyscall.o libmem.o
|
||||
@${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs}
|
||||
@${objdump} -S $@ > $@.asm
|
||||
|
||||
shell: shell_port.o libserial.o shell_cmd_list.o shell.o shell_ext.o libfs_to_client.o libipc.o session.o usyscall.o arch_usyscall.o libmem.o
|
||||
@${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs}
|
||||
@${objdump} -S $@ > $@.asm
|
||||
|
||||
init: init.o libfs_to_client.o libipc.o session.o libserial.o usyscall.o libmem.o
|
||||
init: init.o libfs_to_client.o libipc.o session.o libserial.o usyscall.o arch_usyscall.o libmem.o
|
||||
@${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs}
|
||||
@${objdump} -S $@ > $@.asm
|
||||
|
||||
test_fs: test_fs.o libfs_to_client.o libipc.o session.o libserial.o usyscall.o libmem.o
|
||||
test_fs: test_fs.o libfs_to_client.o libipc.o session.o libserial.o usyscall.o arch_usyscall.o libmem.o
|
||||
@${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs}
|
||||
@${objdump} -S $@ > $@.asm
|
||||
|
||||
simple_client: simple_client.o libserial.o libipc.o session.o simple_service.o libfs_to_client.o usyscall.o libmem.o
|
||||
simple_client: simple_client.o libserial.o libipc.o session.o simple_service.o libfs_to_client.o usyscall.o arch_usyscall.o libmem.o
|
||||
@${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs}
|
||||
@${objdump} -S $@ > $@.asm
|
||||
|
||||
simple_server: simple_server.o libserial.o libipc.o session.o simple_service.o usyscall.o libmem.o
|
||||
simple_server: simple_server.o libserial.o libipc.o session.o simple_service.o usyscall.o arch_usyscall.o libmem.o
|
||||
@${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs}
|
||||
@${objdump} -S $@ > $@.asm
|
||||
|
||||
fs_server: fs_server.o libfs_to_client.o fs.o libserial.o libipc.o session.o block_io.o usyscall.o libmem.o
|
||||
fs_server: fs_server.o libfs_to_client.o fs.o libserial.o libipc.o session.o block_io.o usyscall.o arch_usyscall.o libmem.o
|
||||
@${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs}
|
||||
@${objdump} -S $@ > $@.asm
|
||||
|
||||
test_priority: test_priority.o libserial.o usyscall.o libmem.o
|
||||
test_priority: test_priority.o libserial.o usyscall.o arch_usyscall.o libmem.o
|
||||
@${ld} ${user_ldflags} -e main -o $@ $^ ${board_specs}
|
||||
@${objdump} -S $@ > $@.asm
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ signed short userShellRead(char* data, unsigned short len)
|
||||
while (length--) {
|
||||
cur_read = getc();
|
||||
if (cur_read == 0xff) {
|
||||
yield();
|
||||
yield(SYS_TASK_YIELD_NO_REASON);
|
||||
}
|
||||
// *data++ = getc();
|
||||
*data++ = cur_read;
|
||||
|
||||
@@ -84,7 +84,7 @@ int main(int argc, char** argv)
|
||||
if (argc >= 2) {
|
||||
id = string_to_integer(argv[1]);
|
||||
}
|
||||
printf("This is Simple Client %d, size is 0x%x\n", id, task_heap_base());
|
||||
// printf("This is Simple Client %d, size is 0x%x\n", id, task_heap_base());
|
||||
|
||||
struct Session session_wait;
|
||||
struct Session session_nowait;
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
#include "libipc.h"
|
||||
#include "libserial.h"
|
||||
#include "usyscall.h"
|
||||
|
||||
/// this file is only used for debug
|
||||
#pragma once
|
||||
IPC_SERVICES(IpcSwIntrHandler, Ipc_intr_3, Ipc_wait_intr_3);
|
||||
|
||||
void printf(char* fmt, ...);
|
||||
|
||||
char getc();
|
||||
enum {
|
||||
SW_INTERRUPT_3 = 3,
|
||||
};
|
||||
35
Ubiquitous/XiZi_AIoT/services/app/test_irq_block.c
Normal file
35
Ubiquitous/XiZi_AIoT/services/app/test_irq_block.c
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
#include "test_irq.h"
|
||||
|
||||
IPC_INTERFACE(Ipc_wait_intr_3, 1, ignore, 0);
|
||||
int wait_intr(struct Session* session, void* ignore_param)
|
||||
{
|
||||
return IPC_CALL(Ipc_wait_intr_3)(session, NULL);
|
||||
}
|
||||
|
||||
static char prog_name[] = "TEST_IRQ_BLOCK";
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
struct Session session;
|
||||
if (connect_session(&session, "TestIRQ", 4096) < 0) {
|
||||
printf("connect session failed\n");
|
||||
exit();
|
||||
}
|
||||
|
||||
printf("%s start waiting for IRQ.\n", prog_name);
|
||||
wait_intr(&session, NULL);
|
||||
printf("%s return from waiting for IRQ.\n", prog_name);
|
||||
|
||||
exit();
|
||||
}
|
||||
55
Ubiquitous/XiZi_AIoT/services/app/test_irq_handler.c
Normal file
55
Ubiquitous/XiZi_AIoT/services/app/test_irq_handler.c
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
#include "test_irq.h"
|
||||
|
||||
static bool has_one_interrupt = false;
|
||||
int IPC_DO_SERVE_FUNC(Ipc_intr_3)(void* ignore)
|
||||
{
|
||||
printf("TEST_SW_HDLR: In %s()\n", __func__);
|
||||
has_one_interrupt = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IPC_DO_SERVE_FUNC(Ipc_wait_intr_3)(void* ignore)
|
||||
{
|
||||
// delay the this handle
|
||||
if (!has_one_interrupt) {
|
||||
delay_session();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// serve can be done by now
|
||||
has_one_interrupt = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
IPC_SERVER_INTERFACE(Ipc_intr_3, 1);
|
||||
IPC_SERVER_INTERFACE(Ipc_wait_intr_3, 1);
|
||||
IPC_SERVER_REGISTER_INTERFACES(IpcSwIntrHandler, 2, Ipc_intr_3, Ipc_wait_intr_3);
|
||||
int main()
|
||||
{
|
||||
if (register_irq(SW_INTERRUPT_3, Ipc_intr_3) < 0) {
|
||||
printf("TEST_SW_HDLR: bind failed");
|
||||
exit();
|
||||
}
|
||||
|
||||
static char prog_name[] = "TestIRQ";
|
||||
if (register_server("TestIRQ") < 0) {
|
||||
printf("register server name: %s failed.\n", prog_name);
|
||||
exit();
|
||||
}
|
||||
|
||||
ipc_server_loop(&IpcSwIntrHandler);
|
||||
|
||||
exit();
|
||||
}
|
||||
@@ -15,10 +15,12 @@ c_useropts = -O0
|
||||
INC_DIR = -I$(KERNEL_ROOT)/services/fs/libfs \
|
||||
-I$(KERNEL_ROOT)/services/lib/ipc \
|
||||
-I$(KERNEL_ROOT)/services/lib/memory \
|
||||
-I$(KERNEL_ROOT)/services/lib/serial \
|
||||
-I$(KERNEL_ROOT)/services/lib/usyscall \
|
||||
-I$(KERNEL_ROOT)/services/boards/$(BOARD) \
|
||||
-I$(KERNEL_ROOT)/services/app
|
||||
|
||||
board: libserial.o usyscall.o
|
||||
board: libserial.o arch_usyscall.o test_irq_sender.o
|
||||
@mv $^ ../../app
|
||||
|
||||
%.o: %.c
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
#include "usyscall.h"
|
||||
|
||||
int syscall(int sys_num, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
__asm__ volatile(
|
||||
"mov r0, %1;\
|
||||
mov r1, %2;\
|
||||
mov r2, %3;\
|
||||
mov r3, %4;\
|
||||
mov r4, %5;\
|
||||
swi 0;\
|
||||
dsb;\
|
||||
isb;\
|
||||
mov %0, r0"
|
||||
: "=r"(ret)
|
||||
: "r"(sys_num), "r"(a1), "r"(a2), "r"(a3), "r"(a4)
|
||||
: "memory", "r0", "r1", "r2", "r3", "r4");
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
#include "libserial.h"
|
||||
#include "usyscall.h"
|
||||
|
||||
enum {
|
||||
SW_INTERRUPT_3 = 3,
|
||||
};
|
||||
|
||||
enum {
|
||||
ARM_PERIPHERAL_BASE = 0x00A00000,
|
||||
MX6Q_GICD_BASE_OFFSET = 0x1000,
|
||||
MX6Q_GICC_BASE_OFFSET = 0x100,
|
||||
|
||||
ARM_PERIPHERAL_VIRT_BASE = 0x50000000,
|
||||
};
|
||||
|
||||
enum _gicd_sgi_filter {
|
||||
//! Forward the interrupt to the CPU interfaces specified in the @a target_list parameter.
|
||||
kGicSgiFilter_UseTargetList = 0,
|
||||
|
||||
//! Forward the interrupt to all CPU interfaces except that of the processor that requested
|
||||
//! the interrupt.
|
||||
kGicSgiFilter_AllOtherCPUs = 1,
|
||||
|
||||
//! Forward the interrupt only to the CPU interface of the processor that requested the
|
||||
//! interrupt.
|
||||
kGicSgiFilter_OnlyThisCPU = 2
|
||||
};
|
||||
|
||||
struct _gicd_registers {
|
||||
uint32_t CTLR; //!< Distributor Control Register.
|
||||
uint32_t TYPER; //!< Interrupt Controller Type Register.
|
||||
uint32_t IIDR; //!< Distributor Implementer Identification Register.
|
||||
uint32_t _reserved0[29];
|
||||
uint32_t IGROUPRn[8]; //!< Interrupt Group Registers.
|
||||
uint32_t _reserved1[24];
|
||||
uint32_t ISENABLERn[32]; //!< Interrupt Set-Enable Registers.
|
||||
uint32_t ICENABLERn[32]; //!< Interrupt Clear-Enable Registers.
|
||||
uint32_t ISPENDRn[32]; //!< Interrupt Set-Pending Registers.
|
||||
uint32_t ICPENDRn[32]; //!< Interrupt Clear-Pending Registers.
|
||||
uint32_t ICDABRn[32]; //!< Active Bit Registers.
|
||||
uint32_t _reserved2[32];
|
||||
uint8_t IPRIORITYRn[255 * sizeof(uint32_t)]; //!< Interrupt Priority Registers. (Byte accessible)
|
||||
uint32_t _reserved3;
|
||||
uint8_t ITARGETSRn[255 * sizeof(uint32_t)]; //!< Interrupt Processor Targets Registers. (Byte accessible)
|
||||
uint32_t _reserved4;
|
||||
uint32_t ICFGRn[64]; //!< Interrupt Configuration Registers.
|
||||
uint32_t _reserved5[128];
|
||||
uint32_t SGIR; //!< Software Generated Interrupt Register
|
||||
};
|
||||
typedef volatile struct _gicd_registers gicd_t;
|
||||
|
||||
enum _gicd_sgir_fields {
|
||||
kBP_GICD_SGIR_TargetListFilter = 24,
|
||||
kBM_GICD_SGIR_TargetListFilter = (0x3 << kBP_GICD_SGIR_TargetListFilter),
|
||||
|
||||
kBP_GICD_SGIR_CPUTargetList = 16,
|
||||
kBM_GICD_SGIR_CPUTargetList = (0xff << kBP_GICD_SGIR_CPUTargetList),
|
||||
|
||||
kBP_GICD_SGIR_NSATT = 15,
|
||||
kBM_GICD_SGIR_NSATT = (1 << kBP_GICD_SGIR_NSATT),
|
||||
|
||||
kBP_GICD_SGIR_SGIINTID = 0,
|
||||
kBM_GICD_SGIR_SGIINTID = 0xf
|
||||
};
|
||||
|
||||
void gic_send_sgi(uint32_t irqID, uint32_t target_list, uint32_t filter_list)
|
||||
{
|
||||
gicd_t* gicd = (gicd_t*)(ARM_PERIPHERAL_VIRT_BASE + MX6Q_GICD_BASE_OFFSET);
|
||||
gicd->SGIR = (filter_list << kBP_GICD_SGIR_TargetListFilter) //
|
||||
| (target_list << kBP_GICD_SGIR_CPUTargetList) //
|
||||
| (irqID & 0xf);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
static char prog_name[] = "TEST_IRQ_SEND";
|
||||
printf("%s: Mapping GIC\n", prog_name);
|
||||
mmap(ARM_PERIPHERAL_VIRT_BASE, ARM_PERIPHERAL_BASE, 0x2000, true);
|
||||
|
||||
// int send_time = 1000;
|
||||
int send_time = 1;
|
||||
printf("%s: Sending soft interrupt for %d times\n", prog_name, send_time);
|
||||
for (int i = 0; i < send_time; i++) {
|
||||
gic_send_sgi(SW_INTERRUPT_3, 0xF, kGicSgiFilter_UseTargetList);
|
||||
printf("%s: Soft interrupt send 1 time\n", prog_name);
|
||||
}
|
||||
printf("%s: Soft interrupt send done\n", prog_name);
|
||||
exit();
|
||||
}
|
||||
@@ -19,10 +19,12 @@ INC_DIR = -I$(KERNEL_ROOT)/services/fs/libfs \
|
||||
-I$(KERNEL_ROOT)/services/fs/fs_server/include \
|
||||
-I$(KERNEL_ROOT)/services/lib/ipc \
|
||||
-I$(KERNEL_ROOT)/services/lib/memory \
|
||||
-I$(KERNEL_ROOT)/services/lib/serial \
|
||||
-I$(KERNEL_ROOT)/services/lib/usyscall \
|
||||
-I$(KERNEL_ROOT)/services/boards/$(BOARD) \
|
||||
-I$(KERNEL_ROOT)/services/app
|
||||
|
||||
board: libserial.o stub.o usyscall.o
|
||||
board: libserial.o stub.o arch_usyscall.o
|
||||
@mv $^ ../../app
|
||||
|
||||
%.o: %.c
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
#include "usyscall.h"
|
||||
|
||||
int syscall(int sys_num, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
__asm__ volatile(
|
||||
"mov r0, %1;\
|
||||
mov r1, %2;\
|
||||
mov r2, %3;\
|
||||
mov r3, %4;\
|
||||
mov r4, %5;\
|
||||
swi 0;\
|
||||
dsb;\
|
||||
isb;\
|
||||
mov %0, r0"
|
||||
: "=r"(ret)
|
||||
: "r"(sys_num), "r"(a1), "r"(a2), "r"(a3), "r"(a4)
|
||||
: "memory", "r0", "r1", "r2", "r3", "r4");
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
#include "usyscall.h"
|
||||
#include "libmem.h"
|
||||
|
||||
static int
|
||||
syscall(int sys_num, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
__asm__ volatile(
|
||||
"mov r0, %1;\
|
||||
mov r1, %2;\
|
||||
mov r2, %3;\
|
||||
mov r3, %4;\
|
||||
mov r4, %5;\
|
||||
swi 0;\
|
||||
dsb;\
|
||||
isb;\
|
||||
mov %0, r0"
|
||||
: "=r"(ret)
|
||||
: "r"(sys_num), "r"(a1), "r"(a2), "r"(a3), "r"(a4)
|
||||
: "memory", "r0", "r1", "r2", "r3", "r4");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int spawn(struct Session* session, int fd, ipc_read_fn ipc_read, ipc_fsize_fn ipc_fsize, char* name, char** argv)
|
||||
{
|
||||
int file_size = ipc_fsize(session, fd);
|
||||
void* img = malloc(file_size);
|
||||
int read_len = 0, cur_read_len = 0;
|
||||
while (read_len < file_size) {
|
||||
cur_read_len = file_size - read_len < 4096 ? file_size - read_len : 4096;
|
||||
read_len += ipc_read(session, fd, img + read_len, read_len, cur_read_len);
|
||||
}
|
||||
int ret = syscall(SYSCALL_SPAWN, (intptr_t)img, (intptr_t)name, (intptr_t)argv, 0);
|
||||
free(img);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int exit()
|
||||
{
|
||||
return syscall(SYSCALL_EXIT, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
int yield()
|
||||
{
|
||||
return syscall(SYSCALL_YIELD, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
int kill(int pid)
|
||||
{
|
||||
return syscall(SYSCALL_KILL, (intptr_t)pid, 0, 0, 0);
|
||||
}
|
||||
|
||||
int register_server(char* name)
|
||||
{
|
||||
return syscall(SYSCALL_SERVER, (intptr_t)name, 0, 0, 0);
|
||||
}
|
||||
|
||||
int session(char* path, int capacity, struct Session* user_session)
|
||||
{
|
||||
return syscall(SYSCALL_SESSION, (intptr_t)path, (intptr_t)capacity, (intptr_t)user_session, 0);
|
||||
}
|
||||
|
||||
int poll_session(struct Session* userland_session_arr, int arr_capacity)
|
||||
{
|
||||
return syscall(SYSCALL_POLL_SESSION, (intptr_t)userland_session_arr, (intptr_t)arr_capacity, 0, 0);
|
||||
}
|
||||
|
||||
int close_session(struct Session* session)
|
||||
{
|
||||
return syscall(SYSCALL_CLOSE_SESSION, (intptr_t)session, 0, 0, 0);
|
||||
}
|
||||
|
||||
int get_memblock_info(sys_state_info* info)
|
||||
{
|
||||
return syscall(SYSCALL_SYS_STATE, SYS_STATE_MEMBLOCK_INFO, (intptr_t)info, 0, 0);
|
||||
}
|
||||
|
||||
int set_priority(sys_state_info* info)
|
||||
{
|
||||
return syscall(SYSCALL_SYS_STATE, SYS_STATE_SET_TASK_PRIORITY, (intptr_t)info, 0, 0);
|
||||
}
|
||||
|
||||
int task_heap_base()
|
||||
{
|
||||
return syscall(SYSCALL_SYS_STATE, SYS_STATE_GET_HEAP_BASE, 0, 0, 0);
|
||||
}
|
||||
|
||||
int show_task()
|
||||
{
|
||||
return syscall(SYSCALL_SYS_STATE, SYS_STATE_SHOW_TASKS, 0, 0, 0);
|
||||
}
|
||||
|
||||
int show_mem()
|
||||
{
|
||||
return syscall(SYSCALL_SYS_STATE, SYS_STATE_SHOW_MEM_INFO, 0, 0, 0);
|
||||
}
|
||||
|
||||
int show_cpu()
|
||||
{
|
||||
return syscall(SYSCALL_SYS_STATE, SYS_STATE_SHOW_CPU_INFO, 0, 0, 0);
|
||||
}
|
||||
|
||||
int mmap(uintptr_t vaddr, uintptr_t paddr, int len, bool is_dev)
|
||||
{
|
||||
return syscall(SYSCALL_MMAP, vaddr, paddr, (intptr_t)len, (intptr_t)is_dev);
|
||||
}
|
||||
|
||||
int register_irq(int irq, int opcode)
|
||||
{
|
||||
return syscall(SYSCALL_REGISTER_IRQ, (intptr_t)irq, (intptr_t)opcode, 0, 0);
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libserial.h"
|
||||
#include "session.h"
|
||||
|
||||
// clang-format off
|
||||
#define SYSCALL_TEST 0
|
||||
#define SYSCALL_SPAWN 1 // generate a brand new task to run elf
|
||||
#define SYSCALL_EXIT 2 // exit task, delete the task cb
|
||||
#define SYSCALL_YIELD 3 // yield task, go to scheduler
|
||||
|
||||
#define SYSCALL_MMAP 4 // map a virt page to phy page
|
||||
#define SYSCALL_SERVER 5 // register current task as a server
|
||||
#define SYSCALL_SESSION 6 // create a session to a server
|
||||
#define SYSCALL_POLL_SESSION 7 // server poll for it's server sessions
|
||||
#define SYSCALL_CLOSE_SESSION 8 // client close it's client sessions
|
||||
|
||||
#define SYSCALL_EXEC 9 // run elf using current task
|
||||
#define SYSCALL_SYS_STATE 10 // run system state
|
||||
#define SYSCALL_REGISTER_IRQ 11 //
|
||||
|
||||
#define SYSCALL_KILL 12 // kill the task by id
|
||||
// clang-format on
|
||||
|
||||
typedef enum {
|
||||
SYS_STATE_TEST = 0,
|
||||
SYS_STATE_SET_TASK_PRIORITY,
|
||||
SYS_STATE_GET_HEAP_BASE,
|
||||
SYS_STATE_MEMBLOCK_INFO,
|
||||
SYS_STATE_SHOW_TASKS,
|
||||
SYS_STATE_SHOW_MEM_INFO,
|
||||
SYS_STATE_SHOW_CPU_INFO,
|
||||
} sys_state_option;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uintptr_t memblock_start;
|
||||
uintptr_t memblock_end;
|
||||
} memblock_info;
|
||||
int priority;
|
||||
} sys_state_info;
|
||||
|
||||
typedef int (*ipc_read_fn)(struct Session* session, int fd, char* dst, int offset, int len);
|
||||
typedef int (*ipc_fsize_fn)(struct Session* session, int fd);
|
||||
typedef int (*ipc_write_fn)(struct Session* session, int fd, char* src, int offset, int len);
|
||||
|
||||
int spawn(struct Session* session, int fd, ipc_read_fn ipc_read, ipc_fsize_fn ipc_fsize, char* name, char** argv);
|
||||
int exit();
|
||||
int yield();
|
||||
int kill(int pid);
|
||||
int register_server(char* name);
|
||||
int session(char* path, int capacity, struct Session* user_session);
|
||||
int poll_session(struct Session* userland_session_arr, int arr_capacity);
|
||||
int close_session(struct Session* session);
|
||||
int task_heap_base();
|
||||
int get_memblock_info(sys_state_info* info);
|
||||
int set_priority(sys_state_info* info);
|
||||
int show_task();
|
||||
int show_mem();
|
||||
int show_cpu();
|
||||
int mmap(uintptr_t vaddr, uintptr_t paddr, int len, bool is_dev);
|
||||
int register_irq(int irq, int opcode);
|
||||
@@ -19,6 +19,8 @@ INC_DIR = -I$(KERNEL_ROOT)/services/fs/libfs \
|
||||
-I$(KERNEL_ROOT)/services/fs/fs_server/include \
|
||||
-I$(KERNEL_ROOT)/services/lib/ipc \
|
||||
-I$(KERNEL_ROOT)/services/lib/memory \
|
||||
-I$(KERNEL_ROOT)/services/lib/serial \
|
||||
-I$(KERNEL_ROOT)/services/lib/usyscall \
|
||||
-I$(KERNEL_ROOT)/services/boards/$(BOARD) \
|
||||
-I$(KERNEL_ROOT)/services/app
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ struct Inode {
|
||||
};
|
||||
|
||||
// directory entry
|
||||
#define DIR_NAME_SIZE 14
|
||||
#define DIR_NAME_SIZE 30
|
||||
struct DirectEntry {
|
||||
uint16_t inum;
|
||||
char name[DIR_NAME_SIZE];
|
||||
|
||||
@@ -18,6 +18,8 @@ c_useropts = -O0
|
||||
INC_DIR = -I$(KERNEL_ROOT)/services/fs/libfs \
|
||||
-I$(KERNEL_ROOT)/services/lib/ipc \
|
||||
-I$(KERNEL_ROOT)/services/lib/memory \
|
||||
-I$(KERNEL_ROOT)/services/lib/serial \
|
||||
-I$(KERNEL_ROOT)/services/lib/usyscall \
|
||||
-I$(KERNEL_ROOT)/services/boards/$(BOARD) \
|
||||
-I$(KERNEL_ROOT)/services/app
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
SRC_DIR := ipc memory
|
||||
SRC_DIR := ipc memory usyscall
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ c_useropts = -O0
|
||||
|
||||
INC_DIR = -I$(KERNEL_ROOT)/services/lib/ipc \
|
||||
-I$(KERNEL_ROOT)/services/lib/memory \
|
||||
-I$(KERNEL_ROOT)/services/lib/serial \
|
||||
-I$(KERNEL_ROOT)/services/lib/usyscall \
|
||||
-I$(KERNEL_ROOT)/services/boards/$(BOARD) \
|
||||
-I$(KERNEL_ROOT)/services/app
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ void ipc_msg_send_wait(struct IpcMsg* msg)
|
||||
msg->header.done = 0;
|
||||
while (msg->header.done == 0) {
|
||||
/// @todo syscall yield with prio decrease
|
||||
yield();
|
||||
yield(SYS_TASK_YIELD_BLOCK_IPC);
|
||||
}
|
||||
assert(msg->header.done == 1);
|
||||
}
|
||||
@@ -138,7 +138,7 @@ int ipc_session_wait(struct Session* session)
|
||||
struct IpcMsg* msg = IPCSESSION_MSG(session);
|
||||
while (msg->header.done == 0) {
|
||||
/// @todo syscall yield with prio decrease
|
||||
yield();
|
||||
yield(SYS_TASK_YIELD_BLOCK_IPC);
|
||||
}
|
||||
assert(msg->header.done == 1);
|
||||
return msg->header.ret_val;
|
||||
@@ -156,9 +156,15 @@ void delay_session(void)
|
||||
session_delayed = true;
|
||||
}
|
||||
|
||||
bool is_cur_session_delayed(void)
|
||||
{
|
||||
return session_delayed;
|
||||
}
|
||||
|
||||
void ipc_server_loop(struct IpcNode* ipc_node)
|
||||
{
|
||||
struct Session session_list[NR_MAX_SESSION];
|
||||
memset(session_list, 0, sizeof(session_list));
|
||||
for (;;) {
|
||||
/* if connect sessions are greater than NR_MAX_SESSION,
|
||||
a full round will require multiple polls.
|
||||
@@ -167,40 +173,49 @@ void ipc_server_loop(struct IpcNode* ipc_node)
|
||||
*/
|
||||
poll_session(session_list, NR_MAX_SESSION);
|
||||
/* handle each session */
|
||||
for (int i = 0; i < NR_MAX_SESSION; i++) {
|
||||
if (session_list[i].buf == NULL) {
|
||||
yield();
|
||||
break;
|
||||
}
|
||||
cur_sess_id = session_list[i].id;
|
||||
struct IpcMsg* msg = IPCSESSION_MSG(&session_list[i]);
|
||||
/* handle every message in current session
|
||||
a session could be delay in case one of its message(current message) needs to wait for an interrupt message's arrival
|
||||
interfaces[opcode] should explicitly call delay_session() and return to delay this session
|
||||
*/
|
||||
while (msg->header.magic == IPC_MSG_MAGIC && msg->header.valid == 1 && msg->header.done != 1) {
|
||||
// printf("session %d [%d, %d]\n", session_list[i].id, session_list[i].head, session_list[i].tail);
|
||||
if (session_used_size(&session_list[i]) == 0 && session_forward_tail(&session_list[i], msg->header.len) < 0) {
|
||||
bool has_delayed = true;
|
||||
for (int repeat = 0; repeat <= 1 && has_delayed; repeat++) {
|
||||
has_delayed = false;
|
||||
for (int i = 0; i < NR_MAX_SESSION; i++) {
|
||||
session_delayed = false;
|
||||
if (session_list[i].buf == NULL) {
|
||||
yield(SYS_TASK_YIELD_NO_REASON);
|
||||
break;
|
||||
}
|
||||
if (ipc_node->interfaces[msg->header.opcode]) {
|
||||
ipc_node->interfaces[msg->header.opcode](msg);
|
||||
// check if this session is delayed by op handler, all messages after the delayed message in current session is blocked.
|
||||
if (session_delayed) {
|
||||
session_delayed = false;
|
||||
cur_sess_id = session_list[i].id;
|
||||
struct IpcMsg* msg = IPCSESSION_MSG(&session_list[i]);
|
||||
/* handle every message in current session
|
||||
a session could be delay in case one of its message(current message) needs to wait for an interrupt message's arrival
|
||||
interfaces[opcode] should explicitly call delay_session() and return to delay this session
|
||||
*/
|
||||
while (msg->header.magic == IPC_MSG_MAGIC && msg->header.valid == 1 && msg->header.done == 0) {
|
||||
// printf("session %d [%d, %d]\n", session_list[i].id, session_list[i].head, session_list[i].tail);
|
||||
if (session_used_size(&session_list[i]) == 0 && session_forward_tail(&session_list[i], msg->header.len) < 0) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
printf("Unsupport opcode(%d) for server: %s\n", msg->header.opcode, ipc_node->name);
|
||||
|
||||
// this is a message needs to handle
|
||||
if (ipc_node->interfaces[msg->header.opcode]) {
|
||||
ipc_node->interfaces[msg->header.opcode](msg);
|
||||
// check if this session is delayed by op handler, all messages after the delayed message in current session is blocked.
|
||||
if (is_cur_session_delayed()) {
|
||||
msg->header.delayed = 1;
|
||||
has_delayed = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
printf("Unsupport opcode(%d) for server: %s\n", msg->header.opcode, ipc_node->name);
|
||||
}
|
||||
// current msg is a message that needs to ignore
|
||||
// finish this message in server's perspective
|
||||
if (session_forward_head(&session_list[i], msg->header.len) < 0) {
|
||||
break;
|
||||
}
|
||||
msg = IPCSESSION_MSG(&session_list[i]);
|
||||
}
|
||||
// finish this message in server's perspective
|
||||
while (session_forward_head(&session_list[i], msg->header.len) < 0) {
|
||||
yield();
|
||||
}
|
||||
msg = IPCSESSION_MSG(&session_list[i]);
|
||||
// stop handle this session
|
||||
cur_sess_id = -1;
|
||||
}
|
||||
// stop handle this session
|
||||
cur_sess_id = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ Modification:
|
||||
#include "ipcargs.h"
|
||||
#include "session.h"
|
||||
|
||||
#define NR_MAX_SESSION 16
|
||||
#define NR_MAX_SESSION 32
|
||||
#define IPC_MSG_MAGIC 0xABCDDCBA
|
||||
|
||||
typedef struct {
|
||||
@@ -47,7 +47,7 @@ typedef struct {
|
||||
uint64_t valid : 1; // for server to peek new msg
|
||||
uint64_t done : 1; // for client to check request done
|
||||
uint64_t init : 1; // for client to check request done
|
||||
uint64_t reserved : 1;
|
||||
uint64_t delayed : 1;
|
||||
uint64_t nr_args : 4;
|
||||
uint64_t opcode : 8;
|
||||
uint64_t len : 16;
|
||||
@@ -225,6 +225,7 @@ void ipc_server_loop(struct IpcNode* ipc_node);
|
||||
return res; \
|
||||
}
|
||||
|
||||
bool is_cur_session_delayed(void);
|
||||
#define IPC_SERVER_INTERFACE(ipc_name, argc) \
|
||||
static int IPC_SERVE(ipc_name)(struct IpcMsg * msg) \
|
||||
{ \
|
||||
@@ -233,8 +234,10 @@ void ipc_server_loop(struct IpcNode* ipc_node);
|
||||
argv[i] = ipc_msg_get_nth_arg_buf(msg, i); \
|
||||
} \
|
||||
int32_t _ret = IPC_DO_SERVE##argc(ipc_name); \
|
||||
ipc_msg_set_return(msg, &_ret); \
|
||||
msg->header.done = 1; \
|
||||
if (!is_cur_session_delayed()) { \
|
||||
ipc_msg_set_return(msg, &_ret); \
|
||||
msg->header.done = 1; \
|
||||
} \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,6 @@ bool session_free_buf(struct Session* session, int len)
|
||||
if (len > session_used_size(session)) {
|
||||
return false;
|
||||
}
|
||||
assert(session_forward_head(session, len) != 1);
|
||||
assert(session_forward_head(session, len) != -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -55,8 +55,8 @@ __attribute__((__always_inline__)) static inline int session_remain_capacity(str
|
||||
|
||||
__attribute__((__always_inline__)) static inline int session_forward_head(struct Session* session, int len)
|
||||
{
|
||||
if (((session->head + len) % session->capacity) > session->tail) {
|
||||
printf("forward head with too much size\n");
|
||||
if (len > session_used_size(session)) {
|
||||
printf("forward head with too much size, session used size: %d\n", session_used_size(session));
|
||||
return -1;
|
||||
}
|
||||
session->head = (session->head + len) % session->capacity;
|
||||
|
||||
@@ -16,6 +16,8 @@ INC_DIR = -I$(KERNEL_ROOT)/services/app \
|
||||
-I$(KERNEL_ROOT)/services/fs/libfs \
|
||||
-I$(KERNEL_ROOT)/services/boards/$(BOARD) \
|
||||
-I$(KERNEL_ROOT)/services/lib/memory \
|
||||
-I$(KERNEL_ROOT)/services/lib/serial \
|
||||
-I$(KERNEL_ROOT)/services/lib/usyscall \
|
||||
-I$(KERNEL_ROOT)/services/lib/ipc
|
||||
|
||||
all: libmem.o
|
||||
|
||||
28
Ubiquitous/XiZi_AIoT/services/lib/usyscall/Makefile
Normal file
28
Ubiquitous/XiZi_AIoT/services/lib/usyscall/Makefile
Normal file
@@ -0,0 +1,28 @@
|
||||
ifeq ($(BOARD), imx6q-sabrelite)
|
||||
toolchain ?= arm-none-eabi-
|
||||
endif
|
||||
ifeq ($(BOARD), zynq7000-zc702)
|
||||
toolchain ?= arm-xilinx-eabi-
|
||||
endif
|
||||
cc = ${toolchain}gcc
|
||||
ld = ${toolchain}g++
|
||||
objdump = ${toolchain}objdump
|
||||
user_ldflags = -N -Ttext 0
|
||||
|
||||
cflags = -std=c11 -march=armv7-a -mtune=cortex-a9 -nostdlib -nodefaultlibs -mfloat-abi=soft -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -ggdb -Wno-unused -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pie
|
||||
c_useropts = -O0
|
||||
|
||||
INC_DIR = -I$(KERNEL_ROOT)/services/app \
|
||||
-I$(KERNEL_ROOT)/services/fs/libfs \
|
||||
-I$(KERNEL_ROOT)/services/boards/$(BOARD) \
|
||||
-I$(KERNEL_ROOT)/services/lib/memory \
|
||||
-I$(KERNEL_ROOT)/services/lib/serial \
|
||||
-I$(KERNEL_ROOT)/services/lib/usyscall \
|
||||
-I$(KERNEL_ROOT)/services/lib/ipc
|
||||
|
||||
all: usyscall.o
|
||||
@mv $^ ../../app
|
||||
|
||||
%.o: %.c
|
||||
@echo "cc $^"
|
||||
@${cc} ${cflags} ${c_useropts} ${INC_DIR} -o $@ -c $^
|
||||
@@ -12,28 +12,6 @@
|
||||
#include "usyscall.h"
|
||||
#include "libmem.h"
|
||||
|
||||
static int
|
||||
syscall(int sys_num, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
__asm__ volatile(
|
||||
"mov r0, %1;\
|
||||
mov r1, %2;\
|
||||
mov r2, %3;\
|
||||
mov r3, %4;\
|
||||
mov r4, %5;\
|
||||
swi 0;\
|
||||
dsb;\
|
||||
isb;\
|
||||
mov %0, r0"
|
||||
: "=r"(ret)
|
||||
: "r"(sys_num), "r"(a1), "r"(a2), "r"(a3), "r"(a4)
|
||||
: "memory", "r0", "r1", "r2", "r3", "r4");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int spawn(struct Session* session, int fd, ipc_read_fn ipc_read, ipc_fsize_fn ipc_fsize, char* name, char** argv)
|
||||
{
|
||||
int file_size = ipc_fsize(session, fd);
|
||||
@@ -53,9 +31,9 @@ int exit()
|
||||
return syscall(SYSCALL_EXIT, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
int yield()
|
||||
int yield(task_yield_reason reason)
|
||||
{
|
||||
return syscall(SYSCALL_YIELD, 0, 0, 0, 0);
|
||||
return syscall(SYSCALL_YIELD, (uintptr_t)reason, 0, 0, 0);
|
||||
}
|
||||
|
||||
int kill(int pid)
|
||||
@@ -44,6 +44,12 @@ typedef enum {
|
||||
SYS_STATE_SHOW_CPU_INFO,
|
||||
} sys_state_option;
|
||||
|
||||
typedef enum {
|
||||
SYS_TASK_YIELD_NO_REASON = 0x0,
|
||||
SYS_TASK_YIELD_FOREVER = 0x1,
|
||||
SYS_TASK_YIELD_BLOCK_IPC = 0x2,
|
||||
} task_yield_reason;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uintptr_t memblock_start;
|
||||
@@ -56,9 +62,11 @@ typedef int (*ipc_read_fn)(struct Session* session, int fd, char* dst, int offse
|
||||
typedef int (*ipc_fsize_fn)(struct Session* session, int fd);
|
||||
typedef int (*ipc_write_fn)(struct Session* session, int fd, char* src, int offset, int len);
|
||||
|
||||
int syscall(int sys_num, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4);
|
||||
|
||||
int spawn(struct Session* session, int fd, ipc_read_fn ipc_read, ipc_fsize_fn ipc_fsize, char* name, char** argv);
|
||||
int exit();
|
||||
int yield();
|
||||
int yield(task_yield_reason reason);
|
||||
int kill(int pid);
|
||||
int register_server(char* name);
|
||||
int session(char* path, int capacity, struct Session* user_session);
|
||||
@@ -18,6 +18,8 @@ c_useropts = -O0
|
||||
INC_DIR = -I$(KERNEL_ROOT)/services/app \
|
||||
-I$(KERNEL_ROOT)/services/fs/libfs \
|
||||
-I$(KERNEL_ROOT)/services/lib/memory \
|
||||
-I$(KERNEL_ROOT)/services/lib/serial \
|
||||
-I$(KERNEL_ROOT)/services/lib/usyscall \
|
||||
-I$(KERNEL_ROOT)/services/lib/ipc \
|
||||
-I$(KERNEL_ROOT)/services/boards/$(BOARD)
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ struct Inode {
|
||||
};
|
||||
|
||||
// Directory is a file containing a sequence of DirEntry structures.
|
||||
#define DIR_NAME_SIZE 14
|
||||
#define DIR_NAME_SIZE 30
|
||||
struct DirEntry {
|
||||
ushort inum;
|
||||
char name[DIR_NAME_SIZE];
|
||||
|
||||
@@ -68,7 +68,6 @@ struct KFreeList {
|
||||
struct double_list_node list_head;
|
||||
};
|
||||
|
||||
#define MAX_NR_PAGES MAX_NR_FREE_PAGES
|
||||
struct KBuddy {
|
||||
uint32_t n_pages;
|
||||
uint32_t use_lock;
|
||||
@@ -77,7 +76,7 @@ struct KBuddy {
|
||||
struct KPage* first_page;
|
||||
uint32_t mem_start;
|
||||
uint32_t mem_end;
|
||||
struct KPage pages[MAX_NR_PAGES];
|
||||
struct KPage* pages;
|
||||
};
|
||||
|
||||
/*********************************************
|
||||
@@ -89,6 +88,7 @@ struct KBuddy {
|
||||
* @param mem_end free memory region end
|
||||
* @return void
|
||||
*/
|
||||
bool KBuddyInit(struct KBuddy* pbuddy, uint32_t mem_start, uint32_t mem_end);
|
||||
void KBuddySysInit(struct KBuddy* pbuddy, uint32_t mem_start, uint32_t mem_end);
|
||||
|
||||
/*
|
||||
@@ -105,6 +105,8 @@ char* KBuddyAlloc(struct KBuddy* pbuddy, uint32_t size);
|
||||
*/
|
||||
bool KBuddyFree(struct KBuddy* pbuddy, char* vaddr);
|
||||
|
||||
void KBuddyDestory(struct KBuddy* pbuddy);
|
||||
|
||||
/*
|
||||
* Print current free pages for debug.
|
||||
*/
|
||||
|
||||
@@ -41,7 +41,7 @@ typedef struct {
|
||||
uint64_t valid : 1; // for server to peek new msg
|
||||
uint64_t done : 1; // for client to check request done
|
||||
uint64_t init : 1; // for client to check request done
|
||||
uint64_t reserved : 1;
|
||||
uint64_t delayed : 1;
|
||||
uint64_t nr_args : 4;
|
||||
uint64_t opcode : 8;
|
||||
uint64_t len : 16;
|
||||
|
||||
@@ -29,13 +29,14 @@ Modification:
|
||||
*************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "uart_common_ope.h"
|
||||
|
||||
#define OUTPUT_LEVLE_LOG 0
|
||||
#define OUTPUT_LEVLE_DEBUG 1
|
||||
#define OUTPUT_LEVLE_ERROR 2
|
||||
|
||||
#define OUTPUT_LEVLE OUTPUT_LEVLE_DEBUG
|
||||
|
||||
extern void KPrintf(char* fmt, ...);
|
||||
// #define OUTPUT_LEVLE OUTPUT_LEVLE_LOG
|
||||
|
||||
#if (OUTPUT_LEVLE >= OUTPUT_LEVLE_LOG)
|
||||
#define LOG_PRINTF(f, args...) \
|
||||
|
||||
@@ -47,4 +47,9 @@ static inline struct CPU* cur_cpu(void)
|
||||
return &global_cpus[cur_cpuid()];
|
||||
}
|
||||
|
||||
struct spinlock whole_kernel_lock;
|
||||
extern struct spinlock whole_kernel_lock;
|
||||
|
||||
void xizi_enter_kernel();
|
||||
bool xizi_try_enter_kernel();
|
||||
void xizi_leave_kernel();
|
||||
bool xizi_is_in_kernel();
|
||||
@@ -69,6 +69,7 @@ struct XiziPageManager {
|
||||
|
||||
extern struct MmuCommonDone* _p_pgtbl_mmu_access;
|
||||
uintptr_t* _page_walk(uintptr_t* pgdir, uintptr_t vaddr, bool alloc);
|
||||
void _free_user_pgdir(struct TopLevelPageDirectory* pgdir);
|
||||
|
||||
extern struct TopLevelPageDirectory kern_pgdir;
|
||||
void load_kern_pgdir(struct TraceTag* mmu_driver_tag, struct TraceTag* intr_driver_tag);
|
||||
|
||||
@@ -64,6 +64,12 @@ typedef enum {
|
||||
SYS_STATE_SHOW_CPU_INFO,
|
||||
} sys_state_option;
|
||||
|
||||
typedef enum {
|
||||
SYS_TASK_YIELD_NO_REASON = 0x0,
|
||||
SYS_TASK_YIELD_FOREVER = 0x1,
|
||||
SYS_TASK_YIELD_BLOCK_IPC = 0x2,
|
||||
} task_yield_reason;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uintptr_t memblock_start;
|
||||
@@ -80,17 +86,19 @@ int syscall(int sys_num, uintptr_t param1, uintptr_t param2, uintptr_t param3, u
|
||||
|
||||
int sys_spawn(char* img_start, char* name, char** argv);
|
||||
int sys_exit(struct TaskMicroDescriptor* ptask);
|
||||
int sys_yield();
|
||||
int sys_yield(task_yield_reason reason);
|
||||
int sys_kill(int id);
|
||||
|
||||
int sys_register_as_server(char* name);
|
||||
int sys_connect_session(char* path, int capacity, struct Session* user_session);
|
||||
int sys_poll_session(struct Session* userland_session_arr, int arr_capacity);
|
||||
int sys_close_session(struct Session* session);
|
||||
int sys_close_session(struct TaskMicroDescriptor* task, struct Session* session);
|
||||
|
||||
int sys_exec(char* img_start, char* name, char** argv);
|
||||
int sys_state(sys_state_option option, sys_state_info* info);
|
||||
int sys_mmap(uintptr_t vaddr, uintptr_t paddr, int len, int is_dev);
|
||||
|
||||
int sys_register_irq(int irq_num, int irq_opcode);
|
||||
int sys_unbind_irq_all(struct TaskMicroDescriptor* task);
|
||||
int sys_unbind_irq(struct TaskMicroDescriptor* task, int irq_num);
|
||||
#endif
|
||||
|
||||
@@ -31,6 +31,7 @@ Modification:
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#include "buddy.h"
|
||||
#include "list.h"
|
||||
#include "object_allocator.h"
|
||||
#include "pagetable.h"
|
||||
@@ -47,6 +48,8 @@ enum ProcState {
|
||||
READY,
|
||||
RUNNING,
|
||||
DEAD,
|
||||
BLOCKED,
|
||||
NEVER_RUN,
|
||||
};
|
||||
|
||||
/* Thread Control Block */
|
||||
@@ -59,33 +62,39 @@ struct Thread {
|
||||
|
||||
/* Process Control Block */
|
||||
struct TaskMicroDescriptor {
|
||||
struct double_list_node node;
|
||||
|
||||
struct spinlock lock;
|
||||
/* task->lock needed */
|
||||
/* task debug resources */
|
||||
int pid;
|
||||
bool bind_irq;
|
||||
bool dead;
|
||||
char name[TASK_NAME_MAX_LEN];
|
||||
|
||||
/// @todo support return value
|
||||
int ret; // state val that be returned to parent
|
||||
/// @todo support parent
|
||||
struct TaskMicroDescriptor* parent;
|
||||
enum ProcState state;
|
||||
/// @todo support ret value
|
||||
int ret; // state val that be returned to parent
|
||||
|
||||
/* task context resources */
|
||||
struct Thread main_thread; // will only access by task itself
|
||||
|
||||
/* task memory resources */
|
||||
struct TopLevelPageDirectory pgdir; // [phy] vm pgtbl base address
|
||||
uintptr_t heap_base; // mem size of proc used(allocated by kernel)
|
||||
/// @todo support heap_base
|
||||
uintptr_t mem_size;
|
||||
|
||||
/* task communication resources */
|
||||
struct double_list_node cli_sess_listhead;
|
||||
struct double_list_node svr_sess_listhead;
|
||||
bool current_ipc_handled;
|
||||
struct KBuddy* massive_ipc_allocator;
|
||||
struct TraceTag server_identifier;
|
||||
|
||||
/* task->lock not necessary */
|
||||
struct Thread main_thread; // will only access by task itself
|
||||
/* task schedule attributes */
|
||||
struct double_list_node node;
|
||||
enum ProcState state;
|
||||
int priority; // priority
|
||||
int remain_tick;
|
||||
int maxium_tick;
|
||||
|
||||
struct TraceTag cwd; // current directory
|
||||
|
||||
int priority; // priority
|
||||
|
||||
/// @todo support mem_size
|
||||
uintptr_t mem_size; // mem size of proc used(allocated by kernel)
|
||||
char name[TASK_NAME_MAX_LEN];
|
||||
};
|
||||
|
||||
struct SchedulerRightGroup {
|
||||
@@ -94,17 +103,13 @@ struct SchedulerRightGroup {
|
||||
};
|
||||
|
||||
struct XiziTaskManager {
|
||||
struct spinlock lock; // lock to organize free and used task list
|
||||
struct double_list_node task_list_head[TASK_MAX_PRIORITY]; /* list of task control blocks that are allocated */
|
||||
int nr_pcb_used; // for debug
|
||||
struct double_list_node task_running_list_head;
|
||||
struct double_list_node task_blocked_list_head;
|
||||
struct slab_allocator task_allocator;
|
||||
|
||||
/// @todo Add pid to task
|
||||
struct slab_allocator task_buddy_allocator;
|
||||
uint32_t next_pid;
|
||||
|
||||
/* number of tcbs in which one page contains */
|
||||
int nr_tcb_per_page;
|
||||
|
||||
/* init task manager */
|
||||
void (*init)();
|
||||
/* new a task control block, checkout #sys_spawn for usage */
|
||||
@@ -112,14 +117,19 @@ struct XiziTaskManager {
|
||||
/* free a task control block, this calls #free_user_pgdir to free all vitual spaces */
|
||||
void (*free_pcb)(struct TaskMicroDescriptor*);
|
||||
/* init a task control block, set name, remain_tick, state, cwd, priority, etc. */
|
||||
void (*task_set_default_schedule_attr)(struct TaskMicroDescriptor*, struct TraceTag* cwd);
|
||||
void (*task_set_default_schedule_attr)(struct TaskMicroDescriptor*);
|
||||
|
||||
/* use by task_scheduler, find next READY task, should be in locked */
|
||||
struct TaskMicroDescriptor* (*next_runnable_task)(void);
|
||||
/* function that's runing by kernel thread context, schedule use tasks */
|
||||
void (*task_scheduler)(struct SchedulerRightGroup);
|
||||
|
||||
/* handle task state */
|
||||
/* call to yield current use task */
|
||||
void (*cur_task_yield_noschedule)(void);
|
||||
void (*task_yield_noschedule)(struct TaskMicroDescriptor* task, bool is_blocking);
|
||||
/* block and unblock task */
|
||||
void (*task_block)(struct TaskMicroDescriptor* task);
|
||||
void (*task_unblock)(struct TaskMicroDescriptor* task);
|
||||
/* set task priority */
|
||||
void (*set_cur_task_priority)(int priority);
|
||||
};
|
||||
|
||||
@@ -35,24 +35,25 @@ Modification:
|
||||
#include "assert.h"
|
||||
#include "task.h"
|
||||
|
||||
extern uint32_t _binary_init_start[], _binary_default_fs_start[];
|
||||
static struct TraceTag hardkernel_tag, softkernel_tag;
|
||||
struct spinlock whole_kernel_lock;
|
||||
|
||||
static int core_init_done = 0;
|
||||
int main(void)
|
||||
extern uint32_t _binary_init_start[], _binary_default_fs_start[];
|
||||
extern int sys_spawn(char* img_start, char* name, char** argv);
|
||||
|
||||
static struct TraceTag hardkernel_tag, softkernel_tag;
|
||||
static volatile int core_init_done = 0;
|
||||
__attribute__((optimize("O0"))) int main(void)
|
||||
{
|
||||
/* init tracer */
|
||||
uint32_t cpu_id = cur_cpuid();
|
||||
|
||||
if (cpu_id == 0) {
|
||||
tracer_init(); // init tracer system
|
||||
// clang-format off
|
||||
if (!CreateResourceTag(&hardkernel_tag, RequireRootTag(), "hardkernel", TRACER_OWNER, NULL) ||
|
||||
if (!CreateResourceTag(&hardkernel_tag, RequireRootTag(), "hardkernel", TRACER_OWNER, NULL) || //
|
||||
!CreateResourceTag(&softkernel_tag, RequireRootTag(), "softkernel", TRACER_OWNER, NULL)) {
|
||||
ERROR("Failed to create hardkernel owner and softkernel owner.\n");
|
||||
return -1;
|
||||
}
|
||||
// clang-format on
|
||||
/* init hardkernel */
|
||||
if (!hardkernel_init(&hardkernel_tag)) {
|
||||
return -1;
|
||||
@@ -80,23 +81,24 @@ int main(void)
|
||||
|
||||
/* start first task */
|
||||
char* init_task_param[2] = { "/app/init", 0 };
|
||||
spawn_embedded_task((char*)_binary_init_start, "init", init_task_param);
|
||||
sys_spawn((char*)_binary_init_start, "init", init_task_param);
|
||||
char* fs_server_task_param[2] = { "/app/fs_server", 0 };
|
||||
spawn_embedded_task((char*)_binary_default_fs_start, "memfs", fs_server_task_param);
|
||||
sys_spawn((char*)_binary_default_fs_start, "memfs", fs_server_task_param);
|
||||
}
|
||||
|
||||
/* start scheduler */
|
||||
struct SchedulerRightGroup scheduler_rights;
|
||||
assert(AchieveResourceTag(&scheduler_rights.mmu_driver_tag, &hardkernel_tag, "mmu-ac-resource"));
|
||||
assert(AchieveResourceTag(&scheduler_rights.intr_driver_tag, &hardkernel_tag, "intr-ac-resource"));
|
||||
|
||||
core_init_done |= (1 << cpu_id);
|
||||
LOG_PRINTF("CPU %d init done\n", cpu_id);
|
||||
spinlock_unlock(&whole_kernel_lock);
|
||||
|
||||
while (core_init_done != (1 << NR_CPU) - 1)
|
||||
;
|
||||
// sync memory
|
||||
__sync_synchronize();
|
||||
start_smp_cache_broadcast(cpu_id);
|
||||
// enter kernel seriously
|
||||
xizi_enter_kernel();
|
||||
xizi_task_manager.task_scheduler(scheduler_rights);
|
||||
|
||||
// never reached
|
||||
|
||||
@@ -29,6 +29,7 @@ Modification:
|
||||
*************************************************/
|
||||
|
||||
#include "buddy.h"
|
||||
#include "kalloc.h"
|
||||
#include "log.h"
|
||||
|
||||
static void _buddy_split_page(struct KPage* page, uint32_t low_order, uint32_t high_order, struct KFreeList* list)
|
||||
@@ -138,8 +139,15 @@ static void KBuddyPagesFree(struct KBuddy* pbuddy, struct KPage* page)
|
||||
return;
|
||||
}
|
||||
|
||||
void KBuddySysInit(struct KBuddy* pbuddy, uint32_t mem_start, uint32_t mem_end)
|
||||
bool KBuddyInit(struct KBuddy* pbuddy, uint32_t mem_start, uint32_t mem_end)
|
||||
{
|
||||
if (pbuddy->pages == NULL) {
|
||||
if ((pbuddy->pages = (struct KPage*)kalloc(((mem_end - mem_start) >> LEVEL4_PTE_SHIFT) * sizeof(struct KPage))) == NULL) {
|
||||
ERROR("Not space to init a buddy object.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t i = 0;
|
||||
struct KPage* page = NULL;
|
||||
struct KFreeList* free_list = NULL;
|
||||
@@ -173,6 +181,16 @@ void KBuddySysInit(struct KBuddy* pbuddy, uint32_t mem_start, uint32_t mem_end)
|
||||
doubleListNodeInit(&page->node);
|
||||
KBuddyPagesFree(pbuddy, page);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void KBuddySysInit(struct KBuddy* pbuddy, uint32_t mem_start, uint32_t mem_end)
|
||||
{
|
||||
#define MAX_NR_PAGES MAX_NR_FREE_PAGES
|
||||
static struct KPage kern_free_pages[MAX_NR_PAGES];
|
||||
pbuddy->pages = kern_free_pages;
|
||||
KBuddyInit(pbuddy, mem_start, mem_end);
|
||||
}
|
||||
|
||||
char* KBuddyAlloc(struct KBuddy* pbuddy, uint32_t size)
|
||||
@@ -211,6 +229,13 @@ bool KBuddyFree(struct KBuddy* pbuddy, char* vaddr)
|
||||
return true;
|
||||
}
|
||||
|
||||
void KBuddyDestory(struct KBuddy* pbuddy)
|
||||
{
|
||||
if (pbuddy->pages) {
|
||||
kfree((void*)pbuddy->pages);
|
||||
}
|
||||
}
|
||||
|
||||
void KFreePagesInfo(struct KBuddy* pbuddy)
|
||||
{
|
||||
DEBUG("Buddy structure:");
|
||||
|
||||
@@ -45,7 +45,7 @@ bool module_phymem_init()
|
||||
uint32_t user_freemem_start = PHY_USER_FREEMEM_BASE;
|
||||
uint32_t user_freemem_end = PHY_MEM_STOP;
|
||||
KBuddySysInit(&kern_virtmem_buddy, kern_freemem_start, kern_freemem_end);
|
||||
KBuddySysInit(&user_phy_freemem_buddy, user_freemem_start, user_freemem_end);
|
||||
KBuddyInit(&user_phy_freemem_buddy, user_freemem_start, user_freemem_end);
|
||||
LOG_PRINTF("Free memory organized done.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -84,9 +84,14 @@ void* slab_alloc(struct slab_allocator* const allocator)
|
||||
allocator->full->prev = full_head;
|
||||
}
|
||||
allocator->full = full_head;
|
||||
return allocator->full->data + slot * allocator->element_size;
|
||||
|
||||
void* return_addr = allocator->full->data + slot * allocator->element_size;
|
||||
memset(return_addr, 0, allocator->element_size);
|
||||
return return_addr;
|
||||
} else {
|
||||
return allocator->partial->data + slot * allocator->element_size;
|
||||
void* return_addr = allocator->partial->data + slot * allocator->element_size;
|
||||
memset(return_addr, 0, allocator->element_size);
|
||||
return return_addr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +114,8 @@ void* slab_alloc(struct slab_allocator* const allocator)
|
||||
allocator->partial->refcount = 1;
|
||||
}
|
||||
allocator->partial->bitmap = allocator->bitmap_empty ^ BITMAP_FIRST_BIT;
|
||||
assert(allocator->partial->data != NULL);
|
||||
memset(allocator->partial->data, 0, allocator->element_size);
|
||||
return allocator->partial->data;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,8 @@ static bool _map_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t paddr, uintp
|
||||
|
||||
uintptr_t* pte;
|
||||
while (true) {
|
||||
if ((pte = _page_walk(pgdir, vaddr, true)) == 0) {
|
||||
if ((pte = _page_walk(pgdir, vaddr, true)) == NULL) {
|
||||
ERROR("pte not found for vaddr %x.\n", vaddr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -81,6 +82,7 @@ static bool _map_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t paddr, uintp
|
||||
paddr += PAGE_SIZE;
|
||||
}
|
||||
|
||||
assert(vaddr == vaddr_last);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -94,7 +96,8 @@ static bool _unmap_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t len)
|
||||
|
||||
uintptr_t* pte;
|
||||
while (true) {
|
||||
if ((pte = _page_walk(pgdir, vaddr, true)) == 0) {
|
||||
if ((pte = _page_walk(pgdir, vaddr, false)) == NULL) {
|
||||
ERROR("pte not found for vaddr %x.\n", vaddr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -112,6 +115,7 @@ static bool _unmap_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t len)
|
||||
vaddr += PAGE_SIZE;
|
||||
}
|
||||
|
||||
assert(vaddr == vaddr_last);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -140,33 +144,6 @@ static bool _map_user_pages(uintptr_t* pgdir, uintptr_t vaddr, uintptr_t paddr,
|
||||
return _map_pages(pgdir, vaddr, paddr, len, mem_attr);
|
||||
}
|
||||
|
||||
static void _free_user_pgdir(struct TopLevelPageDirectory* pgdir)
|
||||
{
|
||||
uintptr_t low_bound = kern_virtmem_buddy.mem_start, high_bound = kern_virtmem_buddy.mem_end;
|
||||
uintptr_t user_low_bound = user_phy_freemem_buddy.mem_start, user_high_bound = user_phy_freemem_buddy.mem_end;
|
||||
uintptr_t end_idx = USER_MEM_TOP >> LEVEL3_PDE_SHIFT;
|
||||
|
||||
for (uintptr_t i = 0; i < end_idx; i++) {
|
||||
// free each page table
|
||||
uintptr_t* pgtbl_paddr = (uintptr_t*)LEVEL4_PTE_ADDR(pgdir->pd_addr[i]);
|
||||
if (pgtbl_paddr != 0) {
|
||||
// free each page
|
||||
for (uintptr_t j = 0; j < NUM_LEVEL4_PTE; j++) {
|
||||
uintptr_t* page_paddr = (uintptr_t*)ALIGNDOWN(((uintptr_t*)P2V(pgtbl_paddr))[j], PAGE_SIZE);
|
||||
if (page_paddr != NULL) {
|
||||
if (LIKELY((uintptr_t)page_paddr >= low_bound && (uintptr_t)page_paddr < high_bound)) {
|
||||
kfree(P2V(page_paddr));
|
||||
} else if (LIKELY((uintptr_t)page_paddr >= user_low_bound && (uintptr_t)page_paddr < user_high_bound)) {
|
||||
raw_free((char*)page_paddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
kfree(P2V(pgtbl_paddr));
|
||||
}
|
||||
}
|
||||
kfree((char*)pgdir->pd_addr);
|
||||
}
|
||||
|
||||
/// assume that a user pagedir is allocated from [0, size)
|
||||
/// if new_size > old_size, allocate more space,
|
||||
/// if old_size > new_size, free extra space, to avoid unnecessary alloc/free.
|
||||
@@ -191,7 +168,9 @@ static uintptr_t _resize_user_pgdir(struct TopLevelPageDirectory* pgdir, uintptr
|
||||
}
|
||||
memset(new_page, 0, PAGE_SIZE);
|
||||
|
||||
xizi_pager.map_pages(pgdir->pd_addr, cur_size, V2P(new_page), PAGE_SIZE, false);
|
||||
if (!xizi_pager.map_pages(pgdir->pd_addr, cur_size, V2P(new_page), PAGE_SIZE, false)) {
|
||||
return cur_size;
|
||||
}
|
||||
cur_size += PAGE_SIZE;
|
||||
}
|
||||
|
||||
@@ -294,11 +273,9 @@ void load_kern_pgdir(struct TraceTag* mmu_driver_tag, struct TraceTag* intr_driv
|
||||
_map_pages((uintptr_t*)kern_pgdir.pd_addr, DEV_VRTMEM_BASE, DEV_PHYMEM_BASE, DEV_MEM_SZ, dev_attr);
|
||||
|
||||
_p_pgtbl_mmu_access->LoadPgdir((uintptr_t)V2P(kern_pgdir.pd_addr));
|
||||
// _p_pgtbl_mmu_access->LoadPgdirCrit((uintptr_t)V2P(kern_pgdir.pd_addr), intr_driver_tag);
|
||||
}
|
||||
|
||||
void secondary_cpu_load_kern_pgdir(struct TraceTag* mmu_driver_tag, struct TraceTag* intr_driver_tag)
|
||||
{
|
||||
_p_pgtbl_mmu_access->LoadPgdir((uintptr_t)V2P(kern_pgdir.pd_addr));
|
||||
// _p_pgtbl_mmu_access->LoadPgdirCrit((uintptr_t)V2P(kern_pgdir.pd_addr), intr_driver_tag);
|
||||
}
|
||||
@@ -29,6 +29,11 @@ Modification:
|
||||
*************************************************/
|
||||
#include <stdint.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "memlayout.h"
|
||||
|
||||
#include "assert.h"
|
||||
#include "buddy.h"
|
||||
#include "kalloc.h"
|
||||
#include "pagetable.h"
|
||||
|
||||
@@ -36,6 +41,7 @@ uintptr_t* _page_walk(uintptr_t* pgdir, uintptr_t vaddr, bool alloc)
|
||||
{
|
||||
|
||||
// get page table addr
|
||||
assert(pgdir != NULL);
|
||||
uintptr_t pde_attr = 0;
|
||||
_p_pgtbl_mmu_access->MmuPdeAttr(&pde_attr);
|
||||
|
||||
@@ -55,4 +61,37 @@ uintptr_t* _page_walk(uintptr_t* pgdir, uintptr_t vaddr, bool alloc)
|
||||
}
|
||||
|
||||
return &pgtbl_vaddr[LEVEL4_PTE_IDX(vaddr)];
|
||||
}
|
||||
|
||||
void _free_user_pgdir(struct TopLevelPageDirectory* pgdir)
|
||||
{
|
||||
uintptr_t low_bound = kern_virtmem_buddy.mem_start, high_bound = kern_virtmem_buddy.mem_end;
|
||||
uintptr_t user_low_bound = user_phy_freemem_buddy.mem_start, user_high_bound = user_phy_freemem_buddy.mem_end;
|
||||
uintptr_t end_idx = USER_MEM_TOP >> LEVEL3_PDE_SHIFT;
|
||||
|
||||
for (uintptr_t level4_entry_idx = 0; level4_entry_idx < end_idx; level4_entry_idx++) {
|
||||
// free each level4 page table
|
||||
uintptr_t* pgtbl_paddr = (uintptr_t*)LEVEL4_PTE_ADDR(pgdir->pd_addr[level4_entry_idx]);
|
||||
if (pgtbl_paddr != NULL) {
|
||||
// free each page
|
||||
for (uintptr_t page_entry_idx = 0; page_entry_idx < NUM_LEVEL4_PTE; page_entry_idx++) {
|
||||
uintptr_t vaddr = (level4_entry_idx << LEVEL3_PDE_SHIFT) | (page_entry_idx << LEVEL4_PTE_SHIFT);
|
||||
|
||||
// get page paddr
|
||||
uintptr_t* page_paddr = (uintptr_t*)ALIGNDOWN(((uintptr_t*)P2V(pgtbl_paddr))[page_entry_idx], PAGE_SIZE);
|
||||
if (page_paddr != NULL) {
|
||||
// IPC vaddr should not be addressed here.
|
||||
assert(vaddr < USER_IPC_SPACE_BASE || vaddr >= USER_IPC_SPACE_TOP);
|
||||
|
||||
if (LIKELY((uintptr_t)page_paddr >= low_bound && (uintptr_t)page_paddr < high_bound)) {
|
||||
kfree(P2V(page_paddr));
|
||||
} else if (LIKELY((uintptr_t)page_paddr >= user_low_bound && (uintptr_t)page_paddr < user_high_bound)) {
|
||||
raw_free((char*)page_paddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
kfree(P2V(pgtbl_paddr));
|
||||
}
|
||||
}
|
||||
kfree((char*)pgdir->pd_addr);
|
||||
}
|
||||
@@ -92,8 +92,24 @@ static uintptr_t map_task_share_page(struct TaskMicroDescriptor* task, const uin
|
||||
struct MmuCommonDone* p_mmu_driver = AchieveResource(&right_group.mmu_driver_tag);
|
||||
|
||||
// map double vaddr page to support uniform ring buffer r/w
|
||||
uintptr_t vaddr = alloc_share_page_addr(task, nr_pages * 2);
|
||||
if (UNLIKELY(vaddr == 0)) {
|
||||
uintptr_t vaddr = (uintptr_t)NULL;
|
||||
if (task->massive_ipc_allocator != NULL) {
|
||||
vaddr = (uintptr_t)KBuddyAlloc(task->massive_ipc_allocator, PAGE_SIZE * nr_pages * 2);
|
||||
assert(xizi_pager.address_translate(&task->pgdir, vaddr) == (uintptr_t)NULL);
|
||||
} else {
|
||||
vaddr = alloc_share_page_addr(task, nr_pages * 2);
|
||||
if (vaddr >= USER_IPC_USE_ALLOCATOR_WATERMARK) {
|
||||
task->massive_ipc_allocator = (struct KBuddy*)slab_alloc(&xizi_task_manager.task_buddy_allocator);
|
||||
KBuddyInit(task->massive_ipc_allocator, USER_IPC_USE_ALLOCATOR_WATERMARK, USER_IPC_SPACE_TOP);
|
||||
if (!task->massive_ipc_allocator) {
|
||||
ERROR("Alloc task buddy failed.\n");
|
||||
return (uintptr_t)NULL;
|
||||
}
|
||||
return map_task_share_page(task, paddr, nr_pages);
|
||||
}
|
||||
}
|
||||
|
||||
if (UNLIKELY(vaddr == (uintptr_t)NULL)) {
|
||||
return (uintptr_t)NULL;
|
||||
}
|
||||
if (!xizi_pager.map_pages(task->pgdir.pd_addr, vaddr, paddr, nr_pages * PAGE_SIZE, false)) {
|
||||
@@ -107,9 +123,7 @@ static uintptr_t map_task_share_page(struct TaskMicroDescriptor* task, const uin
|
||||
p_mmu_driver->TlbFlush(vaddr, 2 * nr_pages * PAGE_SIZE);
|
||||
|
||||
/// @todo clean range rather than all
|
||||
// p_dcache_done->flushall();
|
||||
p_dcache_done->invalidateall();
|
||||
// p_dcache_done->flush(vaddr, vaddr + 2 * nr_pages * PAGE_SIZE);
|
||||
}
|
||||
return vaddr;
|
||||
}
|
||||
@@ -133,9 +147,7 @@ uintptr_t task_map_pages(struct TaskMicroDescriptor* task, const uintptr_t vaddr
|
||||
p_mmu_driver->TlbFlush(vaddr, nr_pages * PAGE_SIZE);
|
||||
|
||||
/// @todo clean range rather than all
|
||||
// p_dcache_done->flushall();
|
||||
p_dcache_done->invalidateall();
|
||||
// p_dcache_done->flush(vaddr, vaddr + nr_pages * PAGE_SIZE);
|
||||
}
|
||||
|
||||
return vaddr;
|
||||
@@ -149,13 +161,14 @@ void unmap_task_share_pages(struct TaskMicroDescriptor* task, const uintptr_t ta
|
||||
|
||||
xizi_pager.unmap_pages(task->pgdir.pd_addr, task_vaddr, nr_pages * PAGE_SIZE);
|
||||
xizi_pager.unmap_pages(task->pgdir.pd_addr, task_vaddr + (nr_pages * PAGE_SIZE), nr_pages * PAGE_SIZE);
|
||||
if (task_vaddr >= USER_IPC_USE_ALLOCATOR_WATERMARK) {
|
||||
KBuddyFree(task->massive_ipc_allocator, (void*)task_vaddr);
|
||||
}
|
||||
if (task == cur_cpu()->task) {
|
||||
p_mmu_driver->TlbFlush(task_vaddr, 2 * nr_pages * PAGE_SIZE);
|
||||
|
||||
/// @todo clean range rather than all
|
||||
// p_dcache_done->flushall();
|
||||
p_dcache_done->invalidateall();
|
||||
// p_dcache_done->flush(task_vaddr, task_vaddr + 2 * nr_pages * PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,12 +191,14 @@ struct session_backend* create_share_pages(struct TaskMicroDescriptor* client, s
|
||||
uintptr_t client_vaddr = map_task_share_page(client, V2P_WO(kern_vaddr), nr_pages);
|
||||
if (UNLIKELY(client_vaddr == 0)) {
|
||||
kfree((char*)kern_vaddr);
|
||||
slab_free(SessionAllocator(), session_backend);
|
||||
return NULL;
|
||||
}
|
||||
uintptr_t server_vaddr = map_task_share_page(server, V2P_WO(kern_vaddr), nr_pages);
|
||||
if (UNLIKELY(server_vaddr == 0)) {
|
||||
unmap_task_share_pages(client, client_vaddr, nr_pages);
|
||||
kfree((char*)kern_vaddr);
|
||||
slab_free(SessionAllocator(), session_backend);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -208,6 +223,9 @@ struct session_backend* create_share_pages(struct TaskMicroDescriptor* client, s
|
||||
doubleListNodeInit(&session_backend->server_side.node);
|
||||
doubleListAddOnBack(&session_backend->server_side.node, &server->svr_sess_listhead);
|
||||
|
||||
server->mem_size += true_capacity;
|
||||
client->mem_size += true_capacity;
|
||||
|
||||
return session_backend;
|
||||
}
|
||||
|
||||
@@ -223,18 +241,31 @@ int delete_share_pages(struct session_backend* session_backend)
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(session_backend->server_side.closed || session_backend->client_side.closed);
|
||||
|
||||
/* unmap share pages */
|
||||
if (session_backend->client) {
|
||||
doubleListDel(&session_backend->client_side.node);
|
||||
// close ssesion in server's perspective
|
||||
if (session_backend->server_side.closed && session_backend->server != NULL) {
|
||||
xizi_share_page_manager.unmap_task_share_pages(session_backend->server, session_backend->server_side.buf_addr, session_backend->nr_pages);
|
||||
doubleListDel(&session_backend->server_side.node);
|
||||
session_backend->server->mem_size -= session_backend->nr_pages * PAGE_SIZE;
|
||||
session_backend->server = NULL;
|
||||
}
|
||||
|
||||
if (session_backend->server) {
|
||||
doubleListDel(&session_backend->server_side.node);
|
||||
// close ssesion in client's perspective
|
||||
if (session_backend->client_side.closed && session_backend->client != NULL) {
|
||||
xizi_share_page_manager.unmap_task_share_pages(session_backend->client, session_backend->client_side.buf_addr, session_backend->nr_pages);
|
||||
doubleListDel(&session_backend->client_side.node);
|
||||
session_backend->client->mem_size -= session_backend->nr_pages * PAGE_SIZE;
|
||||
session_backend->client = NULL;
|
||||
}
|
||||
|
||||
/* free seesion backend */
|
||||
kfree((void*)session_backend->buf_kernel_addr);
|
||||
slab_free(SessionAllocator(), (void*)session_backend);
|
||||
if (session_backend->server_side.closed && session_backend->client_side.closed) {
|
||||
assert(session_backend->client == NULL && session_backend->server == NULL);
|
||||
kfree((void*)session_backend->buf_kernel_addr);
|
||||
slab_free(SessionAllocator(), (void*)session_backend);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -33,9 +33,13 @@ Modification:
|
||||
#include "syscall.h"
|
||||
#include "task.h"
|
||||
|
||||
int sys_close_session(struct Session* session)
|
||||
/// @brief close a session syscall
|
||||
/// @warning best to be called by a client
|
||||
/// @param cur_task
|
||||
/// @param session
|
||||
/// @return
|
||||
int sys_close_session(struct TaskMicroDescriptor* cur_task, struct Session* session)
|
||||
{
|
||||
struct TaskMicroDescriptor* cur_task = cur_cpu()->task;
|
||||
assert(cur_task != NULL);
|
||||
/* check if session is available */
|
||||
if (session->buf == NULL || (uintptr_t)session->buf < USER_IPC_SPACE_BASE || (uintptr_t)session->buf > USER_IPC_SPACE_TOP) {
|
||||
@@ -44,18 +48,16 @@ int sys_close_session(struct Session* session)
|
||||
|
||||
/* check if session is a client one or a server one */
|
||||
struct session_backend* session_backend = NULL;
|
||||
bool session_valid = false;
|
||||
|
||||
struct client_session* client_session = NULL;
|
||||
DOUBLE_LIST_FOR_EACH_ENTRY(client_session, &cur_task->cli_sess_listhead, node)
|
||||
{
|
||||
if ((uintptr_t)session->buf == client_session->buf_addr) {
|
||||
session_valid = true;
|
||||
session_backend = CLIENT_SESSION_BACKEND(client_session);
|
||||
if (!client_session->closed) {
|
||||
client_session->closed = true;
|
||||
xizi_share_page_manager.unmap_task_share_pages(cur_task, session_backend->client_side.buf_addr, session_backend->nr_pages);
|
||||
}
|
||||
assert(session_backend->client == cur_task);
|
||||
assert(client_session->closed == false);
|
||||
client_session->closed = true;
|
||||
xizi_share_page_manager.delete_share_pages(session_backend);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -64,20 +66,19 @@ int sys_close_session(struct Session* session)
|
||||
DOUBLE_LIST_FOR_EACH_ENTRY(server_session, &cur_task->svr_sess_listhead, node)
|
||||
{
|
||||
if ((uintptr_t)session->buf == server_session->buf_addr) {
|
||||
session_valid = true;
|
||||
session_backend = SERVER_SESSION_BACKEND(server_session);
|
||||
if (!server_session->closed) {
|
||||
server_session->closed = true;
|
||||
xizi_share_page_manager.unmap_task_share_pages(cur_task, session_backend->server_side.buf_addr, session_backend->nr_pages);
|
||||
}
|
||||
assert(session_backend->server == cur_task);
|
||||
assert(server_session->closed == false);
|
||||
server_session->closed = true;
|
||||
xizi_share_page_manager.delete_share_pages(session_backend);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* close this session */
|
||||
if (UNLIKELY(session_backend->client_side.closed && session_backend->server_side.closed) && LIKELY(session_valid)) {
|
||||
xizi_share_page_manager.delete_share_pages(session_backend);
|
||||
if (session_backend == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -35,13 +35,14 @@ Modification:
|
||||
#include "syscall.h"
|
||||
#include "task.h"
|
||||
|
||||
int create_session_inner(struct TaskMicroDescriptor* client, struct TaskMicroDescriptor* server, int capacity, struct Session* user_session)
|
||||
struct session_backend* create_session_inner(struct TaskMicroDescriptor* client, struct TaskMicroDescriptor* server, int capacity, struct Session* user_session)
|
||||
{
|
||||
// create share pages
|
||||
assert(server != NULL && client != NULL);
|
||||
struct session_backend* session_backend = xizi_share_page_manager.create_share_pages(client, server, capacity);
|
||||
if (UNLIKELY(session_backend == NULL)) {
|
||||
DEBUG("create_share_pages failed\n");
|
||||
return -1;
|
||||
DEBUG("create_share_pages to server: %s failed\n", server->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// init user_session
|
||||
@@ -51,7 +52,7 @@ int create_session_inner(struct TaskMicroDescriptor* client, struct TaskMicroDes
|
||||
user_session->tail = 0;
|
||||
user_session->id = session_backend->session_id;
|
||||
|
||||
return 0;
|
||||
return session_backend;
|
||||
}
|
||||
|
||||
int sys_connect_session(char* path, int capacity, struct Session* user_session)
|
||||
@@ -76,5 +77,8 @@ int sys_connect_session(char* path, int capacity, struct Session* user_session)
|
||||
|
||||
struct TaskMicroDescriptor* server = AchieveResource(&server_tag);
|
||||
assert(server != NULL);
|
||||
return create_session_inner(client, server, capacity, user_session);
|
||||
if (create_session_inner(client, server, capacity, user_session) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -69,9 +69,15 @@ Modification:
|
||||
int task_exec(struct TaskMicroDescriptor* task, char* img_start, char* name, char** argv)
|
||||
{
|
||||
/* load img to task */
|
||||
if (img_start == NULL) {
|
||||
return -1;
|
||||
}
|
||||
/* 1. load elf header */
|
||||
struct elfhdr elf;
|
||||
memcpy((void*)&elf, img_start, sizeof(elf));
|
||||
if (elf.magic != ELF_MAGIC) {
|
||||
return -1;
|
||||
}
|
||||
// pgdir for new task
|
||||
struct TopLevelPageDirectory pgdir;
|
||||
pgdir.pd_addr = NULL;
|
||||
@@ -106,7 +112,7 @@ int task_exec(struct TaskMicroDescriptor* task, char* img_start, char* name, cha
|
||||
for (int addr_offset = 0; addr_offset < ph.filesz; addr_offset += PAGE_SIZE) {
|
||||
uintptr_t page_paddr = xizi_pager.address_translate(&pgdir, ph.vaddr + addr_offset);
|
||||
if (page_paddr == 0) {
|
||||
ERROR("copy elf file to unmapped addr\n");
|
||||
ERROR("copy elf file to unmapped addr: %x(pgdir: %x)\n", ph.vaddr + addr_offset, pgdir.pd_addr);
|
||||
goto error_exec;
|
||||
}
|
||||
uintptr_t read_size = (ph.filesz - addr_offset < PAGE_SIZE ? ph.filesz - addr_offset : PAGE_SIZE);
|
||||
@@ -169,13 +175,12 @@ int task_exec(struct TaskMicroDescriptor* task, char* img_start, char* name, cha
|
||||
}
|
||||
strncpy(task->name, last, sizeof(task->name));
|
||||
|
||||
struct TopLevelPageDirectory old_pgdir = task->pgdir;
|
||||
if (task->pgdir.pd_addr != NULL) {
|
||||
xizi_pager.free_user_pgdir(&task->pgdir);
|
||||
}
|
||||
task->pgdir = pgdir;
|
||||
|
||||
/// @todo record mem size used b task
|
||||
task->mem_size = ALIGNUP(load_size, PAGE_SIZE);
|
||||
|
||||
xizi_pager.free_user_pgdir(&old_pgdir);
|
||||
task->heap_base = ALIGNUP(load_size, PAGE_SIZE);
|
||||
task->mem_size = task->heap_base + USER_STACK_SIZE;
|
||||
return 0;
|
||||
|
||||
error_exec:
|
||||
|
||||
@@ -39,51 +39,12 @@ Modification:
|
||||
int sys_exit(struct TaskMicroDescriptor* ptask)
|
||||
{
|
||||
assert(ptask != NULL);
|
||||
|
||||
/* handle sessions for condition 1, ref. delete_share_pages() */
|
||||
// close all server_sessions
|
||||
struct server_session* server_session = NULL;
|
||||
while (!IS_DOUBLE_LIST_EMPTY(&ptask->svr_sess_listhead)) {
|
||||
server_session = CONTAINER_OF(ptask->svr_sess_listhead.next, struct server_session, node);
|
||||
// cut the connection from task to session
|
||||
if (!server_session->closed) {
|
||||
xizi_share_page_manager.unmap_task_share_pages(ptask, server_session->buf_addr, CLIENT_SESSION_BACKEND(server_session)->nr_pages);
|
||||
server_session->closed = true;
|
||||
}
|
||||
doubleListDel(&server_session->node);
|
||||
SERVER_SESSION_BACKEND(server_session)->server = NULL;
|
||||
// delete session (also cut connection from session to task)
|
||||
if (SERVER_SESSION_BACKEND(server_session)->client_side.closed) {
|
||||
xizi_share_page_manager.delete_share_pages(SERVER_SESSION_BACKEND(server_session));
|
||||
}
|
||||
ptask->dead = true;
|
||||
// free that task straightly if it's a blocked task
|
||||
if (ptask->state == BLOCKED) {
|
||||
xizi_task_manager.free_pcb(ptask);
|
||||
}
|
||||
// close all client_sessions
|
||||
struct client_session* client_session = NULL;
|
||||
while (!IS_DOUBLE_LIST_EMPTY(&ptask->cli_sess_listhead)) {
|
||||
client_session = CONTAINER_OF(ptask->cli_sess_listhead.next, struct client_session, node);
|
||||
// cut the connection from task to session
|
||||
if (!client_session->closed) {
|
||||
xizi_share_page_manager.unmap_task_share_pages(ptask, client_session->buf_addr, CLIENT_SESSION_BACKEND(client_session)->nr_pages);
|
||||
client_session->closed = true;
|
||||
}
|
||||
doubleListDel(&client_session->node);
|
||||
CLIENT_SESSION_BACKEND(client_session)->client = NULL;
|
||||
// delete session (also cut connection from session to task)
|
||||
if (CLIENT_SESSION_BACKEND(client_session)->server_side.closed) {
|
||||
xizi_share_page_manager.delete_share_pages(CLIENT_SESSION_BACKEND(client_session));
|
||||
}
|
||||
}
|
||||
|
||||
if (ptask->server_identifier.meta != NULL) {
|
||||
struct TraceTag server_identifier_owner;
|
||||
AchieveResourceTag(&server_identifier_owner, RequireRootTag(), "softkernel/server-identifier");
|
||||
assert(server_identifier_owner.meta != NULL);
|
||||
DeleteResource(&ptask->server_identifier, &server_identifier_owner);
|
||||
}
|
||||
|
||||
// delete task for pcb_list
|
||||
xizi_task_manager.cur_task_yield_noschedule();
|
||||
ptask->state = DEAD;
|
||||
|
||||
// yield current task in case it wants to exit itself
|
||||
xizi_task_manager.task_yield_noschedule(cur_cpu()->task, false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,25 @@ extern int sys_exit(struct TaskMicroDescriptor* task);
|
||||
int sys_kill(int id)
|
||||
{
|
||||
struct TaskMicroDescriptor* task = NULL;
|
||||
// check if task is a running one
|
||||
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_running_list_head, node)
|
||||
{
|
||||
if (task->pid == id) {
|
||||
sys_exit(task);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// check if task is a blocking one
|
||||
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_blocked_list_head, node)
|
||||
{
|
||||
if (task->pid == id) {
|
||||
sys_exit(task);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// check if task is a ready one
|
||||
for (int prio = 0; prio < TASK_MAX_PRIORITY; prio++) {
|
||||
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_list_head[prio], node)
|
||||
{
|
||||
|
||||
@@ -63,5 +63,7 @@ int sys_mmap(uintptr_t vaddr, uintptr_t paddr, int len, int is_dev)
|
||||
load_len += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
cur_task->mem_size += true_len;
|
||||
return vaddr + true_len;
|
||||
}
|
||||
@@ -28,11 +28,20 @@ Modification:
|
||||
1. first version
|
||||
*************************************************/
|
||||
#include "assert.h"
|
||||
#include "ipc.h"
|
||||
#include "multicores.h"
|
||||
#include "share_page.h"
|
||||
#include "syscall.h"
|
||||
#include "task.h"
|
||||
|
||||
#define IPCSESSION_MSG(session) ((struct IpcMsg*)((char*)((session)->buf) + (session)->head))
|
||||
|
||||
static inline bool is_msg_needed(struct IpcMsg* msg)
|
||||
{
|
||||
assert(msg != NULL);
|
||||
return msg->header.magic == IPC_MSG_MAGIC && msg->header.valid == 1 && msg->header.done == 0 && msg->header.delayed == 0;
|
||||
}
|
||||
|
||||
int sys_poll_session(struct Session* userland_session_arr, int arr_capacity)
|
||||
{
|
||||
struct TaskMicroDescriptor* cur_task = cur_cpu()->task;
|
||||
@@ -55,51 +64,65 @@ int sys_poll_session(struct Session* userland_session_arr, int arr_capacity)
|
||||
return -1;
|
||||
}
|
||||
// update session_backend
|
||||
// if current session is handled
|
||||
if (server_session->head != userland_session_arr[i].head) {
|
||||
struct TaskMicroDescriptor* client = SERVER_SESSION_BACKEND(server_session)->client;
|
||||
if (client->state == BLOCKED) {
|
||||
xizi_task_manager.task_unblock(client);
|
||||
} else {
|
||||
client->current_ipc_handled = true;
|
||||
}
|
||||
}
|
||||
server_session->head = userland_session_arr[i].head;
|
||||
server_session->tail = userland_session_arr[i].tail;
|
||||
doubleListDel(cur_node);
|
||||
doubleListAddOnBack(cur_node, &cur_task->svr_sess_listhead);
|
||||
}
|
||||
|
||||
/* handle sessions for condition 2, ref. delete_share_pages() */
|
||||
bool has_delete = true;
|
||||
while (has_delete) {
|
||||
has_delete = false;
|
||||
|
||||
DOUBLE_LIST_FOR_EACH_ENTRY(server_session, &cur_task->svr_sess_listhead, node)
|
||||
{
|
||||
if (SERVER_SESSION_BACKEND(server_session)->client_side.closed) {
|
||||
// client had closed it, then server will close it too
|
||||
struct session_backend* session_backend = SERVER_SESSION_BACKEND(server_session);
|
||||
|
||||
if (!session_backend->server_side.closed) {
|
||||
session_backend->server_side.closed = true;
|
||||
xizi_share_page_manager.unmap_task_share_pages(cur_task, session_backend->server_side.buf_addr, session_backend->nr_pages);
|
||||
}
|
||||
xizi_share_page_manager.delete_share_pages(session_backend);
|
||||
has_delete = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* poll with new sessions */
|
||||
int i = 0;
|
||||
int nr_sessions_need_to_handle = 0;
|
||||
bool has_middle_delete = false;
|
||||
int session_idx = 0;
|
||||
DOUBLE_LIST_FOR_EACH_ENTRY(server_session, &cur_task->svr_sess_listhead, node)
|
||||
{
|
||||
if (i >= arr_capacity) {
|
||||
if (session_idx >= arr_capacity) {
|
||||
break;
|
||||
}
|
||||
userland_session_arr[i++] = (struct Session) {
|
||||
|
||||
if (SERVER_SESSION_BACKEND(server_session)->client_side.closed) {
|
||||
// client had closed it, then server will close it too
|
||||
struct session_backend* session_backend = SERVER_SESSION_BACKEND(server_session);
|
||||
assert(session_backend->server == cur_task);
|
||||
assert(session_backend->client == NULL);
|
||||
assert(server_session->closed == false);
|
||||
server_session->closed = true;
|
||||
xizi_share_page_manager.delete_share_pages(session_backend);
|
||||
// signal that there is a middle deletion of session
|
||||
has_middle_delete = true;
|
||||
break;
|
||||
}
|
||||
|
||||
userland_session_arr[session_idx] = (struct Session) {
|
||||
.buf = (void*)server_session->buf_addr,
|
||||
.capacity = server_session->capacity,
|
||||
.head = server_session->head,
|
||||
.tail = server_session->tail,
|
||||
.id = SERVER_SESSION_BACKEND(server_session)->session_id,
|
||||
};
|
||||
|
||||
struct IpcMsg* msg = IPCSESSION_MSG(&userland_session_arr[session_idx]);
|
||||
if (is_msg_needed(msg)) {
|
||||
nr_sessions_need_to_handle++;
|
||||
}
|
||||
|
||||
session_idx++;
|
||||
}
|
||||
if (LIKELY(i < arr_capacity)) {
|
||||
userland_session_arr[i].buf = 0;
|
||||
if (session_idx < arr_capacity) {
|
||||
userland_session_arr[session_idx].buf = NULL;
|
||||
if (!has_middle_delete && nr_sessions_need_to_handle == 0) {
|
||||
xizi_task_manager.task_yield_noschedule(cur_task, false);
|
||||
xizi_task_manager.task_block(cur_task);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -34,65 +34,126 @@ Modification:
|
||||
#include "actracer.h"
|
||||
#include "assert.h"
|
||||
#include "ipc.h"
|
||||
#include "kalloc.h"
|
||||
#include "multicores.h"
|
||||
#include "share_page.h"
|
||||
#include "syscall.h"
|
||||
#include "task.h"
|
||||
|
||||
static struct TaskMicroDescriptor kernel_irq_proxy;
|
||||
static struct TaskMicroDescriptor* kernel_irq_proxy;
|
||||
static struct {
|
||||
struct TaskMicroDescriptor* handle_task;
|
||||
struct Session* session;
|
||||
struct Session session;
|
||||
struct session_backend* p_kernel_session;
|
||||
int opcode;
|
||||
} irq_forward_table[NR_IRQS];
|
||||
|
||||
static void send_irq_to_user(int irq_num)
|
||||
{
|
||||
int len = IPC_ARG_INFO_BASE_OFFSET;
|
||||
/* add session tail */
|
||||
struct IpcMsg* buf = irq_forward_table[irq_num].session->buf + irq_forward_table[irq_num].session->tail;
|
||||
irq_forward_table[irq_num].session->tail += len;
|
||||
memset((void*)buf, 0, len);
|
||||
/* construct message */
|
||||
buf->header.len = len;
|
||||
buf->header.nr_args = 0;
|
||||
buf->header.init = 1;
|
||||
buf->header.opcode = irq_forward_table[irq_num].opcode;
|
||||
buf->header.done = 0;
|
||||
buf->header.magic = IPC_MSG_MAGIC;
|
||||
buf->header.valid = 1;
|
||||
/* add session head */
|
||||
irq_forward_table[irq_num].session->head += len;
|
||||
if (irq_forward_table[irq_num].handle_task != NULL) {
|
||||
struct Session* session = &irq_forward_table[irq_num].session;
|
||||
int len = IPC_ARG_INFO_BASE_OFFSET;
|
||||
len += sizeof(struct IpcArgInfo);
|
||||
|
||||
/* get message space and add session tail */
|
||||
void* session_kern_vaddr = P2V(xizi_pager.address_translate(&kernel_irq_proxy->pgdir, (uintptr_t)session->buf));
|
||||
struct IpcMsg* buf = session_kern_vaddr + session->tail;
|
||||
|
||||
/* check if server session is full */
|
||||
if (buf->header.magic == IPC_MSG_MAGIC && buf->header.done == 0) {
|
||||
DEBUG("irq server cannot handle new interrupt by now.\n");
|
||||
return;
|
||||
}
|
||||
memset((void*)buf, 0, len);
|
||||
session->tail = (session->tail + len) % session->capacity;
|
||||
|
||||
/* construct message */
|
||||
buf->header.len = len;
|
||||
buf->header.nr_args = 1;
|
||||
buf->header.init = 1;
|
||||
buf->header.opcode = irq_forward_table[irq_num].opcode;
|
||||
buf->header.done = 0;
|
||||
buf->header.magic = IPC_MSG_MAGIC;
|
||||
buf->header.valid = 1;
|
||||
|
||||
if (irq_forward_table[irq_num].handle_task->state == BLOCKED) {
|
||||
xizi_task_manager.task_unblock(irq_forward_table[irq_num].handle_task);
|
||||
}
|
||||
|
||||
/* add session head */
|
||||
session->head = (session->head + len) % session->capacity;
|
||||
}
|
||||
}
|
||||
|
||||
int user_irq_handler(int irq, void* tf, void* arg)
|
||||
{
|
||||
send_irq_to_user(irq);
|
||||
next_task_emergency = irq_forward_table[irq].handle_task;
|
||||
xizi_task_manager.cur_task_yield_noschedule();
|
||||
if (irq_forward_table[irq].handle_task != NULL) {
|
||||
send_irq_to_user(irq);
|
||||
|
||||
next_task_emergency = irq_forward_table[irq].handle_task;
|
||||
if (cur_cpu()->task != NULL) {
|
||||
xizi_task_manager.task_yield_noschedule(cur_cpu()->task, false);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int create_session_inner(struct TaskMicroDescriptor* client, struct TaskMicroDescriptor* server, int capacity, struct Session* user_session);
|
||||
extern struct session_backend* create_session_inner(struct TaskMicroDescriptor* client, struct TaskMicroDescriptor* server, int capacity, struct Session* user_session);
|
||||
/// @warning no tested.
|
||||
|
||||
static struct XiziTrapDriver* p_intr_driver = NULL;
|
||||
int sys_register_irq(int irq_num, int irq_opcode)
|
||||
{
|
||||
static struct TraceTag intr_ac_tag;
|
||||
if (!AchieveResourceTag(&intr_ac_tag, RequireRootTag(), "hardkernel/intr-ac-resource")) {
|
||||
ERROR("intr not initialized.\n");
|
||||
return -1;
|
||||
// init intr resource;
|
||||
if (p_intr_driver == NULL) {
|
||||
struct TraceTag intr_ac_tag;
|
||||
if (!AchieveResourceTag(&intr_ac_tag, RequireRootTag(), "hardkernel/intr-ac-resource")) {
|
||||
ERROR("intr not initialized.\n");
|
||||
return -1;
|
||||
}
|
||||
p_intr_driver = (struct XiziTrapDriver*)AchieveResource(&intr_ac_tag);
|
||||
}
|
||||
struct XiziTrapDriver* p_intr_driver = AchieveResource(&intr_ac_tag);
|
||||
|
||||
if (p_intr_driver->sw_irqtbl[irq_num].handler != NULL) {
|
||||
// init kerenl sender proxy
|
||||
if (kernel_irq_proxy == NULL) {
|
||||
kernel_irq_proxy = xizi_task_manager.new_task_cb();
|
||||
kernel_irq_proxy->state = NEVER_RUN;
|
||||
xizi_pager.new_pgdir(&kernel_irq_proxy->pgdir);
|
||||
memcpy(kernel_irq_proxy->pgdir.pd_addr, kern_pgdir.pd_addr, TOPLEVLE_PAGEDIR_SIZE);
|
||||
}
|
||||
|
||||
// bind irq to session
|
||||
if (irq_forward_table[irq_num].handle_task != NULL) {
|
||||
ERROR("irq %d is occupied.\n", irq_num);
|
||||
return -1;
|
||||
}
|
||||
struct TaskMicroDescriptor* cur_task = cur_cpu()->task;
|
||||
irq_forward_table[irq_num].handle_task = cur_task;
|
||||
irq_forward_table[irq_num].opcode = irq_opcode;
|
||||
create_session_inner(&kernel_irq_proxy, cur_task, PAGE_SIZE, irq_forward_table[irq_num].session);
|
||||
irq_forward_table[irq_num].p_kernel_session = create_session_inner(kernel_irq_proxy, cur_task, PAGE_SIZE, &irq_forward_table[irq_num].session);
|
||||
p_intr_driver->bind_irq_handler(irq_num, user_irq_handler);
|
||||
cur_task->bind_irq = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_unbind_irq(struct TaskMicroDescriptor* task, int irq_num)
|
||||
{
|
||||
if (irq_forward_table[irq_num].handle_task != task) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
irq_forward_table[irq_num].handle_task = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_unbind_irq_all(struct TaskMicroDescriptor* task)
|
||||
{
|
||||
for (int idx = 0; idx < NR_IRQS; idx++) {
|
||||
if (irq_forward_table[idx].handle_task == task) {
|
||||
sys_unbind_irq(task, idx);
|
||||
}
|
||||
}
|
||||
task->bind_irq = false;
|
||||
return 0;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ int sys_spawn(char* img_start, char* name, char** argv)
|
||||
return -1;
|
||||
}
|
||||
// init pcb
|
||||
xizi_task_manager.task_set_default_schedule_attr(new_task_cb, RequireRootTag());
|
||||
xizi_task_manager.task_set_default_schedule_attr(new_task_cb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -40,52 +40,58 @@ Modification:
|
||||
|
||||
extern uint8_t _binary_fs_img_start[], _binary_fs_img_end[];
|
||||
|
||||
/// @brief Padding task name length to TASK_NAME_MAX_LEN
|
||||
static inline void _padding(char* name)
|
||||
{
|
||||
int i;
|
||||
size_t length = strlen(name);
|
||||
for (i = length; i < TASK_NAME_MAX_LEN - 1; i++) {
|
||||
name[i] = ' ';
|
||||
}
|
||||
name[i] = '\0';
|
||||
return;
|
||||
}
|
||||
#define SHOWINFO_BORDER_LINE() LOG_PRINTF("******************************************************\n");
|
||||
#define SHOWTASK_TASK_BASE_INFO(task) LOG_PRINTF(" %-4d %-16s %-4d 0x%x(%-d)\n", task->pid, task->name, task->priority, task->mem_size >> 10, task->mem_size >> 10)
|
||||
|
||||
void show_tasks(void)
|
||||
{
|
||||
struct TaskMicroDescriptor* task = NULL;
|
||||
LOG_PRINTF("******************************************************\n");
|
||||
SHOWINFO_BORDER_LINE();
|
||||
for (int i = 0; i < NR_CPU; i++) {
|
||||
LOG_PRINTF("CPU %d: ", i);
|
||||
if (global_cpus[i].task != NULL) {
|
||||
LOG_PRINTF("%s\n", global_cpus[i].task->name);
|
||||
} else {
|
||||
LOG_PRINTF("NULL\n");
|
||||
}
|
||||
LOG_PRINTF("CPU %-2d: %s\n", i, (global_cpus[i].task == NULL ? "NULL" : global_cpus[i].task->name));
|
||||
}
|
||||
LOG_PRINTF("******************************************************\n");
|
||||
LOG_PRINTF("STAT ID TASK PRI LEFT_TICKS\n");
|
||||
SHOWINFO_BORDER_LINE();
|
||||
LOG_PRINTF("%-8s %-4s %-16s %-4s %-8s\n", "STAT", "ID", "TASK", "PRI", "MEM(KB)");
|
||||
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_running_list_head, node)
|
||||
{
|
||||
LOG_PRINTF("%-8s", "RUNNING");
|
||||
SHOWTASK_TASK_BASE_INFO(task);
|
||||
}
|
||||
|
||||
for (int i = 0; i < TASK_MAX_PRIORITY; i++) {
|
||||
if (IS_DOUBLE_LIST_EMPTY(&xizi_task_manager.task_list_head[i])) {
|
||||
continue;
|
||||
}
|
||||
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_list_head[i], node)
|
||||
{
|
||||
if (task->state == INIT)
|
||||
LOG_PRINTF(" INIT ");
|
||||
else if (task->state == READY)
|
||||
LOG_PRINTF(" READY ");
|
||||
else if (task->state == RUNNING)
|
||||
LOG_PRINTF("RUNNING ");
|
||||
else if (task->state == DEAD)
|
||||
LOG_PRINTF(" DEAD ");
|
||||
switch (task->state) {
|
||||
case INIT:
|
||||
LOG_PRINTF("%-8s", "INIT");
|
||||
break;
|
||||
case READY:
|
||||
LOG_PRINTF("%-8s", "READY");
|
||||
break;
|
||||
case RUNNING:
|
||||
LOG_PRINTF("%-8s", "RUNNING");
|
||||
break;
|
||||
case DEAD:
|
||||
LOG_PRINTF("%-8s", "DEAD");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_padding(task->name);
|
||||
LOG_PRINTF(" %d %s %d %d\n", task->pid, task->name, task->priority, task->remain_tick);
|
||||
SHOWTASK_TASK_BASE_INFO(task);
|
||||
}
|
||||
}
|
||||
LOG_PRINTF("******************************************************\n");
|
||||
|
||||
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_blocked_list_head, node)
|
||||
{
|
||||
LOG_PRINTF("%-8s", "BLOCK");
|
||||
SHOWTASK_TASK_BASE_INFO(task);
|
||||
}
|
||||
|
||||
SHOWINFO_BORDER_LINE();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -94,19 +100,21 @@ extern struct KBuddy kern_virtmem_buddy;
|
||||
extern uint32_t kernel_data_end[];
|
||||
void show_mem(void)
|
||||
{
|
||||
LOG_PRINTF("*********************************************************\n");
|
||||
LOG_PRINTF(" TOTAL(KB) USED(KB) FREE(KB) \n");
|
||||
SHOWINFO_BORDER_LINE();
|
||||
|
||||
uint32_t total = (PHY_MEM_STOP - V2P(kernel_data_end)) >> 10;
|
||||
uint32_t used = 0;
|
||||
uint64_t total = (PHY_MEM_STOP - V2P(kernel_data_end));
|
||||
uint64_t user_dynamic_free = 0;
|
||||
uint64_t kernel_free = 0;
|
||||
for (int j = 0; j < MAX_BUDDY_ORDER; j++) {
|
||||
used += user_phy_freemem_buddy.free_list[j].n_free_pages * (1 << j) * PAGE_SIZE;
|
||||
used += kern_virtmem_buddy.free_list[j].n_free_pages * (1 << j) * PAGE_SIZE;
|
||||
user_dynamic_free += user_phy_freemem_buddy.free_list[j].n_free_pages * (1 << j) * PAGE_SIZE;
|
||||
kernel_free += kern_virtmem_buddy.free_list[j].n_free_pages * (1 << j) * PAGE_SIZE;
|
||||
}
|
||||
used = used >> 10;
|
||||
LOG_PRINTF("%-16s 0x%064lx\n", "TOTAL(B)", total);
|
||||
LOG_PRINTF("%-16s 0x%064lx\n", "KERNEL USED(B)", (kern_virtmem_buddy.mem_end - kern_virtmem_buddy.mem_start - kernel_free));
|
||||
LOG_PRINTF("%-16s 0x%064lx\n", "LIBMEM USED(B)", (user_phy_freemem_buddy.mem_end - user_phy_freemem_buddy.mem_start - user_dynamic_free));
|
||||
LOG_PRINTF("%-16s 0x%064lx\n", "FREE(B)", user_dynamic_free + kernel_free);
|
||||
|
||||
LOG_PRINTF(" %d %d %d\n", total, total - used, used);
|
||||
LOG_PRINTF("*********************************************************\n");
|
||||
SHOWINFO_BORDER_LINE();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -123,8 +131,6 @@ void show_cpu(void)
|
||||
struct TaskMicroDescriptor* current_task = cur_cpu()->task;
|
||||
assert(current_task != NULL);
|
||||
|
||||
_padding(current_task->name);
|
||||
|
||||
LOG_PRINTF(" ID COMMAND USED_TICKS FREE_TICKS \n");
|
||||
LOG_PRINTF(" %d %s %d %d\n", cpu_id, current_task->name, TASK_CLOCK_TICK - current_task->remain_tick, current_task->remain_tick);
|
||||
|
||||
@@ -138,7 +144,7 @@ int sys_state(sys_state_option option, sys_state_info* info)
|
||||
info->memblock_info.memblock_start = (uintptr_t)V2P(_binary_fs_img_start);
|
||||
info->memblock_info.memblock_end = (uintptr_t)V2P(_binary_fs_img_end);
|
||||
} else if (option == SYS_STATE_GET_HEAP_BASE) {
|
||||
return cur_cpu()->task->mem_size;
|
||||
return cur_cpu()->task->heap_base;
|
||||
} else if (option == SYS_STATE_SET_TASK_PRIORITY) {
|
||||
xizi_task_manager.set_cur_task_priority(info->priority);
|
||||
} else if (option == SYS_STATE_SHOW_TASKS) {
|
||||
|
||||
@@ -31,10 +31,32 @@ Modification:
|
||||
#include "syscall.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "assert.h"
|
||||
|
||||
int sys_yield()
|
||||
int sys_yield(task_yield_reason reason)
|
||||
{
|
||||
xizi_task_manager.cur_task_yield_noschedule();
|
||||
struct TaskMicroDescriptor* cur_task = cur_cpu()->task;
|
||||
xizi_task_manager.task_yield_noschedule(cur_task, false);
|
||||
|
||||
// handle ipc block
|
||||
if ((reason & SYS_TASK_YIELD_BLOCK_IPC) != 0) {
|
||||
if (cur_task->current_ipc_handled) {
|
||||
cur_task->current_ipc_handled = false;
|
||||
} else {
|
||||
xizi_task_manager.task_block(cur_task);
|
||||
}
|
||||
}
|
||||
|
||||
// wake up all possible server
|
||||
struct client_session* client_session = NULL;
|
||||
DOUBLE_LIST_FOR_EACH_ENTRY(client_session, &cur_task->cli_sess_listhead, node)
|
||||
{
|
||||
assert(client_session != NULL);
|
||||
struct session_backend* session_backend = CLIENT_SESSION_BACKEND(client_session);
|
||||
if (session_backend->server->state == BLOCKED) {
|
||||
xizi_task_manager.task_unblock(session_backend->server);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -48,7 +48,7 @@ int syscall(int sys_num, uintptr_t param1, uintptr_t param2, uintptr_t param3, u
|
||||
ret = sys_exit(cur_cpu()->task);
|
||||
break;
|
||||
case SYSCALL_YIELD:
|
||||
ret = sys_yield();
|
||||
ret = sys_yield((task_yield_reason)param1);
|
||||
break;
|
||||
case SYSCALL_SERVER:
|
||||
ret = sys_register_as_server((char*)param1);
|
||||
@@ -60,7 +60,7 @@ int syscall(int sys_num, uintptr_t param1, uintptr_t param2, uintptr_t param3, u
|
||||
ret = sys_poll_session((struct Session*)param1, (int)param2);
|
||||
break;
|
||||
case SYSCALL_CLOSE_SESSION:
|
||||
ret = sys_close_session((struct Session*)param1);
|
||||
ret = sys_close_session(cur_cpu()->task, (struct Session*)param1);
|
||||
break;
|
||||
case SYSCALL_EXEC:
|
||||
ret = sys_exec((char*)param1, (char*)param2, (char**)param3);
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
SRC_FILES := task.c scheduler.c spawn_default_task.c
|
||||
SRC_FILES := task.c schedule.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
||||
@@ -27,24 +27,25 @@ Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. first version
|
||||
*************************************************/
|
||||
#include "log.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
struct TaskMicroDescriptor* max_priority_runnable_task(void)
|
||||
{
|
||||
struct TaskMicroDescriptor* task = NULL;
|
||||
uint32_t priority = 0;
|
||||
static struct TaskMicroDescriptor* task = NULL;
|
||||
static int priority = 0;
|
||||
|
||||
priority = __builtin_ffs(ready_task_priority) - 1;
|
||||
if (priority > 31 || priority < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_list_head[priority], node)
|
||||
{
|
||||
if (task->state == READY) {
|
||||
if (task->state == READY && !task->dead) {
|
||||
// found a runnable task, stop this look up
|
||||
task->state = RUNNING;
|
||||
return task;
|
||||
} else if (task->state == DEAD) {
|
||||
// found a killed task, stop this loop
|
||||
// change in pcb_list may break this loop, so find a runnable in next look up
|
||||
} else if (task->dead && task->state != RUNNING) {
|
||||
xizi_task_manager.free_pcb(task);
|
||||
return NULL;
|
||||
}
|
||||
@@ -58,14 +59,10 @@ struct TaskMicroDescriptor* round_robin_runnable_task(uint32_t priority)
|
||||
|
||||
DOUBLE_LIST_FOR_EACH_ENTRY(task, &xizi_task_manager.task_list_head[priority], node)
|
||||
{
|
||||
|
||||
if (task->state == READY) {
|
||||
if (task->state == READY && !task->dead) {
|
||||
// found a runnable task, stop this look up
|
||||
task->state = RUNNING;
|
||||
return task;
|
||||
} else if (task->state == DEAD) {
|
||||
// found a killed task, stop this loop
|
||||
// change in pcb_list may break this loop, so find a runnable in next look up
|
||||
} else if (task->dead && task->state != RUNNING) {
|
||||
xizi_task_manager.free_pcb(task);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
/**
|
||||
* @file spawn_default_task.c
|
||||
* @brief spawn task that embeded in kernel image
|
||||
* @version 3.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.08.25
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: spawn_default_task.c
|
||||
Description: spawn task that embeded in kernel image
|
||||
Others:
|
||||
History:
|
||||
1. Date: 2023-08-28
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. first version
|
||||
*************************************************/
|
||||
#include "actracer.h"
|
||||
#include "assert.h"
|
||||
#include "kalloc.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "execelf.h"
|
||||
|
||||
int spawn_embedded_task(char* img_start, char* name, char** argv)
|
||||
{
|
||||
struct TaskMicroDescriptor* new_task_cb = xizi_task_manager.new_task_cb();
|
||||
if (UNLIKELY(!new_task_cb)) {
|
||||
ERROR("Unable to new task control block.\n");
|
||||
return -1;
|
||||
}
|
||||
// init trapframe
|
||||
arch_init_trapframe(new_task_cb->main_thread.trapframe, 0, 0);
|
||||
|
||||
/* load img to task */
|
||||
/* 1. load elf header */
|
||||
struct elfhdr* elf = (struct elfhdr*)img_start;
|
||||
// pgdir for new task
|
||||
struct TopLevelPageDirectory pgdir;
|
||||
if (UNLIKELY(!xizi_pager.new_pgdir(&pgdir))) {
|
||||
ERROR("create new pgdir failed.\n");
|
||||
goto error_exec;
|
||||
}
|
||||
memcpy(pgdir.pd_addr, kern_pgdir.pd_addr, TOPLEVLE_PAGEDIR_SIZE);
|
||||
|
||||
/* 2. load elf content */
|
||||
uint32_t load_size = 0;
|
||||
struct proghdr ph;
|
||||
for (int sec_idx = 0, off = elf->phoff; sec_idx < elf->phnum; sec_idx++, off += sizeof(ph)) {
|
||||
// load proghdr
|
||||
memcpy((char*)&ph, img_start + off, sizeof(ph));
|
||||
|
||||
if (ph.type != ELF_PROG_LOAD)
|
||||
continue;
|
||||
if (ph.memsz < ph.filesz) {
|
||||
ERROR("elf header mem size less than file size\n");
|
||||
goto error_exec;
|
||||
}
|
||||
|
||||
// read section
|
||||
// 1. alloc space
|
||||
if ((load_size = xizi_pager.resize_user_pgdir(&pgdir, load_size, ph.vaddr + ph.memsz))
|
||||
!= ph.vaddr + ph.memsz) {
|
||||
goto error_exec;
|
||||
}
|
||||
// 2. copy inode to space
|
||||
assert(ph.vaddr % PAGE_SIZE == 0);
|
||||
for (int addr_offset = 0; addr_offset < ph.filesz; addr_offset += PAGE_SIZE) {
|
||||
uintptr_t page_paddr = xizi_pager.address_translate(&pgdir, ph.vaddr + addr_offset);
|
||||
if (page_paddr == 0) {
|
||||
panic("copy elf file to unmapped addr");
|
||||
}
|
||||
uintptr_t read_size = (ph.filesz - addr_offset < PAGE_SIZE ? ph.filesz - addr_offset : PAGE_SIZE);
|
||||
memcpy(P2V(page_paddr), img_start + (ph.off + addr_offset), read_size);
|
||||
}
|
||||
}
|
||||
|
||||
/// elf file content now in memory
|
||||
// alloc stack page and map to TOP of user vspace
|
||||
uintptr_t* stack_bottom = (uintptr_t*)kalloc(USER_STACK_SIZE);
|
||||
if (UNLIKELY(stack_bottom == NULL)) {
|
||||
ERROR("No memory.\n");
|
||||
goto error_exec;
|
||||
}
|
||||
xizi_pager.map_pages(pgdir.pd_addr, USER_MEM_TOP - USER_STACK_SIZE, V2P(stack_bottom), USER_STACK_SIZE, false);
|
||||
|
||||
uintptr_t user_vspace_sp = USER_MEM_TOP;
|
||||
/// @todo change 32 to some macro
|
||||
uintptr_t user_stack_init[32];
|
||||
uintptr_t argc = 0;
|
||||
uintptr_t copy_len = 0;
|
||||
for (argc = 0; argv != NULL && argv[argc] != NULL; argc++) {
|
||||
/// @todo handle with large number of parameters
|
||||
|
||||
// copy param to user stack
|
||||
copy_len = strlen(argv[argc]) + 1;
|
||||
user_vspace_sp = (user_vspace_sp - copy_len) & ~3;
|
||||
uintptr_t copied_len = xizi_pager.cross_vspace_data_copy(&pgdir, user_vspace_sp, (uintptr_t)argv[argc], copy_len);
|
||||
if (UNLIKELY(copied_len != copy_len)) {
|
||||
ERROR("Something went wrong when copying params.\n");
|
||||
goto error_exec;
|
||||
}
|
||||
user_stack_init[argc] = user_vspace_sp;
|
||||
}
|
||||
user_stack_init[argc] = 0;
|
||||
copy_len = (argc + 1) * sizeof(uintptr_t);
|
||||
user_vspace_sp -= copy_len;
|
||||
uintptr_t copied_len = xizi_pager.cross_vspace_data_copy(&pgdir, user_vspace_sp, (uintptr_t)user_stack_init, copy_len);
|
||||
if (UNLIKELY(copied_len != copy_len)) {
|
||||
ERROR("Something went wrong when copying params.\n");
|
||||
goto error_exec;
|
||||
}
|
||||
|
||||
// init task trapframe, which stores in svc stack
|
||||
// do not go tp error_exec once we change trapframe!
|
||||
assert(copied_len == (argc + 1) * sizeof(uintptr_t));
|
||||
arch_trapframe_set_sp_pc(new_task_cb->main_thread.trapframe, user_vspace_sp, elf->entry);
|
||||
arch_set_main_params(new_task_cb->main_thread.trapframe, argc, user_vspace_sp);
|
||||
|
||||
// save program name
|
||||
strncpy(new_task_cb->name, name, sizeof(new_task_cb->name));
|
||||
|
||||
struct TopLevelPageDirectory old_pgdir = new_task_cb->pgdir;
|
||||
new_task_cb->pgdir = pgdir;
|
||||
|
||||
/// @todo record mem size used b task
|
||||
new_task_cb->mem_size = ALIGNUP(load_size, PAGE_SIZE);
|
||||
|
||||
xizi_pager.free_user_pgdir(&old_pgdir);
|
||||
|
||||
xizi_task_manager.task_set_default_schedule_attr(new_task_cb, RequireRootTag());
|
||||
return 0;
|
||||
|
||||
error_exec:
|
||||
if (pgdir.pd_addr != NULL) {
|
||||
xizi_pager.free_user_pgdir(&pgdir);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -32,23 +32,47 @@ Modification:
|
||||
#include "core.h"
|
||||
|
||||
#include "assert.h"
|
||||
#include "kalloc.h"
|
||||
#include "log.h"
|
||||
#include "multicores.h"
|
||||
#include "kalloc.h"
|
||||
#include "scheduler.h"
|
||||
#include "syscall.h"
|
||||
#include "task.h"
|
||||
|
||||
struct CPU global_cpus[NR_CPU];
|
||||
uint32_t ready_task_priority;
|
||||
|
||||
static inline void task_node_leave_list(struct TaskMicroDescriptor* task)
|
||||
{
|
||||
doubleListDel(&task->node);
|
||||
if (IS_DOUBLE_LIST_EMPTY(&xizi_task_manager.task_list_head[task->priority])) {
|
||||
ready_task_priority &= ~((uint32_t)1 << task->priority);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void task_node_add_to_ready_list_head(struct TaskMicroDescriptor* task)
|
||||
{
|
||||
doubleListAddOnHead(&task->node, &xizi_task_manager.task_list_head[task->priority]);
|
||||
ready_task_priority |= ((uint32_t)1 << task->priority);
|
||||
}
|
||||
|
||||
static inline void task_node_add_to_ready_list_back(struct TaskMicroDescriptor* task)
|
||||
{
|
||||
doubleListAddOnBack(&task->node, &xizi_task_manager.task_list_head[task->priority]);
|
||||
ready_task_priority |= ((uint32_t)1 << task->priority);
|
||||
}
|
||||
|
||||
static void _task_manager_init()
|
||||
{
|
||||
// init task list to NULL
|
||||
for (int i = 0; i < TASK_MAX_PRIORITY; i++) {
|
||||
doubleListNodeInit(&xizi_task_manager.task_list_head[i]);
|
||||
}
|
||||
doubleListNodeInit(&xizi_task_manager.task_blocked_list_head);
|
||||
doubleListNodeInit(&xizi_task_manager.task_running_list_head);
|
||||
// init task (slab) allocator
|
||||
slab_init(&xizi_task_manager.task_allocator, sizeof(struct TaskMicroDescriptor));
|
||||
slab_init(&xizi_task_manager.task_buddy_allocator, sizeof(struct KBuddy));
|
||||
|
||||
// pid pool
|
||||
xizi_task_manager.next_pid = 0;
|
||||
@@ -69,12 +93,54 @@ static struct TaskMicroDescriptor* _alloc_task_cb()
|
||||
// set pid once task is allocated
|
||||
memset(task, 0, sizeof(*task));
|
||||
task->pid = xizi_task_manager.next_pid++;
|
||||
// update pcb used
|
||||
xizi_task_manager.nr_pcb_used += 1;
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
int _task_retrieve_sys_resources(struct TaskMicroDescriptor* ptask)
|
||||
{
|
||||
assert(ptask != NULL);
|
||||
|
||||
/* handle sessions for condition 1, ref. delete_share_pages() */
|
||||
struct session_backend* session_backend = NULL;
|
||||
// close all server_sessions
|
||||
struct server_session* server_session = NULL;
|
||||
while (!IS_DOUBLE_LIST_EMPTY(&ptask->svr_sess_listhead)) {
|
||||
server_session = CONTAINER_OF(ptask->svr_sess_listhead.next, struct server_session, node);
|
||||
assert(server_session != NULL);
|
||||
session_backend = SERVER_SESSION_BACKEND(server_session);
|
||||
assert(session_backend->server == ptask);
|
||||
// cut the connection from task to session
|
||||
server_session->closed = true;
|
||||
xizi_share_page_manager.delete_share_pages(session_backend);
|
||||
}
|
||||
// close all client_sessions
|
||||
struct client_session* client_session = NULL;
|
||||
while (!IS_DOUBLE_LIST_EMPTY(&ptask->cli_sess_listhead)) {
|
||||
client_session = CONTAINER_OF(ptask->cli_sess_listhead.next, struct client_session, node);
|
||||
assert(client_session != NULL);
|
||||
session_backend = CLIENT_SESSION_BACKEND(client_session);
|
||||
assert(session_backend->client == ptask);
|
||||
// cut the connection from task to session
|
||||
client_session->closed = true;
|
||||
xizi_share_page_manager.delete_share_pages(session_backend);
|
||||
}
|
||||
|
||||
if (ptask->server_identifier.meta != NULL) {
|
||||
struct TraceTag server_identifier_owner;
|
||||
AchieveResourceTag(&server_identifier_owner, RequireRootTag(), "softkernel/server-identifier");
|
||||
assert(server_identifier_owner.meta != NULL);
|
||||
DeleteResource(&ptask->server_identifier, &server_identifier_owner);
|
||||
}
|
||||
|
||||
// delete registered irq if there is one
|
||||
if (ptask->bind_irq) {
|
||||
sys_unbind_irq_all(ptask);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief this function changes task list without locking, so it must be called inside a lock critical area
|
||||
/// @param task
|
||||
static void _dealloc_task_cb(struct TaskMicroDescriptor* task)
|
||||
@@ -84,6 +150,8 @@ static void _dealloc_task_cb(struct TaskMicroDescriptor* task)
|
||||
return;
|
||||
}
|
||||
|
||||
_task_retrieve_sys_resources(task);
|
||||
|
||||
// stack is mapped in vspace, so it should be free by pgdir
|
||||
if (task->pgdir.pd_addr) {
|
||||
xizi_pager.free_user_pgdir(&task->pgdir);
|
||||
@@ -92,25 +160,22 @@ static void _dealloc_task_cb(struct TaskMicroDescriptor* task)
|
||||
kfree((char*)task->main_thread.stack_addr);
|
||||
}
|
||||
|
||||
struct double_list_node* cur_node = &task->node;
|
||||
// remove it from used task list
|
||||
doubleListDel(cur_node);
|
||||
task_node_leave_list(task);
|
||||
|
||||
// free task back to allocator
|
||||
slab_free(&xizi_task_manager.task_allocator, (void*)task);
|
||||
xizi_task_manager.nr_pcb_used -= 1;
|
||||
|
||||
// remove priority
|
||||
if (IS_DOUBLE_LIST_EMPTY(&xizi_task_manager.task_list_head[task->priority])) {
|
||||
ready_task_priority &= ~(1 << task->priority);
|
||||
if (task->massive_ipc_allocator != NULL) {
|
||||
KBuddyDestory(task->massive_ipc_allocator);
|
||||
slab_free(&xizi_task_manager.task_buddy_allocator, (void*)task->massive_ipc_allocator);
|
||||
}
|
||||
slab_free(&xizi_task_manager.task_allocator, (void*)task);
|
||||
}
|
||||
|
||||
/* alloc a new task with init */
|
||||
extern void trap_return(void);
|
||||
void task_prepare_enter()
|
||||
__attribute__((optimize("O0"))) void task_prepare_enter()
|
||||
{
|
||||
spinlock_unlock(&whole_kernel_lock);
|
||||
xizi_leave_kernel();
|
||||
trap_return();
|
||||
}
|
||||
|
||||
@@ -122,10 +187,7 @@ static struct TaskMicroDescriptor* _new_task_cb()
|
||||
return NULL;
|
||||
}
|
||||
// init vm
|
||||
if (!xizi_pager.new_pgdir(&task->pgdir)) {
|
||||
_dealloc_task_cb(task);
|
||||
return NULL;
|
||||
}
|
||||
task->pgdir.pd_addr = NULL;
|
||||
/* init basic task member */
|
||||
doubleListNodeInit(&task->cli_sess_listhead);
|
||||
doubleListNodeInit(&task->svr_sess_listhead);
|
||||
@@ -155,15 +217,21 @@ static struct TaskMicroDescriptor* _new_task_cb()
|
||||
return task;
|
||||
}
|
||||
|
||||
static void _task_set_default_schedule_attr(struct TaskMicroDescriptor* task, struct TraceTag* cwd)
|
||||
static void _task_set_default_schedule_attr(struct TaskMicroDescriptor* task)
|
||||
{
|
||||
task->remain_tick = TASK_CLOCK_TICK;
|
||||
task->maxium_tick = TASK_CLOCK_TICK * 10;
|
||||
task->state = READY;
|
||||
task->cwd = *cwd;
|
||||
task->priority = TASK_DEFAULT_PRIORITY;
|
||||
doubleListAddOnHead(&task->node, &xizi_task_manager.task_list_head[task->priority]);
|
||||
ready_task_priority |= (1 << task->priority);
|
||||
task_node_add_to_ready_list_head(task);
|
||||
}
|
||||
|
||||
static void task_state_set_running(struct TaskMicroDescriptor* task)
|
||||
{
|
||||
assert(task != NULL && task->state == READY);
|
||||
task->state = RUNNING;
|
||||
task_node_leave_list(task);
|
||||
doubleListAddOnHead(&task->node, &xizi_task_manager.task_running_list_head);
|
||||
}
|
||||
|
||||
struct TaskMicroDescriptor* next_task_emergency = NULL;
|
||||
@@ -172,66 +240,77 @@ static void _scheduler(struct SchedulerRightGroup right_group)
|
||||
{
|
||||
struct MmuCommonDone* p_mmu_driver = AchieveResource(&right_group.mmu_driver_tag);
|
||||
struct TaskMicroDescriptor* next_task;
|
||||
struct CPU* cpu = cur_cpu();
|
||||
|
||||
spinlock_lock(&whole_kernel_lock);
|
||||
while (1) {
|
||||
next_task = NULL;
|
||||
/* find next runnable task */
|
||||
assert(cur_cpu()->task == NULL);
|
||||
if (next_task_emergency != NULL) {
|
||||
if (next_task_emergency != NULL && next_task_emergency->state == READY) {
|
||||
next_task = next_task_emergency;
|
||||
next_task->state = RUNNING;
|
||||
next_task_emergency = NULL;
|
||||
} else {
|
||||
next_task = xizi_task_manager.next_runnable_task();
|
||||
}
|
||||
spinlock_unlock(&whole_kernel_lock);
|
||||
next_task_emergency = NULL;
|
||||
|
||||
/* not a runnable task */
|
||||
if (UNLIKELY(next_task == NULL) || UNLIKELY(next_task->state != RUNNING)) {
|
||||
spinlock_lock(&whole_kernel_lock);
|
||||
/* if there's not a runnable task, wait for one */
|
||||
if (next_task == NULL) {
|
||||
xizi_leave_kernel();
|
||||
// there is no task to run, into low power mode
|
||||
cpu_into_low_power();
|
||||
|
||||
/* leave kernel for other cores, so they may create a runnable task */
|
||||
xizi_enter_kernel();
|
||||
// activate cpu
|
||||
cpu_leave_low_power();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* a runnable task */
|
||||
spinlock_lock(&whole_kernel_lock);
|
||||
struct CPU* cpu = cur_cpu();
|
||||
/* run the chosen task */
|
||||
task_state_set_running(next_task);
|
||||
cpu->task = next_task;
|
||||
p_mmu_driver->LoadPgdir((uintptr_t)V2P(next_task->pgdir.pd_addr));
|
||||
context_switch(&cpu->scheduler, next_task->main_thread.context);
|
||||
assert(next_task->state != RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t yield_cnt = 0;
|
||||
static void _cur_task_yield_noschedule(void)
|
||||
static void _task_yield_noschedule(struct TaskMicroDescriptor* task, bool blocking)
|
||||
{
|
||||
yield_cnt++;
|
||||
|
||||
struct TaskMicroDescriptor* current_task = cur_cpu()->task;
|
||||
assert(current_task != NULL);
|
||||
assert(task != NULL);
|
||||
/// @warning only support current task yield now
|
||||
assert(task == cur_cpu()->task && task->state == RUNNING);
|
||||
|
||||
// rearrage current task position
|
||||
doubleListDel(¤t_task->node);
|
||||
// DEBUG("%s,%d\n", current_task->name, strcmp(current_task->name, name1));
|
||||
if (current_task->maxium_tick <= 0) {
|
||||
if (IS_DOUBLE_LIST_EMPTY(&xizi_task_manager.task_list_head[current_task->priority])) {
|
||||
ready_task_priority &= ~(1 << current_task->priority);
|
||||
}
|
||||
current_task->priority += 1;
|
||||
current_task->maxium_tick = TASK_CLOCK_TICK * 10;
|
||||
task_node_leave_list(task);
|
||||
if (task->state == RUNNING) {
|
||||
task->state = READY;
|
||||
}
|
||||
doubleListAddOnBack(¤t_task->node, &xizi_task_manager.task_list_head[current_task->priority]);
|
||||
ready_task_priority |= (1 << current_task->priority);
|
||||
// set current task state
|
||||
current_task->state = READY;
|
||||
current_task->remain_tick = TASK_CLOCK_TICK;
|
||||
task->remain_tick = TASK_CLOCK_TICK;
|
||||
cur_cpu()->task = NULL;
|
||||
if (yield_cnt == 50) {
|
||||
recover_priority();
|
||||
yield_cnt = 0;
|
||||
}
|
||||
task_node_add_to_ready_list_back(task);
|
||||
}
|
||||
|
||||
static void _task_block(struct TaskMicroDescriptor* task)
|
||||
{
|
||||
assert(task != NULL);
|
||||
assert(task->state != RUNNING);
|
||||
task_node_leave_list(task);
|
||||
task->state = BLOCKED;
|
||||
doubleListAddOnHead(&task->node, &xizi_task_manager.task_blocked_list_head);
|
||||
}
|
||||
|
||||
static void _task_unblock(struct TaskMicroDescriptor* task)
|
||||
{
|
||||
assert(task != NULL);
|
||||
assert(task->state == BLOCKED);
|
||||
task_node_leave_list(task);
|
||||
task->state = READY;
|
||||
task_node_add_to_ready_list_head(task);
|
||||
}
|
||||
|
||||
/// @brief @warning not tested function
|
||||
/// @param priority
|
||||
static void _set_cur_task_priority(int priority)
|
||||
{
|
||||
if (priority < 0 || priority >= TASK_MAX_PRIORITY) {
|
||||
@@ -240,14 +319,13 @@ static void _set_cur_task_priority(int priority)
|
||||
}
|
||||
|
||||
struct TaskMicroDescriptor* current_task = cur_cpu()->task;
|
||||
assert(current_task != NULL);
|
||||
assert(current_task != NULL && current_task->state == RUNNING);
|
||||
|
||||
task_node_leave_list(current_task);
|
||||
|
||||
current_task->priority = priority;
|
||||
|
||||
doubleListDel(¤t_task->node);
|
||||
doubleListAddOnBack(¤t_task->node, &xizi_task_manager.task_list_head[current_task->priority]);
|
||||
|
||||
ready_task_priority |= (1 << current_task->priority);
|
||||
task_node_add_to_ready_list_back(current_task);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -260,7 +338,10 @@ struct XiziTaskManager xizi_task_manager = {
|
||||
|
||||
.next_runnable_task = max_priority_runnable_task,
|
||||
.task_scheduler = _scheduler,
|
||||
.cur_task_yield_noschedule = _cur_task_yield_noschedule,
|
||||
|
||||
.task_block = _task_block,
|
||||
.task_unblock = _task_unblock,
|
||||
.task_yield_noschedule = _task_yield_noschedule,
|
||||
.set_cur_task_priority = _set_cur_task_priority
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
SRC_FILES := default_irq_handler.c \
|
||||
clock_irq_handler.c \
|
||||
software_irq_handler.c
|
||||
software_irq_handler.c \
|
||||
abort_handler.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
||||
90
Ubiquitous/XiZi_AIoT/softkernel/trap/abort_handler.c
Normal file
90
Ubiquitous/XiZi_AIoT/softkernel/trap/abort_handler.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/* Copyright (c) 2006-2018 Frans Kaashoek, Robert Morris, Russ Cox,
|
||||
* Massachusetts Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* @file abort_handler.c
|
||||
* @brief handle program abort
|
||||
* @version 3.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2023.11.23
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: abort_handler.c
|
||||
Description: handle program abort
|
||||
Others:
|
||||
History:
|
||||
1. Date: 2023-11-23
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. Modify iabort and dabort handler(in dabort_handler() and iabort_handler())
|
||||
*************************************************/
|
||||
#include "core.h"
|
||||
#include "memlayout.h"
|
||||
#include "spinlock.h"
|
||||
#include "trap_common.h"
|
||||
|
||||
#include "assert.h"
|
||||
#include "multicores.h"
|
||||
#include "syscall.h"
|
||||
#include "task.h"
|
||||
|
||||
extern void context_switch(struct context**, struct context*);
|
||||
__attribute__((optimize("O0"))) void dabort_handler(struct trapframe* r)
|
||||
{
|
||||
if (r->pc >= DEV_VRTMEM_BASE && is_spinlock_hold_by_current_cpu(&whole_kernel_lock)) {
|
||||
assert(is_spinlock_hold_by_current_cpu(&whole_kernel_lock));
|
||||
ERROR("dabort in kernel, current task: %s\n", cur_cpu()->task == NULL ? "NULL" : cur_cpu()->task->name);
|
||||
dabort_reason(r);
|
||||
panic("data abort exception\n");
|
||||
}
|
||||
|
||||
struct TaskMicroDescriptor* cur_task = cur_cpu()->task;
|
||||
ERROR("dabort in user space: %s\n", cur_task->name);
|
||||
dabort_reason(r);
|
||||
|
||||
xizi_enter_kernel();
|
||||
sys_exit(cur_task);
|
||||
assert(cur_cpu()->task == NULL);
|
||||
context_switch(&cur_task->main_thread.context, cur_cpu()->scheduler);
|
||||
panic("dabort end should never be reashed.\n");
|
||||
}
|
||||
|
||||
__attribute__((optimize("O0"))) void iabort_handler(struct trapframe* r)
|
||||
{
|
||||
if (r->pc >= DEV_VRTMEM_BASE && is_spinlock_hold_by_current_cpu(&whole_kernel_lock)) {
|
||||
assert(is_spinlock_hold_by_current_cpu(&whole_kernel_lock));
|
||||
ERROR("iabort in kernel, current task: %s\n", cur_cpu()->task == NULL ? "NULL" : cur_cpu()->task->name);
|
||||
iabort_reason(r);
|
||||
panic("kernel prefetch abort exception\n");
|
||||
}
|
||||
|
||||
struct TaskMicroDescriptor* cur_task = cur_cpu()->task;
|
||||
ERROR("iabort in user space: %s\n", cur_task->name);
|
||||
iabort_reason(r);
|
||||
|
||||
xizi_enter_kernel();
|
||||
sys_exit(cur_task);
|
||||
assert(cur_cpu()->task == NULL);
|
||||
context_switch(&cur_task->main_thread.context, cur_cpu()->scheduler);
|
||||
panic("iabort end should never be reashed.\n");
|
||||
}
|
||||
@@ -58,7 +58,7 @@ int xizi_clock_handler(int irq, void* tf, void* arg)
|
||||
current_task->remain_tick--;
|
||||
current_task->maxium_tick--;
|
||||
if (current_task->remain_tick == 0) {
|
||||
xizi_task_manager.cur_task_yield_noschedule();
|
||||
xizi_task_manager.task_yield_noschedule(current_task, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,54 +46,72 @@ bool intr_distributer_init(struct IrqDispatcherRightGroup* _right_group)
|
||||
return p_intr_driver != NULL;
|
||||
}
|
||||
|
||||
void default_interrupt_routine(void)
|
||||
void default_interrupt_routine(int irq)
|
||||
{
|
||||
/* default handler borrow the rights of dispatcher */
|
||||
///@todo Support other cores. (currently assume that CPU_0 is used)
|
||||
ERROR("Interrupt %d has been asserted\n", p_intr_driver->curr_int[0]);
|
||||
ERROR("Interrupt %d has been asserted\n", irq);
|
||||
}
|
||||
|
||||
extern void context_switch(struct context**, struct context*);
|
||||
void intr_irq_dispatch(struct trapframe* tf)
|
||||
{
|
||||
assert(p_intr_driver != NULL);
|
||||
|
||||
p_intr_driver->cpu_irq_disable();
|
||||
xizi_enter_kernel();
|
||||
|
||||
// enter irq
|
||||
assert(p_intr_driver != NULL);
|
||||
uintptr_t int_info = 0;
|
||||
if ((int_info = p_intr_driver->hw_before_irq()) == 0) {
|
||||
return;
|
||||
goto intr_leave_interrupt;
|
||||
}
|
||||
spinlock_lock(&whole_kernel_lock);
|
||||
|
||||
struct TaskMicroDescriptor* current_task = cur_cpu()->task;
|
||||
if (LIKELY(current_task != NULL)) {
|
||||
current_task->main_thread.trapframe = tf;
|
||||
}
|
||||
assert(current_task != NULL);
|
||||
current_task->main_thread.trapframe = tf;
|
||||
|
||||
unsigned cpu = p_intr_driver->hw_cur_int_cpu(int_info);
|
||||
int cpu = cur_cpuid();
|
||||
assert(cpu >= 0 && cpu < NR_CPU);
|
||||
unsigned irq = p_intr_driver->hw_cur_int_num(int_info);
|
||||
p_intr_driver->curr_int[cpu] = irq;
|
||||
|
||||
// distribute irq
|
||||
irq_handler_t isr = p_intr_driver->sw_irqtbl[irq].handler;
|
||||
if (isr) {
|
||||
if (isr != NULL) {
|
||||
isr(irq, tf, NULL);
|
||||
} else {
|
||||
default_interrupt_routine();
|
||||
default_interrupt_routine(irq);
|
||||
}
|
||||
|
||||
// finish irq.
|
||||
p_intr_driver->curr_int[cpu] = 0;
|
||||
p_intr_driver->hw_after_irq(int_info);
|
||||
|
||||
if ((cur_cpu()->task == NULL && current_task != NULL) || current_task->state != RUNNING) {
|
||||
if (cur_cpu()->task == NULL || current_task->state != RUNNING) {
|
||||
cur_cpu()->task = NULL;
|
||||
context_switch(¤t_task->main_thread.context, cur_cpu()->scheduler);
|
||||
}
|
||||
assert(current_task == cur_cpu()->task);
|
||||
|
||||
spinlock_unlock(&whole_kernel_lock);
|
||||
p_intr_driver->cpu_irq_enable();
|
||||
intr_leave_interrupt:
|
||||
xizi_leave_kernel();
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) inline void xizi_enter_kernel()
|
||||
{
|
||||
/// @warning trampoline is responsible for closing interrupt
|
||||
spinlock_lock(&whole_kernel_lock);
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) inline bool xizi_try_enter_kernel()
|
||||
{
|
||||
/// @warning trampoline is responsible for closing interrupt
|
||||
if (spinlock_try_lock(&whole_kernel_lock)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) inline void xizi_leave_kernel()
|
||||
{
|
||||
/// @warning trampoline is responsible for eabling interrupt by using user's state register
|
||||
spinlock_unlock(&whole_kernel_lock);
|
||||
}
|
||||
|
||||
@@ -48,12 +48,9 @@ bool swi_distributer_init(struct SwiDispatcherRightGroup* _right_group)
|
||||
extern void context_switch(struct context**, struct context*);
|
||||
void software_irq_dispatch(struct trapframe* tf)
|
||||
{
|
||||
|
||||
xizi_enter_kernel();
|
||||
assert(p_intr_driver != NULL);
|
||||
|
||||
p_intr_driver->cpu_irq_disable();
|
||||
spinlock_lock(&whole_kernel_lock);
|
||||
|
||||
// get current task
|
||||
struct TaskMicroDescriptor* cur_task = cur_cpu()->task;
|
||||
/// @todo: Handle dead task
|
||||
@@ -74,11 +71,10 @@ void software_irq_dispatch(struct trapframe* tf)
|
||||
cur_cpu()->task = NULL;
|
||||
context_switch(&cur_task->main_thread.context, cur_cpu()->scheduler);
|
||||
}
|
||||
assert(cur_task == cur_cpu()->task);
|
||||
if (syscall_num == SYSCALL_EXIT) {
|
||||
panic("Exit reaches");
|
||||
}
|
||||
|
||||
spinlock_unlock(&whole_kernel_lock);
|
||||
p_intr_driver->cpu_irq_enable();
|
||||
assert(cur_task == cur_cpu()->task);
|
||||
xizi_leave_kernel();
|
||||
}
|
||||
@@ -28,6 +28,7 @@
|
||||
* @date 2022-08-08
|
||||
*/
|
||||
#include "ch32v30x.h"
|
||||
#include "connect_can.h"
|
||||
#include "connect_ether.h"
|
||||
#include "connect_uart.h"
|
||||
#include "core_riscv.h"
|
||||
@@ -57,24 +58,27 @@ static uint32_t _SysTick_Config(uint32_t ticks)
|
||||
/**
|
||||
* This function will initial your board.
|
||||
*/
|
||||
|
||||
void InitBoardHardware()
|
||||
{
|
||||
USART_Printf_Init(115200);
|
||||
/* System Tick Configuration */
|
||||
_SysTick_Config(SystemCoreClock / TICK_PER_SECOND);
|
||||
/* initialize memory system */
|
||||
InitBoardMemory(MEMORY_START_ADDRESS, (void*)MEMORY_END_ADDRESS);
|
||||
InitHwUart();
|
||||
InstallConsole("uart1", "uart1_drv", "uart1_dev1");
|
||||
#ifdef BSP_USING_UART4
|
||||
InstallConsole("uart4", "uart4_drv", "uart4_dev4");
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_ETH
|
||||
InitHwEth();
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_CAN
|
||||
InitHwCan();
|
||||
#endif
|
||||
|
||||
KPrintf("consle init completed.\n");
|
||||
KPrintf("board initialization......\n");
|
||||
// KPrintf("memory address range: [0x%08x - 0x%08x], size: %d\n", (x_ubase) MEMORY_START_ADDRESS, (x_ubase) MEMORY_END_ADDRESS, gd32vf103_SRAM_SIZE);
|
||||
/* initialize memory system */
|
||||
|
||||
KPrintf("board init done.\n");
|
||||
KPrintf("start okernel...\n");
|
||||
|
||||
@@ -19,4 +19,23 @@ menuconfig BSP_USING_ETH
|
||||
bool "Using Ethernet"
|
||||
default y
|
||||
|
||||
|
||||
menuconfig BSP_USING_CAN
|
||||
bool "Using CAN device"
|
||||
default y
|
||||
select RESOURCES_CAN
|
||||
if BSP_USING_CAN
|
||||
source "$BSP_DIR/third_party_driver/can/Kconfig"
|
||||
endif
|
||||
|
||||
|
||||
menuconfig BSP_USING_USB
|
||||
bool "Using USB device"
|
||||
default y
|
||||
select BSP_USING_USBH
|
||||
select RESOURCES_USB
|
||||
select RESOURCES_USB_HOST
|
||||
select USBH_MSTORAGE
|
||||
select RESOURCES_USB_DEVICE
|
||||
if BSP_USING_USB
|
||||
source "$BSP_DIR/third_party_driver/usb/Kconfig"
|
||||
endif
|
||||
|
||||
@@ -13,4 +13,12 @@ ifeq ($(CONFIG_BSP_USING_ETH),y)
|
||||
SRC_DIR += ethernet
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BSP_USING_CAN),y)
|
||||
SRC_DIR += can
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BSP_USING_USB),y)
|
||||
SRC_DIR += usb
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
11
Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/Kconfig
Executable file
11
Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/Kconfig
Executable file
@@ -0,0 +1,11 @@
|
||||
config CAN_BUS_NAME_1
|
||||
string "can bus name"
|
||||
default "can1"
|
||||
|
||||
config CAN_DRIVER_NAME
|
||||
string "can driver name"
|
||||
default "can1_drv"
|
||||
|
||||
config CAN_1_DEVICE_NAME_1
|
||||
string "can bus 1 device 1 name"
|
||||
default "can1_dev1"
|
||||
4
Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/Makefile
Executable file
4
Ubiquitous/XiZi_IIoT/board/ch32v307vct6/third_party_driver/can/Makefile
Executable file
@@ -0,0 +1,4 @@
|
||||
SRC_FILES := connect_can.c
|
||||
SRC_DIR := test
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,249 @@
|
||||
|
||||
#include <connect_can.h>
|
||||
#include <ch32v30x_gpio.h>
|
||||
#include <ch32v30x_rcc.h>
|
||||
#include <ch32v30x_misc.h>
|
||||
|
||||
static struct CanSendConfigure can_send_deconfig =
|
||||
{
|
||||
.stdid = 0x12,
|
||||
.exdid = 0x12,
|
||||
.ide = 0 ,
|
||||
.rtr = 0,
|
||||
.data_lenth = 8
|
||||
};
|
||||
|
||||
static void CanGPIOInit(void)
|
||||
{
|
||||
CAN_FilterInitTypeDef can1_filter;
|
||||
GPIO_InitTypeDef gpio_initstructure;
|
||||
CAN_InitTypeDef can_initstruction;
|
||||
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO |RCC_APB2Periph_GPIOB, ENABLE);
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
|
||||
|
||||
GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
|
||||
|
||||
gpio_initstructure.GPIO_Pin = GPIO_Pin_9;
|
||||
gpio_initstructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
gpio_initstructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init( GPIOB, &gpio_initstructure);
|
||||
|
||||
gpio_initstructure.GPIO_Pin = GPIO_Pin_8;
|
||||
gpio_initstructure.GPIO_Mode = GPIO_Mode_IPU;
|
||||
GPIO_Init( GPIOB, &gpio_initstructure);
|
||||
}
|
||||
|
||||
static void Can1NvicConfig(void)
|
||||
{
|
||||
NVIC_InitTypeDef can_nvic_config;
|
||||
|
||||
can_nvic_config.NVIC_IRQChannel = CAN1_RX1_IRQn;
|
||||
can_nvic_config.NVIC_IRQChannelPreemptionPriority = 2;
|
||||
can_nvic_config.NVIC_IRQChannelSubPriority = 2;
|
||||
can_nvic_config.NVIC_IRQChannelCmd = ENABLE;
|
||||
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
|
||||
NVIC_Init(&can_nvic_config);
|
||||
}
|
||||
|
||||
static uint32 CanModeInit(void *drv, struct BusConfigureInfo *configure_info)
|
||||
{
|
||||
NULL_PARAM_CHECK(drv);
|
||||
NULL_PARAM_CHECK(configure_info);
|
||||
CAN_FilterInitTypeDef can1_filter;
|
||||
CAN_InitTypeDef can_initstruction;
|
||||
|
||||
struct CanDriverConfigure *config = ( struct CanDriverConfigure *)configure_info->private_data;
|
||||
|
||||
can_initstruction.CAN_TTCM = DISABLE;
|
||||
can_initstruction.CAN_ABOM = DISABLE;
|
||||
can_initstruction.CAN_AWUM = DISABLE;
|
||||
can_initstruction.CAN_NART = ENABLE;
|
||||
can_initstruction.CAN_TXFP = DISABLE;
|
||||
can_initstruction.CAN_Mode = config->mode;
|
||||
can_initstruction.CAN_RFLM = DISABLE;
|
||||
can_initstruction.CAN_SJW = config->tsjw;
|
||||
can_initstruction.CAN_BS1 = config->tbs1;
|
||||
can_initstruction.CAN_BS2 = config->tbs2;
|
||||
can_initstruction.CAN_Prescaler = config->brp;
|
||||
|
||||
CAN_Init(CAN1, &can_initstruction);
|
||||
|
||||
can1_filter.CAN_FilterNumber=0;
|
||||
can1_filter.CAN_FilterMode=CAN_FilterMode_IdMask;
|
||||
can1_filter.CAN_FilterScale=CAN_FilterScale_32bit;
|
||||
can1_filter.CAN_FilterIdHigh=0x0000;
|
||||
can1_filter.CAN_FilterIdLow=0x0000;
|
||||
can1_filter.CAN_FilterMaskIdHigh=0x0000;
|
||||
can1_filter.CAN_FilterMaskIdLow=0x0006;
|
||||
can1_filter.CAN_FilterFIFOAssignment=CAN_Filter_FIFO1;
|
||||
can1_filter.CAN_FilterActivation=ENABLE;
|
||||
CAN_FilterInit(&can1_filter);
|
||||
|
||||
#ifdef CAN_USING_INTERRUPT
|
||||
Can1NvicConfig();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32 CanSendMsg(void * dev , struct BusBlockWriteParam *write_param )
|
||||
{
|
||||
NULL_PARAM_CHECK(write_param);
|
||||
|
||||
uint8 *data = (uint8 * ) write_param->buffer;
|
||||
u8 messege_box;
|
||||
u16 i = 0;
|
||||
u16 timer_count = 1000;
|
||||
CanTxMsg tx_data;
|
||||
tx_data.StdId = 0x55;
|
||||
tx_data.ExtId = 0x00;
|
||||
tx_data.IDE = 0;
|
||||
tx_data.RTR = 0;
|
||||
tx_data.DLC = write_param->size;
|
||||
|
||||
for(i = 0;i < tx_data.DLC;i ++) {
|
||||
tx_data.Data[i] = data[i];
|
||||
}
|
||||
|
||||
messege_box = CAN_Transmit(CAN1,&tx_data);
|
||||
|
||||
while (CAN_TransmitStatus(CAN1,messege_box)== CAN_TxStatus_Failed &&timer_count) {
|
||||
timer_count--;
|
||||
}
|
||||
|
||||
if (timer_count<=0) {
|
||||
return ERROR;
|
||||
}
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static uint32 CanRecvMsg(void *dev , struct BusBlockReadParam *databuf)
|
||||
{
|
||||
NULL_PARAM_CHECK(dev);
|
||||
int i;
|
||||
uint8 * buf = (uint8 *)databuf->buffer;
|
||||
CanRxMsg msg;
|
||||
if (CAN_MessagePending(CAN1, CAN_FIFO0) == 0)
|
||||
return 0;
|
||||
CAN_Receive(CAN1, CAN_FIFO0, &msg);
|
||||
for(i = 0 ;i < msg.DLC;i ++)
|
||||
buf[i] = msg.Data[i];
|
||||
databuf->size = msg.DLC ;
|
||||
|
||||
return msg.DLC;
|
||||
}
|
||||
|
||||
static struct CanDevDone dev_done =
|
||||
{
|
||||
.open = NONE,
|
||||
.close = NONE,
|
||||
.write = CanSendMsg,
|
||||
.read = CanRecvMsg
|
||||
};
|
||||
|
||||
static struct CanHardwareDevice dev;
|
||||
|
||||
#ifdef CAN_USING_INTERRUPT
|
||||
void CAN1_RX0_IRQHandler(void)
|
||||
{
|
||||
CanRxMsg rxmsg;
|
||||
int i = 0;
|
||||
CAN_Receive(CAN1, 0, &rxmsg);
|
||||
for (i = 0;i < 8;i ++)
|
||||
KPrintf("rxbuf [%d] = :%d",i,rxmsg.Data[i]);
|
||||
}
|
||||
DECLARE_HW_IRQ(CAN1_RX0_IRQn, CAN1_RX0_IRQHandler, NONE);
|
||||
#endif
|
||||
|
||||
static int BoardCanBusInit(struct CanDev *CanDev_bus, struct CanDriver *can_driver)
|
||||
{
|
||||
x_err_t ret = EOK;
|
||||
|
||||
/*Init the can bus */
|
||||
ret = CanBusInit(&CanDev_bus->can_bus, CanDev_bus->bus_name);
|
||||
if (EOK != ret) {
|
||||
KPrintf("Board_can_init canBusInit error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/*Init the can driver*/
|
||||
ret = CanDriverInit(can_driver, CAN_DRIVER_NAME);
|
||||
if (EOK != ret) {
|
||||
KPrintf("Board_can_init canDriverInit error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/*Attach the can driver to the can bus*/
|
||||
ret = CanDriverAttachToBus(CAN_DRIVER_NAME, CanDev_bus->bus_name);
|
||||
if (EOK != ret) {
|
||||
KPrintf("Board_can_init CanDriverAttachToBus error %d\n", ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static x_err_t HwCanDeviceAttach(const char *bus_name, const char *device_name)
|
||||
{
|
||||
NULL_PARAM_CHECK(bus_name);
|
||||
NULL_PARAM_CHECK(device_name);
|
||||
|
||||
x_err_t result;
|
||||
struct CanHardwareDevice *can_device;
|
||||
|
||||
/* attach the device to can bus*/
|
||||
can_device = (struct CanHardwareDevice *)x_malloc(sizeof(struct CanHardwareDevice));
|
||||
CHECK(can_device);
|
||||
memset(can_device, 0, sizeof(struct CanHardwareDevice));
|
||||
can_device->dev_done = &dev_done;
|
||||
|
||||
result = CanDeviceRegister(can_device, NONE, device_name);
|
||||
if (EOK != result) {
|
||||
KPrintf("board_can_init canDeviceInit device %s error %d\n", "can1", result);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
result = CanDeviceAttachToBus(device_name, bus_name);
|
||||
if (result != EOK) {
|
||||
SYS_ERR("%s attach to %s faild, %d\n", device_name, bus_name, result);
|
||||
}
|
||||
|
||||
CHECK(result == EOK);
|
||||
|
||||
KPrintf("%s attach to %s done\n", device_name, bus_name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct CanDev can1;
|
||||
|
||||
int InitHwCan(void)
|
||||
{
|
||||
x_err_t ret = EOK;
|
||||
struct CanDev *can_bus;
|
||||
|
||||
static struct CanDriver can_driver;
|
||||
memset(&can_driver, 0, sizeof(struct CanDriver));
|
||||
can_driver.configure = CanModeInit;
|
||||
|
||||
CanGPIOInit();
|
||||
can_bus = &can1;
|
||||
can_bus->instance = CAN1;
|
||||
can_bus->bus_name = CAN_BUS_NAME_1;
|
||||
can_bus->can_bus.private_data = &can1;
|
||||
|
||||
ret = BoardCanBusInit(can_bus, &can_driver);
|
||||
|
||||
if (EOK != ret) {
|
||||
KPrintf(" can_bus_init %s error ret %u\n", can_bus->bus_name, ret);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = HwCanDeviceAttach(CAN_BUS_NAME_1,CAN_1_DEVICE_NAME_1);
|
||||
if (EOK != ret) {
|
||||
KPrintf(" HwCanDeviceAttach %s error ret %u\n", can_bus->bus_name, ret);
|
||||
return ERROR;
|
||||
}
|
||||
return EOK;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
SRC_FILES := can_test.c
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file can_test.c
|
||||
* @brief test ch32v307 can
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024-03-14
|
||||
*/
|
||||
#include "shell.h"
|
||||
#include "ch32v30x.h"
|
||||
#include "connect_can.h"
|
||||
#include <ch32v30x_gpio.h>
|
||||
#include <ch32v30x_rcc.h>
|
||||
#include <ch32v30x_misc.h>
|
||||
|
||||
static int init_can()
|
||||
{
|
||||
KPrintf("init can\r\n");
|
||||
|
||||
CAN_FilterInitTypeDef can1_filter;
|
||||
CAN_InitTypeDef can_initstruction;
|
||||
|
||||
can_initstruction.CAN_TTCM = DISABLE;
|
||||
can_initstruction.CAN_ABOM = DISABLE;
|
||||
can_initstruction.CAN_AWUM = DISABLE;
|
||||
can_initstruction.CAN_NART = ENABLE;
|
||||
can_initstruction.CAN_TXFP = DISABLE;
|
||||
can_initstruction.CAN_Mode = CAN_Mode_Silent_LoopBack;
|
||||
can_initstruction.CAN_RFLM = DISABLE;
|
||||
can_initstruction.CAN_SJW = CAN_SJW_1tq;
|
||||
can_initstruction.CAN_BS1 = CAN_BS1_6tq;
|
||||
can_initstruction.CAN_BS2 = CAN_BS2_5tq;
|
||||
can_initstruction.CAN_Prescaler = 12;
|
||||
CAN_Init(CAN1, &can_initstruction);
|
||||
|
||||
can1_filter.CAN_FilterNumber = 0;
|
||||
can1_filter.CAN_FilterMode = CAN_FilterMode_IdMask;
|
||||
can1_filter.CAN_FilterScale = CAN_FilterScale_32bit;
|
||||
can1_filter.CAN_FilterIdHigh = 0x0000;
|
||||
can1_filter.CAN_FilterIdLow = 0x0000;
|
||||
can1_filter.CAN_FilterMaskIdHigh = 0x0000;
|
||||
can1_filter.CAN_FilterMaskIdLow = 0x0006;
|
||||
can1_filter.CAN_FilterFIFOAssignment = CAN_Filter_FIFO1;
|
||||
can1_filter.CAN_FilterActivation = ENABLE;
|
||||
CAN_FilterInit(&can1_filter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 CAN_Send_Msg(u8 *msg, u8 len)
|
||||
{
|
||||
u8 mbox;
|
||||
u16 i = 0;
|
||||
|
||||
CanTxMsg CanTxStructure;
|
||||
|
||||
CanTxStructure.StdId = 0x317;
|
||||
CanTxStructure.IDE = CAN_Id_Standard;
|
||||
CanTxStructure.RTR = CAN_RTR_Data;
|
||||
CanTxStructure.DLC = len;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
CanTxStructure.Data[i] = msg[i];
|
||||
}
|
||||
|
||||
mbox = CAN_Transmit(CAN1, &CanTxStructure);
|
||||
|
||||
i = 0;
|
||||
|
||||
while ((CAN_TransmitStatus(CAN1, mbox) != CAN_TxStatus_Ok) && (i < 0xFFF))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == 0xFFF)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 CAN_Receive_Msg(u8 *buf)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
CanRxMsg CanRxStructure;
|
||||
|
||||
if (CAN_MessagePending(CAN1, CAN_FIFO1) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
CAN_Receive(CAN1, CAN_FIFO1, &CanRxStructure);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
buf[i] = CanRxStructure.Data[i];
|
||||
}
|
||||
|
||||
return CanRxStructure.DLC;
|
||||
}
|
||||
|
||||
int test_can(int argc, char *argv[])
|
||||
{
|
||||
u8 i;
|
||||
u8 cnt = 0;
|
||||
u8 tx, rx;
|
||||
u8 txbuf[8];
|
||||
u8 rxbuf[8];
|
||||
init_can();
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
txbuf[i] = cnt + i;
|
||||
}
|
||||
tx = CAN_Send_Msg(txbuf, 8);
|
||||
|
||||
if (tx)
|
||||
{
|
||||
KPrintf("CAN1 Send Failed\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
KPrintf("CAN1 Send Success\r\n");
|
||||
KPrintf("CAN1 Send Data:\r\n");
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
KPrintf("%02x\r\n", txbuf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
rx = CAN_Receive_Msg(rxbuf);
|
||||
|
||||
if (rx)
|
||||
{
|
||||
KPrintf("CAN1 Receive Data:\r\n");
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
KPrintf("%02x\r\n", txbuf[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
KPrintf("CAN1 No Receive Data\r\n");
|
||||
}
|
||||
|
||||
cnt++;
|
||||
if (cnt == 0xFF)
|
||||
{
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
|
||||
test_can, test_can, test CAN);
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
0.该测试在Ubiquitous中测试通过(将驱动中静态的收发初始化操作在测试文件中实现),在APP_Framework的测试中BusFind,BusFindDriver,BusFindDevice可找到相应的设备,但无法通过其进行读写等操作
|
||||
|
||||
```
|
||||
// APP_Framework/Applications/main.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <transform.h>
|
||||
#include <bus.h>
|
||||
#define CAN_BUS "can1"
|
||||
|
||||
#define CAN_DRIVER "can1_drv"
|
||||
|
||||
#define CAN_DEVICE "can1_dev1"
|
||||
|
||||
void TestCAN(void)
|
||||
{
|
||||
KPrintf("Test can start\n");
|
||||
struct Bus *bus;
|
||||
struct HardwareDev *dev;
|
||||
struct Driver *drv;
|
||||
char test_str[] = "Hello AIIT!\r\n";
|
||||
/* find the serial bus pointer */
|
||||
bus = BusFind(CAN_BUS);
|
||||
if (NONE == bus)
|
||||
{
|
||||
KPrintf("BusFind %s failed\n", CAN_BUS);
|
||||
return;
|
||||
}
|
||||
/* find the serial driver pointer */
|
||||
drv = BusFindDriver(bus, CAN_DRIVER);
|
||||
if (NONE == drv)
|
||||
{
|
||||
KPrintf("BusFindDriver %s failed\n", CAN_DRIVER);
|
||||
return;
|
||||
}
|
||||
/* find the serial device pointer */
|
||||
dev = BusFindDevice(bus, CAN_DEVICE);
|
||||
if (NONE == dev)
|
||||
{
|
||||
KPrintf("BusFindDevice %s failed\n", CAN_DEVICE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PRIV_SHELL_CMD_FUNCTION(TestCAN, a can test sample, PRIV_SHELL_CMD_MAIN_ATTR);
|
||||
```
|
||||
|
||||
1.make BOARD=ch32v307vct6 menuconfig中配置can相关参数 ch32v307vct6 feature ---> Using CAN device --->
|
||||
|
||||
2.在can_test.c中can_initstruction.CAN_Mode表示can的收发模式,修改该参数可实现不同的收发方式,有CAN_Mode_Normal,CAN_Mode_LoopBack,CAN_Mode_Silent,CAN_Mode_Silent_LoopBack四种模式,此处用CAN_Mode_Silent_LoopBack该模式,实现自收自发,如果需要通过主机收发可修改为CAN_Mode_Normal
|
||||
|
||||
3.编译后将其烧录至开发板上,执行test_can命令,运行can测试。
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef CONNECT_CAN_H
|
||||
#define CONNECT_CAN_H
|
||||
|
||||
|
||||
#include <bus_can.h>
|
||||
#include <dev_can.h>
|
||||
|
||||
|
||||
#include <ch32v30x.h>
|
||||
#include <ch32v30x_can.h>
|
||||
|
||||
|
||||
struct CanDev
|
||||
{
|
||||
CAN_TypeDef *instance;
|
||||
|
||||
char *bus_name;
|
||||
|
||||
// CAN_InitTypeDef init;
|
||||
|
||||
uint8 can_flag;
|
||||
struct CanBus can_bus;
|
||||
};
|
||||
|
||||
int InitHwCan(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file connect_usb.h
|
||||
* @brief define aiit-arm32-board usb function and struct
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#ifndef CONNECT_USB_H
|
||||
#define CONNECT_USB_H
|
||||
|
||||
|
||||
#include <bus_usb.h>
|
||||
#include <dev_usb.h>
|
||||
#ifdef RESOURCES_USB_HOST
|
||||
#ifdef BSP_USING_USBH
|
||||
#include <ch32v30x_usbhs_host.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int InitHwUsb(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
menuconfig BSP_USING_UART1
|
||||
bool "Enable UART1"
|
||||
default y
|
||||
default n
|
||||
if BSP_USING_UART1
|
||||
config SERIAL_BUS_NAME_1
|
||||
string "serial bus name"
|
||||
@@ -12,3 +12,48 @@ menuconfig BSP_USING_UART1
|
||||
string "serial bus device name"
|
||||
default "uart1_dev1"
|
||||
endif
|
||||
|
||||
menuconfig BSP_USING_UART2
|
||||
bool "Enable UART2"
|
||||
default n
|
||||
if BSP_USING_UART2
|
||||
config SERIAL_BUS_NAME_2
|
||||
string "serial bus name"
|
||||
default "uart2"
|
||||
config SERIAL_DRV_NAME_2
|
||||
string "serial bus driver name"
|
||||
default "uart2_drv"
|
||||
config SERIAL_2_DEVICE_NAME_0
|
||||
string "serial bus device name"
|
||||
default "uart2_dev2"
|
||||
endif
|
||||
|
||||
menuconfig BSP_USING_UART4
|
||||
bool "Enable UART4"
|
||||
default y
|
||||
if BSP_USING_UART4
|
||||
config SERIAL_BUS_NAME_4
|
||||
string "serial bus name"
|
||||
default "uart4"
|
||||
config SERIAL_DRV_NAME_4
|
||||
string "serial bus driver name"
|
||||
default "uart4_drv"
|
||||
config SERIAL_4_DEVICE_NAME_0
|
||||
string "serial bus device name"
|
||||
default "uart4_dev4"
|
||||
endif
|
||||
|
||||
menuconfig BSP_USING_UART5
|
||||
bool "Enable UART5"
|
||||
default y
|
||||
if BSP_USING_UART5
|
||||
config SERIAL_BUS_NAME_5
|
||||
string "serial bus name"
|
||||
default "uart5"
|
||||
config SERIAL_DRV_NAME_5
|
||||
string "serial bus driver name"
|
||||
default "uart5_drv"
|
||||
config SERIAL_5_DEVICE_NAME_0
|
||||
string "serial bus device name"
|
||||
default "uart5_dev5"
|
||||
endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
SRC_FILES := connect_uart.c
|
||||
SRC_FILES := connect_uart.c test_uart.c
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user