This commit is contained in:
liuqh
2024-05-08 15:36:46 +08:00
181 changed files with 10418 additions and 1429 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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()

View File

@@ -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);

View File

@@ -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("");
}

View File

@@ -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.

View File

@@ -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,
};

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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,

View File

@@ -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 */

View File

@@ -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);

View 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_

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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,
};

View 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();
}

View 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();
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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];

View File

@@ -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

View File

@@ -1,4 +1,4 @@
SRC_DIR := ipc memory
SRC_DIR := ipc memory usyscall
include $(KERNEL_ROOT)/compiler.mk

View File

@@ -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

View File

@@ -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;
}
}
}

View File

@@ -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; \
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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

View 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 $^

View File

@@ -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)

View File

@@ -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);

View File

@@ -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)

View File

@@ -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];

View File

@@ -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.
*/

View File

@@ -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;

View File

@@ -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...) \

View File

@@ -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();

View File

@@ -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);

View File

@@ -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

View File

@@ -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);
};

View File

@@ -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

View File

@@ -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:");

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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:

View File

@@ -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;
}
}

View File

@@ -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)
{

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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(&current_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(&current_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(&current_task->node);
doubleListAddOnBack(&current_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
};

View File

@@ -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

View 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");
}

View File

@@ -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);
}
}
}

View File

@@ -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(&current_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);
}

View File

@@ -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();
}

View File

@@ -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");

View File

@@ -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

View File

@@ -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

View 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"

View File

@@ -0,0 +1,4 @@
SRC_FILES := connect_can.c
SRC_DIR := test
include $(KERNEL_ROOT)/compiler.mk

View File

@@ -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;
}

View File

@@ -0,0 +1,4 @@
SRC_FILES := can_test.c
include $(KERNEL_ROOT)/compiler.mk

View File

@@ -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);

View File

@@ -0,0 +1,55 @@
0.该测试在Ubiquitous中测试通过将驱动中静态的收发初始化操作在测试文件中实现在APP_Framework的测试中BusFindBusFindDriverBusFindDevice可找到相应的设备但无法通过其进行读写等操作
```
// 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测试。

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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