From c9508111d56ed8638bb123d730c85d700c73add9 Mon Sep 17 00:00:00 2001 From: Wu Shifang Date: Fri, 22 Mar 2024 09:28:59 +0800 Subject: [PATCH 01/35] lib/tnsystick: implement lib/tnsystick managing os tick and system timer Signed-off-by: Wu Shifang --- drivers/Makefile.uk | 1 + drivers/sysclock/Config.uk | 9 + drivers/sysclock/Makefile.uk | 9 + .../sysclock/arm_generic_timer/Makefile.uk | 9 + .../arm_generic_timer/arm_generic_timer.c | 186 +++++++++++ .../include/uk/sysclock/arm_generic_timer.h | 21 ++ drivers/sysclock/exportsyms.uk | 1 + include/uk/plat/time.h | 25 +- lib/Makefile.uk | 1 + lib/tnsystick/Config.uk | 22 ++ lib/tnsystick/Makefile.uk | 7 + lib/tnsystick/exportsyms.uk | 8 + lib/tnsystick/include/tn/systick.h | 99 ++++++ lib/tnsystick/include/tn/systick_impl.h | 72 +++++ lib/tnsystick/tnsystick.c | 303 ++++++++++++++++++ lib/ukboot/boot.c | 10 + lib/ukintctlr/ukintctlr.c | 3 +- plat/common/include/uk/plat/common/_time.h | 7 + plat/kvm/Makefile.uk | 2 + 19 files changed, 792 insertions(+), 3 deletions(-) create mode 100644 drivers/sysclock/Config.uk create mode 100644 drivers/sysclock/Makefile.uk create mode 100644 drivers/sysclock/arm_generic_timer/Makefile.uk create mode 100644 drivers/sysclock/arm_generic_timer/arm_generic_timer.c create mode 100644 drivers/sysclock/arm_generic_timer/include/uk/sysclock/arm_generic_timer.h create mode 100644 drivers/sysclock/exportsyms.uk create mode 100644 lib/tnsystick/Config.uk create mode 100644 lib/tnsystick/Makefile.uk create mode 100644 lib/tnsystick/exportsyms.uk create mode 100644 lib/tnsystick/include/tn/systick.h create mode 100644 lib/tnsystick/include/tn/systick_impl.h create mode 100644 lib/tnsystick/tnsystick.c diff --git a/drivers/Makefile.uk b/drivers/Makefile.uk index 35ae739a..3a409856 100644 --- a/drivers/Makefile.uk +++ b/drivers/Makefile.uk @@ -10,3 +10,4 @@ $(eval $(call import_lib,$(UK_DRIV_BASE)/ukbus)) $(eval $(call import_lib,$(UK_DRIV_BASE)/ukintctlr)) $(eval $(call import_lib,$(UK_DRIV_BASE)/uktty)) $(eval $(call import_lib,$(UK_DRIV_BASE)/virtio)) +$(eval $(call import_lib,$(UK_DRIV_BASE)/sysclock)) diff --git a/drivers/sysclock/Config.uk b/drivers/sysclock/Config.uk new file mode 100644 index 00000000..9ac0ac0f --- /dev/null +++ b/drivers/sysclock/Config.uk @@ -0,0 +1,9 @@ +menuconfig SYSCLOCK + bool "Systerm timer" + default y + depends on HAVE_SYSTICK + +config ARM_GENERIC_TIMER + bool "arm_generic_timer(used in arm cortex-a/cortex-r)" + default n + depends on SYSCLOCK diff --git a/drivers/sysclock/Makefile.uk b/drivers/sysclock/Makefile.uk new file mode 100644 index 00000000..4ccaaf4e --- /dev/null +++ b/drivers/sysclock/Makefile.uk @@ -0,0 +1,9 @@ +################################################################################ +# +# Driver registrations +# +################################################################################ + +UK_DRIV_SYSCLOCK_BASE := $(UK_DRIV_BASE)/sysclock + +$(eval $(call import_lib,$(UK_DRIV_SYSCLOCK_BASE)/arm_generic_timer)) diff --git a/drivers/sysclock/arm_generic_timer/Makefile.uk b/drivers/sysclock/arm_generic_timer/Makefile.uk new file mode 100644 index 00000000..a4fa8c96 --- /dev/null +++ b/drivers/sysclock/arm_generic_timer/Makefile.uk @@ -0,0 +1,9 @@ +$(eval $(call addlib_s,arm_generic_timer,$(CONFIG_ARM_GENERIC_TIMER))) + +ASINCLUDES-$(CONFIG_ARM_GENERIC_TIMER) += -I$(ARM_GENERIC_TIMER_BASE)/include +CINCLUDES-$(CONFIG_ARM_GENERIC_TIMER) += -I$(ARM_GENERIC_TIMER_BASE)/include +CXXINCLUDES-$(CONFIG_ARM_GENERIC_TIMER) += -I$(ARM_GENERIC_TIMER_BASE)/include + +ARM_GENERIC_TIMER_CINCLUDES-y += -I$(CONFIG_UK_BASE)/plat/common/include + +ARM_GENERIC_TIMER_SRCS-$(CONFIG_ARM_GENERIC_TIMER) += $(ARM_GENERIC_TIMER_BASE)/arm_generic_timer.c diff --git a/drivers/sysclock/arm_generic_timer/arm_generic_timer.c b/drivers/sysclock/arm_generic_timer/arm_generic_timer.c new file mode 100644 index 00000000..e36b1287 --- /dev/null +++ b/drivers/sysclock/arm_generic_timer/arm_generic_timer.c @@ -0,0 +1,186 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ssANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char *sysclock_name = "arm generic timer"; +static struct uk_intctlr_irq irq; +static struct sysclock_ops ops; + +/* Bits definition of cntv_ctl register */ +#define ARM_GENERIC_TIMER_ENABLE 0x01 +#define ARM_GENERIC_TIMER_MASK_IRQ 0x02 +#define ARM_GENERIC_TIMER_IRQ_STATUS 0x04 + +static const char *const sysclock_list[] = {"arm,armv8-timer", + "arm,armv7-timer", NULL}; + +static void sysclock_enable(void) +{ + set_el0(cntv_ctl, get_el0(cntv_ctl) | GT_TIMER_ENABLE); + + /* Ensure the write of sys register is visible */ + isb(); +} + +static inline void sysclock_disable(void) +{ + set_el0(cntv_ctl, get_el0(cntv_ctl) & ~GT_TIMER_ENABLE); + + isb(); +} + +static inline void sysclock_clear_status(void) +{ + set_el0(cntv_ctl, get_el0(cntv_ctl) & ~GT_TIMER_IRQ_STATUS); + + isb(); +} + +static inline void sysclock_update_compare_value(uint64_t new_val) +{ + set_el0(cntv_cval, new_val); + + isb(); +} + +static inline void sysclock_update_timer_value(uint64_t new_val) +{ + set_el0(cntv_tval, new_val); + + isb(); +} + +void sysclock_mask_irq(void) +{ + set_el0(cntv_ctl, get_el0(cntv_ctl) | GT_TIMER_MASK_IRQ); + + isb(); +} + +void sysclock_unmask_irq(void) +{ + set_el0(cntv_ctl, get_el0(cntv_ctl) & ~GT_TIMER_MASK_IRQ); + + isb(); +} + +#ifdef CONFIG_ARM64_ERRATUM_858921 +/* + * The errata #858921 describes that Cortex-A73 (r0p0 - r0p2) counter + * read can return a wrong value when the counter crosses a 32bit boundary. + * But newer Cortex-A73 are not affected. + * + * The workaround involves performing the read twice, compare bit[32] of + * the two read values. If bit[32] is different, keep the first value, + * otherwise keep the second value. + */ +uint64_t sysclock_get_counts(void) +{ + uint64_t val_1st, val_2nd; + + val_1st = get_el0(cntvct); + val_2nd = get_el0(cntvct); + return (((val_1st ^ val_2nd) >> 32) & 1) ? val_1st : val_2nd; +} +#else +uint64_t sysclock_get_counts(void) +{ + return get_el0(cntvct); +} +#endif + +static void sysclock_set_next(uint64_t set_counts, uint8_t is_start __unused) +{ + sysclock_clear_status(); + + sysclock_update_timer_value(set_counts); +} + +uint32_t sysclock_get_frequency(int fdt_timer) +{ + int len; + const uint64_t *fdt_freq; + + /* + * On a few platforms the frequency is not configured correctly + * by the firmware. A property in the DT (clock-frequency) has + * been introduced to workaround those firmware. + */ + fdt_freq = fdt_getprop((void *)ukplat_bootinfo_get()->dtb, fdt_timer, + "clock-frequency", &len); + if (!fdt_freq || (len <= 0)) { + uk_pr_info( + "No clock-frequency found, reading from register.\n"); + + /* No workaround, get from register directly */ + return get_el0(cntfrq); + } + + return fdt32_to_cpu(fdt_freq[0]); +} + +int uk_sysclock_probe(void) +{ + int ret, offs; + uint32_t freq; + + /* Currently, we only support 1 timer per system */ + offs = fdt_node_offset_by_compatible_list( + (void *)ukplat_bootinfo_get()->dtb, -1, sysclock_list); + if (unlikely(offs < 0)) { + uk_pr_crit("Could not find arch timer (%d)\n", offs); + return 1; + } + + /* Get counter frequency from DTB or register (in Hz) */ + freq = sysclock_get_frequency(offs); + + ret = uk_intctlr_irq_fdt_xlat((void *)ukplat_bootinfo_get()->dtb, offs, + 2, &irq); + if (unlikely(ret < 0)) { + uk_pr_crit("Could not get IRQ from dtb (%d)\n", ret); + return 1; + } + uk_intctlr_irq_configure(&irq); + irq.id = irq.id; + irq.trigger = UK_INTCTLR_IRQ_TRIGGER_LEVEL; + + /* + * Mask IRQ before scheduler start working. Otherwise we will get + * unexpected timer interrupts when system is booting. + */ + sysclock_mask_irq(); + + ops.set_next = sysclock_set_next; + ops.get_count = sysclock_get_counts; + ops.mask_base_irq = sysclock_mask_irq; + ops.unmask_base_irq = sysclock_unmask_irq; + + tn_systick_register(sysclock_name, freq, &irq, &ops); + sysclock_enable(); + + return 0; +} diff --git a/drivers/sysclock/arm_generic_timer/include/uk/sysclock/arm_generic_timer.h b/drivers/sysclock/arm_generic_timer/include/uk/sysclock/arm_generic_timer.h new file mode 100644 index 00000000..b0da20e2 --- /dev/null +++ b/drivers/sysclock/arm_generic_timer/include/uk/sysclock/arm_generic_timer.h @@ -0,0 +1,21 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ssANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ARM_GENERIC_TIMER_H__ +#define __ARM_GENERIC_TIMER_H__ + +int uk_sysclock_probe(void); + +#endif /* __ARM_GENERIC_TIMER_H__ */ diff --git a/drivers/sysclock/exportsyms.uk b/drivers/sysclock/exportsyms.uk new file mode 100644 index 00000000..d7dd2008 --- /dev/null +++ b/drivers/sysclock/exportsyms.uk @@ -0,0 +1 @@ +uk_sysclock_probe diff --git a/include/uk/plat/time.h b/include/uk/plat/time.h index 6e558d7a..03a1eff9 100644 --- a/include/uk/plat/time.h +++ b/include/uk/plat/time.h @@ -36,6 +36,9 @@ #include #include +#ifdef CONFIG_HAVE_SYSTICK +#include +#endif /* CONFIG_HAVE_SYSTICK */ #ifdef __cplusplus extern "C" { @@ -43,10 +46,28 @@ extern "C" { void ukplat_time_init(void); void ukplat_time_fini(void); -uint32_t ukplat_time_get_irq(void); -__nsec ukplat_time_get_ticks(void); +#ifndef CONFIG_HAVE_SYSTICK __nsec ukplat_monotonic_clock(void); +uint32_t ukplat_time_get_irq(void); +__nsec ukplat_time_get_ticks(void); +#else +static inline __nsec ukplat_monotonic_clock(void) +{ + return tn_systick_get_monotonic(); +} + +static inline uint32_t ukplat_time_get_irq(void) +{ + return tn_systick_get_irq(); +} + +static inline __nsec ukplat_time_get_ticks(void) +{ + return (__nsec)tn_systick_get_tick(); +} +#endif /* CONFIG_HAVE_SYSTICK */ + __nsec ukplat_wall_clock(void); /* Time tick length */ diff --git a/lib/Makefile.uk b/lib/Makefile.uk index 161ea305..d392af3a 100644 --- a/lib/Makefile.uk +++ b/lib/Makefile.uk @@ -69,3 +69,4 @@ $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/vfscore)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukrust)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukreloc)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukofw)) +$(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tnsystick)) diff --git a/lib/tnsystick/Config.uk b/lib/tnsystick/Config.uk new file mode 100644 index 00000000..aefc38fe --- /dev/null +++ b/lib/tnsystick/Config.uk @@ -0,0 +1,22 @@ +config HAVE_SYSTICK + bool + +menuconfig LIBTNSYSTICK + bool "systick: Kernel systick configuration" + default y + depends on HAVE_SYSTICK + +if LIBTNSYSTICK + +config LIBTNSYSTICK_TICKLESS + bool "Trigger kernel systick interrupt in tickless mode" + default n + +config LIBTNSYSTICK_FREQ + int "Frequency of triggering kernel systick" + default 1000 + +config LIBTNSYSTICK_SUPPORT_OVERFLOW + bool "Support systick overflow counts" + default n +endif diff --git a/lib/tnsystick/Makefile.uk b/lib/tnsystick/Makefile.uk new file mode 100644 index 00000000..5b9ef3e6 --- /dev/null +++ b/lib/tnsystick/Makefile.uk @@ -0,0 +1,7 @@ +$(eval $(call addlib_s,libtnsystick,$(CONFIG_LIBTNSYSTICK))) + +ASINCLUDES-$(CONFIG_LIBTNSYSTICK) += -I$(LIBTNSYSTICK_BASE)/include +CINCLUDES-$(CONFIG_LIBTNSYSTICK) += -I$(LIBTNSYSTICK_BASE)/include +CXXINCLUDES-$(CONFIG_LIBTNSYSTICK) += -I$(LIBTNSYSTICK_BASE)/include + +LIBTNSYSTICK_SRCS-$(CONFIG_LIBTNSYSTICK) += $(LIBTNSYSTICK_BASE)/tnsystick.c diff --git a/lib/tnsystick/exportsyms.uk b/lib/tnsystick/exportsyms.uk new file mode 100644 index 00000000..c972c09d --- /dev/null +++ b/lib/tnsystick/exportsyms.uk @@ -0,0 +1,8 @@ +tn_systick_get_tick +tn_systick_init +tn_systick_start +tn_systick_add_timeout +tn_systick_get_irq +tn_systick_register +tn_systick_until +tn_systick_get_monotonic diff --git a/lib/tnsystick/include/tn/systick.h b/lib/tnsystick/include/tn/systick.h new file mode 100644 index 00000000..3f6a9ba9 --- /dev/null +++ b/lib/tnsystick/include/tn/systick.h @@ -0,0 +1,99 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TN_LIBTNSYSTICK_H__ +#define __TN_LIBTNSYSTICK_H__ + +#include +#include + +typedef uint64_t systick_t; + +/* sysclock oprations */ +struct sysclock_ops { + /* counts for the next time-base irq occurring + * set_auto_reload = 1 means that the sysclock support auto-reload + * mode.When time-base irq occurs periodically,we don't have to reset + * the next interrupt occurrence each time in a subsequent time-base + * interrupt. + * set_auto_reload = 0 means there is no need to work in auto-reloade + * mode for this operation, or the sysclock is working in tickless mode + * If sysclock does not support auto-reload mode, set_auto_reload will + * always be set to 0. + */ + void (*set_next)(uint64_t counts, uint8_t set_auto_reload); + /* Get cumulative hardware sys count */ + uint64_t (*get_count)(void); + /* mask time base interrupt */ + void (*mask_base_irq)(void); + /* Release the time base interrupt mask */ + void (*unmask_base_irq)(void); +}; + +/* sysclock oprations */ +struct sysclock_desc { + /* Name of the system timer */ + const char *name; + uint32_t freq; + struct uk_intctlr_irq *irq; + /* sysclock oprations */ + struct sysclock_ops *ops; +}; + +/** + * Initialise system tick + * + * This function initialises the system clock driver and systick. + * + */ +int tn_systick_init(void); + +/** + * Get current systick value + * + * @return current systick value + */ +systick_t tn_systick_get_tick(void); + +/** + * Get systick irq number + * + * Irq number was initialised during tn_systick_init. + * + * @return systick irq number + */ +uint32_t tn_systick_get_irq(void); + +/** + * Start systick irq + * + * This function does only one thing: unmasks the interrupt of systick. + * + */ +void tn_systick_start(void); + +/** + * Add a timeout event based on the system tick + * + * todo + * + */ +void tn_systick_add_timeout(void); + +/* adapt original delayed programme */ +void tn_systick_until(__nsec until); +__nsec tn_systick_get_monotonic(void); + +#endif /* __TN_LIBTNSYSTICK_H__ */ diff --git a/lib/tnsystick/include/tn/systick_impl.h b/lib/tnsystick/include/tn/systick_impl.h new file mode 100644 index 00000000..2ffd0b0a --- /dev/null +++ b/lib/tnsystick/include/tn/systick_impl.h @@ -0,0 +1,72 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TN_LIBTNSYSTICK_IMPL_H__ +#define __TN_LIBTNSYSTICK_IMPL_H__ + +#include +#include +#include + +#define __MAX_CONVERT_SECS 3600UL +#define __MAX_CONVERT_NS (__MAX_CONVERT_SECS * ukarch_time_sec_to_nsec(1)) + +/* + * Calculate multiplier/shift factors for scaled math. + */ +static inline void calculate_mult_shift(uint32_t *mult, uint8_t *shift, + uint64_t from, uint64_t to) +{ + uint64_t tmp; + uint32_t sft, sftacc = 32; + + /* + * Calculate the shift factor which is limiting the conversion + * range: + */ + tmp = ((uint64_t)__MAX_CONVERT_SECS * from) >> 32; + while (tmp) { + tmp >>= 1; + sftacc--; + } + + /* + * Calculate shift factor (S) and scaling multiplier (M). + * + * (S) needs to be the largest shift factor (<= max_shift) where + * the result of the M calculation below fits into uint32_t + * without truncation. + * + * multiplier = (target << shift) / source + */ + for (sft = 32; sft > 0; sft--) { + tmp = (uint64_t)to << sft; + + /* Ensuring we round to nearest when calculating the + * multiplier + */ + tmp += from / 2; + tmp /= from; + if ((tmp >> sftacc) == 0) + break; + } + *mult = tmp; + *shift = sft; +} + +void tn_systick_register(const char *name, uint32_t freq, + struct uk_intctlr_irq *irq, struct sysclock_ops *ops); + +#endif /* __TN_LIBTNSYSTICK_IMPL_H__ */ diff --git a/lib/tnsystick/tnsystick.c b/lib/tnsystick/tnsystick.c new file mode 100644 index 00000000..f20188f6 --- /dev/null +++ b/lib/tnsystick/tnsystick.c @@ -0,0 +1,303 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ssANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* current tick value */ +static systick_t cur_systick; + +#ifdef CONFIG_LIBTNSYSTICK_SUPPORT_OVERFLOW +static uint32_t systick_overflow; +#endif /* CONFIG_LIBTNSYSTICK_SUPPORT_OVERFLOW */ + +struct sysclock_desc sysclock; +static uint32_t systick_freq; + +/* Shift factor for converting ticks to ns */ +static uint8_t shift_tick_to_ns; +/* Shift factor for converting ns to ticks */ +static uint8_t shift_ns_to_tick; +/* Shift factor for converting counts to ticks */ +static uint8_t shift_count_to_tick; +/* Shift factor for converting ticks to counts */ +static uint8_t shift_tick_to_count; +/* Multiplier for converting ticks to nsecs */ +static uint32_t ns_per_tick; +/* Multiplier for converting nsecs to ticks */ +static uint32_t tick_per_ns; +/* Multiplier for converting ticks to counts */ +static uint32_t count_per_tick; +/* Multiplier for converting counts to ticks */ +static uint32_t tick_per_count; +/* Total (absolute) number of counts per tick */ +static uint64_t tot_counts_per_tick; +/* Total (absolute) number of nanoseconds per tick */ +static uint64_t tot_ns_per_tick; + +static uint64_t max_convert_ticks; + +static inline uint64_t counts_to_ticks(uint64_t counts) +{ + return (count_per_tick * counts) >> shift_count_to_tick; +} + +static inline uint64_t ticks_to_counts(uint64_t ticks) +{ + return (tick_per_count * ticks) >> shift_tick_to_count; +} + +static inline void systick_update(void) +{ +#ifdef CONFIG_LIBTNSYSTICK_SUPPORT_OVERFLOW + systick_t last_tick = cur_systick; +#endif /* CONFIG_LIBTNSYSTICK_SUPPORT_OVERFLOW */ + + cur_systick = counts_to_ticks(sysclock.ops->get_count()); + +#ifdef CONFIG_LIBTNSYSTICK_SUPPORT_OVERFLOW + if (cur_systick < last_tick) { + systick_overflow++; + uk_pr_warn("systick overflowed %d times!\n", systick_overflow); + } +#endif /* CONFIG_LIBTNSYSTICK_SUPPORT_OVERFLOW */ +} + +extern unsigned long sched_have_pending_events; + +static int sys_timer_irq_handler(void *arg __unused) +{ + /* 1、update cur_systick */ + systick_update(); + uk_pr_debug("cur_systick: 0x%x count freq: 0x%x\n", + (unsigned int)cur_systick, sysclock.freq); + +#ifndef CONFIG_LIBTNSYSTICK_TICKLESS + sysclock.ops->set_next(tot_counts_per_tick, 0); +#endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ + /* 2、todo :expired timer functions */ + /* 3、todo :schedprio to check timeout threads */ + + /* 4、set next time-base irq */ +#ifdef CONFIG_LIBTNSYSTICK_TICKLESS + uint64_t timeout; + + timeout = get_current_smallest_timeout(); + sysclock.ops->set_next(timeout, 0); +#endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ + return 0; +} + +systick_t tn_systick_get_tick(void) +{ +#ifdef CONFIG_LIBTNSYSTICK_TICKLESS + return cur_systick + sysclock.ops->get_count() / freq_tick_to_count; +#else + return cur_systick; +#endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ +} + +static void systick_convert_init(void) +{ + /* Absolute number of ns per tick */ + tot_ns_per_tick = ukarch_time_sec_to_nsec(1) / CONFIG_LIBTNSYSTICK_FREQ; + + /* Absolute number of counts per tick */ + tot_counts_per_tick = sysclock.freq / CONFIG_LIBTNSYSTICK_FREQ; + + /* + * Calculate the shift factor and scaling multiplier for + * converting ticks to ns. + */ + calculate_mult_shift(&ns_per_tick, &shift_tick_to_ns, + CONFIG_LIBTNSYSTICK_FREQ, + ukarch_time_sec_to_nsec(1)); + + /* We disallow zero ns_per_tick */ + UK_BUGON(!ns_per_tick); + + /* + * Calculate the shift factor and scaling multiplier for + * converting ns to ticks. + */ + calculate_mult_shift(&tick_per_ns, &shift_ns_to_tick, + ukarch_time_sec_to_nsec(1), + CONFIG_LIBTNSYSTICK_FREQ); + + /* We disallow zero tick_per_ns */ + UK_BUGON(!tick_per_ns); + + /* + * Calculate the shift factor and scaling multiplier for + * converting ticks to counts. + */ + calculate_mult_shift(&count_per_tick, &shift_count_to_tick, + (uint64_t)sysclock.freq, CONFIG_LIBTNSYSTICK_FREQ); + + /* We disallow zero count_per_tick */ + UK_BUGON(!count_per_tick); + + /* + * Calculate the shift factor and scaling multiplier for + * converting counts to ticks. + */ + calculate_mult_shift(&tick_per_count, &shift_tick_to_count, + CONFIG_LIBTNSYSTICK_FREQ, (uint64_t)sysclock.freq); + + /* We disallow zero tick_per_count */ + UK_BUGON(!tick_per_count); + + max_convert_ticks = __MAX_CONVERT_SECS * CONFIG_LIBTNSYSTICK_FREQ; +} + +int tn_systick_init(void) +{ + int ret; + + ret = uk_sysclock_probe(); + if (ret != 0) + return ret; + + systick_freq = CONFIG_LIBTNSYSTICK_FREQ; + if ((systick_freq == 0) || (systick_freq > sysclock.freq)) { + uk_pr_info( + "invalid system tick frequency, set it default : %d\n", + sysclock.freq); + systick_freq = sysclock.freq; + } + tot_counts_per_tick = sysclock.freq / CONFIG_LIBTNSYSTICK_FREQ; + + /* initialize cur_systick convert value */ + systick_convert_init(); + /* register time base irq */ + uk_pr_debug("sysclock.irq->id : %d\n", sysclock.irq->id); + uk_intctlr_irq_register(sysclock.irq->id, sys_timer_irq_handler, NULL); + + sysclock.ops->mask_base_irq(); + sysclock.ops->set_next(tot_counts_per_tick, 1); + + return 0; +} + +void tn_systick_start(void) +{ + sysclock.ops->unmask_base_irq(); +} + +uint32_t tn_systick_get_irq(void) +{ + return sysclock.irq->id; +} + +void tn_systick_add_timeout(void) +{ + /* todo */ +} + +void tn_systick_register(const char *name, uint32_t freq, + struct uk_intctlr_irq *irq, struct sysclock_ops *ops) +{ + sysclock.name = name; + sysclock.freq = freq; + sysclock.irq = irq; + sysclock.ops = ops; +} + +static inline uint64_t ticks_to_ns(uint64_t ticks) +{ + if (ticks > max_convert_ticks) { + /* We have reached the maximum number of ticks to convert using + * the shift factor + */ + return (ticks * tot_ns_per_tick); + } else { + return (ns_per_tick * ticks) >> shift_tick_to_ns; + } +} + +static inline uint64_t ns_to_ticks(uint64_t ns) +{ + if (ns > __MAX_CONVERT_NS) { + /* We have reached the maximum number of ns to convert using the + * shift factor + */ + return (ns / tot_ns_per_tick); + } else { + return (tick_per_ns * ns) >> shift_ns_to_tick; + } +} + +/* + * Returns early if any interrupts are serviced, or if the requested delay is + * too short. Must be called with interrupts disabled, will enable interrupts + * "atomically" during idle loop. + * + * This function must be called only from the scheduler. It will screw + * your system if you do otherwise. And, there is no reason you + * actually want to use it anywhere else. THIS IS NOT A YIELD or any + * kind of mutex_lock. It will simply halt the cpu, not allowing any + * other thread to execute. + */ +static void cpu_block_until(uint64_t until_ns) +{ + uint64_t now_ns; + systick_t until_ticks; + + UK_ASSERT(ukplat_lcpu_irqs_disabled()); + + /* Record current ns */ + now_ns = ticks_to_ns((uint64_t)tn_systick_get_tick()); + + if (now_ns < until_ns) { + /* Calculate until_ticks for timer */ + until_ticks = + tn_systick_get_tick() + ns_to_ticks(until_ns - now_ns); + sysclock.ops->set_next(until_ticks, 0); + sysclock.ops->unmask_base_irq(); + __asm__ __volatile__("wfi"); + + /* Give the IRQ handler a chance to handle whatever woke + * us up + */ + ukplat_lcpu_enable_irq(); + ukplat_lcpu_disable_irq(); + } +} + +#if (CONFIG_ARCH_ARM_32 || CONFIG_ARCH_ARM_64) +unsigned long sched_have_pending_events; +#else +extern unsigned long sched_have_pending_events; +#endif /* CONFIG_ARCH_ARM_32 || CONFIG_ARCH_ARM_64 */ + +/* return ns which based on ticks */ +__nsec tn_systick_get_monotonic(void) +{ + return ticks_to_ns((uint64_t)tn_systick_get_tick()); +} + +void tn_systick_until(__nsec until) +{ + while (tn_systick_get_monotonic() < until) { + cpu_block_until(until); + if (__uk_test_and_clear_bit(0, &sched_have_pending_events)) + break; + } +} diff --git a/lib/ukboot/boot.c b/lib/ukboot/boot.c index 2e0208ea..76b188f5 100644 --- a/lib/ukboot/boot.c +++ b/lib/ukboot/boot.c @@ -349,7 +349,13 @@ void ukplat_entry(int argc, char *argv[]) /* On most platforms the timer depend on an initialized IRQ subsystem */ uk_pr_info("Initialize platform time...\n"); +#if CONFIG_HAVE_SYSTICK + rc = tn_systick_init(); + if (unlikely(rc)) + UK_CRASH("Could not initialize the systick\n"); +#else ukplat_time_init(); +#endif /* CONFIG_HAVE_SYSTICK */ #if !CONFIG_LIBUKBOOT_NOSCHED uk_pr_info("Initialize scheduling...\n"); @@ -403,6 +409,10 @@ void ukplat_entry(int argc, char *argv[]) print_banner(stdout); fflush(stdout); +#if CONFIG_HAVE_SYSTICK + tn_systick_start(); +#endif /* CONFIG_HAVE_SYSTICK */ + #if !CONFIG_LIBUKBOOT_MAINTHREAD do_main(ictx.cmdline.argc, ictx.cmdline.argv); tctx.target = UKPLAT_HALT; diff --git a/lib/ukintctlr/ukintctlr.c b/lib/ukintctlr/ukintctlr.c index 5b470587..4e2a826b 100644 --- a/lib/ukintctlr/ukintctlr.c +++ b/lib/ukintctlr/ukintctlr.c @@ -186,6 +186,7 @@ void uk_intctlr_irq_handle(struct __regs *regs, unsigned int irq) if (irq_handlers[irq][i].func == NULL) break; h = &irq_handlers[irq][i]; +#ifndef CONFIG_HAVE_SYSTICK if (irq != ukplat_time_get_irq()) /* ukplat_time_get_irq() gives the IRQ reserved for a timer, * responsible to wake up cpu from halt, so it can check if @@ -198,7 +199,7 @@ void uk_intctlr_irq_handle(struct __regs *regs, unsigned int irq) * that work. */ __uk_test_and_set_bit(0, &sched_have_pending_events); - +#endif /* CONFIG_HAVE_SYSTICK */ if (h->func(h->arg) == 1) goto exit; } diff --git a/plat/common/include/uk/plat/common/_time.h b/plat/common/include/uk/plat/common/_time.h index 31a2c9a9..2e92fef0 100644 --- a/plat/common/include/uk/plat/common/_time.h +++ b/plat/common/include/uk/plat/common/_time.h @@ -35,6 +35,13 @@ #include +#ifndef CONFIG_HAVE_SYSTICK void time_block_until(__snsec until); +#else +static inline void time_block_until(__snsec until) +{ + tn_systick_until((__nsec)until); +} +#endif /* CONFIG_HAVE_SYSTICK */ #endif /* __PLAT_CMN_TIME_H__ */ diff --git a/plat/kvm/Makefile.uk b/plat/kvm/Makefile.uk index 64b1bfa9..e9a2eee9 100644 --- a/plat/kvm/Makefile.uk +++ b/plat/kvm/Makefile.uk @@ -89,8 +89,10 @@ LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/cpu_native.c LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/cache64.S|common LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/smccc.c|common LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/smccc_invoke.S|common +ifneq ($(CONFIG_HAVE_SYSTICK),y) LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/time.c|common LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/generic_timer.c|common +endif LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/lcpu.c|arm64_common LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/traps_arm64.c|isr LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/tls.c|common -- Gitee From 220e679e73d8d58884cef6ba0547a53d2ae00061 Mon Sep 17 00:00:00 2001 From: Yifan Zhang Date: Wed, 27 Mar 2024 18:30:37 +0800 Subject: [PATCH 02/35] lib/ukintctrl,lib/tnsystick: move sched_have_pending_events to lib/tnsystick Signed-off-by: Yifan Zhang --- lib/tnsystick/tnsystick.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/tnsystick/tnsystick.c b/lib/tnsystick/tnsystick.c index f20188f6..c34d48d0 100644 --- a/lib/tnsystick/tnsystick.c +++ b/lib/tnsystick/tnsystick.c @@ -53,6 +53,10 @@ static uint64_t tot_counts_per_tick; static uint64_t tot_ns_per_tick; static uint64_t max_convert_ticks; +#ifdef CONFIG_LIBTNSYSTICK_TICKLESS +/* Last count recoreded when systick is updated*/ +static uint64_t last_count; +#endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ static inline uint64_t counts_to_ticks(uint64_t counts) { @@ -70,6 +74,10 @@ static inline void systick_update(void) systick_t last_tick = cur_systick; #endif /* CONFIG_LIBTNSYSTICK_SUPPORT_OVERFLOW */ +#ifdef CONFIG_LIBTNSYSTICK_TICKLESS + last_count = sysclock.ops->get_count(); +#endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ + cur_systick = counts_to_ticks(sysclock.ops->get_count()); #ifdef CONFIG_LIBTNSYSTICK_SUPPORT_OVERFLOW @@ -100,15 +108,24 @@ static int sys_timer_irq_handler(void *arg __unused) uint64_t timeout; timeout = get_current_smallest_timeout(); - sysclock.ops->set_next(timeout, 0); + sysclock.ops->set_next(ticks_to_counts(timeout), 0); #endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ - return 0; + __uk_test_and_clear_bit(0, &sched_have_pending_events); + return 1; } systick_t tn_systick_get_tick(void) { #ifdef CONFIG_LIBTNSYSTICK_TICKLESS - return cur_systick + sysclock.ops->get_count() / freq_tick_to_count; + + if (sysclock.ops) + return cur_systick + + counts_to_ticks(sysclock.ops->get_count() + - last_count); + else + /* if sysclock is not initialised, return 0 */ + return 0; + #else return cur_systick; #endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ -- Gitee From d0d13f0e6439fdb5850745d9266ac3f52039a7e9 Mon Sep 17 00:00:00 2001 From: Wu Shifang Date: Thu, 28 Mar 2024 17:45:14 +0800 Subject: [PATCH 03/35] lib/tnsystick:add sysclock/systick test cases Signed-off-by: Wu Shifang --- drivers/sysclock/Config.uk | 5 + drivers/sysclock/Makefile.uk | 5 + .../arm_generic_timer/arm_generic_timer.c | 6 +- drivers/sysclock/tests/test_sysclock.c | 79 +++++++++ drivers/sysclock/tests/test_sysclock.h | 29 ++++ lib/tnsystick/Config.uk | 6 + lib/tnsystick/Makefile.uk | 4 + lib/tnsystick/include/tn/systick_impl.h | 1 + lib/tnsystick/tests/test_systick.c | 154 ++++++++++++++++++ lib/tnsystick/tests/test_systick.h | 23 +++ lib/tnsystick/tnsystick.c | 6 +- lib/ukboot/boot.c | 12 +- 12 files changed, 321 insertions(+), 9 deletions(-) create mode 100644 drivers/sysclock/tests/test_sysclock.c create mode 100644 drivers/sysclock/tests/test_sysclock.h create mode 100644 lib/tnsystick/tests/test_systick.c create mode 100644 lib/tnsystick/tests/test_systick.h diff --git a/drivers/sysclock/Config.uk b/drivers/sysclock/Config.uk index 9ac0ac0f..f971ea8e 100644 --- a/drivers/sysclock/Config.uk +++ b/drivers/sysclock/Config.uk @@ -7,3 +7,8 @@ config ARM_GENERIC_TIMER bool "arm_generic_timer(used in arm cortex-a/cortex-r)" default n depends on SYSCLOCK + +config SYSCLOCK_TEST + bool "Enable unit tests" + depends on (SYSCLOCK && LIBUKTEST) + default n diff --git a/drivers/sysclock/Makefile.uk b/drivers/sysclock/Makefile.uk index 4ccaaf4e..65043219 100644 --- a/drivers/sysclock/Makefile.uk +++ b/drivers/sysclock/Makefile.uk @@ -7,3 +7,8 @@ UK_DRIV_SYSCLOCK_BASE := $(UK_DRIV_BASE)/sysclock $(eval $(call import_lib,$(UK_DRIV_SYSCLOCK_BASE)/arm_generic_timer)) +$(eval $(call addlib_s,sysclock,$(CONFIG_SYSCLOCK))) + +ifneq ($(filter y,$(CONFIG_SYSCLOCK_TEST) $(CONFIG_LIBUKTEST_ALL)),) +SYSCLOCK_SRCS-y += $(UK_DRIV_SYSCLOCK_BASE)/tests/test_sysclock.c +endif diff --git a/drivers/sysclock/arm_generic_timer/arm_generic_timer.c b/drivers/sysclock/arm_generic_timer/arm_generic_timer.c index e36b1287..9964b375 100644 --- a/drivers/sysclock/arm_generic_timer/arm_generic_timer.c +++ b/drivers/sysclock/arm_generic_timer/arm_generic_timer.c @@ -26,7 +26,8 @@ #include static const char *sysclock_name = "arm generic timer"; -static struct uk_intctlr_irq irq; +struct uk_intctlr_irq irq; +uint32_t freq; static struct sysclock_ops ops; /* Bits definition of cntv_ctl register */ @@ -112,7 +113,7 @@ uint64_t sysclock_get_counts(void) } #endif -static void sysclock_set_next(uint64_t set_counts, uint8_t is_start __unused) +void sysclock_set_next(uint64_t set_counts, uint8_t is_start __unused) { sysclock_clear_status(); @@ -145,7 +146,6 @@ uint32_t sysclock_get_frequency(int fdt_timer) int uk_sysclock_probe(void) { int ret, offs; - uint32_t freq; /* Currently, we only support 1 timer per system */ offs = fdt_node_offset_by_compatible_list( diff --git a/drivers/sysclock/tests/test_sysclock.c b/drivers/sysclock/tests/test_sysclock.c new file mode 100644 index 00000000..2ac99e06 --- /dev/null +++ b/drivers/sysclock/tests/test_sysclock.c @@ -0,0 +1,79 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "test_sysclock.h" + +/* 测试系统定时器定时功能场景 + * current_count:测试时基中断产生的时间戳 + * test_time_base_irq_handled:测试时基中断函数是否发生 + */ +static uint64_t current_count; +static uint8_t test_time_base_irq_handled; + +/* 测试时基中断函数 */ +static int test_sysclock_irq_handler(void *arg __unused) +{ + current_count = sysclock_get_counts(); + sysclock_mask_irq(); + test_time_base_irq_handled = 1; + return 1; +} + +/* TEST_TIMING_SECS:测试定时器超时时长,单位秒(s) + * TEST_TIMING_BIAS_NANOSECS:允许时间戳误差,单位纳秒(ns) + * TEST_TIMING_BIAS_COUNT:允许时间戳误差,单位count + */ +#define TEST_TIMING_SECS 2 +/* 误差设定为0.2s */ +#define TEST_TIMING_BIAS_NANOSECS 200000000ULL +#define TEST_TIMING_BIAS_COUNT \ + ((TEST_TIMING_BIAS_NANOSECS / (1000000000ULL / freq))) + +UK_TESTCASE(uk_driver_sysclock, test_driver_sysclock_timing) +{ + uint64_t last_count, delta_count, next_count; + + /* 1.初始化测试场景 */ + /* 1.1设置定时器超时时长 */ + next_count = freq * TEST_TIMING_SECS; + + /* 1.2注册测试时基中断函数 */ + uk_intctlr_irq_register(irq.id, test_sysclock_irq_handler, NULL); + + /* 2.测试系统定时器定时功能场景 */ + /* 2.1保存当前时间戳与开始系统定时器定时 */ + last_count = sysclock_get_counts(); + sysclock_set_next((uint64_t)next_count, 0); + sysclock_unmask_irq(); + + /* 2.2处理测试时基中断 */ + while (test_time_base_irq_handled != 1) + __asm__ __volatile__("wfi"); + + /* 3.计算超时时间,校验测试结果 */ + delta_count = current_count - last_count; + /* 实际超时时间预期在预设时间允许误差内(+-BIAS) */ + UK_TEST_EXPECT_SNUM_GT(delta_count, + next_count - (uint64_t)TEST_TIMING_BIAS_COUNT); + UK_TEST_EXPECT_SNUM_LT(delta_count, + next_count + (uint64_t)TEST_TIMING_BIAS_COUNT); + + /* 4.恢复环境 */ + uk_intctlr_irq_unregister(irq.id, test_sysclock_irq_handler); +} + +uk_testsuite_register(uk_driver_sysclock, NULL); diff --git a/drivers/sysclock/tests/test_sysclock.h b/drivers/sysclock/tests/test_sysclock.h new file mode 100644 index 00000000..f97cadd0 --- /dev/null +++ b/drivers/sysclock/tests/test_sysclock.h @@ -0,0 +1,29 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TEST_SYSCLOCK_H__ +#define __TEST_SYSCLOCK_H__ + +#include + +extern struct uk_intctlr_irq irq; +extern uint32_t freq; + +uint64_t sysclock_get_counts(void); +void sysclock_unmask_irq(void); +void sysclock_mask_irq(void); +void sysclock_set_next(uint64_t set_counts, uint8_t is_start __unused); + +#endif /* __TEST_SYSCLOCK_H__ */ diff --git a/lib/tnsystick/Config.uk b/lib/tnsystick/Config.uk index aefc38fe..33aee276 100644 --- a/lib/tnsystick/Config.uk +++ b/lib/tnsystick/Config.uk @@ -19,4 +19,10 @@ config LIBTNSYSTICK_FREQ config LIBTNSYSTICK_SUPPORT_OVERFLOW bool "Support systick overflow counts" default n + +config LIBTNSYSTICK_TEST + bool "Enable unit tests" + default n + select LIBUKTEST + endif diff --git a/lib/tnsystick/Makefile.uk b/lib/tnsystick/Makefile.uk index 5b9ef3e6..d4ec664c 100644 --- a/lib/tnsystick/Makefile.uk +++ b/lib/tnsystick/Makefile.uk @@ -5,3 +5,7 @@ CINCLUDES-$(CONFIG_LIBTNSYSTICK) += -I$(LIBTNSYSTICK_BASE)/include CXXINCLUDES-$(CONFIG_LIBTNSYSTICK) += -I$(LIBTNSYSTICK_BASE)/include LIBTNSYSTICK_SRCS-$(CONFIG_LIBTNSYSTICK) += $(LIBTNSYSTICK_BASE)/tnsystick.c + +ifneq ($(filter y,$(CONFIG_LIBTNSYSTICK_TEST) $(CONFIG_LIBUKTEST_ALL)),) +LIBTNSYSTICK_SRCS-y += $(LIBTNSYSTICK_BASE)/tests/test_systick.c +endif diff --git a/lib/tnsystick/include/tn/systick_impl.h b/lib/tnsystick/include/tn/systick_impl.h index 2ffd0b0a..64988d5f 100644 --- a/lib/tnsystick/include/tn/systick_impl.h +++ b/lib/tnsystick/include/tn/systick_impl.h @@ -18,6 +18,7 @@ #include #include +#include #include #define __MAX_CONVERT_SECS 3600UL diff --git a/lib/tnsystick/tests/test_systick.c b/lib/tnsystick/tests/test_systick.c new file mode 100644 index 00000000..3354758a --- /dev/null +++ b/lib/tnsystick/tests/test_systick.c @@ -0,0 +1,154 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ssANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "test_systick.h" + +/* test calculate_mult_shift */ +UK_TESTCASE(tnsystick, test_calculate_mult_shift) +{ + uint64_t test_origin_data, test_target_data; + uint32_t target_per_origin; + uint8_t shift_origin_to_target; + + test_origin_data = 3000000; + test_target_data = 10000000; + + calculate_mult_shift(&target_per_origin, &shift_origin_to_target, + test_origin_data, test_target_data); + + uint64_t test_data = + (test_origin_data * target_per_origin) >> shift_origin_to_target; + + UK_TEST_EXPECT_SNUM_EQ(test_data + 1, test_target_data); +} + +/* test APIs */ +#define TEST_SET_NEXT 1 +#define TEST_GET_COUNT 2 +#define TEST_MASK_BASE_IRQ 3 +#define TEST_UNMASK_BASE_IRQ 4 +#define TEST_IRQ_ID 11 + +static int test_ret; +static uint64_t test_count; + +static void test_systick_set_next(uint64_t counts __unused, + uint8_t set_auto_reload __unused) +{ + test_ret = TEST_SET_NEXT; +} + +static uint64_t test_systick_get_count(void) +{ + test_ret = TEST_GET_COUNT; + return test_count; +} + +static void test_systick_mask_base_irq(void) +{ + test_ret = TEST_MASK_BASE_IRQ; +} +static void test_systick_unmask_base_irq(void) +{ + test_ret = TEST_UNMASK_BASE_IRQ; +} + +UK_TESTCASE(tnsystick, test_systick_ops) +{ + struct sysclock_ops test_sysclock_ops; + struct uk_intctlr_irq test_irq; + struct sysclock_desc ori_sysclock; + const char *test_sysclock_name = "test sysclock"; + + ori_sysclock = sysclock; + test_irq.id = TEST_IRQ_ID; + test_irq.trigger = 0; + + test_sysclock_ops.set_next = test_systick_set_next; + test_sysclock_ops.get_count = test_systick_get_count; + test_sysclock_ops.mask_base_irq = test_systick_mask_base_irq; + test_sysclock_ops.unmask_base_irq = test_systick_unmask_base_irq; + + tn_systick_register(test_sysclock_name, 0, &test_irq, + &test_sysclock_ops); + + /* test tn_systick_register */ + UK_TEST_EXPECT_PTR_EQ(sysclock.ops, &test_sysclock_ops); + + /* test tn_systick_get_irq */ + UK_TEST_EXPECT_SNUM_EQ(TEST_IRQ_ID, tn_systick_get_irq()); + + /* test tn_systick_start */ + test_ret = 0; + tn_systick_start(); + UK_TEST_EXPECT_SNUM_EQ(test_ret, TEST_UNMASK_BASE_IRQ); + + tn_systick_register(ori_sysclock.name, ori_sysclock.freq, + ori_sysclock.irq, ori_sysclock.ops); +} + +/* test tn_systick_get_tick */ +#define TEST_COUNTS 1000000 +UK_TESTCASE(tnsystick, test_get_systick) +{ + systick_t start_tick, dealta_tick, target_tick; + uint64_t start_count, target_count; + struct sysclock_ops test_sysclock_ops; + struct uk_intctlr_irq test_irq; + struct sysclock_desc ori_sysclock; + const char *test_sysclock_name = "test sysclock"; + + ori_sysclock = sysclock; + test_irq.id = TEST_IRQ_ID; + test_irq.trigger = 0; + + test_sysclock_ops.set_next = test_systick_set_next; + test_sysclock_ops.get_count = test_systick_get_count; + test_sysclock_ops.mask_base_irq = test_systick_mask_base_irq; + test_sysclock_ops.unmask_base_irq = test_systick_unmask_base_irq; + + tn_systick_register(test_sysclock_name, ori_sysclock.freq, &test_irq, + &test_sysclock_ops); + + /* test case 1: delay TEST_COUNTS counts and updated ticks */ + sys_timer_irq_handler(NULL); + start_count = sysclock.ops->get_count(); + start_tick = tn_systick_get_tick(); + target_count = start_count + TEST_COUNTS; + + test_count = target_count; + sys_timer_irq_handler(NULL); + + dealta_tick = tn_systick_get_tick() - start_tick; + target_tick = TEST_COUNTS * CONFIG_LIBTNSYSTICK_FREQ / sysclock.freq; + + UK_TEST_EXPECT_SNUM_EQ(dealta_tick, target_tick); + + /* test case 2: delay TEST_COUNTS counts but not updated ticks*/ + start_tick = tn_systick_get_tick(); + test_count = target_count + TEST_COUNTS; + dealta_tick = tn_systick_get_tick() - start_tick; + + UK_TEST_EXPECT_SNUM_EQ(dealta_tick, 0); + + tn_systick_register(ori_sysclock.name, ori_sysclock.freq, + ori_sysclock.irq, ori_sysclock.ops); +} + +uk_testsuite_register(tnsystick, NULL); diff --git a/lib/tnsystick/tests/test_systick.h b/lib/tnsystick/tests/test_systick.h new file mode 100644 index 00000000..a351c645 --- /dev/null +++ b/lib/tnsystick/tests/test_systick.h @@ -0,0 +1,23 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ssANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __TEST_SYSTICK_H__ +#define __TEST_SYSTICK_H__ + +#include + +extern struct sysclock_desc sysclock; +int sys_timer_irq_handler(void *arg __unused); + +#endif /* __TEST_SYSTICK_H__ */ diff --git a/lib/tnsystick/tnsystick.c b/lib/tnsystick/tnsystick.c index c34d48d0..315914b9 100644 --- a/lib/tnsystick/tnsystick.c +++ b/lib/tnsystick/tnsystick.c @@ -90,7 +90,7 @@ static inline void systick_update(void) extern unsigned long sched_have_pending_events; -static int sys_timer_irq_handler(void *arg __unused) +int sys_timer_irq_handler(void *arg __unused) { /* 1、update cur_systick */ systick_update(); @@ -111,7 +111,9 @@ static int sys_timer_irq_handler(void *arg __unused) sysclock.ops->set_next(ticks_to_counts(timeout), 0); #endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ __uk_test_and_clear_bit(0, &sched_have_pending_events); - return 1; + + /* todo: Interrupt processing temporarily returns 0 */ + return 0; } systick_t tn_systick_get_tick(void) diff --git a/lib/ukboot/boot.c b/lib/ukboot/boot.c index 76b188f5..338ed434 100644 --- a/lib/ukboot/boot.c +++ b/lib/ukboot/boot.c @@ -409,10 +409,6 @@ void ukplat_entry(int argc, char *argv[]) print_banner(stdout); fflush(stdout); -#if CONFIG_HAVE_SYSTICK - tn_systick_start(); -#endif /* CONFIG_HAVE_SYSTICK */ - #if !CONFIG_LIBUKBOOT_MAINTHREAD do_main(ictx.cmdline.argc, ictx.cmdline.argv); tctx.target = UKPLAT_HALT; @@ -518,6 +514,14 @@ static inline int do_main(int argc, char *argv[]) uk_pr_info("])\n"); #endif /* CONFIG_LIBUKDEBUG_PRINTK_INFO */ +#if CONFIG_HAVE_SYSTICK + tn_systick_start(); +#endif /* CONFIG_HAVE_SYSTICK */ + +#if CONFIG_HAVE_SYSTICK + tn_systick_start(); +#endif /* CONFIG_HAVE_SYSTICK */ + ret = main(argc, argv); uk_pr_info("main returned %d\n", ret); return ret; -- Gitee From d189a6702abfee56214778c99ddcf5f5628fc623 Mon Sep 17 00:00:00 2001 From: sunhaoyi Date: Wed, 6 Mar 2024 18:54:15 +0800 Subject: [PATCH 04/35] plat/common: [upstream][bugfix]Fix bootinfo can only get one block ram memory information Signed-off-by: sunhaoyi --- plat/common/bootinfo_fdt.c | 103 +++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 33 deletions(-) diff --git a/plat/common/bootinfo_fdt.c b/plat/common/bootinfo_fdt.c index 64f75587..ee734c2b 100644 --- a/plat/common/bootinfo_fdt.c +++ b/plat/common/bootinfo_fdt.c @@ -15,6 +15,8 @@ static void fdt_bootinfo_mem_mrd(struct ukplat_bootinfo *bi, void *fdtp) { struct ukplat_memregion_desc mrd = {0}; __u64 mem_base, mem_sz; + int len, ranges, range_index; + int parent_offset, naddr, nsize; int nmem; int rc; @@ -30,42 +32,77 @@ static void fdt_bootinfo_mem_mrd(struct ukplat_bootinfo *bi, void *fdtp) * For now, we only support one memory bank. * TODO: Support more than one memory@ node/regs/ranges properties. */ - rc = fdt_get_address(fdtp, nmem, 0, &mem_base, &mem_sz); - if (unlikely(rc)) - ukplat_bootinfo_crash("Get memory device address/size failed"); - if (unlikely(!RANGE_CONTAIN(mem_base, mem_sz, - __BASE_ADDR, __END - __BASE_ADDR))) - ukplat_bootinfo_crash("Image outside of RAM"); - - /* Check that we are not placed at the top of the memory region */ - mrd.len = __BASE_ADDR - mem_base; - if (!mrd.len) - goto end_mrd; - - mrd.vbase = (__vaddr_t)mem_base; - mrd.pbase = (__paddr_t)mem_base; - mrd.type = UKPLAT_MEMRT_FREE; - mrd.flags = UKPLAT_MEMRF_READ | UKPLAT_MEMRF_WRITE; - - rc = ukplat_memregion_list_insert(&bi->mrds, &mrd); - if (unlikely(rc < 0)) - ukplat_bootinfo_crash("Could not add free memory descriptor"); + parent_offset = fdt_parent_offset(fdtp, nmem); + naddr = fdt_address_cells(fdtp, parent_offset); + nsize = fdt_size_cells(fdtp, parent_offset); + + fdt_getprop(fdtp, nmem, "reg", &len); + ranges = len / (sizeof(fdt32_t) * (nsize + naddr)); + + for (range_index = 0; range_index < ranges; range_index++) { + rc = fdt_get_address(fdtp, nmem, range_index, + &mem_base, &mem_sz); + if (unlikely(rc)) + ukplat_bootinfo_crash( + "Get memory device address/size failed"); + + if (unlikely(!RANGE_CONTAIN(mem_base, mem_sz, + __BASE_ADDR, __END - __BASE_ADDR))){ + mrd.len = mem_sz; + if (!mrd.len) + continue; + mrd.vbase = (__vaddr_t)mem_base; + mrd.pbase = (__paddr_t)mem_base; + mrd.type = UKPLAT_MEMRT_FREE; + mrd.flags = UKPLAT_MEMRF_READ | UKPLAT_MEMRF_WRITE; + rc = ukplat_memregion_list_insert(&bi->mrds, &mrd); + + if (unlikely(rc < 0)) + ukplat_bootinfo_crash( + "Could not add free memory descriptor"); + + continue; + + } + + /* + * Check that we are not placed at the top of + * the memory region + */ + mrd.len = __BASE_ADDR - mem_base; + if (!mrd.len) + goto end_mrd; + + mrd.vbase = (__vaddr_t)mem_base; + mrd.pbase = (__paddr_t)mem_base; + mrd.type = UKPLAT_MEMRT_FREE; + mrd.flags = UKPLAT_MEMRF_READ | UKPLAT_MEMRF_WRITE; + + rc = ukplat_memregion_list_insert(&bi->mrds, &mrd); + if (unlikely(rc < 0)) + ukplat_bootinfo_crash( + "Could not add free memory descriptor"); end_mrd: - /* Check that we are not placed at the end of the memory region */ - mrd.len = mem_base + mem_sz - __END; - if (!mrd.len) - return; - - mrd.vbase = (__vaddr_t)__END; - mrd.pbase = (__paddr_t)__END; - mrd.type = UKPLAT_MEMRT_FREE; - mrd.flags = UKPLAT_MEMRF_READ | UKPLAT_MEMRF_WRITE; - - rc = ukplat_memregion_list_insert(&bi->mrds, &mrd); - if (unlikely(rc < 0)) - ukplat_bootinfo_crash("Could not add free memory descriptor"); + /* + * Check that we are not placed at the end of + * the memory region + */ + mrd.len = mem_base + mem_sz - __END; + if (!mrd.len) + return; + + mrd.vbase = (__vaddr_t)__END; + mrd.pbase = (__paddr_t)__END; + mrd.type = UKPLAT_MEMRT_FREE; + mrd.flags = UKPLAT_MEMRF_READ | UKPLAT_MEMRF_WRITE; + + rc = ukplat_memregion_list_insert(&bi->mrds, &mrd); + if (unlikely(rc < 0)) + ukplat_bootinfo_crash( + "Could not add free memory descriptor"); + } } static void fdt_bootinfo_cmdl_mrd(struct ukplat_bootinfo *bi, void *fdtp) -- Gitee From 89186dc2d4cbe33ec62656e6d6489b337a0bd861 Mon Sep 17 00:00:00 2001 From: crazykev Date: Tue, 19 Mar 2024 11:47:20 +0800 Subject: [PATCH 05/35] lib/uksched: support priority based scheduler 1. Add feature gate and field to support priority thread. 2. Add priority update and compare API. 3. Sepreate *yield as *yield and *reschedule API. 4. Add 2 API to support 1 args priority thread creation. 5. block with 0 timeout should do no op. Signed-off-by: crazykev --- lib/uksched/Config.uk | 43 ++++++++ lib/uksched/exportsyms.uk | 3 + lib/uksched/include/uk/sched.h | 66 +++++++++++ lib/uksched/include/uk/sched_impl.h | 71 ++++++++---- lib/uksched/include/uk/thread.h | 127 +++++++++++++++++++++ lib/uksched/sched.c | 26 ++++- lib/uksched/thread.c | 164 ++++++++++++++++++++-------- 7 files changed, 427 insertions(+), 73 deletions(-) diff --git a/lib/uksched/Config.uk b/lib/uksched/Config.uk index d0b1751c..1ce1f691 100644 --- a/lib/uksched/Config.uk +++ b/lib/uksched/Config.uk @@ -7,6 +7,49 @@ menuconfig LIBUKSCHED select HAVE_SCHED if LIBUKSCHED + config LIBUKSCHED_THREAD_PRIORITY + bool "Enable thread priority" + default n + select LIBUKSCHED_WAITQ_LIST + select LIBUKSCHED_RUNQ_LIST + + if LIBUKSCHED_THREAD_PRIORITY + config LIBUKSCHED_PRIORITY_LEVEL + int "Max priority level for all thread" + default 256 + help + Increase this value will use more resource, espacially for + some wait_q and ready_q algorithm. + config LIBUKSCHED_LOWEST_PRIORITY + int "Lowest priority number" + default 0 + endif + + choice LIBUKSCHED_RUNQ + prompt "Choice runq algorithm" + default LIBUKSCHED_RUNQ_TAILQ + config LIBUKSCHED_RUNQ_TAILQ + bool "Use linked tail queue based algorithm" + + config LIBUKSCHED_RUNQ_LIST + bool "Use double linked list based algorithm" + depends on LIBUKSCHED_THREAD_PRIORITY + endchoice + + choice LIBUKSCHED_WAITQ + prompt "Choice waitq algorithm" + default LIBUKSCHED_WAITQ_STAILQ + config LIBUKSCHED_WAITQ_STAILQ + depends on !LIBUKSCHED_THREAD_PRIORITY + bool "Use singly-linked tail queue without priority support" + + config LIBUKSCHED_WAITQ_LIST + bool "Use priority double linked list based algorithm as wait queue" + depends on LIBUKSCHED_THREAD_PRIORITY + help + Support thread priority scheduler. + endchoice + # Invisible symbol to enable TCB initialization config LIBUKSCHED_TCB_INIT bool diff --git a/lib/uksched/exportsyms.uk b/lib/uksched/exportsyms.uk index 2a3f0da0..7874cc65 100644 --- a/lib/uksched/exportsyms.uk +++ b/lib/uksched/exportsyms.uk @@ -12,6 +12,7 @@ uk_sched_thread_exit uk_sched_thread_exit2 uk_sched_dumpk_threads uk_sched_thread_gc +uk_sched_thread_set_priority uk_thread_init_bare uk_thread_init_bare_fn0 uk_thread_init_bare_fn1 @@ -22,6 +23,7 @@ uk_thread_init_fn2 uk_thread_create_bare uk_thread_create_container uk_thread_create_container2 +uk_thread_prio_create_container uk_thread_container_init_bare uk_thread_container_init_fn0 uk_thread_container_init_fn1 @@ -29,6 +31,7 @@ uk_thread_container_init_fn2 uk_thread_create_fn0 uk_thread_create_fn1 uk_thread_create_fn2 +uk_thread_prio_create_fn1 uk_thread_set_exited uk_thread_release uk_thread_block_until diff --git a/lib/uksched/include/uk/sched.h b/lib/uksched/include/uk/sched.h index 8d5ee4d2..dd2042c1 100644 --- a/lib/uksched/include/uk/sched.h +++ b/lib/uksched/include/uk/sched.h @@ -63,6 +63,7 @@ static inline struct uk_sched *uk_sched_current(void) typedef void (*uk_sched_yield_func_t) (struct uk_sched *s); +typedef void (*uk_sched_reschedule_func_t)(struct uk_sched *s); typedef int (*uk_sched_thread_add_func_t) (struct uk_sched *s, struct uk_thread *t); typedef void (*uk_sched_thread_remove_func_t) @@ -72,6 +73,13 @@ typedef void (*uk_sched_thread_blocked_func_t) typedef void (*uk_sched_thread_woken_func_t) (struct uk_sched *s, struct uk_thread *t); +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY +typedef void (*uk_sched_thread_set_prio_func_t)(struct uk_sched *s, + struct uk_thread *thread, + int32_t priority); +typedef int (*uk_sched_prio_cmp_func_t)(struct uk_thread *thread_1, + struct uk_thread *thread_2); +#endif typedef const struct uk_thread * (*uk_sched_idle_thread_func_t) (struct uk_sched *s, unsigned int proc_id); @@ -79,12 +87,17 @@ typedef int (*uk_sched_start_t)(struct uk_sched *s, struct uk_thread *main); struct uk_sched { uk_sched_yield_func_t yield; + uk_sched_reschedule_func_t reschedule; uk_sched_thread_add_func_t thread_add; uk_sched_thread_remove_func_t thread_remove; uk_sched_thread_blocked_func_t thread_blocked; uk_sched_thread_woken_func_t thread_woken; uk_sched_thread_woken_func_t thread_woken_isr; +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY + uk_sched_thread_set_prio_func_t thread_set_prio; + uk_sched_prio_cmp_func_t prio_cmp; +#endif uk_sched_idle_thread_func_t idle_thread; uk_sched_start_t sched_start; @@ -113,6 +126,23 @@ static inline void uk_sched_yield(void) s->yield(s); } +/** + * Tell the scheduler may need to reschedule. + * The scheduler will decide if a reschedule is needed. + * This is only wrapper functions over scheduler callbacks + */ +static inline void uk_sched_reschedule(void) +{ + struct uk_sched *s; + struct uk_thread *current = uk_thread_current(); + + UK_ASSERT(current); + + s = current->sched; + UK_ASSERT(s); + s->reschedule(s); +} + /** * Add thread to a scheduler * @@ -385,6 +415,42 @@ void uk_sched_thread_exit2(uk_thread_gc_t gc_fn, void *gc_argp) __noreturn; */ void uk_sched_thread_terminate(struct uk_thread *thread); +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY +/** + * Sets the priority of the given thread, do not reschedule + * @param thread + * Thread to be set (required) + * @param priority + * Priority to be set + * @return + * NULL + */ +void uk_sched_thread_set_priority(struct uk_thread *thread, int32_t priority); + +/** + * Compares the priority of two threads + * @param thread_1 + * First thread to be compared + * @param thread_2 + * Second thread to be compared + * @return + * - (0): The two threads have the same priority + * - (>0): The first thread has a higher priority + * - (<0): The second thread has a higher priority + */ +static inline int uk_sched_prio_cmp(struct uk_thread *thread_1, + struct uk_thread *thread_2) +{ + struct uk_sched *s; + + s = thread_1->sched; + + UK_ASSERT(s && s == thread_2->sched); + + return s->prio_cmp(thread_1, thread_2); +} +#endif + #ifdef __cplusplus } #endif diff --git a/lib/uksched/include/uk/sched_impl.h b/lib/uksched/include/uk/sched_impl.h index 2aca7c4b..298b8811 100644 --- a/lib/uksched/include/uk/sched_impl.h +++ b/lib/uksched/include/uk/sched_impl.h @@ -60,29 +60,56 @@ extern struct uk_sched *uk_sched_head; */ int uk_sched_register(struct uk_sched *s); -#define uk_sched_init(s, start_func, yield_func, \ - thread_add_func, thread_remove_func, \ - thread_blocked_func, thread_woken_func, \ - thread_woken_isr_func, idle_thread_func, \ - def_allocator) \ - do { \ - (s)->sched_start = start_func; \ - (s)->yield = yield_func; \ - (s)->thread_add = thread_add_func; \ - (s)->thread_remove = thread_remove_func; \ - (s)->thread_blocked = thread_blocked_func; \ - (s)->thread_woken = thread_woken_func; \ - (s)->thread_woken_isr = thread_woken_isr_func; \ - (s)->idle_thread = idle_thread_func; \ - uk_sched_register((s)); \ - \ - (s)->a = (def_allocator); \ - (s)->a_stack = (def_allocator); \ - (s)->a_auxstack = (def_allocator); \ - (s)->a_uktls = (def_allocator); \ - UK_TAILQ_INIT(&(s)->thread_list); \ - UK_TAILQ_INIT(&(s)->exited_threads); \ +#if defined(CONFIG_LIBUKSCHED_THREAD_PRIORITY) +#define uk_sched_init(s, start_func, yield_func, reschedule_func, \ + thread_add_func, thread_remove_func, \ + thread_blocked_func, thread_woken_func, \ + thread_woken_isr_func, prio_set_func, prio_cmp_func, \ + idle_thread_func, def_allocator) \ + do { \ + (s)->sched_start = start_func; \ + (s)->yield = yield_func; \ + (s)->reschedule = reschedule_func; \ + (s)->thread_add = thread_add_func; \ + (s)->thread_remove = thread_remove_func; \ + (s)->thread_blocked = thread_blocked_func; \ + (s)->thread_woken = thread_woken_func; \ + (s)->thread_woken_isr = thread_woken_isr_func; \ + (s)->thread_set_prio = prio_set_func; \ + (s)->prio_cmp = prio_cmp_func; \ + (s)->idle_thread = idle_thread_func; \ + uk_sched_register((s)); \ + (s)->a = (def_allocator); \ + (s)->a_stack = (def_allocator); \ + (s)->a_auxstack = (def_allocator); \ + (s)->a_uktls = (def_allocator); \ + UK_TAILQ_INIT(&(s)->thread_list); \ + UK_TAILQ_INIT(&(s)->exited_threads); \ } while (0) +#else +#define uk_sched_init(s, start_func, yield_func, reschedule_func, \ + thread_add_func, thread_remove_func, \ + thread_blocked_func, thread_woken_func, \ + thread_woken_isr_func, idle_thread_func, def_allocator) \ + do { \ + (s)->sched_start = start_func; \ + (s)->yield = yield_func; \ + (s)->reschedule = reschedule_func; \ + (s)->thread_add = thread_add_func; \ + (s)->thread_remove = thread_remove_func; \ + (s)->thread_blocked = thread_blocked_func; \ + (s)->thread_woken = thread_woken_func; \ + (s)->thread_woken_isr = thread_woken_isr_func; \ + (s)->idle_thread = idle_thread_func; \ + uk_sched_register((s)); \ + (s)->a = (def_allocator); \ + (s)->a_stack = (def_allocator); \ + (s)->a_auxstack = (def_allocator); \ + (s)->a_uktls = (def_allocator); \ + UK_TAILQ_INIT(&(s)->thread_list); \ + UK_TAILQ_INIT(&(s)->exited_threads); \ + } while (0) +#endif /* CONFIG_LIBUKSCHED_THREAD_PRIORITY */ /** * Releases self-exited threads (garbage collection) diff --git a/lib/uksched/include/uk/thread.h b/lib/uksched/include/uk/thread.h index 5bc71e8b..844d516e 100644 --- a/lib/uksched/include/uk/thread.h +++ b/lib/uksched/include/uk/thread.h @@ -61,7 +61,14 @@ struct uk_thread { __uptr uktlsp; /**< Unikraft TLS pointer */ __uptr auxsp; /**< Unikraft Auxiliary Stack Pointer */ + /* TODO: Remove this, only for compatible*/ + UK_TAILQ_ENTRY(struct uk_thread) sleep_queue; +#if defined(CONFIG_LIBUKSCHED_RUNQ_TAILQ) UK_TAILQ_ENTRY(struct uk_thread) queue; +#elif defined(CONFIG_LIBUKSCHED_RUNQ_LIST) + struct uk_list_head queue; +#endif + uint32_t flags; __snsec wakeup_time; struct uk_sched *sched; @@ -78,6 +85,9 @@ struct uk_thread { uk_thread_gc_t _gc_fn; /**< Extra gc function (internal!) */ void *_gc_argp; /**< Argument for gc fn (internal!) */ +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY + int32_t prio; /**< Thread priority */ +#endif uk_thread_dtor_t dtor; /**< User provided destructor */ void *priv; /**< Private field, free for use */ @@ -155,6 +165,19 @@ struct uk_thread *uk_thread_current(void) */ #define UK_THREADF_QUEUEABLE (0x010) +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY +#define UK_THREADF_LOWEST_PRIO CONFIG_LIBUKSCHED_LOWEST_PRIORITY +#define UK_THREADF_HIGHEST_PRIO \ + (CONFIG_LIBUKSCHED_PRIORITY_LEVEL + UK_THREADF_LOWEST_PRIO - 1) +#define UK_THREADF_IDLE_PRIO UK_THREADF_LOWEST_PRIO +#define UK_THREADF_DEFAULT_PRIO (UK_THREADF_IDLE_PRIO + 1) +#else +#define UK_THREADF_LOWEST_PRIO 0 +#define UK_THREADF_HIGHEST_PRIO 0 +#define UK_THREADF_IDLE_PRIO 0 +#define UK_THREADF_DEFAULT_PRIO 0 +#endif + #define uk_thread_is_exited(t) ((t)->flags & UK_THREADF_EXITED) #define uk_thread_is_runnable(t) (!uk_thread_is_exited(t) \ && ((t)->flags & UK_THREADF_RUNNABLE)) @@ -903,6 +926,110 @@ struct uk_thread *uk_thread_create_fn2(struct uk_alloc *a, void *priv, uk_thread_dtor_t dtor); +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY +/** + * Allocates a raw uk_thread structure with priority. Such a thread can then be + * assigned to a scheduler. When the thread starts, the general-purpose + * registers are reset. + * + * @param a + * Reference to an allocator (required) + * @param fn + * Thread entry function (required) + * @param argp + * Thread entry function argument(required) + * @param a_stack + * Reference to an allocator for allocating a stack (required) + * @param stack_len + * Size of the thread stack. If set to 0, a default stack size is used + * for the stack allocation. + * @param a_uktls + * Reference to an allocator for allocating (Unikraft) thread local storage. + * If `NULL` is passed, a thread without TLS is allocated. + * @param no_ectx + * If set, no memory is allocated for saving/restoring extended CPU + * context state (e.g., floating point, vector registers). In such a + * case, no extended context is saved nor restored on thread switches. + * Executed functions must be ISR-safe. + * @param name + * Optional name for the thread + * @param prio + * Priority of the thread + * @param priv + * Reference to external data that corresponds to this thread + * @param dtor + * Destructor that is called when this thread is released + * @return + * - (NULL): Allocation failed + * - Reference to initialized uk_thread + */ +struct uk_thread *uk_thread_prio_create_fn1(struct uk_alloc *a, + uk_thread_fn1_t fn, + void *argp, + struct uk_alloc *a_stack, + size_t stack_len, + struct uk_alloc *a_auxstack, + size_t auxstack_len, + struct uk_alloc *a_uktls, + bool no_ectx, + const char *name, + int32_t prio, + void *priv, + uk_thread_dtor_t dtor); + +/** + * Allocates a uk_thread container with stack, TLS and priority. The entry point + * is not set and the thread is not marked as runnable. Such a thread should + * only be assigned to a scheduler after an entry point is configured + * (`thread->ctx`) and the thread was marked as runnable. + * + * @param a + * Reference to an allocator (required) + * @param a_stack + * Reference to an allocator for allocating a stack + * Set to `NULL` to continue without a stack. + * @param stack_len + * Size of the thread stack. If set to 0, a default stack size is used + * for the stack allocation. + * @param a_auxstack + * Reference to an allocator for allocating an auxiliary stack + * @param auxstack_len + * Size of the thread auxiliary stack. If set to 0, a default stack size is + * used for the allocation. + * @param a_uktls + * Reference to an allocator for allocating (Unikraft) thread local storage. + * If `NULL` is passed, a thread without TLS is allocated. + * @param no_ectx + * If set, no memory is allocated for saving/restoring extended CPU + * context state (e.g., floating point, vector registers). In such a + * case, no extended context is saved nor restored on thread switches. + * Executed functions must be ISR-safe. + * @param name + * Optional name for the thread + * @param prio + * Priority of the thread + * @param priv + * Reference to external data that corresponds to this thread + * @param dtor + * Destructor that is called when this thread is released + * @return + * - (NULL): Allocation failed + * - Reference to initialized uk_thread + */ +struct uk_thread *uk_thread_prio_create_container(struct uk_alloc *a, + struct uk_alloc *a_stack, + size_t stack_len, + struct uk_alloc *a_auxstack, + size_t auxstack_len, + struct uk_alloc *a_uktls, + bool no_ectx, + const char *name, + int32_t prio, + void *priv, + uk_thread_dtor_t dtor); + +#endif /* CONFIG_LIBUKSCHED_THREAD_PRIORITY */ + /* Release a thread,set as exited and free memory * @param t * Thread to be released diff --git a/lib/uksched/sched.c b/lib/uksched/sched.c index a656da75..94fee450 100644 --- a/lib/uksched/sched.c +++ b/lib/uksched/sched.c @@ -221,6 +221,9 @@ int uk_sched_start(struct uk_sched *s) ret = -ENOMEM; goto err_out; } +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY + main_thread->prio = UK_THREADF_DEFAULT_PRIO; +#endif main_thread->sched = s; /* Because `main_thread` acts as container for storing the current @@ -311,7 +314,7 @@ void uk_sched_thread_terminate(struct uk_thread *thread) thread_list); /* leave this thread */ - sched->yield(sched); /* we won't return */ + sched->reschedule(sched); /* we won't return */ UK_CRASH("Unexpectedly returned to exited thread %p\n", thread); } else { /* free thread resources immediately */ @@ -357,13 +360,18 @@ int uk_sched_thread_add(struct uk_sched *s, struct uk_thread *t) flags = ukplat_lcpu_save_irqf(); rc = s->thread_add(s, t); - if (rc < 0) - goto out; + if (rc < 0) { + ukplat_lcpu_restore_irqf(flags); + return rc; + } t->sched = s; UK_TAILQ_INSERT_TAIL(&s->thread_list, t, thread_list); -out: ukplat_lcpu_restore_irqf(flags); + + if (uk_sched_current() == s) + s->reschedule(s); + return rc; } @@ -442,3 +450,13 @@ UK_SYSCALL_R_DEFINE(int, sched_setaffinity, int, pid, long, cpusetsize, UK_WARN_STUBBED(); return 0; } + +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY +void uk_sched_thread_set_priority(struct uk_thread *thread, int32_t priority) +{ + UK_ASSERT(thread); + UK_ASSERT(thread->sched); + + thread->sched->thread_set_prio(thread->sched, thread, priority); +} +#endif diff --git a/lib/uksched/thread.c b/lib/uksched/thread.c index fff25e87..c86c8441 100644 --- a/lib/uksched/thread.c +++ b/lib/uksched/thread.c @@ -230,6 +230,7 @@ static void _uk_thread_struct_init(struct uk_thread *t, bool is_uktls, struct ukarch_ectx *ectx, const char *name, + int32_t prio, void *priv, uk_thread_dtor_t dtor) { @@ -245,12 +246,16 @@ static void _uk_thread_struct_init(struct uk_thread *t, t->dtor = dtor; t->exec_time = 0; +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY + t->prio = prio; +#endif + if (!auxsp) auxsp = ukplat_auxsp_alloc(uk_alloc_get_default(), #if CONFIG_LIBUKVMEM uk_vas_get_active(), -#endif /* CONFIG_LIBUKVMEM */ - 0); /* Default auxsp size */ +#endif /* CONFIG_LIBUKVMEM */ + 0); /* Default auxsp size */ t->auxsp = auxsp; @@ -282,8 +287,8 @@ int uk_thread_init_bare(struct uk_thread *t, UK_ASSERT(t); UK_ASSERT(t != uk_thread_current()); - _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, priv, - dtor); + _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, + UK_THREADF_DEFAULT_PRIO, priv, dtor); ukarch_ctx_init_bare(&t->ctx, sp, ip); if (ip) @@ -308,8 +313,8 @@ int uk_thread_init_bare_fn0(struct uk_thread *t, UK_ASSERT(sp); /* stack pointer is required for ctx_entry */ UK_ASSERT(fn); - _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, priv, - dtor); + _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, + UK_THREADF_DEFAULT_PRIO, priv, dtor); ukarch_ctx_init_entry0(&t->ctx, sp, 0, (ukarch_ctx_entry0) fn); uk_thread_set_runnable(t); @@ -334,8 +339,8 @@ int uk_thread_init_bare_fn1(struct uk_thread *t, UK_ASSERT(sp); /* stack pointer is required for ctx_entry */ UK_ASSERT(fn); - _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, priv, - dtor); + _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, + UK_THREADF_DEFAULT_PRIO, priv, dtor); ukarch_ctx_init_entry1(&t->ctx, sp, 0, (ukarch_ctx_entry1) fn, (long) argp); @@ -361,8 +366,8 @@ int uk_thread_init_bare_fn2(struct uk_thread *t, UK_ASSERT(sp); /* stack pointer is required for ctx_entry */ UK_ASSERT(fn); - _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, priv, - dtor); + _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, + UK_THREADF_DEFAULT_PRIO, priv, dtor); ukarch_ctx_init_entry2(&t->ctx, sp, 0, (ukarch_ctx_entry2) fn, (long) argp0, (long) argp1); @@ -381,6 +386,7 @@ static int _uk_thread_struct_init_alloc(struct uk_thread *t, bool custom_ectx, struct ukarch_ectx *ectx, const char *name, + int32_t prio, void *priv, uk_thread_dtor_t dtor) { @@ -441,9 +447,8 @@ static int _uk_thread_struct_init_alloc(struct uk_thread *t, tlsp = ukarch_tls_tlsp(tls); } - _uk_thread_struct_init(t, (__uptr)auxstack, tlsp, !(!tlsp), ectx, - name, priv, - dtor); + _uk_thread_struct_init(t, (__uptr)auxstack, tlsp, !(!tlsp), ectx, name, + prio, priv, dtor); /* Set uk_thread fields related to stack and TLS */ if (stack) { @@ -530,11 +535,9 @@ int uk_thread_init_fn0(struct uk_thread *t, UK_ASSERT(t != uk_thread_current()); UK_ASSERT(fn); - ret = _uk_thread_struct_init_alloc(t, - a_stack, stack_len, - a_auxstack, auxstack_len, - a_uktls, custom_ectx, ectx, name, - priv, dtor); + ret = _uk_thread_struct_init_alloc( + t, a_stack, stack_len, a_auxstack, auxstack_len, a_uktls, + custom_ectx, ectx, name, UK_THREADF_DEFAULT_PRIO, priv, dtor); if (ret < 0) goto err_out; @@ -574,11 +577,9 @@ int uk_thread_init_fn1(struct uk_thread *t, UK_ASSERT(t != uk_thread_current()); UK_ASSERT(fn); - ret = _uk_thread_struct_init_alloc(t, - a_stack, stack_len, - a_auxstack, auxstack_len, - a_uktls, custom_ectx, ectx, name, - priv, dtor); + ret = _uk_thread_struct_init_alloc( + t, a_stack, stack_len, a_auxstack, auxstack_len, a_uktls, + custom_ectx, ectx, name, UK_THREADF_DEFAULT_PRIO, priv, dtor); if (ret < 0) goto err_out; @@ -618,11 +619,9 @@ int uk_thread_init_fn2(struct uk_thread *t, UK_ASSERT(t != uk_thread_current()); UK_ASSERT(fn); - ret = _uk_thread_struct_init_alloc(t, - a_stack, stack_len, - a_auxstack, auxstack_len, - a_uktls, custom_ectx, ectx, name, - priv, dtor); + ret = _uk_thread_struct_init_alloc( + t, a_stack, stack_len, a_auxstack, auxstack_len, a_uktls, + custom_ectx, ectx, name, UK_THREADF_DEFAULT_PRIO, priv, dtor); if (ret < 0) goto err_out; @@ -680,16 +679,18 @@ struct uk_thread *uk_thread_create_bare(struct uk_alloc *a, /** Allocates `struct uk_thread` along with stack and TLS but do not initialize * the architecture context with an entry function (set to NULL) */ -struct uk_thread *uk_thread_create_container(struct uk_alloc *a, - struct uk_alloc *a_stack, - size_t stack_len, - struct uk_alloc *a_auxstack, - size_t auxstack_len, - struct uk_alloc *a_uktls, - bool no_ectx, - const char *name, - void *priv, - uk_thread_dtor_t dtor) +static inline struct uk_thread * +_uk_thread_create_container(struct uk_alloc *a, + struct uk_alloc *a_stack, + size_t stack_len, + struct uk_alloc *a_auxstack, + size_t auxstack_len, + struct uk_alloc *a_uktls, + bool no_ectx, + const char *name, + int32_t prio, + void *priv, + uk_thread_dtor_t dtor) { struct uk_thread *t; size_t t_size; @@ -718,13 +719,10 @@ struct uk_thread *uk_thread_create_container(struct uk_alloc *a, ((1 << CONFIG_UKPLAT_AUXSP_PAGE_ORDER) * PAGE_SIZE); - if (_uk_thread_struct_init_alloc(t, - a_stack, stack_len, - a_auxstack, auxstack_len, - a_uktls, - !(!ectx), - ectx, - name, priv, dtor) < 0) + if (_uk_thread_struct_init_alloc(t, a_stack, stack_len, a_auxstack, + auxstack_len, a_uktls, !(!ectx), ectx, + name, prio, priv, dtor) + < 0) goto err_free_thread; t->_mem.t_a = a; @@ -750,6 +748,41 @@ err_out: return NULL; } +struct uk_thread *uk_thread_create_container(struct uk_alloc *a, + struct uk_alloc *a_stack, + size_t stack_len, + struct uk_alloc *a_auxstack, + size_t auxstack_len, + struct uk_alloc *a_uktls, + bool no_ectx, + const char *name, + void *priv, + uk_thread_dtor_t dtor) +{ + return _uk_thread_create_container(a, a_stack, stack_len, a_auxstack, + auxstack_len, a_uktls, no_ectx, name, + UK_THREADF_DEFAULT_PRIO, priv, dtor); +} + +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY +struct uk_thread *uk_thread_prio_create_container(struct uk_alloc *a, + struct uk_alloc *a_stack, + size_t stack_len, + struct uk_alloc *a_auxstack, + size_t auxstack_len, + struct uk_alloc *a_uktls, + bool no_ectx, + const char *name, + int32_t prio, + void *priv, + uk_thread_dtor_t dtor) +{ + return _uk_thread_create_container(a, a_stack, stack_len, a_auxstack, + auxstack_len, a_uktls, no_ectx, name, + prio, priv, dtor); +} +#endif + /** Allocates `struct uk_thread` along with ectx (if requested), take stack * and TLS from caller but do not initialize the architecture context with * an entry function (set to NULL) @@ -786,8 +819,8 @@ struct uk_thread *uk_thread_create_container2(struct uk_alloc *a, + sizeof(*t), ukarch_ectx_align()); - _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, priv, - dtor); + _uk_thread_struct_init(t, auxsp, tlsp, is_uktls, ectx, name, + UK_THREADF_DEFAULT_PRIO, priv, dtor); t->_mem.t_a = a; /* Minimal context initialization where the stack pointer @@ -927,6 +960,40 @@ err_out: return NULL; } +#ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY +struct uk_thread *uk_thread_prio_create_fn1(struct uk_alloc *a, + uk_thread_fn1_t fn, + void *argp, + struct uk_alloc *a_stack, + size_t stack_len, + struct uk_alloc *a_auxstack, + size_t auxstack_len, + struct uk_alloc *a_uktls, + bool no_ectx, + const char *name, + int32_t prio, + void *priv, + uk_thread_dtor_t dtor) +{ + struct uk_thread *t; + + UK_ASSERT(fn); + UK_ASSERT(a_stack); /* A stack is required for ctx initialization */ + + t = uk_thread_prio_create_container(a, a_stack, stack_len, a_auxstack, + auxstack_len, a_uktls, no_ectx, + name, prio, priv, dtor); + if (!t) + goto err_out; + + uk_thread_container_init_fn1(t, fn, argp); + return t; + +err_out: + return NULL; +} +#endif + struct uk_thread *uk_thread_create_fn2(struct uk_alloc *a, uk_thread_fn2_t fn, void *argp0, void *argp1, @@ -1024,6 +1091,9 @@ void uk_thread_block_until(struct uk_thread *thread, __snsec until) void uk_thread_block_timeout(struct uk_thread *thread, __nsec nsec) { + if (!nsec) + return; + __snsec until = (__snsec) ukplat_monotonic_clock() + nsec; UK_ASSERT(thread); -- Gitee From 1cadd51f7a2cf72dc7f35740e74777077866a663 Mon Sep 17 00:00:00 2001 From: crazykev Date: Tue, 19 Mar 2024 11:56:04 +0800 Subject: [PATCH 06/35] include/uk: Add uk_list_add_before op for uk list Signed-off-by: crazykev --- include/uk/list.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/uk/list.h b/include/uk/list.h index e5c4ab6c..d0fe14a4 100644 --- a/include/uk/list.h +++ b/include/uk/list.h @@ -209,6 +209,12 @@ uk_list_add_tail(struct uk_list_head *new_entry, struct uk_list_head *head) __uk_list_add(new_entry, head->prev, head); } +static inline void uk_list_add_before(struct uk_list_head *new_entry, + struct uk_list_head *old_entry) +{ + __uk_list_add(new_entry, old_entry->prev, old_entry); +} + static inline void uk_list_move(struct uk_list_head *list, struct uk_list_head *head) { -- Gitee From 972e8173f4f9760c994bcecdef6f4191066b7e58 Mon Sep 17 00:00:00 2001 From: crazykev Date: Tue, 19 Mar 2024 11:57:37 +0800 Subject: [PATCH 07/35] lib/uksched: Support priority based wait queue 1. Refactor: wait_q support multiple backed algorithm 2. Add uk list based wait_q implement as priority aware queue. 3. waitq wake_up should wake target thread instead of wait operation. Signed-off-by: crazykev --- lib/uksched/include/uk/isr/wait.h | 4 + lib/uksched/include/uk/wait.h | 160 ++++++++++++++-------------- lib/uksched/include/uk/wait_queue.h | 135 +++++++++++++++++++++++ lib/uksched/include/uk/wait_types.h | 18 ++++ 4 files changed, 239 insertions(+), 78 deletions(-) create mode 100644 lib/uksched/include/uk/wait_queue.h diff --git a/lib/uksched/include/uk/isr/wait.h b/lib/uksched/include/uk/isr/wait.h index f2441375..a64f138c 100644 --- a/lib/uksched/include/uk/isr/wait.h +++ b/lib/uksched/include/uk/isr/wait.h @@ -19,6 +19,10 @@ static inline void uk_waitq_wake_up_isr(struct uk_waitq *wq) UK_STAILQ_FOREACH_SAFE(curr, &wq->wait_list, thread_list, tmp) uk_thread_wake_isr(curr->thread); ukplat_spin_unlock_irqrestore(&wq->sl, flags); + + // TODO: Uncomment the following line when scheduler know whether in isr + // context. + // uk_sched_reschedule(); } #endif /* __UK_SCHED_WAIT_ISR_H__ */ diff --git a/lib/uksched/include/uk/wait.h b/lib/uksched/include/uk/wait.h index aeaa5a80..30d21df6 100644 --- a/lib/uksched/include/uk/wait.h +++ b/lib/uksched/include/uk/wait.h @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -40,7 +41,7 @@ static inline void uk_waitq_init(struct uk_waitq *wq) { ukarch_spin_init(&(wq->sl)); - UK_STAILQ_INIT(&(wq->wait_list)); + __WAIT_QUEUE_INIT(wq); } static inline @@ -54,7 +55,7 @@ void uk_waitq_entry_init(struct uk_waitq_entry *entry, static inline int uk_waitq_empty(struct uk_waitq *wq) { - return UK_STAILQ_EMPTY(&(wq->wait_list)); + return _is_waitq_empty(wq); } static inline @@ -62,7 +63,7 @@ void uk_waitq_add(struct uk_waitq *wq, struct uk_waitq_entry *entry) { if (!entry->waiting) { - UK_STAILQ_INSERT_TAIL(&(wq->wait_list), entry, thread_list); + _waitq_add(wq, entry); entry->waiting = 1; } } @@ -72,8 +73,7 @@ void uk_waitq_remove(struct uk_waitq *wq, struct uk_waitq_entry *entry) { if (entry->waiting) { - UK_STAILQ_REMOVE(&(wq->wait_list), entry, - struct uk_waitq_entry, thread_list); + _waitq_remove(wq, entry); entry->waiting = 0; } } @@ -95,77 +95,74 @@ do { \ ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ } while (0) -#define __wq_wait_event_deadline(wq, condition, deadline, deadline_condition, \ - lock_fn, unlock_fn, lock) \ -({ \ - struct uk_thread *__current; \ - unsigned long flags; \ - int timedout = 0; \ - DEFINE_WAIT(__wait); \ - if (!(condition)) { \ - __current = uk_thread_current(); \ - for (;;) { \ - /* protect the list */ \ - ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ - if (condition) { \ - ukplat_spin_unlock_irqrestore(&((wq)->sl), \ - flags); \ - break; \ - } \ - uk_waitq_add(wq, &__wait); \ - __current->wakeup_time = deadline; \ - uk_thread_set_blocked(__current); \ - uk_sched_thread_blocked(__current); \ - ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ - if (lock) \ - unlock_fn(lock); \ - uk_sched_yield(); \ - if (lock) \ - lock_fn(lock); \ - if (condition) \ - break; \ - if (deadline_condition) { \ - timedout = 1; \ - break; \ - } \ - } \ - ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ - /* need to wake up */ \ - uk_thread_wake(__current); \ - uk_waitq_remove(wq, &__wait); \ - ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ - } \ - timedout; \ -}) - -#define uk_waitq_wait_deadline(wq, lock_fn, unlock_fn, lock, deadline, \ - deadline_condition) \ -({ \ - struct uk_thread *__current; \ - unsigned long flags; \ - int timedout = 0; \ - DEFINE_WAIT(__wait); \ - __current = uk_thread_current(); \ - ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ - uk_waitq_add(wq, &__wait); \ - __current->wakeup_time = deadline; \ - uk_thread_set_blocked(__current); \ - uk_sched_thread_blocked(__current); \ - ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ - if (lock) \ - unlock_fn(lock); \ - uk_sched_yield(); \ - if (lock) \ - lock_fn(lock); \ - if (deadline_condition) \ - timedout = 1; \ - ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ - /* need to wake up */ \ - uk_thread_wake(__current); \ - uk_waitq_remove(wq, &__wait); \ - ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ - timedout; \ -}) +#define __wq_wait_event_deadline(wq, condition, deadline, deadline_condition, \ + lock_fn, unlock_fn, lock) \ + ({ \ + struct uk_thread *__current; \ + unsigned long flags; \ + int timedout = 0; \ + DEFINE_WAIT(__wait); \ + if (!(condition)) { \ + __current = uk_thread_current(); \ + for (;;) { \ + /* protect the list */ \ + ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ + if (condition) { \ + ukplat_spin_unlock_irqrestore( \ + &((wq)->sl), flags); \ + break; \ + } \ + uk_waitq_add(wq, &__wait); \ + __current->wakeup_time = deadline; \ + uk_thread_set_blocked(__current); \ + uk_sched_thread_blocked(__current); \ + ukplat_spin_unlock_irqrestore(&((wq)->sl), \ + flags); \ + if (lock) \ + unlock_fn(lock); \ + uk_sched_yield(); \ + if (lock) \ + lock_fn(lock); \ + if (condition) \ + break; \ + if (deadline_condition) { \ + timedout = 1; \ + break; \ + } \ + } \ + ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ + uk_waitq_remove(wq, &__wait); \ + ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ + } \ + timedout; \ + }) + +#define uk_waitq_wait_deadline(wq, lock_fn, unlock_fn, lock, deadline, \ + deadline_condition) \ + ({ \ + struct uk_thread *__current; \ + unsigned long flags; \ + int timedout = 0; \ + DEFINE_WAIT(__wait); \ + __current = uk_thread_current(); \ + ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ + uk_waitq_add(wq, &__wait); \ + __current->wakeup_time = deadline; \ + uk_thread_set_blocked(__current); \ + uk_sched_thread_blocked(__current); \ + ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ + if (lock) \ + unlock_fn(lock); \ + uk_sched_yield(); \ + if (lock) \ + lock_fn(lock); \ + if (deadline_condition) \ + timedout = 1; \ + ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ + uk_waitq_remove(wq, &__wait); \ + ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ + timedout; \ + }) #define uk_waitq_wait_locked(wq, lock_fn, unlock_fn, lock) \ uk_waitq_wait_deadline(wq, lock_fn, unlock_fn, lock, 0, 0) @@ -199,10 +196,15 @@ void uk_waitq_wake_up(struct uk_waitq *wq) struct uk_waitq_entry *curr, *tmp; unsigned long flags; + /* TODO: Optimize lock range */ ukplat_spin_lock_irqsave(&(wq->sl), flags); - UK_STAILQ_FOREACH_SAFE(curr, &(wq->wait_list), thread_list, tmp) + _waitq_foreach_safe(curr, &(wq->wait_list), thread_list, tmp) + { uk_thread_wake(curr->thread); + } ukplat_spin_unlock_irqrestore(&(wq->sl), flags); + + uk_sched_reschedule(); } static inline @@ -212,10 +214,12 @@ void uk_waitq_wake_up_one(struct uk_waitq *wq) unsigned long flags; ukplat_spin_lock_irqsave(&(wq->sl), flags); - head = UK_STAILQ_FIRST(&wq->wait_list); + head = _waitq_best(wq); if (head) uk_thread_wake(head->thread); ukplat_spin_unlock_irqrestore(&(wq->sl), flags); + if (head) + uk_sched_reschedule(); } #ifdef __cplusplus diff --git a/lib/uksched/include/uk/wait_queue.h b/lib/uksched/include/uk/wait_queue.h new file mode 100644 index 00000000..fda5fbd4 --- /dev/null +++ b/lib/uksched/include/uk/wait_queue.h @@ -0,0 +1,135 @@ +/* Copyright 2023 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __UK_SCHED_WAIT_QUEUE_H__ +#define __UK_SCHED_WAIT_QUEUE_H__ + +#include +#include +#include + +/** + * _is_waitq_empty - check if the wait queue is empty + * _waitq_add - add a waiter to the wait queue + * _waitq_remove - remove a waiter from the wait queue + * __waitq_first - get the first waiter from the wait queue + */ + +#if defined(CONFIG_LIBUKSCHED_WAITQ_STAILQ) +#define _is_waitq_empty waitq_stailq_is_empty +#define _waitq_add waitq_stailq_add +#define _waitq_remove waitq_stailq_remove +#define _waitq_best waitq_stailq_first + +#define _waitq_foreach_safe UK_STAILQ_FOREACH_SAFE + +#elif defined(CONFIG_LIBUKSCHED_WAITQ_LIST) +#define _is_waitq_empty waitq_list_is_empty +#define _waitq_add waitq_list_add +#define _waitq_remove waitq_list_remove +#define _waitq_best waitq_list_best + +#define _waitq_foreach_safe(var, head, field, tvar) \ + uk_list_for_each_entry_safe(var, tvar, head, field) +#endif + +#ifdef CONFIG_LIBUKSCHED_WAITQ_STAILQ +static inline int waitq_stailq_is_empty(struct uk_waitq *wq) +{ + return UK_STAILQ_EMPTY(&(wq->wait_list)); +} + +static inline void waitq_stailq_add(struct uk_waitq *wq, + struct uk_waitq_entry *entry) +{ + UK_STAILQ_INSERT_TAIL(&(wq->wait_list), entry, thread_list); +} + +static inline void waitq_stailq_remove(struct uk_waitq *wq, + struct uk_waitq_entry *entry) +{ + UK_STAILQ_REMOVE(&(wq->wait_list), entry, struct uk_waitq_entry, + thread_list); +} + +static inline struct uk_waitq_entry *waitq_stailq_first(struct uk_waitq *wq) +{ + return UK_STAILQ_FIRST(&(wq->wait_list)); +} + +#elif defined(CONFIG_LIBUKSCHED_WAITQ_LIST) + +static inline int waitq_list_is_empty(struct uk_waitq *wq) +{ + return uk_list_empty(&(wq->wait_list)); +} + +static inline void waitq_list_add(struct uk_waitq *wq, + struct uk_waitq_entry *entry) +{ + struct uk_waitq_entry *tmp = NULL; + + uk_list_for_each_entry(tmp, &wq->wait_list, thread_list) { + if (uk_sched_prio_cmp(entry->thread, tmp->thread) > 0) { + uk_list_add_before(&entry->thread_list, + &tmp->thread_list); + break; + } + } + if (&tmp->thread_list == &wq->wait_list) + uk_list_add_tail(&entry->thread_list, &wq->wait_list); +} + +static inline void waitq_list_remove(struct uk_waitq *wq __unused, + struct uk_waitq_entry *entry) +{ + uk_list_del(&entry->thread_list); +} + +static inline struct uk_waitq_entry *waitq_list_best(struct uk_waitq *wq) +{ + return uk_list_first_entry_or_null(&wq->wait_list, + struct uk_waitq_entry, thread_list); +} +#endif + +// Dump non-priority wait queue +#ifdef CONFIG_LIBUKSCHED_WAITQ_STAILQ +static inline void dump_wait_queue(struct uk_waitq *wq) +{ + struct uk_waitq_entry *t = NULL, *tmp = NULL; + + uk_pr_info("Wait queue: "); + _waitq_foreach_safe(t, &(wq->wait_list), thread_list, tmp) { + uk_pr_info("%s ", t->thread->name); + } + uk_pr_info("\n"); +} + +// Dump priority wait queue +#else +static inline void dump_wait_queue(struct uk_waitq *wq) +{ + struct uk_waitq_entry *t = NULL, *tmp = NULL; + + uk_pr_info("Wait queue: "); + _waitq_foreach_safe(t, &(wq->wait_list), thread_list, tmp) { + uk_pr_info("%s(%d) ", t->thread->name, t->thread->prio); + } + uk_pr_info("\n"); +} +#endif + +#endif /* __UK_SCHED_WAIT_QUEUE_H__ */ diff --git a/lib/uksched/include/uk/wait_types.h b/lib/uksched/include/uk/wait_types.h index 2b0a3e6b..c7676359 100644 --- a/lib/uksched/include/uk/wait_types.h +++ b/lib/uksched/include/uk/wait_types.h @@ -36,20 +36,38 @@ extern "C" { struct uk_waitq_entry { int waiting; struct uk_thread *thread; +#if defined(CONFIG_LIBUKSCHED_WAITQ_STAILQ) UK_STAILQ_ENTRY(struct uk_waitq_entry) thread_list; +#elif defined(CONFIG_LIBUKSCHED_WAITQ_LIST) + struct uk_list_head thread_list; +#endif }; struct uk_waitq { __spinlock sl; +#if defined(CONFIG_LIBUKSCHED_WAITQ_STAILQ) UK_STAILQ_HEAD(wait_list, struct uk_waitq_entry) wait_list; +#elif defined(CONFIG_LIBUKSCHED_WAITQ_LIST) + struct uk_list_head wait_list; +#endif }; +#if defined(CONFIG_LIBUKSCHED_WAITQ_STAILQ) #define __WAIT_QUEUE_INITIALIZER(name) \ { \ UKARCH_SPINLOCK_INITIALIZER(), \ UK_STAILQ_HEAD_INITIALIZER(name.wait_list) \ } +#define __WAIT_QUEUE_INIT(name) UK_STAILQ_INIT(&(name->wait_list)) + +#elif defined(CONFIG_LIBUKSCHED_WAITQ_LIST) +#define __WAIT_QUEUE_INITIALIZER(name) \ + { UKARCH_SPINLOCK_INITIALIZER(), UK_LIST_HEAD_INIT(name.wait_list) } + +#define __WAIT_QUEUE_INIT(name) UK_INIT_LIST_HEAD(&(name->wait_list)) +#endif + #define UK_WAIT_QUEUE_INITIALIZER(name) __WAIT_QUEUE_INITIALIZER(name) #define DEFINE_WAIT_QUEUE(name) \ -- Gitee From 5750cbbf505bb7be6c0c865dc148ddfa11293645 Mon Sep 17 00:00:00 2001 From: crazykev Date: Tue, 19 Mar 2024 12:07:04 +0800 Subject: [PATCH 08/35] lib/ukschedcoop: Adapter changes introduced by lib/uksched AKA support reschedule API. Signed-off-by: crazykev --- lib/ukschedcoop/schedcoop.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/lib/ukschedcoop/schedcoop.c b/lib/ukschedcoop/schedcoop.c index 47e63f83..c3435304 100644 --- a/lib/ukschedcoop/schedcoop.c +++ b/lib/ukschedcoop/schedcoop.c @@ -38,7 +38,7 @@ #include #include "schedcoop.h" -static void schedcoop_schedule(struct uk_sched *s) +static inline void schedcoop_schedule(struct uk_sched *s, bool yield) { struct schedcoop *c = uksched2schedcoop(s); struct uk_thread *prev, *next, *thread, *tmp; @@ -49,7 +49,11 @@ static void schedcoop_schedule(struct uk_sched *s) UK_CRASH("Must not call %s with IRQs disabled\n", __func__); now = ukplat_monotonic_clock(); + prev = uk_thread_current(); + if (!yield && uk_thread_is_runnable(prev)) + return; + flags = ukplat_lcpu_save_irqf(); #if 0 //TODO @@ -126,6 +130,16 @@ static void schedcoop_schedule(struct uk_sched *s) uk_sched_thread_switch(next); } +static void schedcoop_reschedule(struct uk_sched *s) +{ + schedcoop_schedule(s, false); +} + +static void schedcoop_yield(struct uk_sched *s) +{ + schedcoop_schedule(s, true); +} + static int schedcoop_thread_add(struct uk_sched *s, struct uk_thread *t) { struct schedcoop *c = uksched2schedcoop(s); @@ -191,7 +205,7 @@ static __noreturn void idle_thread_fn(void *argp) * Check if something else can be scheduled now. */ ukplat_lcpu_restore_irqf(flags); - schedcoop_schedule(&c->sched); + schedcoop_schedule(&c->sched, true); continue; } @@ -210,7 +224,7 @@ static __noreturn void idle_thread_fn(void *argp) ukplat_lcpu_restore_irqf(flags); /* try to schedule a thread that might now be available */ - schedcoop_schedule(&c->sched); + schedcoop_schedule(&c->sched, true); } } @@ -280,16 +294,11 @@ struct uk_sched *uk_schedcoop_create(struct uk_alloc *a) c->idle.sched = &c->sched; - uk_sched_init(&c->sched, - schedcoop_start, - schedcoop_schedule, - schedcoop_thread_add, - schedcoop_thread_remove, - schedcoop_thread_blocked, - schedcoop_thread_woken_isr, - schedcoop_thread_woken_isr, - schedcoop_idle_thread, - a); + uk_sched_init(&c->sched, schedcoop_start, schedcoop_yield, + schedcoop_reschedule, schedcoop_thread_add, + schedcoop_thread_remove, schedcoop_thread_blocked, + schedcoop_thread_woken_isr, schedcoop_thread_woken_isr, + schedcoop_idle_thread, a); /* Add idle thread to the scheduler's thread list */ UK_TAILQ_INSERT_TAIL(&c->sched.thread_list, &c->idle, thread_list); -- Gitee From bfb77d1c1b372e24f2c0c2a2ad87201097d61747 Mon Sep 17 00:00:00 2001 From: crazykev Date: Tue, 19 Mar 2024 12:14:32 +0800 Subject: [PATCH 09/35] lib/tnschedprio: Add new priority based scheduler 1. Support priority thread 2. Support optional preemtive 3. Support multiple run queue implement(tailq and list based). Signed-off-by: crazykev --- lib/tnschedprio/Config.uk | 24 ++ lib/tnschedprio/Makefile.uk | 7 + lib/tnschedprio/exportsyms.uk | 1 + lib/tnschedprio/include/tn/schedprio.h | 35 +++ lib/tnschedprio/isrwoken.c | 29 +++ lib/tnschedprio/schedprio.c | 327 +++++++++++++++++++++++++ lib/tnschedprio/schedprio.h | 155 ++++++++++++ 7 files changed, 578 insertions(+) create mode 100644 lib/tnschedprio/Config.uk create mode 100644 lib/tnschedprio/Makefile.uk create mode 100644 lib/tnschedprio/exportsyms.uk create mode 100644 lib/tnschedprio/include/tn/schedprio.h create mode 100644 lib/tnschedprio/isrwoken.c create mode 100644 lib/tnschedprio/schedprio.c create mode 100644 lib/tnschedprio/schedprio.h diff --git a/lib/tnschedprio/Config.uk b/lib/tnschedprio/Config.uk new file mode 100644 index 00000000..298d24ee --- /dev/null +++ b/lib/tnschedprio/Config.uk @@ -0,0 +1,24 @@ +menuconfig LIBTNSCHEDPRIO + bool "tnschedprio: Priority scheduler with preemptive support" + default n + select LIBNOLIBC if !HAVE_LIBC + select LIBUKSCHED + select LIBUKSCHED_THREAD_PRIORITY + +if LIBTNSCHEDPRIO + config LIBTNSCHEDPRIO_ENABLE_PREEMTIVE + bool "Preemte low level thread when higher is ready" + default y + + choice LIBTNSCHEDPRIO_RUNQ + prompt "Choice runq algorithm" + default LIBTNSCHEDPRIO_RUNQ_TAILQ + config LIBTNSCHEDPRIO_RUNQ_TAILQ + depends on LIBUKSCHED_RUNQ_TAILQ + bool "Use linked queue based algorithm for run queue" + + config LIBTNSCHEDPRIO_RUNQ_LIST + depends on LIBUKSCHED_RUNQ_LIST + bool "Use double linked list based algorithm for run queue" + endchoice +endif diff --git a/lib/tnschedprio/Makefile.uk b/lib/tnschedprio/Makefile.uk new file mode 100644 index 00000000..63d21ac3 --- /dev/null +++ b/lib/tnschedprio/Makefile.uk @@ -0,0 +1,7 @@ +$(eval $(call addlib_s,libtnschedprio,$(CONFIG_LIBTNSCHEDPRIO))) + +CINCLUDES-$(CONFIG_LIBTNSCHEDPRIO) += -I$(LIBTNSCHEDPRIO_BASE)/include +CXXINCLUDES-$(CONFIG_LIBTNSCHEDPRIO) += -I$(LIBTNSCHEDPRIO_BASE)/include + +LIBTNSCHEDPRIO_SRCS-y += $(LIBTNSCHEDPRIO_BASE)/schedprio.c +LIBTNSCHEDPRIO_SRCS-y += $(LIBTNSCHEDPRIO_BASE)/isrwoken.c|isr diff --git a/lib/tnschedprio/exportsyms.uk b/lib/tnschedprio/exportsyms.uk new file mode 100644 index 00000000..c99178f7 --- /dev/null +++ b/lib/tnschedprio/exportsyms.uk @@ -0,0 +1 @@ +tn_schedprio_create diff --git a/lib/tnschedprio/include/tn/schedprio.h b/lib/tnschedprio/include/tn/schedprio.h new file mode 100644 index 00000000..7d380506 --- /dev/null +++ b/lib/tnschedprio/include/tn/schedprio.h @@ -0,0 +1,35 @@ +/* Copyright 2023 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Preemptive priority scheduler. + */ + +#ifndef __TN_SCHEDPRIO_H__ +#define __TN_SCHEDPRIO_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct uk_sched *tn_schedprio_create(struct uk_alloc *a); + +#ifdef __cplusplus +} +#endif + +#endif /* __TN_SCHEDPRIO_H__ */ diff --git a/lib/tnschedprio/isrwoken.c b/lib/tnschedprio/isrwoken.c new file mode 100644 index 00000000..1392c174 --- /dev/null +++ b/lib/tnschedprio/isrwoken.c @@ -0,0 +1,29 @@ +/* Copyright 2023 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "schedprio.h" + +void schedprio_thread_woken_isr(struct uk_sched *s, struct uk_thread *t) +{ + struct schedprio *c = uksched2schedprio(s); + + UK_ASSERT(ukplat_lcpu_irqs_disabled()); + + if (t->wakeup_time > 0) + UK_TAILQ_REMOVE(&c->sleep_queue, t, sleep_queue); + if (uk_thread_is_queueable(t) && uk_thread_is_runnable(t)) { + _runq_add(c, t); + uk_thread_clear_queueable(t); + } +} diff --git a/lib/tnschedprio/schedprio.c b/lib/tnschedprio/schedprio.c new file mode 100644 index 00000000..6e7333b0 --- /dev/null +++ b/lib/tnschedprio/schedprio.c @@ -0,0 +1,327 @@ +/* Copyright 2023 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include "schedprio.h" + +static inline void schedprio_schedule(struct schedprio *c, bool yield) +{ + struct uk_thread *prev, *next, *thread, *tmp; + __snsec now, min_wakeup_time; + unsigned long flags; + bool runnable; + int cmp_value; + + if (unlikely(ukplat_lcpu_irqs_disabled())) + UK_CRASH("Must not call %s with IRQs disabled\n", __func__); + + now = ukplat_monotonic_clock(); + prev = uk_thread_current(); + flags = ukplat_lcpu_save_irqf(); + + // TODO: Refactor sleep thread handling when we have a normal timer + // library. + + /* Examine all sleeping threads. + * Wake up expired ones and find the time when the next timeout expires. + */ + min_wakeup_time = 0; + UK_TAILQ_FOREACH_SAFE(thread, &c->sleep_queue, sleep_queue, tmp) + { + if (likely(thread->wakeup_time)) { + if (thread->wakeup_time <= now) + uk_thread_wake(thread); + else if (!min_wakeup_time + || thread->wakeup_time < min_wakeup_time) + min_wakeup_time = thread->wakeup_time; + } + } + + next = _runq_best(c); + runnable = uk_thread_is_runnable(prev); + if (!runnable) { + /* Always switch when current thread is not runnable. + * idle thread will always be runnable, it's safe to do this. + */ + goto switch_thread; + } + + cmp_value = schedprio_prio_cmp(prev, next); + + /* If we have a runnable thread with higher priority than the current + * one, we switch to it. + */ + if (!yield) { +#ifdef CONFIG_LIBTNSCHEDPRIO_ENABLE_PREEMTIVE + if (cmp_value >= 0) + goto out_without_switch; + else + goto switch_thread; + +#else + goto out_without_switch; +#endif + } else { + if (cmp_value > 0) + goto out_without_switch; + else + goto switch_thread; + } + +switch_thread: + if (next != prev) { + /* + * Schedule idle thread that will halt the CPU + * We select the idle thread only if we do not + * have anything else to execute + */ + if (next == &(c->idle)) + c->idle_return_time = min_wakeup_time; + + _runq_remove(c, next); + if (runnable) + _runq_add(c, prev); + + /* + * Queueable is used to cover the case when during a + * context switch, the thread that is about to be + * evacuated is interrupted and woken up. + */ + uk_thread_set_queueable(prev); + uk_thread_clear_queueable(next); + + ukplat_lcpu_restore_irqf(flags); + + /* Interrupting the switch is equivalent to having the next + * thread interrupted at the return instruction. And therefore + * at safe point. + */ + uk_sched_thread_switch(next); + return; + } + +out_without_switch: + ukplat_lcpu_restore_irqf(flags); +} + +static void schedprio_yield(struct uk_sched *s) +{ + struct schedprio *c = uksched2schedprio(s); + + schedprio_schedule(c, true); +} + +static void schedprio_reschedule(struct uk_sched *s) +{ + struct schedprio *c = uksched2schedprio(s); + + schedprio_schedule(c, false); +} + +static int schedprio_thread_add(struct uk_sched *s, struct uk_thread *t) +{ + struct schedprio *c = uksched2schedprio(s); + + UK_ASSERT(t); + UK_ASSERT(!uk_thread_is_exited(t)); + + if (t->prio < UK_THREADF_LOWEST_PRIO + || t->prio > UK_THREADF_HIGHEST_PRIO) { + uk_pr_err("Thread %s has invalid priority %d\n", t->name, + t->prio); + return -EINVAL; + } + + /* Add to run queue in priority ascending order if runnable */ + if (uk_thread_is_runnable(t)) + _runq_add(c, t); + + return 0; +} + +static void schedprio_thread_remove(struct uk_sched *s, struct uk_thread *t) +{ + struct schedprio *c = uksched2schedprio(s); + + /* Remove from run_queue */ + if (t != uk_thread_current() && uk_thread_is_runnable(t)) + _runq_remove(c, t); +} + +static void schedprio_thread_blocked(struct uk_sched *s, struct uk_thread *t) +{ + struct schedprio *c = uksched2schedprio(s); + + UK_ASSERT(ukplat_lcpu_irqs_disabled()); + + if (t != uk_thread_current()) + _runq_remove(c, t); + if (t->wakeup_time > 0) + UK_TAILQ_INSERT_TAIL(&c->sleep_queue, t, sleep_queue); +} + +static __noreturn void idle_thread_fn(void *argp) +{ + struct schedprio *c = (struct schedprio *)argp; + __nsec now, wake_up_time; + unsigned long flags; + + UK_ASSERT(c); + + for (;;) { + flags = ukplat_lcpu_save_irqf(); + /* + * FIXME: We assume that `uk_sched_thread_gc()` is non-blocking + * because we implement a cooperative scheduler. However, + * this assumption may not be true depending on the + * destructor functions that are assigned to the threads + * and are called by `uk_sched_thred_gc()`. + * Also check if in the meantime we got a runnable + * thread. + * NOTE: This idle thread must be non-blocking so that the + * scheduler has always something to schedule. + */ + if (uk_sched_thread_gc(&c->sched) > 0 || !_is_runq_empty(c)) { + /* We collected successfully some garbage or there is + * a runnable thread in the queue. + * Check if something else can be scheduled now. + */ + ukplat_lcpu_restore_irqf(flags); + schedprio_schedule(c, true); + + continue; + } + + /* Read return time set by last schedule operation */ + wake_up_time = c->idle_return_time; + now = ukplat_monotonic_clock(); + + if (!wake_up_time || wake_up_time > now) { + if (wake_up_time) + ukplat_lcpu_halt_irq_until(wake_up_time); + else + ukplat_lcpu_halt_irq(); + + /* handle pending events if any */ + ukplat_lcpu_irqs_handle_pending(); + } + + ukplat_lcpu_restore_irqf(flags); + + /* try to schedule a thread that might now be available */ + schedprio_schedule(c, true); + } +} + +static int schedprio_start(struct uk_sched *s __maybe_unused, + struct uk_thread *main_thread __maybe_unused) +{ + UK_ASSERT(main_thread); + UK_ASSERT(main_thread->sched == s); + UK_ASSERT(uk_thread_is_runnable(main_thread)); + UK_ASSERT(!uk_thread_is_exited(main_thread)); + UK_ASSERT(uk_thread_current() == main_thread); + + /* NOTE: We do not put `main_thread` into the thread list. + * Current running threads will be added as soon as + * a different thread is scheduled. + */ + + ukplat_lcpu_enable_irq(); + + return 0; +} + +static const struct uk_thread *schedprio_idle_thread(struct uk_sched *s, + unsigned int proc_id) +{ + struct schedprio *c = uksched2schedprio(s); + + /* NOTE: We only support one processing LCPU (for now) */ + if (proc_id > 0) + return NULL; + + return &(c->idle); +} + +void schedprio_set_priority(struct uk_sched *s, + struct uk_thread *thread, + int32_t priority) +{ + struct schedprio *c = uksched2schedprio(s); + + UK_ASSERT(thread); + UK_ASSERT(thread->sched == s); + UK_ASSERT(uk_thread_is_runnable(thread)); + UK_ASSERT(!uk_thread_is_exited(thread)); + UK_ASSERT(uk_thread_current() == thread); + UK_ASSERT(priority >= UK_THREADF_LOWEST_PRIO + && priority <= UK_THREADF_HIGHEST_PRIO); + + thread->prio = priority; + + /* Remove from run_queue */ + if (thread != uk_thread_current() && uk_thread_is_runnable(thread)) { + _runq_remove(c, thread); + _runq_add(c, thread); + } +} + +struct uk_sched *tn_schedprio_create(struct uk_alloc *a) +{ + struct schedprio *c = NULL; + int rc; + + uk_pr_info("Initializing cooperative scheduler\n"); + c = uk_zalloc(a, sizeof(struct schedprio)); + if (!c) + goto err_out; + + _runq_init(c); + UK_TAILQ_INIT(&c->sleep_queue); + + /* Create idle thread */ + rc = uk_thread_init_fn1(&c->idle, idle_thread_fn, (void *)c, a, + STACK_SIZE, a, + 0, /* Default auxiliary stack size */ + a, false, NULL, "idle", NULL, NULL); + if (rc < 0) + goto err_free_c; + c->idle.prio = UK_THREADF_IDLE_PRIO; + c->idle.sched = &c->sched; + + uk_sched_init(&c->sched, schedprio_start, schedprio_yield, + schedprio_reschedule, schedprio_thread_add, + schedprio_thread_remove, schedprio_thread_blocked, + schedprio_thread_woken_isr, schedprio_thread_woken_isr, + schedprio_set_priority, schedprio_prio_cmp, + schedprio_idle_thread, a); + + /* Add idle thread to the scheduler's thread list */ + UK_TAILQ_INSERT_TAIL(&c->sched.thread_list, &c->idle, thread_list); + _runq_add(c, &c->idle); + + return &c->sched; + +err_free_c: + uk_free(a, c); +err_out: + return NULL; +} diff --git a/lib/tnschedprio/schedprio.h b/lib/tnschedprio/schedprio.h new file mode 100644 index 00000000..5eae91b1 --- /dev/null +++ b/lib/tnschedprio/schedprio.h @@ -0,0 +1,155 @@ +/* Copyright 2023 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __TN_SCHEDPRIO_SCHEDPRIO_H__ +#define __TN_SCHEDPRIO_SCHEDPRIO_H__ + +#include +#include + +struct schedprio { + struct uk_sched sched; +#if defined(CONFIG_LIBTNSCHEDPRIO_RUNQ_TAILQ) + UK_TAILQ_HEAD(run_queue, struct uk_thread) run_queue; +#elif defined(CONFIG_LIBTNSCHEDPRIO_RUNQ_LIST) + struct uk_list_head run_queue; +#endif + struct uk_thread_list sleep_queue; + + struct uk_thread idle; + __nsec idle_return_time; +}; + +#if defined(CONFIG_LIBTNSCHEDPRIO_RUNQ_TAILQ) +#define _runq_init runq_tailq_init +#define _is_runq_empty runq_tailq_is_empty +#define _runq_add runq_tailq_add +#define _runq_remove runq_tailq_remove +#define _runq_best runq_tailq_best + +#define _runq_foreach UK_TAILQ_FOREACH +#define _runq_foreach_safe UK_TAILQ_FOREACH_SAFE + +#elif defined(CONFIG_LIBTNSCHEDPRIO_RUNQ_LIST) +#define _runq_init runq_list_init +#define _is_runq_empty runq_list_is_empty +#define _runq_add runq_list_add +#define _runq_remove runq_list_remove +#define _runq_best runq_list_best + +#define _runq_foreach uk_list_for_each_entry +#define _runq_foreach_safe(var, head, field, tvar) \ + uk_list_for_each_entry_safe(var, tvar, head, field) +#endif + +static inline int schedprio_prio_cmp(struct uk_thread *t1, struct uk_thread *t2) +{ + return t1->prio - t2->prio; +} + +static inline void dump_run_queue(struct schedprio *c) +{ + struct uk_thread *t = NULL; + + uk_pr_info("Run queue: "); + _runq_foreach(t, &c->run_queue, queue) { + uk_pr_info("%s(%d) ", t->name, t->prio); + } + uk_pr_info("\n"); +} + +#if defined(CONFIG_LIBTNSCHEDPRIO_RUNQ_TAILQ) +static inline void runq_tailq_init(struct schedprio *c) +{ + UK_TAILQ_INIT(&c->run_queue); +} + +static inline bool runq_tailq_is_empty(struct schedprio *c) +{ + return UK_TAILQ_EMPTY(&c->run_queue); +} + +static inline void runq_tailq_add(struct schedprio *c, struct uk_thread *t) +{ + struct uk_thread *tmp = NULL; + + UK_TAILQ_FOREACH(tmp, &c->run_queue, queue) { + if (schedprio_prio_cmp(t, tmp) > 0) + break; + } + if (tmp) + UK_TAILQ_INSERT_BEFORE(tmp, t, queue); + else + UK_TAILQ_INSERT_TAIL(&c->run_queue, t, queue); +} + +static inline struct uk_thread *runq_tailq_best(struct schedprio *c) +{ + return UK_TAILQ_FIRST(&c->run_queue); +} + +static inline void runq_tailq_remove(struct schedprio *c, struct uk_thread *t) +{ + UK_TAILQ_REMOVE(&c->run_queue, t, queue); +} +#endif + +#if defined(CONFIG_LIBTNSCHEDPRIO_RUNQ_LIST) +static inline void runq_list_init(struct schedprio *c) +{ + UK_INIT_LIST_HEAD(&c->run_queue); +} + +static inline bool runq_list_is_empty(struct schedprio *c) +{ + return uk_list_empty(&(c->run_queue)); +} + +static inline void runq_list_add(struct schedprio *c, struct uk_thread *t) +{ + struct uk_thread *tmp = NULL; + + uk_list_for_each_entry(tmp, &c->run_queue, queue) { + if (schedprio_prio_cmp(t, tmp) > 0) { + uk_list_add_before(&t->queue, &tmp->queue); + break; + } + } + if (&tmp->queue == &c->run_queue) + uk_list_add_tail(&t->queue, &c->run_queue); +} + +static inline void runq_list_remove(struct schedprio *c __unused, + struct uk_thread *t) +{ + uk_list_del(&t->queue); +} + +static inline struct uk_thread *runq_list_best(struct schedprio *c) +{ + return uk_list_first_entry_or_null(&c->run_queue, struct uk_thread, + queue); +} +#endif + +static inline struct schedprio *uksched2schedprio(struct uk_sched *s) +{ + UK_ASSERT(s); + + return __containerof(s, struct schedprio, sched); +} + +void schedprio_thread_woken_isr(struct uk_sched *s, struct uk_thread *t); + +#endif /* __TN_SCHEDPRIO_SCHEDPRIO_H__ */ -- Gitee From e5d057bf5ade181d0232531d9e85a83b65b9c16d Mon Sep 17 00:00:00 2001 From: crazykev Date: Tue, 19 Mar 2024 12:28:35 +0800 Subject: [PATCH 10/35] lib/ukboot: Support priority scheduler selection Signed-off-by: crazykev --- lib/Makefile.uk | 1 + lib/ukboot/Config.uk | 6 ++++++ lib/ukboot/boot.c | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/lib/Makefile.uk b/lib/Makefile.uk index d392af3a..4be259c1 100644 --- a/lib/Makefile.uk +++ b/lib/Makefile.uk @@ -56,6 +56,7 @@ $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/uknofault)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukring)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/uksched)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukschedcoop)) +$(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tnschedprio)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/uksglist)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/uksignal)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/uksp)) diff --git a/lib/ukboot/Config.uk b/lib/ukboot/Config.uk index 3d14dba0..73e2a62f 100644 --- a/lib/ukboot/Config.uk +++ b/lib/ukboot/Config.uk @@ -149,6 +149,12 @@ if LIBUKBOOT help Initialize ukschedcoop as cooperative scheduler on the boot CPU. + config LIBUKBOOT_INITSCHEDPRIO + bool "Priority scheduler" + select LIBTNSCHEDPRIO + help + Initialize tnschedprio as priority scheduler on the boot CPU. + config LIBUKBOOT_NOSCHED bool "None" diff --git a/lib/ukboot/boot.c b/lib/ukboot/boot.c index 338ed434..81b53d56 100644 --- a/lib/ukboot/boot.c +++ b/lib/ukboot/boot.c @@ -69,6 +69,8 @@ #endif /* CONFIG_LIBUKSCHED */ #if CONFIG_LIBUKBOOT_INITSCHEDCOOP #include +#elif CONFIG_LIBUKBOOT_INITSCHEDPRIO +#include #endif /* CONFIG_LIBUKBOOT_INITSCHEDCOOP */ #include #include @@ -361,6 +363,8 @@ void ukplat_entry(int argc, char *argv[]) uk_pr_info("Initialize scheduling...\n"); #if CONFIG_LIBUKBOOT_INITSCHEDCOOP s = uk_schedcoop_create(a); +#elif CONFIG_LIBUKBOOT_INITSCHEDPRIO + s = tn_schedprio_create(a); #endif if (unlikely(!s)) UK_CRASH("Failed to initialize scheduling\n"); -- Gitee From c437344d8a541141a3f926dc67f8f7541b9dd4e9 Mon Sep 17 00:00:00 2001 From: crazykev Date: Tue, 19 Mar 2024 14:45:14 +0800 Subject: [PATCH 11/35] format: align params in function declaration in clang-format Signed-off-by: crazykev --- .clang-format | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.clang-format b/.clang-format index 958f4c2f..f39a0e9b 100644 --- a/.clang-format +++ b/.clang-format @@ -3,9 +3,15 @@ BasedOnStyle: LLVM IndentWidth: 8 UseTab: Always -BreakBeforeBraces: Linux +BreakBeforeBraces: Custom BreakBeforeBinaryOperators: NonAssignment AllowShortFunctionsOnASingleLine: Empty AllowShortIfStatementsOnASingleLine: false IndentCaseLabels: false SortIncludes: false +BinPackParameters: false +AlignAfterOpenBracket: Align +BraceWrapping: + AfterControlStatement: false + AfterFunction: true +Cpp11BracedListStyle: false -- Gitee From 784437a116192cbe1d11f6de8ee8ca0f23035728 Mon Sep 17 00:00:00 2001 From: crazykev Date: Fri, 22 Mar 2024 11:07:44 +0800 Subject: [PATCH 12/35] lib/vfscore: [upstream][bugfix] Init mutex when alloc dentry Signed-off-by: crazykev --- lib/vfscore/dentry.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/vfscore/dentry.c b/lib/vfscore/dentry.c index b236d1ef..6f657ec2 100644 --- a/lib/vfscore/dentry.c +++ b/lib/vfscore/dentry.c @@ -97,6 +97,7 @@ dentry_alloc(struct dentry *parent_dp, struct vnode *vp, const char *path) uk_mutex_unlock(&parent_dp->d_lock); } dp->d_parent = parent_dp; + uk_mutex_init(&dp->d_lock); vn_add_name(vp, dp); -- Gitee From ee6c7c6a25071e85003995f61c6518d1f77cd3d6 Mon Sep 17 00:00:00 2001 From: Sunhaoyi Date: Mon, 5 Feb 2024 17:02:31 +0800 Subject: [PATCH 13/35] driver: Add uktty/ns8250 to fit rk3568 platform Signed-off-by: cheng2000160 --- drivers/uktty/Config.uk | 1 + drivers/uktty/Makefile.uk | 1 + drivers/uktty/ns16550/Config.uk | 2 +- drivers/uktty/ns16550/Makefile.uk | 2 +- drivers/uktty/ns8250/Config.uk | 13 + drivers/uktty/ns8250/Makefile.uk | 4 + drivers/uktty/ns8250/exportsyms.uk | 4 + drivers/uktty/ns8250/include/uk/tty/ns8250.h | 24 ++ drivers/uktty/ns8250/ns8250.c | 254 +++++++++++++++++++ 9 files changed, 303 insertions(+), 2 deletions(-) create mode 100644 drivers/uktty/ns8250/Config.uk create mode 100644 drivers/uktty/ns8250/Makefile.uk create mode 100644 drivers/uktty/ns8250/exportsyms.uk create mode 100644 drivers/uktty/ns8250/include/uk/tty/ns8250.h create mode 100644 drivers/uktty/ns8250/ns8250.c diff --git a/drivers/uktty/Config.uk b/drivers/uktty/Config.uk index 64f5c89b..aff36020 100644 --- a/drivers/uktty/Config.uk +++ b/drivers/uktty/Config.uk @@ -2,5 +2,6 @@ menu "Serial console" source "$(KCONFIG_DRIV_BASE)/uktty/pl011/Config.uk" source "$(KCONFIG_DRIV_BASE)/uktty/ns16550/Config.uk" +source "$(KCONFIG_DRIV_BASE)/uktty/ns8250/Config.uk" endmenu diff --git a/drivers/uktty/Makefile.uk b/drivers/uktty/Makefile.uk index da2194ae..18ce89db 100644 --- a/drivers/uktty/Makefile.uk +++ b/drivers/uktty/Makefile.uk @@ -8,3 +8,4 @@ UK_DRIV_TTY_BASE := $(UK_DRIV_BASE)/uktty $(eval $(call import_lib,$(UK_DRIV_TTY_BASE)/ns16550)) $(eval $(call import_lib,$(UK_DRIV_TTY_BASE)/pl011)) +$(eval $(call import_lib,$(UK_DRIV_TTY_BASE)/ns8250)) diff --git a/drivers/uktty/ns16550/Config.uk b/drivers/uktty/ns16550/Config.uk index 0bffcfb8..9bb06445 100644 --- a/drivers/uktty/ns16550/Config.uk +++ b/drivers/uktty/ns16550/Config.uk @@ -1,5 +1,5 @@ menuconfig LIBUKTTY_NS16550 - bool "NS16550 / 8250" + bool "NS16550" default n depends on ARCH_ARM_64 diff --git a/drivers/uktty/ns16550/Makefile.uk b/drivers/uktty/ns16550/Makefile.uk index 0d1645d5..0693daf8 100644 --- a/drivers/uktty/ns16550/Makefile.uk +++ b/drivers/uktty/ns16550/Makefile.uk @@ -1,4 +1,4 @@ -$(eval $(call addplatlib_s,kvm,libuktty_ns16550,$(CONFIG_LIBUKTTY_NS16550))) +$(eval $(call addlib_s,libuktty_ns16550,$(CONFIG_LIBUKTTY_NS16550))) CINCLUDES-y += -I$(LIBUKTTY_NS16550_BASE)/include LIBUKTTY_NS16550_SRCS-y += $(LIBUKTTY_NS16550_BASE)/ns16550.c diff --git a/drivers/uktty/ns8250/Config.uk b/drivers/uktty/ns8250/Config.uk new file mode 100644 index 00000000..206a0c78 --- /dev/null +++ b/drivers/uktty/ns8250/Config.uk @@ -0,0 +1,13 @@ +menuconfig LIBTNTTY_NS8250 + bool "NS8250" + default n + depends on ARCH_ARM_64 + +if LIBTNTTY_NS8250 +config LIBTNTTY_EARLY_PRINT_NS8250_CONSOLE_NAME + string "Description of serial in alisas node in device tree" + default "serial4" + help + uart used for kernel output + +endif diff --git a/drivers/uktty/ns8250/Makefile.uk b/drivers/uktty/ns8250/Makefile.uk new file mode 100644 index 00000000..0919e780 --- /dev/null +++ b/drivers/uktty/ns8250/Makefile.uk @@ -0,0 +1,4 @@ +$(eval $(call addlib_s,libuktty_ns8250,$(CONFIG_LIBTNTTY_NS8250))) + +CINCLUDES-y += -I$(LIBUKTTY_NS8250_BASE)/include +LIBUKTTY_NS8250_SRCS-y += $(LIBUKTTY_NS8250_BASE)/ns8250.c diff --git a/drivers/uktty/ns8250/exportsyms.uk b/drivers/uktty/ns8250/exportsyms.uk new file mode 100644 index 00000000..eaccad20 --- /dev/null +++ b/drivers/uktty/ns8250/exportsyms.uk @@ -0,0 +1,4 @@ +ns8250_console_init +ukplat_cink +ukplat_coutd +ukplat_coutk \ No newline at end of file diff --git a/drivers/uktty/ns8250/include/uk/tty/ns8250.h b/drivers/uktty/ns8250/include/uk/tty/ns8250.h new file mode 100644 index 00000000..b4e08005 --- /dev/null +++ b/drivers/uktty/ns8250/include/uk/tty/ns8250.h @@ -0,0 +1,24 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __TN_TTY_NS8250_H__ +#define __TN_TTY_NS8250_H__ + +/** + * Initialize the ns8250 console driver + */ +void ns8250_console_init(void *dtb); + +#endif /* __UK_TTY_NS8250_H__ */ diff --git a/drivers/uktty/ns8250/ns8250.c b/drivers/uktty/ns8250/ns8250.c new file mode 100644 index 00000000..195614b7 --- /dev/null +++ b/drivers/uktty/ns8250/ns8250.c @@ -0,0 +1,254 @@ +/* + * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +#define NS8250_THR_OFFSET 0x00U +#define NS8250_RBR_OFFSET 0x00U +#define NS8250_DLL_OFFSET 0x00U +#define NS8250_DLM_OFFSET 0x01U +#define NS8250_IER_OFFSET 0x01U +#define NS8250_IIR_OFFSET 0x02U +#define NS8250_FCR_OFFSET 0x02U +#define NS8250_LCR_OFFSET 0x03U +#define NS8250_MCR_OFFSET 0x04U +#define NS8250_LSR_OFFSET 0x05U +#define NS8250_MSR_OFFSET 0x06U + +#define NS8250_MCR_DTR 0x01U /* DTR */ +#define NS8250_MCR_RTS 0x02U /* RTS */ +#define NS8250_MCR_SET (NS8250_MCR_DTR | \ + NS8250_MCR_RTS) + +#define NS8250_LCR_8N1 0x03U +#define NS8250_LCR_DLAB 0x80U +#define NS8250_IIR_NO_INT 0x01U +#define NS8250_FCR_FIFO_EN 0x01U +#define NS8250_FCR_RXSR 0x02U /* Receiver soft reset */ +#define NS8250_FCR_TXSR 0x04U /* Transmitter soft reset */ +#define NS8250_LSR_RX_EMPTY 0x01U +#define NS8250_LSR_TX_EMPTY 0x40U +#define NS8250_FCR_DEFVAL (NS8250_FCR_FIFO_EN | \ + NS8250_FCR_RXSR | \ + NS8250_FCR_TXSR) + +static __u8 ns8250_uart_initialized; +static __u64 ns8250_uart_base; + +/* Early console node name in DTB, help to find related info */ +static char *earlycon_node_name = +CONFIG_LIBTNTTY_EARLY_PRINT_NS8250_CONSOLE_NAME; + +/* The register shift. Default is 0 (device-tree spec v0.4 Sect. 4.2.2) */ +static __u32 ns8250_reg_shift; + +/* The register width. Default is 1 (8-bit register width) */ +static __u32 ns8250_reg_width = 0x01; + +static __u32 ns8250_baudrate = 115200; + +static __u32 ns8250_mode_x_div = 16; + +/* Macros to access ns16550 registers with base address and reg shift */ +#define NS8250_REG(r) (ns8250_uart_base + (r << ns8250_reg_shift)) + +/* Macros to extract int shift/width infos */ +#define EXTRACT_HIGH_BITS(x) ((__u32)((x) & 0xFFFFFFFF) >> 24) + +static inline __u32 ns8250_reg_read(__u32 reg) +{ + __u32 ret; + + switch (ns8250_reg_width) { + case 1: + ret = ioreg_read8((__u8 *)NS8250_REG(reg)) & 0xff; + break; + case 2: + ret = ioreg_read16((__u16 *)NS8250_REG(reg)) & 0xffff; + break; + case 4: + ret = ioreg_read32((__u32 *)NS8250_REG(reg)); + break; + default: + UK_CRASH("Invalid register width: %d\n", ns8250_reg_width); + } + return ret; +} + +static inline void ns8250_reg_write(__u32 reg, __u32 value) +{ + switch (ns8250_reg_width) { + case 1: + ioreg_write8((__u8 *)NS8250_REG(reg), + (__u8)(value & 0xff)); + break; + case 2: + ioreg_write16((__u16 *)NS8250_REG(reg), + (__u16)(value & 0xffff)); + break; + case 4: + ioreg_write32((__u32 *)NS8250_REG(reg), value); + break; + default: + UK_CRASH("Invalid register width: %d\n", ns8250_reg_width); + } +} + +static void ns8250_set_baudrate(__u16 divisor) +{ + /* Enable DLAB */ + ns8250_reg_write(NS8250_LCR_OFFSET, + NS8250_LCR_DLAB | NS8250_LCR_8N1); + /* Set divisor low byte */ + ns8250_reg_write(NS8250_DLL_OFFSET, divisor & 0xff); + /* Set divisor high byte */ + ns8250_reg_write(NS8250_DLM_OFFSET, (divisor >> 8) & 0xff); + /* Set the transceiver signal bit */ + ns8250_reg_write(NS8250_LCR_OFFSET, NS8250_LCR_8N1); +} + +static void init_ns8250(__u64 base) +{ + __u16 ns8250_divisor = 0; + __u32 ns8250_uart_freq = 24000000; + + ns8250_uart_base = base; + ns8250_uart_initialized = 1; + + while (!(ns8250_reg_read(NS8250_LSR_OFFSET) & NS8250_LSR_TX_EMPTY)) + ; + + if (ns8250_baudrate) { + ns8250_divisor = + (ns8250_uart_freq) / (ns8250_mode_x_div * ns8250_baudrate); + } + + /* Disable all interrupts */ + ns8250_reg_write(NS8250_IER_OFFSET, 0x00); + /* DTR RTS */ + ns8250_reg_write(NS8250_MCR_OFFSET, NS8250_MCR_SET); + + ns8250_reg_write(NS8250_FCR_OFFSET, NS8250_FCR_DEFVAL); + /* Set baud rate */ + ns8250_set_baudrate(ns8250_divisor); + +} + +void ns8250_console_init(const void *dtb) +{ + int offset, len, val; + __u64 naddr, nsize, reg_uart_base; + const __u64 *regs; + + if (unlikely((offset = fdt_path_offset_namelen(dtb, + earlycon_node_name, strlen(earlycon_node_name))) < 0)) { + UK_CRASH("No console UART found!\n"); + } + + val = fdt_get_address(dtb, offset, 0, &naddr, &nsize); + if (val < 0) + UK_CRASH("Could not find proper address!\n"); + + reg_uart_base = naddr; + + regs = fdt_getprop(dtb, offset, "reg-shift", &len); + if (regs) + ns8250_reg_shift = EXTRACT_HIGH_BITS(*regs); + + regs = fdt_getprop(dtb, offset, "reg-io-width", &len); + if (regs) + ns8250_reg_width = EXTRACT_HIGH_BITS(*regs); + + init_ns8250(reg_uart_base); + + uk_pr_info("EARLYCON UART initialized\n"); +} + +int ukplat_coutd(const char *str, unsigned int len) +{ + return ukplat_coutk(str, len); +} + +static void _putc(char a) +{ + /* Wait until TX FIFO becomes empty */ + while (!(ns8250_reg_read(NS8250_LSR_OFFSET) & NS8250_LSR_TX_EMPTY)) + ; + + /* Reset DLAB and write to THR */ + ns8250_reg_write(NS8250_LCR_OFFSET, + ns8250_reg_read(NS8250_LCR_OFFSET) & + ~(NS8250_LCR_DLAB)); + ns8250_reg_write(NS8250_THR_OFFSET, a & 0xff); +} + +static void ns8250_putc(char a) +{ + if (a == '\n') + _putc('\r'); + _putc(a); +} + +/* Try to get data from ns16550 UART without blocking */ +static int ns8250_getc(void) +{ + /* If RX FIFO is empty, return -1 immediately */ + if (!(ns8250_reg_read(NS8250_LSR_OFFSET) & NS8250_LSR_RX_EMPTY)) + return -1; + + /* Reset DLAB and read from RBR */ + ns8250_reg_write(NS8250_LCR_OFFSET, + ns8250_reg_read(NS8250_LCR_OFFSET) & + ~(NS8250_LCR_DLAB)); + return (int)(ns8250_reg_read(NS8250_RBR_OFFSET) & 0xff); +} + +int ukplat_coutk(const char *buf, unsigned int len) +{ + /* + * Avoid using the UART before base address initialized, or + * if CONFIG_LIBTNTTY_NS8250_EARLY_CONSOLE_BASE is not enabled. + */ + if (!ns8250_uart_initialized) + return -1; + + for (unsigned int i = 0; i < len; i++) + ns8250_putc(buf[i]); + return len; +} + +int ukplat_cink(char *buf, unsigned int maxlen) +{ + int ret; + unsigned int num = 0; + + /* + * Avoid using the UART before base address initialized, or + * if CONFIG_LIBTNTTY_NS8250_EARLY_CONSOLE_BASE is not enabled. + */ + if (!ns8250_uart_initialized) + return -1; + + while (num < maxlen && (ret = ns8250_getc()) >= 0) { + *(buf++) = (char)ret; + num++; + } + + return (int)num; +} -- Gitee From 401c421653f249da089fb8c3c7e9151f64623e0b Mon Sep 17 00:00:00 2001 From: Yifan Zhang Date: Tue, 9 Apr 2024 15:31:46 +0800 Subject: [PATCH 14/35] lib/tntimer:add tntimer module and adpation for systick --- lib/Makefile.uk | 1 + lib/tnsystick/include/tn/systick.h | 6 + lib/tnsystick/tnsystick.c | 6 +- lib/tntimer/Config.uk | 12 ++ lib/tntimer/Makefile.uk | 14 ++ lib/tntimer/exportsyms.uk | 7 + lib/tntimer/include/tn/tntimer.h | 141 ++++++++++++++++++ lib/tntimer/tests/internal_timer.h | 29 ++++ lib/tntimer/tests/test_tntimer.c | 224 +++++++++++++++++++++++++++++ lib/tntimer/tntimer.c | 189 ++++++++++++++++++++++++ lib/ukboot/boot.c | 10 +- 11 files changed, 629 insertions(+), 10 deletions(-) create mode 100644 lib/tntimer/Config.uk create mode 100644 lib/tntimer/Makefile.uk create mode 100644 lib/tntimer/exportsyms.uk create mode 100644 lib/tntimer/include/tn/tntimer.h create mode 100644 lib/tntimer/tests/internal_timer.h create mode 100644 lib/tntimer/tests/test_tntimer.c create mode 100644 lib/tntimer/tntimer.c diff --git a/lib/Makefile.uk b/lib/Makefile.uk index 4be259c1..0c97ada0 100644 --- a/lib/Makefile.uk +++ b/lib/Makefile.uk @@ -71,3 +71,4 @@ $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukrust)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukreloc)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukofw)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tnsystick)) +$(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tntimer)) diff --git a/lib/tnsystick/include/tn/systick.h b/lib/tnsystick/include/tn/systick.h index 3f6a9ba9..d2291e6e 100644 --- a/lib/tnsystick/include/tn/systick.h +++ b/lib/tnsystick/include/tn/systick.h @@ -19,6 +19,12 @@ #include #include + /**< Maximum number of UINT32 */ +#define TICK_UINT32_MAX 0xffffffff + /**< Maximum number of UINT64 */ +#define TICK_UINT64_MAX 0xffffffffffffffff +#define TICK_MAX TICK_UINT64_MAX + typedef uint64_t systick_t; /* sysclock oprations */ diff --git a/lib/tnsystick/tnsystick.c b/lib/tnsystick/tnsystick.c index 315914b9..80cf4424 100644 --- a/lib/tnsystick/tnsystick.c +++ b/lib/tnsystick/tnsystick.c @@ -100,14 +100,14 @@ int sys_timer_irq_handler(void *arg __unused) #ifndef CONFIG_LIBTNSYSTICK_TICKLESS sysclock.ops->set_next(tot_counts_per_tick, 0); #endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ - /* 2、todo :expired timer functions */ + tn_timer_announce(); /* 3、todo :schedprio to check timeout threads */ /* 4、set next time-base irq */ #ifdef CONFIG_LIBTNSYSTICK_TICKLESS - uint64_t timeout; + systick_t timeout; - timeout = get_current_smallest_timeout(); + timeout = tn_timer_next_tick(); sysclock.ops->set_next(ticks_to_counts(timeout), 0); #endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ __uk_test_and_clear_bit(0, &sched_have_pending_events); diff --git a/lib/tntimer/Config.uk b/lib/tntimer/Config.uk new file mode 100644 index 00000000..df7c278c --- /dev/null +++ b/lib/tntimer/Config.uk @@ -0,0 +1,12 @@ +menuconfig LIBTNTIMER + bool "timer: Kernel timer configuration" + depends on HAVE_SYSTICK + default n + + +if LIBTNTIMER + config LIBTNTIMER_TEST + bool "Enable unit tests" + default n + select LIBUKTEST +endif diff --git a/lib/tntimer/Makefile.uk b/lib/tntimer/Makefile.uk new file mode 100644 index 00000000..8e001a7d --- /dev/null +++ b/lib/tntimer/Makefile.uk @@ -0,0 +1,14 @@ +$(eval $(call addlib_s,libtntimer,$(CONFIG_LIBTNTIMER))) + +ASINCLUDES-$(CONFIG_LIBTNTIMER) += -I$(LIBTNTIMER_BASE)/include +CINCLUDES-$(CONFIG_LIBTNTIMER) += -I$(LIBTNTIMER_BASE)/include +CXXINCLUDES-$(CONFIG_LIBTNTIMER) += -I$(LIBTNTIMER_BASE)/include +LIBTNTIMER_ASINCLUDES-y += -I$(UK_PLAT_COMMON_BASE)/include +LIBTNTIMER_CINCLUDES-y += -I$(UK_PLAT_COMMON_BASE)/include + +LIBTNTIMER_SRCS-$(CONFIG_LIBTNTIMER) += $(LIBTNTIMER_BASE)/tntimer.c + + +ifneq ($(filter y,$(CONFIG_LIBTNTIMER_TEST) $(CONFIG_LIBUKTEST_ALL)),) +LIBTNTIMER_SRCS-y += $(LIBTNTIMER_BASE)/tests/test_tntimer.c +endif diff --git a/lib/tntimer/exportsyms.uk b/lib/tntimer/exportsyms.uk new file mode 100644 index 00000000..6d3652ac --- /dev/null +++ b/lib/tntimer/exportsyms.uk @@ -0,0 +1,7 @@ +tn_timer_create +tn_timer_start +tn_timer_delete +tn_timer_init +tn_timer_add +tn_timer_next_tick +tn_timer_announce \ No newline at end of file diff --git a/lib/tntimer/include/tn/tntimer.h b/lib/tntimer/include/tn/tntimer.h new file mode 100644 index 00000000..2e22a3dd --- /dev/null +++ b/lib/tntimer/include/tn/tntimer.h @@ -0,0 +1,141 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TN_TIMER_H__ +#define __TN_TIMER_H__ + +#include +#include +#include + + +#define TN_TIMER_FLAG_PERIODIC 0x01 +#define TN_TIMER_FLAG_ONE_SHOT 0x02 + + + +struct timer { + /*List node which contains pointers for traversing prev and next*/ + struct uk_list_head list; + + /* + * The relative difference in timeout occurs. + * The tick passed as a parameter when the external component is + * invoked for creation will modify this value + */ + systick_t init_tick; + /* + * an absolute time and is not subject to external modification; + * it can only be altered during 'start' (added to the list). + */ + systick_t timeout_tick; + /* + * Timeout callback function. + * When this timeout expires, this function will be executed. + */ + void (*timeout_func)(void *parameter); + /*Parameters of the timeout callback function.*/ + void *parameter; + /*Timer flag*/ + unsigned long flag; +}; + +/** + * tn_timer_create - Creates a new timer object. + * + * @param init_tick The initial tick count for the timer. + * @param timeout_func: The function to be called upon timer timeout. + * @param parameter: The parameter to be passed to the timeout function. + * @param flag Timer flags (e.g., periodic or one-shot). + * @return timer a pointer to the newly created timer + * Allocates memory for a new timer and initializes its members. + * Returns a pointer to the newly created timer or NULL + * if memory allocation fails. + */ +struct timer *tn_timer_create( + systick_t init_tick, + void (*timeout_func)(void *parameter), + void *parameter, + unsigned long flag); + + +/** + * tn_timer_start - Starts a timer and schedules it in the active timer list. + * @param t: The timer object to start. + * + * Calculates the timeout tick based on the current systick + * value and the timer's initial tick.Adds the timer to the appropriate + * list based on whether an overflow has occurred. + */ +void tn_timer_start(struct timer *timer); + + +/** + * tn_timer_delete - Removes a timer from the active timer list. + * @param t: The timer object to be removed. + * + * Removes the specified timer from the list and handles cleanup if necessary. + */ +void tn_timer_delete(struct timer *timer); + +/** + * tn_timer_init - Initializes a timer object. + * @param t The timer object to initialize. + * @param init_tick: The initial tick count for the timer. + * @param timeout_func: The function to be called upon timer timeout. + * @param parameter: The parameter to be passed to the timeout function. + * @param flag: Timer flags (e.g., periodic or one-shot). + * + * Initializes the members of a timer object. + */ +void tn_timer_init( + struct timer *t, + systick_t init_tick, + void (*timeout_func)(void *parameter), + void *parameter, + unsigned long flag); + +/** + * tn_timer_add - Adds a timer to the specified list based on its timeout tick. + * @param in: The timer object to be added. + * @param head: The list head where the timer will be added. + * + * Iterates through the specified list and inserts + * the timer in the correct position + * based on its timeout tick value. + */ +void tn_timer_add(struct timer *in, struct uk_list_head *head); + +/* + * tn_timer_next_tick - Retrieves the tick value of the soonest expiring timer. + * + * Returns the tick value of the soonest expiring timer or + * TICK_MAX if no timers are active. + */ +systick_t tn_timer_next_tick(void); + + +/* + * tn_timer_announce - Handles timer timeouts and executes associated functions. + * + * Retrieves the current systick value and iterates through + * the active timer list.For each timer with a timeout tick + * less than or equal to the current systick,the associated + * timeout function is called, and the timer is removed from the list. + * If the timer is periodic, it is restarted. + */ +void tn_timer_announce(void); + +#endif /* __TN_TIMER_H__ */ diff --git a/lib/tntimer/tests/internal_timer.h b/lib/tntimer/tests/internal_timer.h new file mode 100644 index 00000000..c63817e8 --- /dev/null +++ b/lib/tntimer/tests/internal_timer.h @@ -0,0 +1,29 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TN_INTERNAL_TIMER_H__ +#define __TN_INTERNAL_TIMER_H__ + +void tn_timer_list_switch(void); + +struct uk_list_head *tn_timer_get_overflow_list(void); + +/* + * tn_timer_get_list - Retrieves the global timer list. + * + * Returns a pointer to the head of the timer list. + */ +struct uk_list_head *tn_timer_get_list(void); +#endif /* __TN_INTERNAL_TIMER_H__ */ diff --git a/lib/tntimer/tests/test_tntimer.c b/lib/tntimer/tests/test_tntimer.c new file mode 100644 index 00000000..475d7852 --- /dev/null +++ b/lib/tntimer/tests/test_tntimer.c @@ -0,0 +1,224 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "internal_timer.h" + +#define pr_info(fmt, ...) \ + _uk_printk(KLVL_INFO, __NULL, __NULL, 0x0, fmt, ##__VA_ARGS__) + + +int excution; + +void timeout_func1(void *parameter) +{ + pr_info("timeout func1\n"); +} + +void timeout_func3(void *parameter) +{ + pr_info("timeout func3\n"); +} + +void timeout_func2(void *parameter) +{ + excution++; +} + +void dump_timer(void) +{ + struct timer *node; + struct uk_list_head *timer_list_head; + + timer_list_head = tn_timer_get_list(); + UK_ASSERT(timer_list_head != NULL); + uk_list_for_each_entry(node, timer_list_head, list) { + pr_info("node timeout is %x,flag is %d\n", + node->timeout_tick, node->flag); + }; +} + + + +UK_TESTCASE(tntimer, test_tn_timer_list_operations) +{ + systick_t t1 = 0x100000; + systick_t t2 = 0x200000; + systick_t t3 = 0x300000; + systick_t t4 = 0x260000; + systick_t t5 = 0x50000; + + systick_t cur = tn_systick_get_tick(); + struct timer *temp; + + struct timer *timer1 = tn_timer_create( + t1, *timeout_func1, NULL, TN_TIMER_FLAG_PERIODIC); + + + struct timer *timer2 = tn_timer_create( + t2, *timeout_func1, NULL, TN_TIMER_FLAG_ONE_SHOT); + struct timer *timer3 = tn_timer_create( + t3, *timeout_func1, NULL, TN_TIMER_FLAG_ONE_SHOT); + struct timer *timer4 = tn_timer_create( + t4, *timeout_func1, NULL, TN_TIMER_FLAG_ONE_SHOT); + struct timer *timer5 = tn_timer_create( + t5, *timeout_func1, NULL, TN_TIMER_FLAG_ONE_SHOT); + + UK_TEST_EXPECT_NOT_NULL(timer1); + UK_TEST_EXPECT_NOT_NULL(timer2); + UK_TEST_EXPECT_NOT_NULL(timer3); + UK_TEST_EXPECT_NOT_NULL(timer4); + + tn_timer_init(timer1, t1, *timeout_func1, NULL, TN_TIMER_FLAG_ONE_SHOT); + UK_TEST_EXPECT(timer1->flag == TN_TIMER_FLAG_ONE_SHOT); + + tn_timer_start(timer1); + tn_timer_start(timer2); + tn_timer_start(timer3); + tn_timer_start(timer4); + tn_timer_start(timer5); + + struct timer *node; + struct uk_list_head *timer_list_head = tn_timer_get_list(); + + dump_timer(); + + tn_timer_delete(timer2); + dump_timer(); + timer2 = tn_timer_create( + t2, *timeout_func1, NULL, TN_TIMER_FLAG_ONE_SHOT); + + systick_t last_tick = tn_timer_next_tick() + cur; + + tn_timer_start(timer2); + dump_timer(); + + temp = uk_list_first_entry_or_null(timer_list_head, struct timer, list); + UK_TEST_EXPECT_NOT_NULL(temp); + UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick, 10); + tn_timer_delete(temp); + + temp = uk_list_first_entry_or_null(timer_list_head, struct timer, list); + UK_TEST_EXPECT_NOT_NULL(temp); + UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick-0xB0000, + 10); + tn_timer_delete(temp); + + temp = uk_list_first_entry_or_null(timer_list_head, struct timer, list); + UK_TEST_EXPECT_NOT_NULL(temp); + UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick - 0x1B0000, + 10); + tn_timer_delete(temp); + + + temp = uk_list_first_entry_or_null(timer_list_head, struct timer, list); + UK_TEST_EXPECT_NOT_NULL(temp); + UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick - 0x210000, + 10); + tn_timer_delete(temp); + + temp = uk_list_first_entry_or_null(timer_list_head, struct timer, list); + UK_TEST_EXPECT_NOT_NULL(temp); + UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick - 0x2B0000, + 10); + tn_timer_delete(temp); + + UK_INIT_LIST_HEAD(tn_timer_get_list()); + +} + + + +UK_TESTCASE(tntimer, test_tn_timer_announce) +{ + systick_t t1 = 100; + systick_t t2 = 200; + systick_t t3 = 200; + systick_t t4 = 300; + systick_t t5 = 302; + + systick_t cur = tn_systick_get_tick(); + + struct timer *node; + struct uk_list_head *timer_list_head = tn_timer_get_list(); + + struct timer *timer1 = tn_timer_create( + t1, *timeout_func2, NULL, TN_TIMER_FLAG_ONE_SHOT); + struct timer *timer2 = tn_timer_create( + t2, *timeout_func2, NULL, TN_TIMER_FLAG_ONE_SHOT); + struct timer *timer3 = tn_timer_create( + t3, *timeout_func2, NULL, TN_TIMER_FLAG_ONE_SHOT); + struct timer *timer4 = tn_timer_create( + t4, *timeout_func2, NULL, TN_TIMER_FLAG_ONE_SHOT); + struct timer *timer5 = tn_timer_create( + t5, *timeout_func2, NULL, TN_TIMER_FLAG_ONE_SHOT); + + UK_TEST_EXPECT_NOT_NULL(timer1); + UK_TEST_EXPECT_NOT_NULL(timer2); + UK_TEST_EXPECT_NOT_NULL(timer3); + + tn_timer_start(timer1); + tn_timer_start(timer2); + tn_timer_start(timer3); + tn_timer_start(timer4); + tn_timer_start(timer5); + + while (excution < 1) { + asm volatile("" ::: "memory"); + /* + *do nothing,wait for timeout func + */ + } + UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 100, 10); + while (excution < 2) { + asm volatile("" ::: "memory"); + /* + *do nothing,wait for timeout func + */ + } + UK_TEST_EXPECT_SNUM_EQ(excution, 3); + UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 200, 10); + while (excution < 4) { + asm volatile("" ::: "memory"); + /* + *do nothing,wait for timeout func + */ + } + UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 300, 10); + while (excution < 5) { + asm volatile("" ::: "memory"); + /* + *do nothing,wait for timeout func + */ + } + UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 302, 10); + dump_timer(); + UK_TEST_EXPECT_SNUM_EQ(excution, 5); + + UK_INIT_LIST_HEAD(tn_timer_get_list()); + +} + + +uk_testsuite_register(tntimer, NULL); diff --git a/lib/tntimer/tntimer.c b/lib/tntimer/tntimer.c new file mode 100644 index 00000000..64446c33 --- /dev/null +++ b/lib/tntimer/tntimer.c @@ -0,0 +1,189 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ssANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include + +static UK_LIST_HEAD(timer_list_head); +static UK_LIST_HEAD(overflow_timer_list_head); +static uint8_t timoutListsOverflowed; + +static systick_t last_tick; +/* + * tn_timer_get_list - Retrieves the global timer list. + * + * Returns a pointer to the head of the timer list. + */ +struct uk_list_head *tn_timer_get_list(void) +{ + return &timer_list_head; +} + +struct uk_list_head *tn_timer_get_overflow_list(void) +{ + return &overflow_timer_list_head; +} + +struct timer *tn_timer_create(systick_t init_tick, + void (*timeout_func)(void *parameter), + void *parameter, unsigned long flag) +{ + struct timer *t; + + t = uk_malloc(uk_alloc_get_default(), sizeof(struct timer)); + if (!t) + return NULL; + + t->timeout_func = timeout_func; + t->parameter = parameter; + t->init_tick = init_tick; + t->flag = flag; + + return t; +} + +void tn_timer_init(struct timer *t, systick_t init_tick, + void (*timeout_func)(void *parameter), void *parameter, + unsigned long flag) +{ + UK_ASSERT(t); + + t->timeout_func = timeout_func; + t->parameter = parameter; + t->init_tick = init_tick; + t->flag = flag; +} + +systick_t tn_timer_next_tick(void) +{ + struct timer *t; + systick_t cur; + + cur = tn_systick_get_tick(); + + t = uk_list_first_entry_or_null(&timer_list_head, struct timer, list); + if (t) + return t->timeout_tick - cur; + if (timoutListsOverflowed) { + t = uk_list_first_entry(&overflow_timer_list_head, struct timer, + list); + return t->timeout_tick - cur; + } + + return TICK_MAX; +} + +void tn_timer_delete(struct timer *t) +{ + UK_ASSERT(t); + + uk_list_del(&t->list); + if (timoutListsOverflowed && uk_list_empty(&timer_list_head)) + tn_timer_list_switch(); +} + +/* + * tn_timer_list_switch + * Handles timer list overflow by switching the active list. + * + * This function is called when the timer list has overflowed + * and needs to switch to the overflow list to maintain + * correct ordering of timers. + */ +void tn_timer_list_switch(void) +{ + struct uk_list_head *temp; + + UK_ASSERT(!uk_list_empty(&overflow_timer_list_head)); + + timer_list_head.next = overflow_timer_list_head.next; + overflow_timer_list_head.next->prev = &timer_list_head; + UK_INIT_LIST_HEAD(&overflow_timer_list_head); + timoutListsOverflowed = 0; +} + +void tn_timer_start(struct timer *t) +{ + systick_t cur; + systick_t sum; + + cur = tn_systick_get_tick(); + sum = cur + t->init_tick; + t->timeout_tick = sum; + if (sum < cur || sum < t->init_tick) { + // 发生了溢出 + tn_timer_add(t, &overflow_timer_list_head); + timoutListsOverflowed = 1; + } else { + tn_timer_add(t, &timer_list_head); + } + last_tick = cur; +} + +void tn_timer_add(struct timer *in, struct uk_list_head *head) +{ + struct timer *node; + struct timer *t; + + uk_list_for_each_entry(t, head, list) { + if (t->timeout_tick <= in->timeout_tick) + continue; + + uk_list_add(&(in)->list, t->list.prev); + return; + } + uk_list_add_tail(&in->list, head); +} + +void tn_timer_announce(void) +{ + struct timer *t; + systick_t cur; + + cur = tn_systick_get_tick(); + + //current tick overflowed,clean the first list + if (cur < last_tick) { + while (!uk_list_empty(&timer_list_head)) { + t = uk_list_first_entry( + &timer_list_head, struct timer, list); + + uk_list_del(&t->list); + t->timeout_func(t->parameter); + if (t->flag & TN_TIMER_FLAG_PERIODIC) + tn_timer_start(t); + } + if (uk_list_empty(&timer_list_head) && timoutListsOverflowed) + tn_timer_list_switch(); + } + + + + while (!uk_list_empty(&timer_list_head)) { + t = uk_list_first_entry( + &timer_list_head, struct timer, list); + if (t->timeout_tick <= cur) { + uk_list_del(&t->list); + t->timeout_func(t->parameter); + if (t->flag & TN_TIMER_FLAG_PERIODIC) + tn_timer_start(t); + } else{ + break; + } + } + + last_tick = cur; +} diff --git a/lib/ukboot/boot.c b/lib/ukboot/boot.c index 81b53d56..bf422786 100644 --- a/lib/ukboot/boot.c +++ b/lib/ukboot/boot.c @@ -385,6 +385,9 @@ void ukplat_entry(int argc, char *argv[]) /* Enable interrupts before starting the application */ ukplat_lcpu_enable_irq(); +#if CONFIG_HAVE_SYSTICK + tn_systick_start(); +#endif /* CONFIG_HAVE_SYSTICK */ /** * Run init table */ @@ -518,13 +521,6 @@ static inline int do_main(int argc, char *argv[]) uk_pr_info("])\n"); #endif /* CONFIG_LIBUKDEBUG_PRINTK_INFO */ -#if CONFIG_HAVE_SYSTICK - tn_systick_start(); -#endif /* CONFIG_HAVE_SYSTICK */ - -#if CONFIG_HAVE_SYSTICK - tn_systick_start(); -#endif /* CONFIG_HAVE_SYSTICK */ ret = main(argc, argv); uk_pr_info("main returned %d\n", ret); -- Gitee From c4d20bbcf67023f72a5f74fc1324a4b677d33b1b Mon Sep 17 00:00:00 2001 From: cheng2000160 Date: Mon, 11 Mar 2024 15:21:15 +0800 Subject: [PATCH 15/35] lib/ukintctlr: add APIs intended for setting irq priority and affinity, ukintctlr drivers modified to match Signed-off-by: cheng2000160 --- .../ukintctlr/bcm_intc/bcm_intc_initialize.c | 11 +- drivers/ukintctlr/gic/Config.uk | 33 ++- drivers/ukintctlr/gic/gic-v2.c | 9 +- drivers/ukintctlr/gic/gic-v3.c | 242 ++++++++++++---- .../ukintctlr/gic/include/uk/intctlr/gic-v3.h | 51 +++- .../ukintctlr/gic/include/uk/intctlr/gic.h | 31 +- drivers/ukintctlr/gic/ukintctlr.c | 11 +- drivers/ukintctlr/xpic/ukintctlr.c | 12 +- drivers/virtio/mmio/virtio_mmio.c | 2 +- lib/ukintctlr/exportsyms.uk | 17 +- lib/ukintctlr/include/uk/intctlr.h | 121 +++++++- lib/ukintctlr/tests/test_intctlr.c | 268 +++++++----------- lib/ukintctlr/ukintctlr.c | 58 +++- plat/Config.uk | 7 + plat/common/arm/lcpu.c | 6 +- plat/common/arm/time.c | 2 +- plat/drivers/rtc/pl031.c | 2 +- plat/kvm/Config.uk | 1 + 18 files changed, 612 insertions(+), 272 deletions(-) diff --git a/drivers/ukintctlr/bcm_intc/bcm_intc_initialize.c b/drivers/ukintctlr/bcm_intc/bcm_intc_initialize.c index 4ed040cd..aea8b71d 100644 --- a/drivers/ukintctlr/bcm_intc/bcm_intc_initialize.c +++ b/drivers/ukintctlr/bcm_intc/bcm_intc_initialize.c @@ -69,7 +69,7 @@ static int fdt_xlat(const void *fdt, int nodeoffset, __u32 index, #endif /* CONFIG_LIBUKOFW */ /* 根据设备树参数来设置中断属性 */ -static int configure_irq(struct uk_intctlr_irq *irq) +static int irq_set_trigger(struct uk_intctlr_irq *irq) { if (irq->trigger != UK_INTCTLR_IRQ_TRIGGER_NONE) /* 调用函数配置irq_trigger */ @@ -101,10 +101,17 @@ init: intctlr.name = "BCM-INTC"; ops.initialize = bcm_intc->ops.initialize; ops.percpu_init = __NULL; - ops.configure_irq = configure_irq; + ops.irq_set_trigger = irq_set_trigger; ops.mask_irq = bcm_intc->ops.disable_irq; ops.unmask_irq = bcm_intc->ops.enable_irq; ops.handle = bcm_intc->ops.handle_irq; + ops.irq_set_affinity = __NULL; + ops.irq_set_priority = __NULL; +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) + ops.irq_get_priority = __NULL; + ops.spi_get_affinity = __NULL; + ops.simulate_spi = __NULL; +#endif /* reserved for software general interrupt to specified core */ ops.sgi_op = __NULL; #if CONFIG_LIBUKOFW diff --git a/drivers/ukintctlr/gic/Config.uk b/drivers/ukintctlr/gic/Config.uk index a62ae038..331fc6d1 100644 --- a/drivers/ukintctlr/gic/Config.uk +++ b/drivers/ukintctlr/gic/Config.uk @@ -7,7 +7,38 @@ config LIBUKINTCTLR_GICV2 depends on (HAVE_INTCTLR && ARCH_ARM_64) select LIBUKINTCTLR_GIC -config LIBUKINTCTLR_GICV3 +menuconfig LIBUKINTCTLR_GICV3 bool "Arm Generic Interrupt Controller (GICv3)" depends on (HAVE_INTCTLR && ARCH_ARM_64) select LIBUKINTCTLR_GIC + default n + +if LIBUKINTCTLR_GICV3 +choice + prompt "GICV3 max priority level" + help + Numbers of interrupt priorities supported in non-secure mode + choose from 16/32/64/128 + +config PRIORITY_MAX_16 + bool "16 non-secure priority levels" + help + The available interrupt priority is [0..15] + +config PRIORITY_MAX_32 + bool "32 non-secure priority levels" + help + The available interrupt priority is [0..31] + +config PRIORITY_MAX_64 + bool "64 non-secure priority levels" + help + The available interrupt priority is [0..63] + +config PRIORITY_MAX_128 + bool "128 non-secure priority levels" + help + The available interrupt priority is [0..127] + +endchoice +endif diff --git a/drivers/ukintctlr/gic/gic-v2.c b/drivers/ukintctlr/gic/gic-v2.c index e6278e76..74543aec 100644 --- a/drivers/ukintctlr/gic/gic-v2.c +++ b/drivers/ukintctlr/gic/gic-v2.c @@ -210,9 +210,11 @@ void gicv2_sgi_gen_to_list(uint32_t sgintid, uint8_t targetlist) /** * Forward the SGI to the CPU specified by cpuid. */ -static void gicv2_sgi_gen_to_cpu(uint8_t sgintid, uint32_t cpuid) +static int gicv2_sgi_gen_to_cpu(uint8_t sgintid, uint32_t cpuid, + va_list cpuid_args __unused) { gicv2_sgi_gen_to_list((uint32_t) sgintid, (uint8_t) (1 << (cpuid % 8))); + return 0; } /** @@ -507,6 +509,11 @@ static void gicv2_set_ops(void) .disable_irq = gicv2_disable_irq, .set_irq_trigger = gicv2_set_irq_trigger, .set_irq_prio = gicv2_set_irq_prio, +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) + .get_irq_prio = NULL, + .simulate_spi = NULL, + .get_spi_affinity = NULL, +#endif .set_irq_affinity = gicv2_set_irq_target, .handle_irq = gicv2_handle_irq, .gic_sgi_gen = gicv2_sgi_gen_to_cpu, diff --git a/drivers/ukintctlr/gic/gic-v3.c b/drivers/ukintctlr/gic/gic-v3.c index 7dc092cc..8533a1b5 100644 --- a/drivers/ukintctlr/gic/gic-v3.c +++ b/drivers/ukintctlr/gic/gic-v3.c @@ -111,6 +111,11 @@ static inline void write_gicd64(uint64_t offset, uint64_t val) ioreg_write64(GIC_DIST_REG(gicv3_drv, offset), val); } +static inline uint64_t read_gicd64(uint64_t offset) +{ + return ioreg_read64(GIC_DIST_REG(gicv3_drv, offset)); +} + static inline uint32_t read_gicd32(uint64_t offset) { return ioreg_read32(GIC_DIST_REG(gicv3_drv, offset)); @@ -126,6 +131,16 @@ static inline uint32_t read_gicrd32(uint64_t offset) return ioreg_read32(GIC_RDIST_REG(gicv3_drv, offset)); } +static inline uint32_t read_gicd8(uint64_t offset) +{ + return ioreg_read8(GIC_DIST_REG(gicv3_drv, offset)); +} + +static inline uint32_t read_gicrd8(uint64_t offset) +{ + return ioreg_read8(GIC_RDIST_REG(gicv3_drv, offset)); +} + /** * Wait for a write completion in [re]distributor * @@ -160,6 +175,26 @@ static uint32_t get_cpu_affinity(void) } #endif /* CONFIG_HAVE_SMP */ +/** + * Affinitize all SPI interrupts to the current cpu + * + * @param irq_number SPI interrupt number + */ +static void affinitize_all_spi_to_current_cpu(uint32_t irq_number) +{ + uint32_t i; + uint64_t mpidr = SYSREG_READ64(MPIDR_EL1); + uint64_t aff = ((mpidr & MPIDR_AFF3_MASK) >> 8) | + (mpidr & MPIDR_AFF2_MASK) | + (mpidr & MPIDR_AFF1_MASK) | + (mpidr & MPIDR_AFF0_MASK); + /* Route all global SPIs to this CPU */ + uint64_t irouter_val = GIC_AFF_TO_ROUTER(aff, 0); + + for (i = GIC_SPI_BASE; i < irq_number; i++) + write_gicd64(GICD_IROUTER(i), irouter_val); +} + /** * Acknowledge IRQ and retrieve highest priority pending interrupt * @@ -175,6 +210,59 @@ static uint32_t gicv3_ack_irq(void) return irq; } +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) +/** + * Set pending bit to simulate specified SPI being triggered + */ +static void gicv3_simulate_spi(uint32_t irq) +{ + UK_ASSERT(irq >= GIC_SPI_BASE && irq <= GIC_MAX_IRQ); + uint32_t pending_offset; + + pending_offset = GICD_ISPENDR(irq); + dist_lock(gicv3_drv); + write_gicd32(pending_offset, 1UL << (irq % 32)); + dist_unlock(gicv3_drv); +} + +/** + * Get the interrupt priority level in non-secure mode + * @param irq irq to get priority information + * @return priority level of irq + */ +static uint8_t gicv3_get_irq_prio(uint32_t irq) +{ + uint8_t prio_level; + + dist_lock(gicv3_drv); + if (irq < GIC_SPI_BASE) /* Change in redistributor */ + prio_level = + read_gicrd8(GICR_IPRIORITYR(irq)); + else + prio_level = + read_gicd8(GICD_IPRIORITYR(irq)); + dist_unlock(gicv3_drv); + return prio_level; +} + +/** + * Get the spi affinity stats + * @param irq irq to get affinity information + * @return affinity information of irq + */ +static uint32_t gicv3_get_spi_affinity(uint32_t irq) +{ + UK_ASSERT(irq >= GIC_SPI_BASE && irq <= GIC_MAX_IRQ); + dist_lock(gicv3_drv); + uint64_t router_value = read_gicd64(GICD_IROUTER(irq)); + + uint32_t aff = (uint32_t)((router_value >> 8) & 0xFFFFFF); + + dist_unlock(gicv3_drv); + return aff; +} +#endif /* CONFIG_LIBUKINTCTLR_TEST || CONFIG_LIBUKTEST_ALL */ + /** * Signal completion of interrupt processing * @@ -186,10 +274,11 @@ static void gicv3_eoi_irq(uint32_t irq) /* Lower the priority */ SYSREG_WRITE32(ICC_EOIR1_EL1, irq); isb(); - +#ifdef CONFIG_VIRTUALIZE_PLAT /* Deactivate */ SYSREG_WRITE32(ICC_DIR_EL1, irq); isb(); +#endif } /** @@ -203,20 +292,6 @@ static void gicv3_enable_irq(uint32_t irq) dist_lock(gicv3_drv); -#ifdef CONFIG_HAVE_SMP - /* Route this IRQ to the running core, i.e., route to the CPU interface - * of the core calling this function - */ - if (irq >= GIC_SPI_BASE) { - uint64_t aff = (uint64_t)get_cpu_affinity(); - uint64_t irouter_val = GIC_AFF_TO_ROUTER(aff, 0); - - write_gicd64(GICD_IROUTER(irq), irouter_val); - uk_pr_debug("IRQ %d routed to 0x%lx (REG: 0x%lx)\n", - irq, aff, irouter_val); - } -#endif /* CONFIG_HAVE_SMP */ - if (irq >= GIC_SPI_BASE) write_gicd32(GICD_ISENABLER(irq), UK_BIT(irq % GICD_I_PER_ISENABLERn)); @@ -228,50 +303,87 @@ static void gicv3_enable_irq(uint32_t irq) } /** - * Send a software generated interrupt to the specified core. + * Send a software generated interrupt to the specified cores. * - * @sgintid the software generated interrupt id - * @cpuid the id of the targeted cpu + * @param sgintid the software generated interrupt id + * @param target_count the number of target cpus, + * zero means sending sgi to a11 PEs in the system except the current one. + * @param va_list argument list of cpuid, could be empty. type: uint32_t + * @return zero on success, negative value on failure */ -static void gicv3_sgi_gen(uint8_t sgintid, uint32_t cpuid) +static int gicv3_sgi_gen(uint8_t sgintid, + uint32_t target_count, va_list cpuid_args) { - uint64_t sgi_register = 0, control_register_rss, type_register_rss; + uint64_t sgi_register = 0, affinity_and_rs_checker = 0; + uint64_t control_register_rss, type_register_rss; uint64_t range_selector = 0, extended_cpuid; uint32_t aff0; - extended_cpuid = (uint64_t) cpuid; - /* Only INTID 0-15 allocated to sgi */ UK_ASSERT(sgintid <= GICD_SGI_MAX_INITID); + UK_ASSERT(target_count <= GICD_SGI_MAX_TARGETLIST); + sgi_register |= (sgintid << 24); - /* Set affinity fields and optional range selector */ - sgi_register |= (extended_cpuid & MPIDR_AFF3_MASK) << 48; - sgi_register |= (extended_cpuid & MPIDR_AFF2_MASK) << 32; - sgi_register |= (extended_cpuid & MPIDR_AFF1_MASK) << 16; - /** - ** For affinity 0, we need to find which group of 16 values is - ** represented by the TargetList field in ICC_SGI1R_EL1. - **/ - aff0 = extended_cpuid & MPIDR_AFF0_MASK; - if (aff0 >= 16) { - control_register_rss = SYSREG_READ64(ICC_CTLR_EL1) & (1 << 18); - type_register_rss = read_gicd32(GICD_TYPER) & (1 << 26); - if (control_register_rss == 1 && type_register_rss == 1) { - range_selector = aff0 / 16; - sgi_register |= (range_selector << 44); - } else { - uk_pr_err("Can't generate interrupt!\n"); - return; - } + if (!target_count) { + sgi_register |= ICC_SGI1R_EL1_IRM_ALL; + dist_lock(gicv3_drv); + SYSREG_WRITE64(ICC_SGI1R_EL1, sgi_register); + dist_unlock(gicv3_drv); + return 0; } - sgi_register |= (1 << (aff0 % 16)); + control_register_rss = + SYSREG_READ64(ICC_CTLR_EL1) & (1 << 18); + type_register_rss = + read_gicd32(GICD_TYPER) & (1 << 26); + + uint8_t i; + + for (i = 0; i < target_count; i++) { + extended_cpuid = (uint64_t)va_arg(cpuid_args, uint32_t); + + /* Set affinity fields and optional range selector */ + sgi_register |= + (extended_cpuid & MPIDR_AFF3_MASK) << 48; + sgi_register |= + (extended_cpuid & MPIDR_AFF2_MASK) << 32; + sgi_register |= + (extended_cpuid & MPIDR_AFF1_MASK) << 16; + + aff0 = extended_cpuid & MPIDR_AFF0_MASK; + range_selector = aff0 / 16; + sgi_register |= ((1 << (aff0 % 16)) | (range_selector << 44)); + + if (i == 0) { + if (range_selector >= 1 && + (control_register_rss != 1 || type_register_rss != 1)) { + uk_pr_err( + "send sgi to target core(s) failed: \r\n" + "mismatch cpuid(0x%lx) and rs(GICD_TYPER.RS: %lu, ICC_CTLR.RS: %lu)\n" + , extended_cpuid, + type_register_rss, + control_register_rss); + return -1; + } + + affinity_and_rs_checker = sgi_register; + continue; + } + + if ((sgi_register & MPIDR_AFFx_AND_RS_MASK) + != (affinity_and_rs_checker & MPIDR_AFFx_AND_RS_MASK)) { + uk_pr_err("send sgi to target core(s) failed: \r\n" + "there are cores having different affinity or range selector\n"); + return -1; + } + } - /* Generate interrupt */ dist_lock(gicv3_drv); SYSREG_WRITE64(ICC_SGI1R_EL1, sgi_register); dist_unlock(gicv3_drv); + + return 0; } /** @@ -315,19 +427,21 @@ static void gicv3_set_irq_affinity(uint32_t irq, uint32_t affinity) * Set priority for an interrupt * * @param irq interrupt number [0..GIC_MAX_IRQ] - * @param priority priority [0..255]. The GIC implementation may not support - * all levels. For example, if only 128 levels are supported every two levels - * (e.g., 0 and 1) map to the same effective value. Lower values correspond - * to higher priority + * @param priority Available interrupt priority range in non-secure mode, + * Lower values correspond to higher priorities + * Refer to the gic documentation for more details. */ static void gicv3_set_irq_prio(uint32_t irq, uint8_t priority) { - dist_lock(gicv3_drv); + UK_ASSERT(priority < (1 << (8 - TRANS_PRIORITY_SHIFT))); + dist_lock(gicv3_drv); if (irq < GIC_SPI_BASE) /* Change in redistributor */ - write_gicrd8(GICR_IPRIORITYR(irq), priority); + write_gicrd8(GICR_IPRIORITYR(irq), + priority << TRANS_PRIORITY_SHIFT); else - write_gicd8(GICD_IPRIORITYR(irq), priority); + write_gicd8(GICD_IPRIORITYR(irq), + priority << TRANS_PRIORITY_SHIFT); dist_unlock(gicv3_drv); } @@ -440,8 +554,7 @@ static void gicv3_init_redist(void) /* Set priority mask register */ SYSREG_WRITE32(ICC_PMR_EL1, 0xff); - /* EOI drops priority, DIR deactivates the interrupt (mode 1) */ - SYSREG_WRITE32(ICC_CTLR_EL1, GICC_CTLR_EL1_EOImode_drop); + SYSREG_WRITE32(ICC_CTLR_EL1, ICC_CTLR_EL1_EOImode); /* Enable Group 1 interrupts */ SYSREG_WRITE32(ICC_IGRPEN1_EL1, 1); @@ -475,14 +588,18 @@ static void gicv3_init_dist(void) for (i = GIC_SPI_BASE; i < irq_number; i += GICD_I_PER_IGROUPRn) write_gicd32(GICD_IGROUPR(i), GICD_DEF_IGROUPRn); + /* Check for 1 of N SPI interrupts support */ + if (val & GICD_TYPE_NO1N_MASK) { + affinitize_all_spi_to_current_cpu(irq_number); + } else { #ifdef CONFIG_HAVE_SMP - /* Route all global SPIs to this CPU */ - uint64_t aff = (uint64_t)get_cpu_affinity(); - uint64_t irouter_val = GIC_AFF_TO_ROUTER(aff, 0); - - for (i = GIC_SPI_BASE; i < irq_number; i++) - write_gicd64(GICD_IROUTER(i), irouter_val); + for (i = GIC_SPI_BASE; i < irq_number; i++) + write_gicd64(GICD_IROUTER(i), + GIC_AFF_TO_ROUTER(0ULL, 1)); +#else + affinitize_all_spi_to_current_cpu(irq_number); #endif /* CONFIG_HAVE_SMP */ + } /* Set all SPI's interrupt type to be level-sensitive */ for (i = GIC_SPI_BASE; i < irq_number; i += GICD_I_PER_ICFGRn) @@ -557,14 +674,14 @@ static int gicv3_initialize(void) } #endif /* CONFIG_HAVE_SMP */ - gicv3_drv.is_initialized = 1; - /* Initialize GICv3 distributor */ gicv3_init_dist(); /* Initialize GICv3 CPU redistributor */ gicv3_init_redist(); + gicv3_drv.is_initialized = 1; + return 0; } @@ -581,6 +698,11 @@ static inline void gicv3_set_ops(void) .set_irq_affinity = gicv3_set_irq_affinity, .handle_irq = gicv3_handle_irq, .gic_sgi_gen = gicv3_sgi_gen, +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) + .get_irq_prio = gicv3_get_irq_prio, + .simulate_spi = gicv3_simulate_spi, + .get_spi_affinity = gicv3_get_spi_affinity, +#endif }; /* Set driver functions */ diff --git a/drivers/ukintctlr/gic/include/uk/intctlr/gic-v3.h b/drivers/ukintctlr/gic/include/uk/intctlr/gic-v3.h index 03380003..9f9e299b 100644 --- a/drivers/ukintctlr/gic/include/uk/intctlr/gic-v3.h +++ b/drivers/ukintctlr/gic/include/uk/intctlr/gic-v3.h @@ -48,6 +48,8 @@ #define MPIDR_AFF1_MASK 0x000000ff00 /** Affinity AFF0 bit mask */ #define MPIDR_AFF0_MASK 0x00000000ff +/** Affinity AFFx and range selector bit mask */ +#define MPIDR_AFFx_AND_RS_MASK 0xfffff0ffff00 /* * GIC System register assembly aliases @@ -62,10 +64,34 @@ #define ICC_SRE_EL1 S3_0_C12_C12_5 #define ICC_IGRPEN1_EL1 S3_0_C12_C12_7 +/* + * Set Group 1 SGIs routing mode + * ICC_SGI1R_EL1_IRM_ALL, SGI routed to all PEs, excluding "self". + * ICC_SGI1R_EL1_IRM, SGI routed to the PEs specified by Aff3.Aff2.Aff1. + */ +#define ICC_SGI1R_EL1_IRM_ALL (1UL << 40) +#define ICC_SGI1R_EL1_IRM (0UL << 40) + +/* + * ICC_CTLR_EL1_EOImode Controls + * whether a write to an End of Interrupt register + * also deactivates the interrupt + * ICC_CTLR_EL1_EOImode_drop provide priority drop functionality only + * ICC_CTLR_EL1_EOImode_drop_deactivation + * provide both priority drop and interrupt deactivation functionality + */ +#define ICC_CTLR_EL1_EOImode_drop (1U << 1) +#define ICC_CTLR_EL1_EOImode_drop_and_deactivation (0U << 1) + +#if defined CONFIG_VIRTUALIZE_PLAT +#define ICC_CTLR_EL1_EOImode ICC_CTLR_EL1_EOImode_drop +#else +#define ICC_CTLR_EL1_EOImode ICC_CTLR_EL1_EOImode_drop_and_deactivation +#endif + /* * Distributor and Redistributor registers */ -#define GICC_CTLR_EL1_EOImode_drop (1U << 1) /* Default size according to ARM Generic Interrupt Controller Architecture * Specification GIC Architecture version 3 and version 4 Issue H. @@ -80,6 +106,7 @@ #define GICD_IROUTER_BASE (0x6000) #define GICD_IROUTER32 (0x6100) #define GICD_IROUTER1019 (0x7FD8) +#define GICD_IROUTER_IRM (1UL << 31) #define GICD_PIDR2 (0xFFE8) #define GICD_CTLR_RWP (1UL << 31) @@ -98,6 +125,11 @@ ((((r) >> GICD_TYPE_ID_BITS_SHIFT) & 0x1f) + 1) #define GICD_TYPE_LPIS (1U << 17) +/* Indicates whether 1 of N SPI interrupts are supported. + * 0b0 1 of N SPI interrupts are supported. + * 0b1 1 of N SPI interrupts are not supported. + */ +#define GICD_TYPE_NO1N_MASK (1U << 25) #define GICR_WAKER_ProcessorSleep (1U << 1) #define GICR_WAKER_ChildrenAsleep (1U << 2) @@ -339,6 +371,7 @@ #define GICD_SGI_FILTER_SHIFT 24 #define GICD_SGI_FILTER_MASK 0x3 #define GICD_SGI_MAX_INITID 15 +#define GICD_SGI_MAX_TARGETLIST 16 #define GICD_PPI_START /* @@ -370,6 +403,22 @@ #define GICC_IAR_INTID_MASK 0x3FF #define GICC_IAR_INTID_SPURIOUS 1023 +/* + * Select the corresponding priority shift bit + * based on the number of interrupt priorities + */ +#if defined(CONFIG_PRIORITY_MAX_16) + #define TRANS_PRIORITY_SHIFT 4 +#elif defined(CONFIG_PRIORITY_MAX_32) + #define TRANS_PRIORITY_SHIFT 3 +#elif defined(CONFIG_PRIORITY_MAX_64) + #define TRANS_PRIORITY_SHIFT 2 +#elif defined(CONFIG_PRIORITY_MAX_128) + #define TRANS_PRIORITY_SHIFT 1 +#else + #define TRANS_PRIORITY_SHIFT 4 +#endif + /** * Probe device tree or ACPI for GICv3 * NOTE: First time must not be called from multiple CPUs in parallel diff --git a/drivers/ukintctlr/gic/include/uk/intctlr/gic.h b/drivers/ukintctlr/gic/include/uk/intctlr/gic.h index 6c7591a8..55f14867 100644 --- a/drivers/ukintctlr/gic/include/uk/intctlr/gic.h +++ b/drivers/ukintctlr/gic/include/uk/intctlr/gic.h @@ -68,27 +68,36 @@ typedef enum _GIC_HW_VER { /** GIC driver operations */ struct _gic_operations { - /** Initialize GIC controller */ + /* Initialize GIC controller */ int (*initialize)(void); - /** Acknowledging IRQ */ + /* Acknowledging IRQ */ uint32_t (*ack_irq)(void); - /** Finish interrupt handling */ + /* Finish interrupt handling */ void (*eoi_irq)(uint32_t irq); - /** Enable IRQ */ + /* Enable IRQ */ void (*enable_irq)(uint32_t irq); - /** Disable IRQ */ + /* Disable IRQ */ void (*disable_irq)(uint32_t irq); - /** Set IRQ trigger type */ + /* Set IRQ trigger type */ void (*set_irq_trigger)(uint32_t irq, enum uk_intctlr_irq_trigger trigger); - /** Set priority for IRQ */ + /* Set priority for IRQ */ void (*set_irq_prio)(uint32_t irq, uint8_t priority); - /** Set IRQ affinity (or "target" for GICv2) */ + /* Set IRQ affinity (or "target" for GICv2) */ void (*set_irq_affinity)(uint32_t irq, uint32_t affinity); - /** Handle IRQ */ + /* Handle IRQ */ void (*handle_irq)(struct __regs *regs); - /** Send a SGI to the specifiec core */ - void (*gic_sgi_gen)(uint8_t sgintid, uint32_t cpuid); + /* Send a SGI to the specified cores or all cores excluding "self" */ + int (*gic_sgi_gen)(uint8_t sgintid, uint32_t target_amount, + va_list cpuid_args); +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) + /* Simulate spi */ + void (*simulate_spi)(uint32_t irq); + /* Get IRQ priority level */ + uint8_t (*get_irq_prio)(uint32_t irq); + /* Get spi affinity */ + uint32_t (*get_spi_affinity)(uint32_t irq); +#endif }; /** GIC controller structure */ diff --git a/drivers/ukintctlr/gic/ukintctlr.c b/drivers/ukintctlr/gic/ukintctlr.c index 4b50c337..344df59a 100644 --- a/drivers/ukintctlr/gic/ukintctlr.c +++ b/drivers/ukintctlr/gic/ukintctlr.c @@ -75,7 +75,7 @@ static int fdt_xlat(const void *fdt, int nodeoffset, __u32 index, } #endif /* CONFIG_LIBUKOFW */ -static int configure_irq(struct uk_intctlr_irq *irq) +static int set_irq_trigger(struct uk_intctlr_irq *irq) { if (irq->trigger != UK_INTCTLR_IRQ_TRIGGER_NONE) gic->ops.set_irq_trigger(irq->id, irq->trigger); @@ -111,9 +111,16 @@ init: if (unlikely(rc)) return rc; - ops.configure_irq = configure_irq; + ops.irq_set_trigger = set_irq_trigger; ops.mask_irq = gic->ops.disable_irq; ops.unmask_irq = gic->ops.enable_irq; + ops.irq_set_priority = gic->ops.set_irq_prio; +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) + ops.irq_get_priority = gic->ops.get_irq_prio; + ops.spi_get_affinity = gic->ops.get_spi_affinity; + ops.simulate_spi = gic->ops.simulate_spi; +#endif + ops.irq_set_affinity = gic->ops.set_irq_affinity; #if CONFIG_LIBUKOFW ops.fdt_xlat = fdt_xlat; #endif /* CONFIG_LIBUKOFW */ diff --git a/drivers/ukintctlr/xpic/ukintctlr.c b/drivers/ukintctlr/xpic/ukintctlr.c index 5581aa9d..33c6f8bf 100644 --- a/drivers/ukintctlr/xpic/ukintctlr.c +++ b/drivers/ukintctlr/xpic/ukintctlr.c @@ -15,7 +15,7 @@ static struct uk_intctlr_desc intctlr; -static int configure_irq(struct uk_intctlr_irq *irq __unused) +static int irq_set_trigger(struct uk_intctlr_irq *irq __unused) { return 0; } @@ -56,12 +56,18 @@ int uk_intctlr_probe(void) #endif /* CONFIG_LIBUKINTCTLR_APIC */ intctlr.ops = ops; - intctlr.ops->configure_irq = configure_irq; + intctlr.ops->irq_set_trigger = irq_set_trigger; intctlr.ops->initialize = __NULL; intctlr.ops->handle = uk_intctlr_xpic_handle_irq; intctlr.ops->fdt_xlat = __NULL; intctlr.ops->sgi_op = __NULL; intctlr.ops->percpu_init = __NULL; - + intctlr.ops->irq_set_priority = __NULL; + intctlr.ops->irq_set_affinity = __NULL; +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) + intctlr.ops->irq_get_priority = __NULL; + intctlr.ops->spi_get_affinity = __NULL; + intctlr.ops->simulate_spi = __NULL; +#endif return uk_intctlr_register(&intctlr); } diff --git a/drivers/virtio/mmio/virtio_mmio.c b/drivers/virtio/mmio/virtio_mmio.c index 881a3181..087e7cf8 100644 --- a/drivers/virtio/mmio/virtio_mmio.c +++ b/drivers/virtio/mmio/virtio_mmio.c @@ -439,7 +439,7 @@ static int virtio_mmio_probe_fdt(struct pf_device *pfdev) if (unlikely(rc < 0)) return -EINVAL; - uk_intctlr_irq_configure(&irq); + uk_intctlr_irq_set_trigger(&irq); prop = fdt_getprop(dtb, offs, "reg", &prop_len); if (unlikely(!prop)) diff --git a/lib/ukintctlr/exportsyms.uk b/lib/ukintctlr/exportsyms.uk index 80ce0e8b..5035f1d1 100644 --- a/lib/ukintctlr/exportsyms.uk +++ b/lib/ukintctlr/exportsyms.uk @@ -1,13 +1,18 @@ uk_intctlr -uk_intctlr_init -uk_intctlr_irq_configure -uk_intctlr_irq_fdt_xlat +uk_intctlr_handle uk_intctlr_irq_alloc +uk_intctlr_irq_fdt_xlat uk_intctlr_irq_free +uk_intctlr_irq_get_priority uk_intctlr_irq_handle -uk_intctlr_handle -uk_intctlr_sgi_op -uk_intctlr_percpu_init uk_intctlr_irq_register +uk_intctlr_irq_set_affinity +uk_intctlr_irq_set_priority +uk_intctlr_irq_set_trigger uk_intctlr_irq_unregister +uk_intctlr_init +uk_intctlr_percpu_init uk_intctlr_register +uk_intctlr_simulate_spi +uk_intctlr_sgi_op +uk_intctlr_spi_get_affinity diff --git a/lib/ukintctlr/include/uk/intctlr.h b/lib/ukintctlr/include/uk/intctlr.h index c49eb62d..63dea1a2 100644 --- a/lib/ukintctlr/include/uk/intctlr.h +++ b/lib/ukintctlr/include/uk/intctlr.h @@ -54,15 +54,74 @@ struct uk_intctlr_irq { * These must be implemented by the interrupt controller */ struct uk_intctlr_driver_ops { - int (*configure_irq)(struct uk_intctlr_irq *irq); + /** + * Configure trigger type for an interrupt + * + * @param irq Interrupt configuration + * @return zero on success or negative value on error + */ + int (*irq_set_trigger)(struct uk_intctlr_irq *irq); int (*fdt_xlat)(const void *fdt, int nodeoffset, __u32 index, struct uk_intctlr_irq *irq); void (*mask_irq)(unsigned int irq); void (*unmask_irq)(unsigned int irq); void (*initialize)(void); void (*handle)(struct __regs *regs); - void (*sgi_op)(uint8_t sgintid, uint32_t cpuid); int (*percpu_init)(void); + + /** + * Send a SGI to the specified core(s). + * + * @param sgintid the software generated interrupt id + * @param target_count the number of target cpus, + * zero means sending sgi to all PEs in the system except "self". + * @param cpuid_args argument list of cpuid, + * could be empty. type: uint32_t + * @return zero on success , negative value on failure + */ + int (*sgi_op)(uint8_t sgintid, uint32_t target_count, + va_list cpuid_args); + + /** + * set priority for interrupt + * + * @param irq IRQ to set priority + * @param priority priority number value [0..GIC_MAX_IRQ] + * smaller priority number indicates a higher priority + */ + void (*irq_set_priority)(unsigned int irq, uint8_t priority); + + /** + * set affinity for SPI interrupt + * + * @param irq IRQ to set affinity + * @param cpuid target CPU id to cope with SPI + */ + void (*irq_set_affinity)(unsigned int irq, uint32_t cpuid); +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) + /** + * Get IRQ priority level in non-secure mode + * + * @param irq IRQ to get priority + * @return IRQ priority level + */ + uint8_t (*irq_get_priority)(unsigned int irq); + + /** + * Get spi affinity status + * + * @param irq spi to get affinity + * @return spi affinity status + */ + uint32_t (*spi_get_affinity)(unsigned int irq); + + /** + * Set pending bit to simulate spi being triggered + * + * @param irq spi to set pending status + */ + void (*simulate_spi)(unsigned int irq); +#endif }; /** Interrupt controller descriptor */ @@ -96,12 +155,12 @@ int uk_intctlr_probe(void); void uk_intctlr_irq_handle(struct __regs *regs, unsigned int irq); /** - * Configure an interrupt + * Configure trigger type for an interrupt * * @param irq Interrupt configuration * @return zero on success or negative value on error */ -int uk_intctlr_irq_configure(struct uk_intctlr_irq *irq); +int uk_intctlr_irq_set_trigger(struct uk_intctlr_irq *irq); /** * Register interrupt controller driver with the uk_intctlr subsystem @@ -198,19 +257,65 @@ int uk_intctlr_irq_fdt_xlat(const void *fdt, int nodeoffset, __u32 index, void uk_intctlr_handle(struct __regs *regs); /** - * Handle function for interrupt controller + * Send a SGI to the specified core(s). * * @param sgintid the software generated interrupt id - * @param cpuid the id of the targeted cpu - * @return zero on success , error code on failure + * @param target_count the number of target cpus, + * zero means sending sgi to all PEs in the system except the current one. + * @param ... optional argument list of cpuid,type:uint32_t + * @return zero on success, negative value on failure */ -int uk_intctlr_sgi_op(uint8_t sgintid, uint32_t cpuid); +int uk_intctlr_sgi_op(uint8_t sgintid, uint32_t target_count, ...); /** * extra initialize function for each cpu core * @return zero on success , error code on failure */ int uk_intctlr_percpu_init(void); + +/** + * set priority for interrupt + * + * @param irq IRQ to set priority + * @param priority priority number value [0..GIC_MAX_IRQ] + * smaller priority number indicates a higher priority + */ +void uk_intctlr_irq_set_priority(unsigned int irq, uint8_t priority); + +/** + * set affinity for SPI interrupt + * + * @param irq SPI Interrupt to set affinity + * @param cpuid target CPU id to cope with SPI + */ +void uk_intctlr_irq_set_affinity(unsigned int irq, uint32_t cpuid); + +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) +/** + * Get IRQ priority level in non-secure mode + * + * @param irq irq to get priority information + * @return irq priority level + */ +uint8_t uk_intctlr_irq_get_priority(unsigned int irq); + +/** + * Get spi affinity status + * + * @param irq spi to get affinity + * @return spi affinity status + */ +uint32_t uk_intctlr_spi_get_affinity(unsigned int irq); + +/** + * sets the status of the corresponding + * peripheral interrupt to pending status + * + * @param irq spi to set pending + */ +void uk_intctlr_simulate_spi(unsigned int irq); +#endif + #endif /* __ASSEMBLY__ */ #ifdef __cplusplus diff --git a/lib/ukintctlr/tests/test_intctlr.c b/lib/ukintctlr/tests/test_intctlr.c index c10e3c54..b0418bbb 100644 --- a/lib/ukintctlr/tests/test_intctlr.c +++ b/lib/ukintctlr/tests/test_intctlr.c @@ -17,199 +17,145 @@ #include #include -static struct uk_intctlr_desc *ori_intctlr; -static struct uk_intctlr_desc test_intctlr; -struct uk_intctlr_driver_ops test_ops; -static int ret; - -enum ukintctlr_test_ret { - TEST_DEFAULT, - TEST_CONFIGURE_IRQ_SUCCESS, - TEST_FDT_XLAT_SUCCESS, - TEST_MASK_IRQ_SUCCESS, - TEST_UNMASK_IRQ_SUCCESS, - TEST_INITIALIZE_SUCCESS, - TEST_HANDLE_SUCCESS, - TEST_SGI_OP_SUCCESS, - TEST_PERCPU_INIT_SUCCESS, -}; - -static int test_configure_irq(struct uk_intctlr_irq *irq __unused) -{ - ret = TEST_CONFIGURE_IRQ_SUCCESS; - return 0; -} - -static int test_fdt_xlat(const void *fdt __unused, int nodeoffset __unused, - __u32 index __unused, - struct uk_intctlr_irq *irq __unused) -{ - ret = TEST_FDT_XLAT_SUCCESS; - return 0; -} -static void test_mask_irq(unsigned int irq __unused) -{ - ret = TEST_MASK_IRQ_SUCCESS; -} +#ifdef CONFIG_LIBUKINTCTLR_GICV3 +#include -static void test_unmask_irq(unsigned int irq __unused) -{ - ret = TEST_UNMASK_IRQ_SUCCESS; -} +static uint32_t global_current_cpu; -static void test_handle(struct __regs *regs __unused) +static int spi_handler(void *args __unused) { - ret = TEST_HANDLE_SUCCESS; -} - -static void test_sgi_op(uint8_t sgintid __unused, uint32_t cpuid __unused) -{ - ret = TEST_SGI_OP_SUCCESS; -} - -static int test_percpu_init(void) -{ - ret = TEST_PERCPU_INIT_SUCCESS; - + printf("spi handler start.\n"); + uint64_t mpidr = SYSREG_READ64(MPIDR_EL1); + uint64_t aff = ((mpidr & MPIDR_AFF3_MASK) >> 8) | + (mpidr & MPIDR_AFF2_MASK) | + (mpidr & MPIDR_AFF1_MASK) | + (mpidr & MPIDR_AFF0_MASK); + + global_current_cpu = (uint32_t)aff; return 0; } -static inline void test_intctlr_init(void) +UK_TESTCASE_DESC(ukintctlr, set_spi_pendings_test_affx_api, + "Affinity irq40 to the current cpu") { - ori_intctlr = uk_intctlr; - ret = 0; - - test_intctlr.name = "TEST_INTCTLR"; - test_ops.configure_irq = test_configure_irq; - test_ops.fdt_xlat = test_fdt_xlat; - test_ops.mask_irq = test_mask_irq; - test_ops.unmask_irq = test_unmask_irq; - test_ops.handle = test_handle; - test_ops.sgi_op = test_sgi_op; - test_ops.percpu_init = test_percpu_init; - test_intctlr.ops = &test_ops; - - uk_intctlr_register(&test_intctlr); -} - -/* 测试configure_irq接口 */ -UK_TESTCASE(ukintctlr, call_intctlr_configure_irq) -{ - struct uk_intctlr_irq irq = {0}; - struct uk_intctlr_irq *p_irq = &irq; - - /* 1.备份原有uk_intctlr,初始化测试环境 */ - test_intctlr_init(); - - /* 2.通过统一接口调用configure_irq,并校验调用结果 */ - (void)uk_intctlr_irq_configure(p_irq); - UK_TEST_EXPECT_SNUM_EQ(ret, TEST_CONFIGURE_IRQ_SUCCESS); + /* 中断号40,亲和至当前cpu */ + uint32_t original_cpu_affinity = uk_intctlr_spi_get_affinity(40); - /* 3.恢复环境 */ - uk_intctlr_register(ori_intctlr); -} + uint64_t current_cpu = SYSREG_READ64(MPIDR_EL1); + uint64_t aff = ((current_cpu & MPIDR_AFF3_MASK) >> 8) | + (current_cpu & MPIDR_AFF2_MASK) | + (current_cpu & MPIDR_AFF1_MASK) | + (current_cpu & MPIDR_AFF0_MASK); -/* 测试fdt_xlat接口 */ -UK_TESTCASE(ukintctlr, call_fdt_xlat) -{ - struct uk_intctlr_irq irq = {0}; - struct uk_intctlr_irq *p_irq = &irq; - const char *fdt = "FDT"; - int nodeoffset = 0; - __u32 index = 0; + uk_intctlr_irq_set_affinity(40, (uint32_t)aff); + uk_intctlr_irq_register(40, spi_handler, NULL); + isb(); - /* 1.备份原有uk_intctlr,初始化测试环境 */ - test_intctlr_init(); + uk_intctlr_simulate_spi(40); + __asm__ __volatile__("wfi"); - /* 2.通过统一接口调用fdt_xlat,并校验调用结果 */ - (void)uk_intctlr_irq_fdt_xlat(fdt, nodeoffset, index, p_irq); - UK_TEST_EXPECT_SNUM_EQ(ret, TEST_FDT_XLAT_SUCCESS); + UK_TEST_EXPECT_SNUM_EQ((uint32_t)aff, global_current_cpu); - /* 3.恢复环境 */ - uk_intctlr_register(ori_intctlr); + /* 恢复现场 */ + uk_intctlr_irq_unregister(40, spi_handler); + uk_intctlr_irq_set_affinity(40, original_cpu_affinity); } -/* 测试mask_irq接口 */ -UK_TESTCASE(ukintctlr, call_mask_irq) -{ - int irq = 0; - - /* 1.备份原有uk_intctlr,初始化测试环境 */ - test_intctlr_init(); - - /* 2.通过统一接口调用mask_irq,并校验调用结果 */ - uk_intctlr_irq_mask(irq); - UK_TEST_EXPECT_SNUM_EQ(ret, TEST_MASK_IRQ_SUCCESS); - - /* 3.恢复环境 */ - uk_intctlr_register(ori_intctlr); -} -/* 测试unmask_irq接口 */ -UK_TESTCASE(ukintctlr, call_unmask_irq) +UK_TESTCASE_DESC(ukintctlr, verify_spi_priority_level_setting, + "Compare the priority of interrupt 60/70") { - int irq = 0; - - /* 1.备份原有uk_intctlr,初始化测试环境 */ - test_intctlr_init(); - - /* 2.通过统一接口调用unmask_irq,并校验调用结果 */ - uk_intctlr_irq_unmask(irq); - UK_TEST_EXPECT_SNUM_EQ(ret, TEST_UNMASK_IRQ_SUCCESS); - - /* 3.恢复环境 */ - uk_intctlr_register(ori_intctlr); + uint8_t irq60_original_prio_level = + uk_intctlr_irq_get_priority(60) >> TRANS_PRIORITY_SHIFT; + uint8_t irq70_original_prio_level = + uk_intctlr_irq_get_priority(70) >> TRANS_PRIORITY_SHIFT; + + +#if defined(CONFIG_PRIORITY_MAX_16) + uk_intctlr_irq_set_priority(60, 15); + uk_intctlr_irq_set_priority(70, 14); + isb(); + UK_TEST_EXPECT_SNUM_GT(uk_intctlr_irq_get_priority(60), + uk_intctlr_irq_get_priority(70)); +#elif defined(CONFIG_PRIORITY_MAX_32) + uk_intctlr_irq_set_priority(60, 30); + uk_intctlr_irq_set_priority(70, 31); + isb(); + UK_TEST_EXPECT_SNUM_GT(uk_intctlr_irq_get_priority(60), + uk_intctlr_irq_get_priority(70)); +#elif defined(CONFIG_PRIORITY_MAX_64) + uk_intctlr_irq_set_priority(60, 62); + uk_intctlr_irq_set_priority(70, 63); + isb(); + UK_TEST_EXPECT_SNUM_GT(uk_intctlr_irq_get_priority(60), + uk_intctlr_irq_get_priority(70)); +#elif defined(CONFIG_PRIORITY_MAX_128) + uk_intctlr_irq_set_priority(60, 126); + uk_intctlr_irq_set_priority(70, 127); + isb(); + UK_TEST_EXPECT_SNUM_GT(uk_intctlr_irq_get_priority(60), + uk_intctlr_irq_get_priority(70)); +#endif + + /*恢复现场*/ + uk_intctlr_irq_set_priority(60, irq60_original_prio_level); + uk_intctlr_irq_set_priority(70, irq70_original_prio_level); } -/* 测试handle接口 */ -UK_TESTCASE(ukintctlr, call_handler) +/* 测试sgi生成接口uk_intctlr_sgi_op + * 场景: 向当前cpu发送/向除自己外的所有cpu发送 + */ +UK_TESTCASE_DESC(ukintctlr, send_sgi_to_bsp_or_all, + "Send a SGI to current cpu/all cpu excluding self") { - struct __regs *regs = NULL; - - /* 1.备份原有uk_intctlr,初始化测试环境 */ - test_intctlr_init(); - - /* 2.通过统一接口调用handle,并校验调用结果 */ - uk_intctlr_handle(regs); - UK_TEST_EXPECT_SNUM_EQ(ret, TEST_HANDLE_SUCCESS); + int r; - /* 3.恢复环境 */ - uk_intctlr_register(ori_intctlr); -} + uint64_t current_cpu = SYSREG_READ64(MPIDR_EL1); + uint64_t aff = ((current_cpu & MPIDR_AFF3_MASK) >> 8) | + (current_cpu & MPIDR_AFF2_MASK) | + (current_cpu & MPIDR_AFF1_MASK) | + (current_cpu & MPIDR_AFF0_MASK); -/* 测试sgi_op接口 */ -UK_TESTCASE(ukintctlr, call_sgi_op) -{ - uint8_t sgintid = 0; - uint32_t cpuid = 0; + /* 将sgi亲和到当前cpu */ + r = uk_intctlr_sgi_op(5, 1, (uint32_t)aff); - /* 1.备份原有uk_intctlr,初始化测试环境 */ - test_intctlr_init(); + UK_TEST_EXPECT_ZERO(r); - /* 2.通过统一接口调用sgi_op,并校验调用结果 */ - (void)uk_intctlr_sgi_op(sgintid, cpuid); - UK_TEST_EXPECT_SNUM_EQ(ret, TEST_SGI_OP_SUCCESS); + /* 将sgi亲和到除自己外的所有cpu */ + r = uk_intctlr_sgi_op(5, 0); - /* 3.恢复环境 */ - uk_intctlr_register(ori_intctlr); + UK_TEST_EXPECT_ZERO(r); } -/* 测试percpu_init接口 */ -UK_TESTCASE(ukintctlr, call_percpu_init) +/* 测试sgi生成接口uk_intctlr_sgi_op + * 场景: cpulist中含有range_selector不同/亲和属性不同/id > 15的cpu + */ +UK_TESTCASE_DESC(ukintctlr, affx_and_rs_check, +"Send a SGI to cpu list with 4 cases: different rs/affx, cpuid>15, normal") { int r; + /* 检测接口是否会检查出targetlist AFFx属性及 + * range selector 不同并报错 + */ - /* 1.备份原有uk_intctlr,初始化测试环境 */ - test_intctlr_init(); + /* 检查是否支持发送至idx 16 及以上的cpu */ + r = uk_intctlr_sgi_op(4, 4, 19, 1, 2, 0); + UK_TEST_EXPECT_SNUM_EQ(r, -1); - /* 2.通过统一接口调用percpu_init,并校验调用结果 */ - r = uk_intctlr_percpu_init(); - UK_TEST_EXPECT_SNUM_EQ(ret, TEST_PERCPU_INIT_SUCCESS); - UK_TEST_EXPECT_ZERO(r); + /* 不同的range selector */ + r = uk_intctlr_sgi_op(4, 4, 0, 1, 2, 19); + UK_TEST_EXPECT_SNUM_EQ(r, -1); + + /* 不同的affx */ + r = uk_intctlr_sgi_op(4, 4, 0, 1, 2, 132000); + UK_TEST_EXPECT_SNUM_EQ(r, -1); - /* 3.恢复环境 */ - uk_intctlr_register(ori_intctlr); + /* affx/rs 相同*/ + r = uk_intctlr_sgi_op(4, 3, 0, 1, 2); + UK_TEST_EXPECT_ZERO(r); } +#endif + uk_testsuite_register(ukintctlr, NULL); diff --git a/lib/ukintctlr/ukintctlr.c b/lib/ukintctlr/ukintctlr.c index 4e2a826b..6a68c27a 100644 --- a/lib/ukintctlr/ukintctlr.c +++ b/lib/ukintctlr/ukintctlr.c @@ -233,12 +233,12 @@ void uk_intctlr_irq_unmask(unsigned int irq) return uk_intctlr->ops->unmask_irq(irq); } -int uk_intctlr_irq_configure(struct uk_intctlr_irq *irq) +int uk_intctlr_irq_set_trigger(struct uk_intctlr_irq *irq) { - UK_ASSERT(uk_intctlr && uk_intctlr->ops->configure_irq); + UK_ASSERT(uk_intctlr && uk_intctlr->ops->irq_set_trigger); UK_ASSERT(irq); - return uk_intctlr->ops->configure_irq(irq); + return uk_intctlr->ops->irq_set_trigger(irq); } int uk_intctlr_irq_fdt_xlat(const void *fdt, int nodeoffset, __u32 index, @@ -319,13 +319,16 @@ void uk_intctlr_handle(struct __regs *regs) return uk_intctlr->ops->handle(regs); } -int uk_intctlr_sgi_op(uint8_t sgintid, uint32_t cpuid) +int uk_intctlr_sgi_op(uint8_t sgintid, uint32_t target_count, ...) { - UK_ASSERT(uk_intctlr->ops->sgi_op); - - uk_intctlr->ops->sgi_op(sgintid, cpuid); - - return 0; + UK_ASSERT(uk_intctlr && uk_intctlr->ops->sgi_op); + va_list cpuid_args; + int ret; + + va_start(cpuid_args, target_count); + ret = uk_intctlr->ops->sgi_op(sgintid, target_count, cpuid_args); + va_end(cpuid_args); + return ret; } int uk_intctlr_percpu_init(void) @@ -335,3 +338,40 @@ int uk_intctlr_percpu_init(void) /* initialize interrupt controller of specified cpu core */ return uk_intctlr->ops->percpu_init(); } + +void uk_intctlr_irq_set_priority(unsigned int irq, uint8_t priority) +{ + UK_ASSERT(uk_intctlr && uk_intctlr->ops->irq_set_priority); + + return uk_intctlr->ops->irq_set_priority(irq, priority); +} + +void uk_intctlr_irq_set_affinity(unsigned int irq, uint32_t cpuid) +{ + UK_ASSERT(uk_intctlr && uk_intctlr->ops->irq_set_affinity); + + return uk_intctlr->ops->irq_set_affinity(irq, cpuid); +} + +#if defined(CONFIG_LIBUKINTCTLR_TEST) || defined(CONFIG_LIBUKTEST_ALL) +uint8_t uk_intctlr_irq_get_priority(unsigned int irq) +{ + UK_ASSERT(uk_intctlr && uk_intctlr->ops->irq_get_priority); + + return uk_intctlr->ops->irq_get_priority(irq); +} + +uint32_t uk_intctlr_spi_get_affinity(unsigned int irq) +{ + UK_ASSERT(uk_intctlr && uk_intctlr->ops->spi_get_affinity); + + return uk_intctlr->ops->spi_get_affinity(irq); +} + +void uk_intctlr_simulate_spi(unsigned int irq) +{ + UK_ASSERT(uk_intctlr && uk_intctlr->ops->simulate_spi); + + return uk_intctlr->ops->simulate_spi(irq); +} +#endif diff --git a/plat/Config.uk b/plat/Config.uk index 1ef6e042..af269219 100644 --- a/plat/Config.uk +++ b/plat/Config.uk @@ -86,6 +86,13 @@ config HAVE_PAGING default y if PAGING default n +config VIRTUALIZE_PLAT + bool + default n + depends on PLAT_KVM + help + The virtualization platform is currently being used + config HAVE_PAGING_DIRECTMAP bool default y if PAGING && ARCH_X86_64 diff --git a/plat/common/arm/lcpu.c b/plat/common/arm/lcpu.c index 927989f4..8e14691c 100644 --- a/plat/common/arm/lcpu.c +++ b/plat/common/arm/lcpu.c @@ -341,17 +341,15 @@ int lcpu_arch_run(struct lcpu *lcpu, const struct ukplat_lcpu_func *fn, if (unlikely(rc)) return rc; - uk_intctlr_sgi_op(*lcpu_run_irqv, lcpu->id); + return uk_intctlr_sgi_op(*lcpu_run_irqv, 1, lcpu->id); - return 0; } int lcpu_arch_wakeup(struct lcpu *lcpu) { UK_ASSERT(lcpu->id != lcpu_arch_id()); - uk_intctlr_sgi_op(*lcpu_wakeup_irqv, lcpu->id); + return uk_intctlr_sgi_op(*lcpu_wakeup_irqv, 1, lcpu->id); - return 0; } #endif /* CONFIG_HAVE_SMP */ diff --git a/plat/common/arm/time.c b/plat/common/arm/time.c index 8d89036a..402fca69 100644 --- a/plat/common/arm/time.c +++ b/plat/common/arm/time.c @@ -131,7 +131,7 @@ void ukplat_time_init(void) if (unlikely(rc < 0)) UK_CRASH("Could not get IRQ from dtb (%d)\n", rc); - uk_intctlr_irq_configure(&irq); + uk_intctlr_irq_set_trigger(&irq); rc = uk_intctlr_irq_register(irq.id, generic_timer_irq_handler, NULL); if (unlikely(rc < 0)) diff --git a/plat/drivers/rtc/pl031.c b/plat/drivers/rtc/pl031.c index 805085df..12a1b223 100644 --- a/plat/drivers/rtc/pl031.c +++ b/plat/drivers/rtc/pl031.c @@ -181,7 +181,7 @@ int pl031_init_rtc(void *dtb) if (unlikely(rc)) return rc; - uk_intctlr_irq_configure(&irq); + uk_intctlr_irq_set_trigger(&irq); pl031_irq = irq.id; diff --git a/plat/kvm/Config.uk b/plat/kvm/Config.uk index c628487d..ad3d9766 100644 --- a/plat/kvm/Config.uk +++ b/plat/kvm/Config.uk @@ -5,6 +5,7 @@ menuconfig PLAT_KVM select LIBUKDEBUG select LIBUKALLOC select LIBUKTIMECONV + select VIRTUALIZE_PLAT select LIBNOLIBC if !HAVE_LIBC select HAVE_FDT if ARCH_ARM_64 imply LIBFDT if ARCH_ARM_64 -- Gitee From 54e77cb720cb7c19ce45aafe94359c19f32ae5a3 Mon Sep 17 00:00:00 2001 From: crazykev Date: Thu, 18 Apr 2024 16:47:09 +0800 Subject: [PATCH 16/35] lib/uksched: [bugfix]store auxstack to free it Signed-off-by: crazykev --- include/uk/plat/memory.h | 50 ++++++++++++++++++++++++++++++- lib/uksched/include/uk/thread.h | 1 + lib/uksched/thread.c | 52 +++++++++++++++++++++++---------- 3 files changed, 87 insertions(+), 16 deletions(-) diff --git a/include/uk/plat/memory.h b/include/uk/plat/memory.h index ccd93eb3..0d08bb73 100644 --- a/include/uk/plat/memory.h +++ b/include/uk/plat/memory.h @@ -272,6 +272,8 @@ int ukplat_mem_init(void); * @param auxsp_len * The custom length of the auxiliary stack. If 0, then * CONFIG_UKPLAT_AUXSP_PAGE_ORDER is used instead as the default length. + * @param auxstack + * Pointer to the allocated auxiliary stack, used to store the start address. * * @return * Pointer to the allocated auxiliary stack @@ -280,7 +282,8 @@ static inline __uptr ukplat_auxsp_alloc(struct uk_alloc __maybe_unused *a, #if CONFIG_LIBUKVMEM struct uk_vas __maybe_unused *vas, #endif /* CONFIG_LIBUKVMEM */ - __sz auxsp_len) + __sz auxsp_len, + __uptr * auxstack) { __vaddr_t auxsp; @@ -331,6 +334,9 @@ static inline __uptr ukplat_auxsp_alloc(struct uk_alloc __maybe_unused *a, } #endif /* !CONFIG_LIBUKVMEM */ + if (auxstack) + *auxstack = auxsp; + /* If auxsp resulted from the previous allocations is ECTX aligned * and auxsp_len is ECTX aligned, then the function call below will * result in an ECTX aligned stack pointer. @@ -338,6 +344,48 @@ static inline __uptr ukplat_auxsp_alloc(struct uk_alloc __maybe_unused *a, return (__uptr)ukarch_gen_sp((__uptr)auxsp, auxsp_len); } +/* Free an auxiliary stack that created by ukplat_auxsp_alloc. + * The size is that given by (1 << CONFIG_AUXSP_PAGE_ORDER) * PAGE_SIZE. + * + * @param a + * The allocator to use for the auxiliary stack + * @param vas + * The virtual address space to use for the mapping of the auxiliary stack. + * This should be used in conjunction with CONFIG_LIBUKVMEM to ensure that + * accesses to the auxiliary stack do not generate page faults in more + * fragile system states. + * @param auxstack + * Pointer to the allocated auxiliary stack, used to store the start address. + * @param auxstack_len + * The custom length of the auxiliary stack. If 0, then + * CONFIG_UKPLAT_AUXSP_PAGE_ORDER is used instead as the default length. + */ +static inline void ukplat_auxsp_free(struct uk_alloc __maybe_unused *a, +#if CONFIG_LIBUKVMEM + struct uk_vas __maybe_unused *vas, +#endif /* CONFIG_LIBUKVMEM */ + __uptr auxstack, + __sz auxstack_len) +{ +#if CONFIG_LIBUKVMEM + int rc; + + /* Compitable with the behavior provided by ukplat_auxsp_alloc */ + if (!auxstack_len) + auxstack_len = + ALIGN_UP(PAGE_SIZE * (1 << CONFIG_UKPLAT_AUXSP_PAGE_ORDER), + UKARCH_ECTX_ALIGN); + + rc = uk_vma_unmap(vas, auxstack, auxstack_len, 0); + if (rc) { + uk_pr_err("Failed to unmap auxiliary stack\n"); + return; + } +#else /* !CONFIG_LIBUKVMEM */ + uk_free(a, auxstack); +#endif /* !CONFIG_LIBUKVMEM */ +} + #ifdef __cplusplus } #endif diff --git a/lib/uksched/include/uk/thread.h b/lib/uksched/include/uk/thread.h index 844d516e..0356d86a 100644 --- a/lib/uksched/include/uk/thread.h +++ b/lib/uksched/include/uk/thread.h @@ -81,6 +81,7 @@ struct uk_thread { struct uk_alloc *uktls_a; void *auxstack; struct uk_alloc *auxstack_a; + __sz auxstack_len; } _mem; /**< Associated allocs (internal!) */ uk_thread_gc_t _gc_fn; /**< Extra gc function (internal!) */ void *_gc_argp; /**< Argument for gc fn (internal!) */ diff --git a/lib/uksched/thread.c b/lib/uksched/thread.c index c86c8441..cd5c544c 100644 --- a/lib/uksched/thread.c +++ b/lib/uksched/thread.c @@ -250,13 +250,22 @@ static void _uk_thread_struct_init(struct uk_thread *t, t->prio = prio; #endif - if (!auxsp) + if (!auxsp) { + /* These seems to be compatible code block, we should store + * necessary staff to free aux stack when release thread. + */ + __uptr auxstack = 0x0; auxsp = ukplat_auxsp_alloc(uk_alloc_get_default(), #if CONFIG_LIBUKVMEM uk_vas_get_active(), -#endif /* CONFIG_LIBUKVMEM */ - 0); /* Default auxsp size */ - +#endif /* CONFIG_LIBUKVMEM */ + 0, /* Default auxsp size */ + &auxstack); + if (auxsp && auxstack) { + t->_mem.auxstack = (void *)auxstack; + t->_mem.auxstack_a = uk_alloc_get_default(); + } + } t->auxsp = auxsp; if (tlsp && is_uktls) { @@ -392,7 +401,8 @@ static int _uk_thread_struct_init_alloc(struct uk_thread *t, { void *stack = NULL; void *tls = NULL; - void *auxstack = 0x0; + __uptr auxstack = 0x0; + __uptr auxsp = 0x0; uintptr_t tlsp = 0x0; int rc; @@ -405,12 +415,12 @@ static int _uk_thread_struct_init_alloc(struct uk_thread *t, } if (a_auxstack && auxstack_len) { - auxstack = (void *)ukplat_auxsp_alloc(a_auxstack, + auxsp = ukplat_auxsp_alloc(a_auxstack, #if CONFIG_LIBUKVMEM - uk_vas_get_active(), + uk_vas_get_active(), #endif /* CONFIG_LIBUKVMEM */ - auxstack_len); - if (unlikely(!auxstack)) { + auxstack_len, &auxstack); + if (unlikely(!auxsp || !auxstack)) { rc = -ENOMEM; goto err_free_stack; } @@ -447,8 +457,8 @@ static int _uk_thread_struct_init_alloc(struct uk_thread *t, tlsp = ukarch_tls_tlsp(tls); } - _uk_thread_struct_init(t, (__uptr)auxstack, tlsp, !(!tlsp), ectx, name, - prio, priv, dtor); + _uk_thread_struct_init(t, auxsp, tlsp, !(!tlsp), ectx, name, prio, priv, + dtor); /* Set uk_thread fields related to stack and TLS */ if (stack) { @@ -456,9 +466,10 @@ static int _uk_thread_struct_init_alloc(struct uk_thread *t, t->_mem.stack_a = a_stack; } - if (auxstack) { - t->_mem.auxstack = auxstack; + if (auxsp && auxstack) { + t->_mem.auxstack = (void *)auxstack; t->_mem.auxstack_a = a_auxstack; + t->_mem.auxstack_len = auxstack_len; } if (tls) { @@ -510,9 +521,14 @@ void _uk_thread_struct_free_alloc(struct uk_thread *t) t->_mem.stack = NULL; } if (t->auxsp) { - uk_free(t->_mem.auxstack_a, t->_mem.auxstack); + ukplat_auxsp_free(t->_mem.auxstack_a, +#if CONFIG_LIBUKVMEM + uk_vas_get_active(), +#endif /* CONFIG_LIBUKVMEM */ + t->_mem.auxstack, t->_mem.auxstack_len); t->_mem.auxstack_a = NULL; t->_mem.auxstack = NULL; + t->_mem.auxstack_len = 0; } } @@ -1036,6 +1052,7 @@ void uk_thread_release(struct uk_thread *t) void *stack; void *auxstack; void *tls; + __sz auxstack_len; UK_ASSERT(t); UK_ASSERT(t != uk_thread_current()); @@ -1052,6 +1069,7 @@ void uk_thread_release(struct uk_thread *t) stack = t->_mem.stack; auxstack_a = t->_mem.auxstack_a; auxstack = t->_mem.auxstack; + auxstack_len = t->_mem.auxstack_len; tls_a = t->_mem.uktls_a; tls = t->_mem.uktls; @@ -1068,7 +1086,11 @@ void uk_thread_release(struct uk_thread *t) if (stack_a && stack) uk_free(stack_a, stack); if (auxstack_a && auxstack) - uk_free(auxstack_a, auxstack); + ukplat_auxsp_free(auxstack_a, +#if CONFIG_LIBUKVMEM + uk_vas_get_active(), +#endif /* CONFIG_LIBUKVMEM */ + auxstack, auxstack_len); if (a) uk_free(a, t); } -- Gitee From 5f4ea0cb41c8a04c35bc31e2db5be5854758d261 Mon Sep 17 00:00:00 2001 From: Li Haode Date: Tue, 9 Apr 2024 10:32:31 +0800 Subject: [PATCH 17/35] lib/sched: refactor uk_sched_thread_sleep use tntimer Signed-off-by: Li Haode --- defconfig | 8 ++++ .../arm_generic_timer/arm_generic_timer.c | 2 +- lib/Config.uk | 4 ++ lib/posix-time/time.c | 2 +- lib/tnschedprio/isrwoken.c | 2 - lib/tnschedprio/schedprio.c | 32 ++----------- lib/tnschedprio/schedprio.h | 1 - lib/tnsystick/Config.uk | 5 +- lib/tnsystick/exportsyms.uk | 2 + lib/tnsystick/include/tn/systick.h | 13 +++++ lib/tnsystick/tnsystick.c | 47 +++++++------------ lib/tntimer/Config.uk | 2 +- lib/tntimer/tntimer.c | 2 +- lib/uksched/Config.uk | 2 + lib/uksched/exportsyms.uk | 4 +- lib/uksched/include/uk/sched.h | 14 +++++- lib/uksched/include/uk/thread.h | 22 +++++++-- lib/uksched/include/uk/wait.h | 6 ++- lib/uksched/isrwake.c | 1 - lib/uksched/sched.c | 13 ++++- lib/uksched/tests/test_sched.c | 14 ++++-- lib/uksched/thread.c | 35 +++++++++----- lib/ukschedcoop/isrwoken.c | 2 - lib/ukschedcoop/schedcoop.c | 28 ++--------- lib/ukschedcoop/schedcoop.h | 2 - plat/common/lcpu.c | 2 - 26 files changed, 143 insertions(+), 124 deletions(-) create mode 100644 defconfig diff --git a/defconfig b/defconfig new file mode 100644 index 00000000..c93e583b --- /dev/null +++ b/defconfig @@ -0,0 +1,8 @@ +CONFIG_ARCH_ARM_64=y +CONFIG_MCPU_ARM64_CORTEX_A53=y +# CONFIG_ARM64_ERRATUM_858921 is not set +CONFIG_PLAT_KVM=y +CONFIG_ARM_GENERIC_TIMER=y +CONFIG_LIBTNSYSTICK_FREQ=100 +CONFIG_ARCH_X86_64=y +CONFIG_UK_NAME="unikraft" diff --git a/drivers/sysclock/arm_generic_timer/arm_generic_timer.c b/drivers/sysclock/arm_generic_timer/arm_generic_timer.c index 9964b375..49d36ad6 100644 --- a/drivers/sysclock/arm_generic_timer/arm_generic_timer.c +++ b/drivers/sysclock/arm_generic_timer/arm_generic_timer.c @@ -164,7 +164,7 @@ int uk_sysclock_probe(void) uk_pr_crit("Could not get IRQ from dtb (%d)\n", ret); return 1; } - uk_intctlr_irq_configure(&irq); + uk_intctlr_irq_set_trigger(&irq); irq.id = irq.id; irq.trigger = UK_INTCTLR_IRQ_TRIGGER_LEVEL; diff --git a/lib/Config.uk b/lib/Config.uk index 29843300..2c27e1a8 100644 --- a/lib/Config.uk +++ b/lib/Config.uk @@ -33,6 +33,10 @@ config HAVE_X86PKU bool default n +config HAVE_SYSTICK + bool + default n + ## # Compatibility entries for legacy libraries ## diff --git a/lib/posix-time/time.c b/lib/posix-time/time.c index fbbd5c79..b90ba63f 100644 --- a/lib/posix-time/time.c +++ b/lib/posix-time/time.c @@ -78,7 +78,7 @@ UK_SYSCALL_R_DEFINE(int, nanosleep, const struct timespec*, req, struct timespec before = ukplat_monotonic_clock(); #if CONFIG_HAVE_SCHED - uk_sched_thread_sleep(nsec); + uk_sched_thread_sleep_ns(nsec); #else __spin_wait(nsec); #endif diff --git a/lib/tnschedprio/isrwoken.c b/lib/tnschedprio/isrwoken.c index 1392c174..19e764d4 100644 --- a/lib/tnschedprio/isrwoken.c +++ b/lib/tnschedprio/isrwoken.c @@ -20,8 +20,6 @@ void schedprio_thread_woken_isr(struct uk_sched *s, struct uk_thread *t) UK_ASSERT(ukplat_lcpu_irqs_disabled()); - if (t->wakeup_time > 0) - UK_TAILQ_REMOVE(&c->sleep_queue, t, sleep_queue); if (uk_thread_is_queueable(t) && uk_thread_is_runnable(t)) { _runq_add(c, t); uk_thread_clear_queueable(t); diff --git a/lib/tnschedprio/schedprio.c b/lib/tnschedprio/schedprio.c index 6e7333b0..b8475a12 100644 --- a/lib/tnschedprio/schedprio.c +++ b/lib/tnschedprio/schedprio.c @@ -24,7 +24,7 @@ static inline void schedprio_schedule(struct schedprio *c, bool yield) { struct uk_thread *prev, *next, *thread, *tmp; - __snsec now, min_wakeup_time; + __snsec now; unsigned long flags; bool runnable; int cmp_value; @@ -36,24 +36,6 @@ static inline void schedprio_schedule(struct schedprio *c, bool yield) prev = uk_thread_current(); flags = ukplat_lcpu_save_irqf(); - // TODO: Refactor sleep thread handling when we have a normal timer - // library. - - /* Examine all sleeping threads. - * Wake up expired ones and find the time when the next timeout expires. - */ - min_wakeup_time = 0; - UK_TAILQ_FOREACH_SAFE(thread, &c->sleep_queue, sleep_queue, tmp) - { - if (likely(thread->wakeup_time)) { - if (thread->wakeup_time <= now) - uk_thread_wake(thread); - else if (!min_wakeup_time - || thread->wakeup_time < min_wakeup_time) - min_wakeup_time = thread->wakeup_time; - } - } - next = _runq_best(c); runnable = uk_thread_is_runnable(prev); if (!runnable) { @@ -92,9 +74,6 @@ switch_thread: * We select the idle thread only if we do not * have anything else to execute */ - if (next == &(c->idle)) - c->idle_return_time = min_wakeup_time; - _runq_remove(c, next); if (runnable) _runq_add(c, prev); @@ -173,8 +152,6 @@ static void schedprio_thread_blocked(struct uk_sched *s, struct uk_thread *t) if (t != uk_thread_current()) _runq_remove(c, t); - if (t->wakeup_time > 0) - UK_TAILQ_INSERT_TAIL(&c->sleep_queue, t, sleep_queue); } static __noreturn void idle_thread_fn(void *argp) @@ -208,9 +185,11 @@ static __noreturn void idle_thread_fn(void *argp) continue; } + ukplat_lcpu_restore_irqf(flags); /* Read return time set by last schedule operation */ - wake_up_time = c->idle_return_time; + wake_up_time = ticks_to_ns( + tn_systick_get_tick() + tn_timer_next_tick()); now = ukplat_monotonic_clock(); if (!wake_up_time || wake_up_time > now) { @@ -223,8 +202,6 @@ static __noreturn void idle_thread_fn(void *argp) ukplat_lcpu_irqs_handle_pending(); } - ukplat_lcpu_restore_irqf(flags); - /* try to schedule a thread that might now be available */ schedprio_schedule(c, true); } @@ -295,7 +272,6 @@ struct uk_sched *tn_schedprio_create(struct uk_alloc *a) goto err_out; _runq_init(c); - UK_TAILQ_INIT(&c->sleep_queue); /* Create idle thread */ rc = uk_thread_init_fn1(&c->idle, idle_thread_fn, (void *)c, a, diff --git a/lib/tnschedprio/schedprio.h b/lib/tnschedprio/schedprio.h index 5eae91b1..c967f52c 100644 --- a/lib/tnschedprio/schedprio.h +++ b/lib/tnschedprio/schedprio.h @@ -25,7 +25,6 @@ struct schedprio { #elif defined(CONFIG_LIBTNSCHEDPRIO_RUNQ_LIST) struct uk_list_head run_queue; #endif - struct uk_thread_list sleep_queue; struct uk_thread idle; __nsec idle_return_time; diff --git a/lib/tnsystick/Config.uk b/lib/tnsystick/Config.uk index 33aee276..64f1857e 100644 --- a/lib/tnsystick/Config.uk +++ b/lib/tnsystick/Config.uk @@ -1,10 +1,7 @@ -config HAVE_SYSTICK - bool - menuconfig LIBTNSYSTICK bool "systick: Kernel systick configuration" default y - depends on HAVE_SYSTICK + select HAVE_SYSTICK if LIBTNSYSTICK diff --git a/lib/tnsystick/exportsyms.uk b/lib/tnsystick/exportsyms.uk index c972c09d..d347bfd9 100644 --- a/lib/tnsystick/exportsyms.uk +++ b/lib/tnsystick/exportsyms.uk @@ -6,3 +6,5 @@ tn_systick_get_irq tn_systick_register tn_systick_until tn_systick_get_monotonic +ticks_to_ns +ns_to_ticks diff --git a/lib/tnsystick/include/tn/systick.h b/lib/tnsystick/include/tn/systick.h index d2291e6e..796f9ae9 100644 --- a/lib/tnsystick/include/tn/systick.h +++ b/lib/tnsystick/include/tn/systick.h @@ -100,6 +100,19 @@ void tn_systick_add_timeout(void); /* adapt original delayed programme */ void tn_systick_until(__nsec until); + +/** + * ticks_to_ns - Convert systicks to ns. + * @param ticks: The ticks need to convert. + */ +__nsec ticks_to_ns(systick_t ticks); + +/** + * ticks_to_ns - Convert ns to systicks. + * @param ns: The ns need to convert. + */ +systick_t ns_to_ticks(__nsec ns); + __nsec tn_systick_get_monotonic(void); #endif /* __TN_LIBTNSYSTICK_H__ */ diff --git a/lib/tnsystick/tnsystick.c b/lib/tnsystick/tnsystick.c index 80cf4424..6f3d3bd5 100644 --- a/lib/tnsystick/tnsystick.c +++ b/lib/tnsystick/tnsystick.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -239,7 +240,7 @@ void tn_systick_register(const char *name, uint32_t freq, sysclock.ops = ops; } -static inline uint64_t ticks_to_ns(uint64_t ticks) +__nsec ticks_to_ns(systick_t ticks) { if (ticks > max_convert_ticks) { /* We have reached the maximum number of ticks to convert using @@ -251,53 +252,41 @@ static inline uint64_t ticks_to_ns(uint64_t ticks) } } -static inline uint64_t ns_to_ticks(uint64_t ns) +systick_t ns_to_ticks(__nsec ns) { + systick_t isceil = 0; + + if (ns % tot_ns_per_tick) + isceil = 1; if (ns > __MAX_CONVERT_NS) { /* We have reached the maximum number of ns to convert using the * shift factor */ - return (ns / tot_ns_per_tick); + return (ns / tot_ns_per_tick + isceil); } else { - return (tick_per_ns * ns) >> shift_ns_to_tick; + return ((tick_per_ns * ns) >> shift_ns_to_tick) + isceil; } } -/* - * Returns early if any interrupts are serviced, or if the requested delay is - * too short. Must be called with interrupts disabled, will enable interrupts - * "atomically" during idle loop. - * - * This function must be called only from the scheduler. It will screw - * your system if you do otherwise. And, there is no reason you - * actually want to use it anywhere else. THIS IS NOT A YIELD or any - * kind of mutex_lock. It will simply halt the cpu, not allowing any - * other thread to execute. - */ -static void cpu_block_until(uint64_t until_ns) +static void cpu_block_until(__nsec until_ns) { - uint64_t now_ns; + __nsec now_ns; systick_t until_ticks; + unsigned long flags; - UK_ASSERT(ukplat_lcpu_irqs_disabled()); - + flags = ukplat_lcpu_save_irqf(); /* Record current ns */ - now_ns = ticks_to_ns((uint64_t)tn_systick_get_tick()); + now_ns = ticks_to_ns((systick_t)tn_systick_get_tick()); if (now_ns < until_ns) { /* Calculate until_ticks for timer */ - until_ticks = - tn_systick_get_tick() + ns_to_ticks(until_ns - now_ns); - sysclock.ops->set_next(until_ticks, 0); + until_ticks = ns_to_ticks(until_ns - now_ns); + sysclock.ops->set_next(ticks_to_counts(until_ticks), 0); sysclock.ops->unmask_base_irq(); __asm__ __volatile__("wfi"); - - /* Give the IRQ handler a chance to handle whatever woke - * us up - */ - ukplat_lcpu_enable_irq(); - ukplat_lcpu_disable_irq(); } + ukplat_lcpu_restore_irqf(flags); + ukplat_lcpu_enable_irq(); } #if (CONFIG_ARCH_ARM_32 || CONFIG_ARCH_ARM_64) diff --git a/lib/tntimer/Config.uk b/lib/tntimer/Config.uk index df7c278c..4cf9ffff 100644 --- a/lib/tntimer/Config.uk +++ b/lib/tntimer/Config.uk @@ -1,6 +1,6 @@ menuconfig LIBTNTIMER bool "timer: Kernel timer configuration" - depends on HAVE_SYSTICK + select LIBTNSYSTICK default n diff --git a/lib/tntimer/tntimer.c b/lib/tntimer/tntimer.c index 64446c33..199c12eb 100644 --- a/lib/tntimer/tntimer.c +++ b/lib/tntimer/tntimer.c @@ -121,7 +121,7 @@ void tn_timer_start(struct timer *t) systick_t sum; cur = tn_systick_get_tick(); - sum = cur + t->init_tick; + sum = cur + MAX(1, t->init_tick); t->timeout_tick = sum; if (sum < cur || sum < t->init_tick) { // 发生了溢出 diff --git a/lib/uksched/Config.uk b/lib/uksched/Config.uk index 1ce1f691..f9b0cee8 100644 --- a/lib/uksched/Config.uk +++ b/lib/uksched/Config.uk @@ -5,6 +5,8 @@ menuconfig LIBUKSCHED select LIBUKDEBUG select LIBUKALLOC select HAVE_SCHED + select LIBTNSYSTICK + select LIBTNTIMER if LIBUKSCHED config LIBUKSCHED_THREAD_PRIORITY diff --git a/lib/uksched/exportsyms.uk b/lib/uksched/exportsyms.uk index 7874cc65..9b1f0537 100644 --- a/lib/uksched/exportsyms.uk +++ b/lib/uksched/exportsyms.uk @@ -7,7 +7,8 @@ uk_sched_thread_create_fn2 uk_sched_thread_add uk_sched_thread_remove uk_sched_thread_terminate -uk_sched_thread_sleep +uk_sched_thread_sleep_ns +uk_sched_thread_sleep_tick uk_sched_thread_exit uk_sched_thread_exit2 uk_sched_dumpk_threads @@ -37,6 +38,7 @@ uk_thread_release uk_thread_block_until uk_thread_block_timeout uk_thread_block +uk_thread_timeout uk_thread_wake uk_thread_wake_isr __uk_sched_thread_current diff --git a/lib/uksched/include/uk/sched.h b/lib/uksched/include/uk/sched.h index dd2042c1..3027e79b 100644 --- a/lib/uksched/include/uk/sched.h +++ b/lib/uksched/include/uk/sched.h @@ -377,6 +377,8 @@ struct uk_thread *uk_sched_thread_create_fn2(struct uk_sched *s, */ void uk_sched_dumpk_threads(int klvl, struct uk_sched *s); +/* used to maintain forward compatibility */ +#define uk_sched_thread_sleep uk_sched_thread_sleep_ns /** * Sleep current thread * @@ -385,7 +387,17 @@ void uk_sched_dumpk_threads(int klvl, struct uk_sched *s); * @return * NULL */ -void uk_sched_thread_sleep(__nsec nsec); +void uk_sched_thread_sleep_ns(__nsec nsec); + +/** + * Sleep current thread + * + * @param tick + * tick period to sleep + * @return + * NULL + */ +void uk_sched_thread_sleep_tick(systick_t tick); /** * Exits the current thread context diff --git a/lib/uksched/include/uk/thread.h b/lib/uksched/include/uk/thread.h index 0356d86a..b9b14734 100644 --- a/lib/uksched/include/uk/thread.h +++ b/lib/uksched/include/uk/thread.h @@ -40,6 +40,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -61,8 +62,6 @@ struct uk_thread { __uptr uktlsp; /**< Unikraft TLS pointer */ __uptr auxsp; /**< Unikraft Auxiliary Stack Pointer */ - /* TODO: Remove this, only for compatible*/ - UK_TAILQ_ENTRY(struct uk_thread) sleep_queue; #if defined(CONFIG_LIBUKSCHED_RUNQ_TAILQ) UK_TAILQ_ENTRY(struct uk_thread) queue; #elif defined(CONFIG_LIBUKSCHED_RUNQ_LIST) @@ -70,7 +69,7 @@ struct uk_thread { #endif uint32_t flags; - __snsec wakeup_time; + struct timer timer; struct uk_sched *sched; struct { @@ -1047,7 +1046,7 @@ void uk_thread_release(struct uk_thread *t); * @return * NULL */ -void uk_thread_block_until(struct uk_thread *thread, __snsec until); +void uk_thread_block_until(struct uk_thread *thread, __nsec until); /* Set the thread as blocked and assign a timeout * @param thread @@ -1075,6 +1074,14 @@ void uk_thread_block(struct uk_thread *thread); */ void uk_thread_wake(struct uk_thread *thread); +/* The callback of thread timeout + * @param thread + * Thread to be blocked + * @return + * NULL + */ +void uk_thread_timeout(struct uk_thread *thread); + /** * Macro to access a Unikraft thread-local (UKTLS) variable of a * (foreign) thread. @@ -1175,6 +1182,13 @@ struct uk_thread_inittab_entry { UK_THREAD_INIT_PRIO_FLAGS(init_fn, term_fn, UK_PRIO_LATEST, \ (UK_THREAD_INITF_ALL)) +#define TN_THREAD_TIMER_START(thread, init_tick) \ + do { \ + tn_timer_init(&(thread->timer), init_tick, \ + uk_thread_timeout, thread, TN_TIMER_FLAG_ONE_SHOT);\ + tn_timer_start(&(thread->timer)); \ + } while (0) + #ifdef __cplusplus } #endif diff --git a/lib/uksched/include/uk/wait.h b/lib/uksched/include/uk/wait.h index 30d21df6..0d5b4eb3 100644 --- a/lib/uksched/include/uk/wait.h +++ b/lib/uksched/include/uk/wait.h @@ -113,7 +113,8 @@ do { \ break; \ } \ uk_waitq_add(wq, &__wait); \ - __current->wakeup_time = deadline; \ + TN_THREAD_TIMER_START(__current, ns_to_ticks( \ + deadline - ukplat_monotonic_clock())); \ uk_thread_set_blocked(__current); \ uk_sched_thread_blocked(__current); \ ukplat_spin_unlock_irqrestore(&((wq)->sl), \ @@ -147,7 +148,8 @@ do { \ __current = uk_thread_current(); \ ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ uk_waitq_add(wq, &__wait); \ - __current->wakeup_time = deadline; \ + TN_THREAD_TIMER_START(__current, ns_to_ticks( \ + deadline - ukplat_monotonic_clock())); \ uk_thread_set_blocked(__current); \ uk_sched_thread_blocked(__current); \ ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ diff --git a/lib/uksched/isrwake.c b/lib/uksched/isrwake.c index 279ba885..d318bfda 100644 --- a/lib/uksched/isrwake.c +++ b/lib/uksched/isrwake.c @@ -16,6 +16,5 @@ void uk_thread_wake_isr(struct uk_thread *thread) if (thread->sched) uk_sched_thread_woken_isr(thread); } - thread->wakeup_time = 0LL; ukplat_lcpu_restore_irqf(flags); } diff --git a/lib/uksched/sched.c b/lib/uksched/sched.c index 94fee450..acfb0dd8 100644 --- a/lib/uksched/sched.c +++ b/lib/uksched/sched.c @@ -339,12 +339,21 @@ void uk_sched_thread_exit(void) uk_sched_thread_exit2(NULL, NULL); } -void uk_sched_thread_sleep(__nsec nsec) +void uk_sched_thread_sleep_ns(__nsec nsec) { struct uk_thread *thread; thread = uk_thread_current(); - uk_thread_block_timeout(thread, nsec); + uk_thread_block_timeout(thread, ns_to_ticks(nsec)); + uk_sched_yield(); +} + +void uk_sched_thread_sleep_tick(systick_t tick) +{ + struct uk_thread *thread; + + thread = uk_thread_current(); + uk_thread_block_timeout(thread, tick); uk_sched_yield(); } diff --git a/lib/uksched/tests/test_sched.c b/lib/uksched/tests/test_sched.c index cc469bdc..80d24c38 100644 --- a/lib/uksched/tests/test_sched.c +++ b/lib/uksched/tests/test_sched.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #if CONFIG_LIBUKBOOT_INITBBUDDY #include #define uk_alloc_init uk_allocbbuddy_init @@ -48,8 +48,14 @@ UK_TESTCASE(uksched, test_sched_register) /*初始化返回值*/ int ret; struct uk_alloc *a = uk_alloc_get_default(); +#ifdef CONFIG_LIBUKSCHEDCOOP struct uk_sched *node1 = uk_schedcoop_create(a); struct uk_sched *node2 = uk_schedcoop_create(a); +#endif +#ifdef CONFIG_LIBTNSCHEDPRIO + struct uk_sched *node1 = tn_schedprio_create(a); + struct uk_sched *node2 = tn_schedprio_create(a); +#endif ret = uk_sched_register(node1); // when the list is empty @@ -122,7 +128,7 @@ UK_TESTCASE(uksched, test_thread_block_no_timeout_then_wake) uk_thread_wake(main_thread); // TODO:add test for irq-safe operation。 UK_TEST_EXPECT_SNUM_EQ(uk_thread_is_runnable(main_thread), 1); - UK_TEST_EXPECT_SNUM_EQ(main_thread->wakeup_time, 0LL); + UK_TEST_EXPECT_SNUM_EQ(main_thread->timer.init_tick, 0LL); } UK_TESTCASE(uksched, test_thread_set_exited) @@ -155,11 +161,11 @@ UK_TESTCASE(uksched, test_sched_thread_sleep) false, "test_sleep", NULL, NULL); ret = uk_sched_thread_add(s, main_thread); - time_t begin = ukplat_monotonic_clock(); + __nsec begin = ukplat_monotonic_clock(); uk_sched_thread_sleep(10000); - time_t end = ukplat_monotonic_clock(); + __nsec end = ukplat_monotonic_clock(); UK_TEST_EXPECT_SNUM_NQ(end-begin, 0); } diff --git a/lib/uksched/thread.c b/lib/uksched/thread.c index cd5c544c..a3064b8a 100644 --- a/lib/uksched/thread.c +++ b/lib/uksched/thread.c @@ -45,6 +45,7 @@ #include #include #include +#include #if CONFIG_LIBUKSCHED_TCB_INIT && !CONFIG_UKARCH_TLS_HAVE_TCB #error CONFIG_LIBUKSCHED_TCB_INIT requires that a TLS contains reserved space for a TCB @@ -1095,39 +1096,44 @@ void uk_thread_release(struct uk_thread *t) uk_free(a, t); } -void uk_thread_block_until(struct uk_thread *thread, __snsec until) +void uk_thread_block_timeout(struct uk_thread *thread, systick_t tick) { unsigned long flags; UK_ASSERT(thread); flags = ukplat_lcpu_save_irqf(); - thread->wakeup_time = until; if (uk_thread_is_runnable(thread)) { uk_thread_set_blocked(thread); + TN_THREAD_TIMER_START(thread, tick); if (thread->sched) uk_sched_thread_blocked(thread); } ukplat_lcpu_restore_irqf(flags); } -void uk_thread_block_timeout(struct uk_thread *thread, __nsec nsec) +void uk_thread_block_until(struct uk_thread *thread, __nsec until) { - if (!nsec) - return; - - __snsec until = (__snsec) ukplat_monotonic_clock() + nsec; - UK_ASSERT(thread); - uk_thread_block_until(thread, until); + __nsec nsec = until - ukplat_monotonic_clock(); + + uk_thread_block_timeout(thread, ns_to_ticks(nsec)); } void uk_thread_block(struct uk_thread *thread) { + unsigned long flags; + UK_ASSERT(thread); - uk_thread_block_until(thread, (__nsec) 0); + flags = ukplat_lcpu_save_irqf(); + if (uk_thread_is_runnable(thread)) { + uk_thread_set_blocked(thread); + if (thread->sched) + uk_sched_thread_blocked(thread); + } + ukplat_lcpu_restore_irqf(flags); } void uk_thread_wake(struct uk_thread *thread) @@ -1140,6 +1146,13 @@ void uk_thread_wake(struct uk_thread *thread) if (thread->sched) uk_sched_thread_woken(thread); } - thread->wakeup_time = 0LL; ukplat_lcpu_restore_irqf(flags); } + +void uk_thread_timeout(struct uk_thread *thread) +{ + uk_thread_wake(thread); + + /* TODO: oepn reschedule when reschedule support interrupt ctx*/ + // uk_sched_reschedule(); +} diff --git a/lib/ukschedcoop/isrwoken.c b/lib/ukschedcoop/isrwoken.c index 7ef783a5..2e573f1f 100644 --- a/lib/ukschedcoop/isrwoken.c +++ b/lib/ukschedcoop/isrwoken.c @@ -11,8 +11,6 @@ void schedcoop_thread_woken_isr(struct uk_sched *s, struct uk_thread *t) UK_ASSERT(ukplat_lcpu_irqs_disabled()); - if (t->wakeup_time > 0) - UK_TAILQ_REMOVE(&c->sleep_queue, t, queue); if (uk_thread_is_queueable(t) && uk_thread_is_runnable(t)) { UK_TAILQ_INSERT_TAIL(&c->run_queue, t, queue); uk_thread_clear_queueable(t); diff --git a/lib/ukschedcoop/schedcoop.c b/lib/ukschedcoop/schedcoop.c index c3435304..c7ea2293 100644 --- a/lib/ukschedcoop/schedcoop.c +++ b/lib/ukschedcoop/schedcoop.c @@ -42,7 +42,7 @@ static inline void schedcoop_schedule(struct uk_sched *s, bool yield) { struct schedcoop *c = uksched2schedcoop(s); struct uk_thread *prev, *next, *thread, *tmp; - __snsec now, min_wakeup_time; + __snsec now; unsigned long flags; if (unlikely(ukplat_lcpu_irqs_disabled())) @@ -69,21 +69,6 @@ static inline void schedcoop_schedule(struct uk_sched *s, bool yield) prev->exec_time += now - c->ts_prev_switch; c->ts_prev_switch = now; - /* Examine all sleeping threads. - * Wake up expired ones and find the time when the next timeout expires. - */ - min_wakeup_time = 0; - UK_TAILQ_FOREACH_SAFE(thread, &c->sleep_queue, - queue, tmp) { - if (likely(thread->wakeup_time)) { - if (thread->wakeup_time <= now) - uk_thread_wake(thread); - else if (!min_wakeup_time - || thread->wakeup_time < min_wakeup_time) - min_wakeup_time = thread->wakeup_time; - } - } - next = UK_TAILQ_FIRST(&c->run_queue); if (next) { UK_ASSERT(next != prev); @@ -107,7 +92,6 @@ static inline void schedcoop_schedule(struct uk_sched *s, bool yield) * We select the idle thread only if we do not have anything * else to execute */ - c->idle_return_time = min_wakeup_time; next = &c->idle; } @@ -172,8 +156,6 @@ static void schedcoop_thread_blocked(struct uk_sched *s, struct uk_thread *t) if (t != uk_thread_current()) UK_TAILQ_REMOVE(&c->run_queue, t, queue); - if (t->wakeup_time > 0) - UK_TAILQ_INSERT_TAIL(&c->sleep_queue, t, queue); } static __noreturn void idle_thread_fn(void *argp) @@ -209,9 +191,11 @@ static __noreturn void idle_thread_fn(void *argp) continue; } + ukplat_lcpu_restore_irqf(flags); /* Read return time set by last schedule operation */ - wake_up_time = (volatile __nsec) c->idle_return_time; + wake_up_time = ticks_to_ns( + tn_systick_get_tick() + tn_timer_next_tick()); now = ukplat_monotonic_clock(); if (!wake_up_time || wake_up_time > now) { @@ -220,9 +204,6 @@ static __noreturn void idle_thread_fn(void *argp) else ukplat_lcpu_halt_irq(); } - - ukplat_lcpu_restore_irqf(flags); - /* try to schedule a thread that might now be available */ schedcoop_schedule(&c->sched, true); } @@ -277,7 +258,6 @@ struct uk_sched *uk_schedcoop_create(struct uk_alloc *a) goto err_out; UK_TAILQ_INIT(&c->run_queue); - UK_TAILQ_INIT(&c->sleep_queue); /* Create idle thread */ rc = uk_thread_init_fn1(&c->idle, diff --git a/lib/ukschedcoop/schedcoop.h b/lib/ukschedcoop/schedcoop.h index d07ca7cc..9af50ae9 100644 --- a/lib/ukschedcoop/schedcoop.h +++ b/lib/ukschedcoop/schedcoop.h @@ -11,10 +11,8 @@ struct schedcoop { struct uk_sched sched; struct uk_thread_list run_queue; - struct uk_thread_list sleep_queue; struct uk_thread idle; - __nsec idle_return_time; __nsec ts_prev_switch; }; diff --git a/plat/common/lcpu.c b/plat/common/lcpu.c index a2c00691..130b51f9 100644 --- a/plat/common/lcpu.c +++ b/plat/common/lcpu.c @@ -191,8 +191,6 @@ void __noreturn ukplat_lcpu_halt(void) void ukplat_lcpu_halt_irq_until(__nsec until) { - UK_ASSERT(ukplat_lcpu_irqs_disabled()); - time_block_until(until); } -- Gitee From 0a39de9e95642ab5d91534cc43a90bfde7d4ffae Mon Sep 17 00:00:00 2001 From: Li Haode Date: Thu, 11 Apr 2024 15:33:17 +0800 Subject: [PATCH 18/35] lib/tnsystick: mask the impact of clock interrupts Signed-off-by: Li Haode --- lib/tnsystick/tests/test_systick.c | 52 +++++++++++++++--------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/lib/tnsystick/tests/test_systick.c b/lib/tnsystick/tests/test_systick.c index 3354758a..fd3b50c9 100644 --- a/lib/tnsystick/tests/test_systick.c +++ b/lib/tnsystick/tests/test_systick.c @@ -45,8 +45,13 @@ UK_TESTCASE(tnsystick, test_calculate_mult_shift) #define TEST_UNMASK_BASE_IRQ 4 #define TEST_IRQ_ID 11 +struct sysclock_ops test_sysclock_ops; +struct uk_intctlr_irq test_irq; +struct sysclock_desc ori_sysclock; + static int test_ret; static uint64_t test_count; +unsigned long flags; static void test_systick_set_next(uint64_t counts __unused, uint8_t set_auto_reload __unused) @@ -69,25 +74,36 @@ static void test_systick_unmask_base_irq(void) test_ret = TEST_UNMASK_BASE_IRQ; } -UK_TESTCASE(tnsystick, test_systick_ops) +static inline void test_systick_init(uint32_t freq) { - struct sysclock_ops test_sysclock_ops; - struct uk_intctlr_irq test_irq; - struct sysclock_desc ori_sysclock; - const char *test_sysclock_name = "test sysclock"; - + flags = ukplat_lcpu_save_irqf(); ori_sysclock = sysclock; test_irq.id = TEST_IRQ_ID; test_irq.trigger = 0; + const char *test_sysclock_name = "test sysclock"; + test_sysclock_ops.set_next = test_systick_set_next; test_sysclock_ops.get_count = test_systick_get_count; test_sysclock_ops.mask_base_irq = test_systick_mask_base_irq; test_sysclock_ops.unmask_base_irq = test_systick_unmask_base_irq; - tn_systick_register(test_sysclock_name, 0, &test_irq, + tn_systick_register(test_sysclock_name, freq, &test_irq, &test_sysclock_ops); +} + +static inline void test_systick_restore(void) +{ + tn_systick_register(ori_sysclock.name, ori_sysclock.freq, + ori_sysclock.irq, ori_sysclock.ops); + + ukplat_lcpu_restore_irqf(flags); +} + +UK_TESTCASE(tnsystick, test_systick_ops) +{ + test_systick_init(0); /* test tn_systick_register */ UK_TEST_EXPECT_PTR_EQ(sysclock.ops, &test_sysclock_ops); @@ -99,8 +115,7 @@ UK_TESTCASE(tnsystick, test_systick_ops) tn_systick_start(); UK_TEST_EXPECT_SNUM_EQ(test_ret, TEST_UNMASK_BASE_IRQ); - tn_systick_register(ori_sysclock.name, ori_sysclock.freq, - ori_sysclock.irq, ori_sysclock.ops); + test_systick_restore(); } /* test tn_systick_get_tick */ @@ -109,22 +124,8 @@ UK_TESTCASE(tnsystick, test_get_systick) { systick_t start_tick, dealta_tick, target_tick; uint64_t start_count, target_count; - struct sysclock_ops test_sysclock_ops; - struct uk_intctlr_irq test_irq; - struct sysclock_desc ori_sysclock; - const char *test_sysclock_name = "test sysclock"; - ori_sysclock = sysclock; - test_irq.id = TEST_IRQ_ID; - test_irq.trigger = 0; - - test_sysclock_ops.set_next = test_systick_set_next; - test_sysclock_ops.get_count = test_systick_get_count; - test_sysclock_ops.mask_base_irq = test_systick_mask_base_irq; - test_sysclock_ops.unmask_base_irq = test_systick_unmask_base_irq; - - tn_systick_register(test_sysclock_name, ori_sysclock.freq, &test_irq, - &test_sysclock_ops); + test_systick_init(sysclock.freq); /* test case 1: delay TEST_COUNTS counts and updated ticks */ sys_timer_irq_handler(NULL); @@ -147,8 +148,7 @@ UK_TESTCASE(tnsystick, test_get_systick) UK_TEST_EXPECT_SNUM_EQ(dealta_tick, 0); - tn_systick_register(ori_sysclock.name, ori_sysclock.freq, - ori_sysclock.irq, ori_sysclock.ops); + test_systick_restore(); } uk_testsuite_register(tnsystick, NULL); -- Gitee From 9a8c36585c1f9c9c53e3dcfa14a3b5727af08b28 Mon Sep 17 00:00:00 2001 From: Li Haode Date: Tue, 16 Apr 2024 17:04:59 +0800 Subject: [PATCH 19/35] lib/sched: modify thread_sleep test Signed-off-by: Li Haode --- lib/uksched/tests/test_sched.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/uksched/tests/test_sched.c b/lib/uksched/tests/test_sched.c index 80d24c38..dc540dd3 100644 --- a/lib/uksched/tests/test_sched.c +++ b/lib/uksched/tests/test_sched.c @@ -26,6 +26,11 @@ #include #include #include +#ifdef CONFIG_LIBUKSCHEDCOOP +#include +#elif CONFIG_LIBTNSCHEDPRIO +#include +#endif #if CONFIG_LIBUKBOOT_INITBBUDDY #include #define uk_alloc_init uk_allocbbuddy_init @@ -153,6 +158,7 @@ UK_TESTCASE(uksched, test_sched_thread_sleep) int ret; struct uk_sched *s = uk_sched_current(); uintptr_t tlsp; + systick_t begin_t, end_t; tlsp = ukplat_tlsp_get(); @@ -161,13 +167,17 @@ UK_TESTCASE(uksched, test_sched_thread_sleep) false, "test_sleep", NULL, NULL); ret = uk_sched_thread_add(s, main_thread); - __nsec begin = ukplat_monotonic_clock(); + begin_t = tn_systick_get_tick(); + uk_sched_thread_sleep_tick(100); + end_t = tn_systick_get_tick(); - uk_sched_thread_sleep(10000); + UK_TEST_EXPECT_SNUM_EQ(end_t-begin_t, 100); - __nsec end = ukplat_monotonic_clock(); + begin_t = tn_systick_get_tick(); + uk_sched_thread_sleep_ns(10000); + end_t = tn_systick_get_tick(); - UK_TEST_EXPECT_SNUM_NQ(end-begin, 0); + UK_TEST_EXPECT_SNUM_EQ(end_t-begin_t, ns_to_ticks(10000)); } static __noreturn void idle_thread_fn(void *argp) -- Gitee From 9615fddc2ef80afad67c4093054fdacc3543160d Mon Sep 17 00:00:00 2001 From: Li Haode Date: Thu, 18 Apr 2024 16:49:49 +0800 Subject: [PATCH 20/35] lib/tntimer: optimize codes to reduce bias Signed-off-by: Li Haode --- lib/tntimer/tests/test_tntimer.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/tntimer/tests/test_tntimer.c b/lib/tntimer/tests/test_tntimer.c index 475d7852..aa5a82cf 100644 --- a/lib/tntimer/tests/test_tntimer.c +++ b/lib/tntimer/tests/test_tntimer.c @@ -69,7 +69,6 @@ UK_TESTCASE(tntimer, test_tn_timer_list_operations) systick_t t4 = 0x260000; systick_t t5 = 0x50000; - systick_t cur = tn_systick_get_tick(); struct timer *temp; struct timer *timer1 = tn_timer_create( @@ -108,40 +107,39 @@ UK_TESTCASE(tntimer, test_tn_timer_list_operations) dump_timer(); timer2 = tn_timer_create( t2, *timeout_func1, NULL, TN_TIMER_FLAG_ONE_SHOT); - - systick_t last_tick = tn_timer_next_tick() + cur; - tn_timer_start(timer2); dump_timer(); + systick_t last_tick = tn_timer_next_tick() + tn_systick_get_tick(); + temp = uk_list_first_entry_or_null(timer_list_head, struct timer, list); UK_TEST_EXPECT_NOT_NULL(temp); - UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick, 10); + UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick, 20); tn_timer_delete(temp); temp = uk_list_first_entry_or_null(timer_list_head, struct timer, list); UK_TEST_EXPECT_NOT_NULL(temp); UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick-0xB0000, - 10); + 20); tn_timer_delete(temp); temp = uk_list_first_entry_or_null(timer_list_head, struct timer, list); UK_TEST_EXPECT_NOT_NULL(temp); UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick - 0x1B0000, - 10); + 20); tn_timer_delete(temp); temp = uk_list_first_entry_or_null(timer_list_head, struct timer, list); UK_TEST_EXPECT_NOT_NULL(temp); UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick - 0x210000, - 10); + 20); tn_timer_delete(temp); temp = uk_list_first_entry_or_null(timer_list_head, struct timer, list); UK_TEST_EXPECT_NOT_NULL(temp); UK_TEST_EXPECT_SNUM_LT(temp->timeout_tick - last_tick - 0x2B0000, - 10); + 20); tn_timer_delete(temp); UK_INIT_LIST_HEAD(tn_timer_get_list()); @@ -158,8 +156,6 @@ UK_TESTCASE(tntimer, test_tn_timer_announce) systick_t t4 = 300; systick_t t5 = 302; - systick_t cur = tn_systick_get_tick(); - struct timer *node; struct uk_list_head *timer_list_head = tn_timer_get_list(); @@ -178,6 +174,8 @@ UK_TESTCASE(tntimer, test_tn_timer_announce) UK_TEST_EXPECT_NOT_NULL(timer2); UK_TEST_EXPECT_NOT_NULL(timer3); + systick_t cur = tn_systick_get_tick(); + tn_timer_start(timer1); tn_timer_start(timer2); tn_timer_start(timer3); @@ -190,29 +188,29 @@ UK_TESTCASE(tntimer, test_tn_timer_announce) *do nothing,wait for timeout func */ } - UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 100, 10); + UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 100, 20); while (excution < 2) { asm volatile("" ::: "memory"); /* *do nothing,wait for timeout func */ } + UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 200, 20); UK_TEST_EXPECT_SNUM_EQ(excution, 3); - UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 200, 10); while (excution < 4) { asm volatile("" ::: "memory"); /* *do nothing,wait for timeout func */ } - UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 300, 10); + UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 300, 20); while (excution < 5) { asm volatile("" ::: "memory"); /* *do nothing,wait for timeout func */ } - UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 302, 10); + UK_TEST_EXPECT_SNUM_LT(tn_systick_get_tick() - cur - 302, 20); dump_timer(); UK_TEST_EXPECT_SNUM_EQ(excution, 5); -- Gitee From 9d791bd2604d53b8c613f778bd013da1382da10f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=B5=9B?= Date: Thu, 18 Apr 2024 11:37:24 +0800 Subject: [PATCH 21/35] lib/tnsystick: support tickless MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 刘赛 --- lib/tnsystick/exportsyms.uk | 2 +- lib/tnsystick/include/tn/systick.h | 8 +++----- lib/tnsystick/tnsystick.c | 12 ++++++------ lib/tntimer/tntimer.c | 28 ++++++++++++++++++++-------- 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/lib/tnsystick/exportsyms.uk b/lib/tnsystick/exportsyms.uk index d347bfd9..59f9c50c 100644 --- a/lib/tnsystick/exportsyms.uk +++ b/lib/tnsystick/exportsyms.uk @@ -1,7 +1,7 @@ tn_systick_get_tick tn_systick_init tn_systick_start -tn_systick_add_timeout +tn_systick_set_timeout tn_systick_get_irq tn_systick_register tn_systick_until diff --git a/lib/tnsystick/include/tn/systick.h b/lib/tnsystick/include/tn/systick.h index 796f9ae9..e4b1aa40 100644 --- a/lib/tnsystick/include/tn/systick.h +++ b/lib/tnsystick/include/tn/systick.h @@ -91,12 +91,10 @@ uint32_t tn_systick_get_irq(void); void tn_systick_start(void); /** - * Add a timeout event based on the system tick - * - * todo - * + * Set the timeout as the next systick irq. + * @param ticks: The ticks need to set. */ -void tn_systick_add_timeout(void); +void tn_systick_set_timeout(systick_t ticks); /* adapt original delayed programme */ void tn_systick_until(__nsec until); diff --git a/lib/tnsystick/tnsystick.c b/lib/tnsystick/tnsystick.c index 6f3d3bd5..4e6b7b31 100644 --- a/lib/tnsystick/tnsystick.c +++ b/lib/tnsystick/tnsystick.c @@ -106,10 +106,7 @@ int sys_timer_irq_handler(void *arg __unused) /* 4、set next time-base irq */ #ifdef CONFIG_LIBTNSYSTICK_TICKLESS - systick_t timeout; - - timeout = tn_timer_next_tick(); - sysclock.ops->set_next(ticks_to_counts(timeout), 0); + tn_systick_set_timeout(tn_timer_next_tick()); #endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ __uk_test_and_clear_bit(0, &sched_have_pending_events); @@ -226,9 +223,12 @@ uint32_t tn_systick_get_irq(void) return sysclock.irq->id; } -void tn_systick_add_timeout(void) +void tn_systick_set_timeout(systick_t ticks) { - /* todo */ + if (ticks == TICK_MAX) + sysclock.ops->set_next(ticks_to_counts(max_convert_ticks), 0); + else + sysclock.ops->set_next(ticks_to_counts(ticks), 0); } void tn_systick_register(const char *name, uint32_t freq, diff --git a/lib/tntimer/tntimer.c b/lib/tntimer/tntimer.c index 199c12eb..3b2450a2 100644 --- a/lib/tntimer/tntimer.c +++ b/lib/tntimer/tntimer.c @@ -67,6 +67,17 @@ void tn_timer_init(struct timer *t, systick_t init_tick, t->flag = flag; } +static inline struct timer *get_next_timer(void) +{ + struct timer *t; + + t = uk_list_first_entry_or_null(&timer_list_head, struct timer, list); + if (!t && timoutListsOverflowed) + t = uk_list_first_entry(&overflow_timer_list_head, struct timer, + list); + return t; +} + systick_t tn_timer_next_tick(void) { struct timer *t; @@ -74,15 +85,10 @@ systick_t tn_timer_next_tick(void) cur = tn_systick_get_tick(); - t = uk_list_first_entry_or_null(&timer_list_head, struct timer, list); + t = get_next_timer(); + if (t) return t->timeout_tick - cur; - if (timoutListsOverflowed) { - t = uk_list_first_entry(&overflow_timer_list_head, struct timer, - list); - return t->timeout_tick - cur; - } - return TICK_MAX; } @@ -143,9 +149,15 @@ void tn_timer_add(struct timer *in, struct uk_list_head *head) continue; uk_list_add(&(in)->list, t->list.prev); - return; + goto update_next_tick; } uk_list_add_tail(&in->list, head); + +update_next_tick: +#ifdef CONFIG_LIBTNSYSTICK_TICKLESS + if (in == get_next_timer()) + tn_systick_set_timeout(tn_timer_next_tick()); +#endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ } void tn_timer_announce(void) -- Gitee From f285fb720b1ac8c43db676b5274e590b8ea17a52 Mon Sep 17 00:00:00 2001 From: sunhaoyi Date: Mon, 22 Apr 2024 18:53:43 +0800 Subject: [PATCH 22/35] drivers/sysclock: using TSC on x86 architectures to provide os tick and system timer Signed-off-by: sunhaoyi --- drivers/Makefile.uk | 2 +- drivers/sysclock/exportsyms.uk | 1 - drivers/{sysclock => tnsysclock}/Config.uk | 7 + drivers/{sysclock => tnsysclock}/Makefile.uk | 14 +- .../arm_generic_timer/Makefile.uk | 4 - .../arm_generic_timer/arm_generic_timer.c | 3 +- drivers/tnsysclock/exportsyms.uk | 1 + .../include/tn/sysclock.h} | 8 +- .../tests/test_sysclock.c | 0 .../tests/test_sysclock.h | 0 drivers/tnsysclock/tsc_i8254/Makefile.uk | 5 + drivers/tnsysclock/tsc_i8254/tsc_i8254.c | 174 ++++++++++++++++++ lib/tnsystick/Config.uk | 4 +- lib/tnsystick/Makefile.uk | 2 + lib/tnsystick/tnsystick.c | 7 +- lib/ukintctlr/exportsyms.uk | 2 + plat/kvm/Config.uk | 2 + plat/kvm/Makefile.uk | 2 + 18 files changed, 216 insertions(+), 22 deletions(-) delete mode 100644 drivers/sysclock/exportsyms.uk rename drivers/{sysclock => tnsysclock}/Config.uk (69%) rename drivers/{sysclock => tnsysclock}/Makefile.uk (36%) rename drivers/{sysclock => tnsysclock}/arm_generic_timer/Makefile.uk (50%) rename drivers/{sysclock => tnsysclock}/arm_generic_timer/arm_generic_timer.c (98%) create mode 100644 drivers/tnsysclock/exportsyms.uk rename drivers/{sysclock/arm_generic_timer/include/uk/sysclock/arm_generic_timer.h => tnsysclock/include/tn/sysclock.h} (82%) rename drivers/{sysclock => tnsysclock}/tests/test_sysclock.c (100%) rename drivers/{sysclock => tnsysclock}/tests/test_sysclock.h (100%) create mode 100644 drivers/tnsysclock/tsc_i8254/Makefile.uk create mode 100644 drivers/tnsysclock/tsc_i8254/tsc_i8254.c diff --git a/drivers/Makefile.uk b/drivers/Makefile.uk index 3a409856..a7f6381b 100644 --- a/drivers/Makefile.uk +++ b/drivers/Makefile.uk @@ -10,4 +10,4 @@ $(eval $(call import_lib,$(UK_DRIV_BASE)/ukbus)) $(eval $(call import_lib,$(UK_DRIV_BASE)/ukintctlr)) $(eval $(call import_lib,$(UK_DRIV_BASE)/uktty)) $(eval $(call import_lib,$(UK_DRIV_BASE)/virtio)) -$(eval $(call import_lib,$(UK_DRIV_BASE)/sysclock)) +$(eval $(call import_lib,$(UK_DRIV_BASE)/tnsysclock)) diff --git a/drivers/sysclock/exportsyms.uk b/drivers/sysclock/exportsyms.uk deleted file mode 100644 index d7dd2008..00000000 --- a/drivers/sysclock/exportsyms.uk +++ /dev/null @@ -1 +0,0 @@ -uk_sysclock_probe diff --git a/drivers/sysclock/Config.uk b/drivers/tnsysclock/Config.uk similarity index 69% rename from drivers/sysclock/Config.uk rename to drivers/tnsysclock/Config.uk index f971ea8e..e222f614 100644 --- a/drivers/sysclock/Config.uk +++ b/drivers/tnsysclock/Config.uk @@ -7,6 +7,13 @@ config ARM_GENERIC_TIMER bool "arm_generic_timer(used in arm cortex-a/cortex-r)" default n depends on SYSCLOCK + depends on ARCH_ARM_64 + +config TSC_I8254 + bool "tsc_i8254(used in x86)" + default n + depends on SYSCLOCK + depends on ARCH_X86_64 config SYSCLOCK_TEST bool "Enable unit tests" diff --git a/drivers/sysclock/Makefile.uk b/drivers/tnsysclock/Makefile.uk similarity index 36% rename from drivers/sysclock/Makefile.uk rename to drivers/tnsysclock/Makefile.uk index 65043219..35e6e0aa 100644 --- a/drivers/sysclock/Makefile.uk +++ b/drivers/tnsysclock/Makefile.uk @@ -4,11 +4,15 @@ # ################################################################################ -UK_DRIV_SYSCLOCK_BASE := $(UK_DRIV_BASE)/sysclock +UK_DRIV_SYSCLOCK_BASE := $(UK_DRIV_BASE)/tnsysclock +$(eval $(call addlib_s,libtnsysclock,$(CONFIG_SYSCLOCK))) + +ASINCLUDES-$(CONFIG_SYSCLOCK) += -I$(UK_DRIV_SYSCLOCK_BASE)/include +CINCLUDES-$(CONFIG_SYSCLOCK) += -I$(UK_DRIV_SYSCLOCK_BASE)/include +CXXINCLUDES-$(CONFIG_SYSCLOCK) += -I$(UK_DRIV_SYSCLOCK_BASE)/include + +LIBTNSYSCLOCK_CINCLUDES-y += -I$(CONFIG_UK_BASE)/plat/common/include $(eval $(call import_lib,$(UK_DRIV_SYSCLOCK_BASE)/arm_generic_timer)) -$(eval $(call addlib_s,sysclock,$(CONFIG_SYSCLOCK))) +$(eval $(call import_lib,$(UK_DRIV_SYSCLOCK_BASE)/tsc_i8254)) -ifneq ($(filter y,$(CONFIG_SYSCLOCK_TEST) $(CONFIG_LIBUKTEST_ALL)),) -SYSCLOCK_SRCS-y += $(UK_DRIV_SYSCLOCK_BASE)/tests/test_sysclock.c -endif diff --git a/drivers/sysclock/arm_generic_timer/Makefile.uk b/drivers/tnsysclock/arm_generic_timer/Makefile.uk similarity index 50% rename from drivers/sysclock/arm_generic_timer/Makefile.uk rename to drivers/tnsysclock/arm_generic_timer/Makefile.uk index a4fa8c96..38d0aa06 100644 --- a/drivers/sysclock/arm_generic_timer/Makefile.uk +++ b/drivers/tnsysclock/arm_generic_timer/Makefile.uk @@ -1,9 +1,5 @@ $(eval $(call addlib_s,arm_generic_timer,$(CONFIG_ARM_GENERIC_TIMER))) -ASINCLUDES-$(CONFIG_ARM_GENERIC_TIMER) += -I$(ARM_GENERIC_TIMER_BASE)/include -CINCLUDES-$(CONFIG_ARM_GENERIC_TIMER) += -I$(ARM_GENERIC_TIMER_BASE)/include -CXXINCLUDES-$(CONFIG_ARM_GENERIC_TIMER) += -I$(ARM_GENERIC_TIMER_BASE)/include - ARM_GENERIC_TIMER_CINCLUDES-y += -I$(CONFIG_UK_BASE)/plat/common/include ARM_GENERIC_TIMER_SRCS-$(CONFIG_ARM_GENERIC_TIMER) += $(ARM_GENERIC_TIMER_BASE)/arm_generic_timer.c diff --git a/drivers/sysclock/arm_generic_timer/arm_generic_timer.c b/drivers/tnsysclock/arm_generic_timer/arm_generic_timer.c similarity index 98% rename from drivers/sysclock/arm_generic_timer/arm_generic_timer.c rename to drivers/tnsysclock/arm_generic_timer/arm_generic_timer.c index 49d36ad6..cb083ff4 100644 --- a/drivers/sysclock/arm_generic_timer/arm_generic_timer.c +++ b/drivers/tnsysclock/arm_generic_timer/arm_generic_timer.c @@ -23,7 +23,6 @@ #include #include #include -#include static const char *sysclock_name = "arm generic timer"; struct uk_intctlr_irq irq; @@ -143,7 +142,7 @@ uint32_t sysclock_get_frequency(int fdt_timer) return fdt32_to_cpu(fdt_freq[0]); } -int uk_sysclock_probe(void) +int tn_sysclock_probe(void) { int ret, offs; diff --git a/drivers/tnsysclock/exportsyms.uk b/drivers/tnsysclock/exportsyms.uk new file mode 100644 index 00000000..52485168 --- /dev/null +++ b/drivers/tnsysclock/exportsyms.uk @@ -0,0 +1 @@ +tn_sysclock_probe diff --git a/drivers/sysclock/arm_generic_timer/include/uk/sysclock/arm_generic_timer.h b/drivers/tnsysclock/include/tn/sysclock.h similarity index 82% rename from drivers/sysclock/arm_generic_timer/include/uk/sysclock/arm_generic_timer.h rename to drivers/tnsysclock/include/tn/sysclock.h index b0da20e2..a0e531a3 100644 --- a/drivers/sysclock/arm_generic_timer/include/uk/sysclock/arm_generic_timer.h +++ b/drivers/tnsysclock/include/tn/sysclock.h @@ -13,9 +13,9 @@ * limitations under the License. */ -#ifndef __ARM_GENERIC_TIMER_H__ -#define __ARM_GENERIC_TIMER_H__ +#ifndef __TN_SYSCLOCK_H__ +#define __TN_SYSCLOCK_H__ -int uk_sysclock_probe(void); +int tn_sysclock_probe(void); -#endif /* __ARM_GENERIC_TIMER_H__ */ +#endif /* __TN_SYSCLOCK_H__ */ diff --git a/drivers/sysclock/tests/test_sysclock.c b/drivers/tnsysclock/tests/test_sysclock.c similarity index 100% rename from drivers/sysclock/tests/test_sysclock.c rename to drivers/tnsysclock/tests/test_sysclock.c diff --git a/drivers/sysclock/tests/test_sysclock.h b/drivers/tnsysclock/tests/test_sysclock.h similarity index 100% rename from drivers/sysclock/tests/test_sysclock.h rename to drivers/tnsysclock/tests/test_sysclock.h diff --git a/drivers/tnsysclock/tsc_i8254/Makefile.uk b/drivers/tnsysclock/tsc_i8254/Makefile.uk new file mode 100644 index 00000000..c467656a --- /dev/null +++ b/drivers/tnsysclock/tsc_i8254/Makefile.uk @@ -0,0 +1,5 @@ +$(eval $(call addlib_s,libtnsysclock_tsc_i8254,$(CONFIG_TSC_I8254))) + +LIBTNSYSCLOCK_TSC_I8254_CINCLUDES-y += -I$(CONFIG_UK_BASE)/plat/common/include + +LIBTNSYSCLOCK_TSC_I8254_SRCS-$(CONFIG_TSC_I8254) += $(LIBTNSYSCLOCK_TSC_I8254_BASE)/tsc_i8254.c diff --git a/drivers/tnsysclock/tsc_i8254/tsc_i8254.c b/drivers/tnsysclock/tsc_i8254/tsc_i8254.c new file mode 100644 index 00000000..a0eff799 --- /dev/null +++ b/drivers/tnsysclock/tsc_i8254/tsc_i8254.c @@ -0,0 +1,174 @@ +/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ssANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#define TIMER_CNTR 0x40 +#define TIMER_MODE 0x43 +#define TIMER_SEL0 0x00 +#define TIMER_LATCH 0x00 +#define TIMER_RATEGEN 0x04 +#define TIMER_ONESHOT 0x08 +#define TIMER_16BIT 0x30 +#define TIMER_HZ 1193182 +#define TIMER_DIVISOR_HZ 100 +#define i8254_MAX_COUNT 65535 + +static const char *sysclock_name = "tsc-i8254"; +uint64_t tsc_freq; +uint64_t i8254_set_threshold; +struct uk_intctlr_irq irq; +static struct sysclock_ops ops; + +static void sysclock_enable(void) +{ + outb(TIMER_MODE, TIMER_SEL0 | TIMER_ONESHOT | TIMER_16BIT); + outb(TIMER_CNTR, 0); + outb(TIMER_CNTR, 0); +} + +void sysclock_mask_irq(void) +{ + uk_intctlr_irq_mask(irq.id); +} + +void sysclock_unmask_irq(void) +{ + uk_intctlr_irq_unmask(irq.id); +} + +uint64_t sysclock_get_counts(void) +{ + return rdtsc(); +} + +void sysclock_set_next(uint64_t set_counts, uint8_t is_start __unused) +{ + uint64_t conuts; + set_counts = MIN(i8254_set_threshold, set_counts); + conuts = (set_counts * TIMER_HZ) / tsc_freq; + + outb(TIMER_MODE, TIMER_SEL0 | TIMER_ONESHOT | TIMER_16BIT); + outb(TIMER_CNTR, (conuts & 0xFF)); + outb(TIMER_CNTR, ((conuts >> 8) & 0xFF)); +} + +/* + * Read the current i8254 channel 0 tick count. + */ +static unsigned int i8254_gettick(void) +{ + __u16 rdval; + + outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); + rdval = inb(TIMER_CNTR); + rdval |= (inb(TIMER_CNTR) << 8); + return rdval; +} + +/* + * Delay for approximately n microseconds using the i8254 channel 0 counter. + * Timer must be programmed appropriately before calling this function. + */ +static void i8254_delay(unsigned int n) +{ + unsigned int cur_tick, initial_tick; + int remaining; + const unsigned long timer_rval = TIMER_HZ / TIMER_DIVISOR_HZ; + + initial_tick = i8254_gettick(); + + remaining = (unsigned long long)n * TIMER_HZ / 1000000; + + while (remaining > 1) { + cur_tick = i8254_gettick(); + if (cur_tick > initial_tick) + remaining -= timer_rval - (cur_tick - initial_tick); + else + remaining -= initial_tick - cur_tick; + initial_tick = cur_tick; + } +} + +uint32_t sysclock_get_frequency(void) +{ + uint64_t freq = 0, base; + uint32_t eax, ebx, ecx, edx; + + /* + * Attempt to retrieve TSC frequency via the hypervisor generic cpuid + * timing information leaf. 0x40000010 returns the (virtual) TSC + * frequency in kHz, or 0 if the feature is not supported by the + * hypervisor. + */ + cpuid(0x40000000, 0, &eax, &ebx, &ecx, &edx); + if (eax >= 0x40000010) { + uk_pr_info("Retrieving TSC clock frequency from hypervisor\n"); + base = rdtsc(); + cpuid(0x40000010, 0, &eax, &ebx, &ecx, &edx); + freq = eax * 1000; + } + + /* + * If we could not retrieve the TSC frequency from the hypervisor, + * calibrate against an 0.1s delay using the i8254 timer. This is + * undesirable as it delays the boot sequence. + */ + if (!freq) { + uk_pr_info("Calibrating TSC clock against i8254 timer\n"); + + /* + * Initialise i8254 timer channel 0 to mode 2 at + * TIMER_DIVISOR_HZ frequency + */ + outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); + outb(TIMER_CNTR, (TIMER_HZ / TIMER_DIVISOR_HZ) & 0xff); + outb(TIMER_CNTR, (TIMER_HZ / TIMER_DIVISOR_HZ) >> 8); + + base = rdtsc(); + i8254_delay(100000); + freq = (rdtsc() - base) * 10; + } + + return freq; +} + +int tn_sysclock_probe(void) +{ + irq.id = 0; + irq.trigger = UK_INTCTLR_IRQ_TRIGGER_LEVEL; + uk_intctlr_irq_set_trigger(&irq); + + tsc_freq = sysclock_get_frequency(); + i8254_set_threshold = + (MIN(i8254_MAX_COUNT * tsc_freq, UINT64_MAX)) / TIMER_HZ; + /* + * Mask IRQ before scheduler start working. Otherwise we will get + * unexpected timer interrupts when system is booting. + */ + sysclock_mask_irq(); + + ops.set_next = sysclock_set_next; + ops.get_count = sysclock_get_counts; + ops.mask_base_irq = sysclock_mask_irq; + ops.unmask_base_irq = sysclock_unmask_irq; + + tn_systick_register(sysclock_name, tsc_freq, &irq, &ops); + + sysclock_enable(); + return 0; +} diff --git a/lib/tnsystick/Config.uk b/lib/tnsystick/Config.uk index 64f1857e..e9277cc8 100644 --- a/lib/tnsystick/Config.uk +++ b/lib/tnsystick/Config.uk @@ -1,6 +1,6 @@ menuconfig LIBTNSYSTICK - bool "systick: Kernel systick configuration" - default y + bool "tnsystick: Kernel systick configuration" + default y if !(PLAT_LINUXU || PLAT_XEN) select HAVE_SYSTICK if LIBTNSYSTICK diff --git a/lib/tnsystick/Makefile.uk b/lib/tnsystick/Makefile.uk index d4ec664c..f9e76f4c 100644 --- a/lib/tnsystick/Makefile.uk +++ b/lib/tnsystick/Makefile.uk @@ -4,6 +4,8 @@ ASINCLUDES-$(CONFIG_LIBTNSYSTICK) += -I$(LIBTNSYSTICK_BASE)/include CINCLUDES-$(CONFIG_LIBTNSYSTICK) += -I$(LIBTNSYSTICK_BASE)/include CXXINCLUDES-$(CONFIG_LIBTNSYSTICK) += -I$(LIBTNSYSTICK_BASE)/include +LIBTNSYSTICK_CINCLUDES-y += -I$(CONFIG_UK_BASE)/plat/common/include + LIBTNSYSTICK_SRCS-$(CONFIG_LIBTNSYSTICK) += $(LIBTNSYSTICK_BASE)/tnsystick.c ifneq ($(filter y,$(CONFIG_LIBTNSYSTICK_TEST) $(CONFIG_LIBUKTEST_ALL)),) diff --git a/lib/tnsystick/tnsystick.c b/lib/tnsystick/tnsystick.c index 4e6b7b31..10e2c6fa 100644 --- a/lib/tnsystick/tnsystick.c +++ b/lib/tnsystick/tnsystick.c @@ -19,8 +19,9 @@ #include #include #include -#include +#include #include +#include /* current tick value */ static systick_t cur_systick; @@ -188,7 +189,7 @@ int tn_systick_init(void) { int ret; - ret = uk_sysclock_probe(); + ret = tn_sysclock_probe(); if (ret != 0) return ret; @@ -283,7 +284,7 @@ static void cpu_block_until(__nsec until_ns) until_ticks = ns_to_ticks(until_ns - now_ns); sysclock.ops->set_next(ticks_to_counts(until_ticks), 0); sysclock.ops->unmask_base_irq(); - __asm__ __volatile__("wfi"); + halt(); } ukplat_lcpu_restore_irqf(flags); ukplat_lcpu_enable_irq(); diff --git a/lib/ukintctlr/exportsyms.uk b/lib/ukintctlr/exportsyms.uk index 5035f1d1..32d74b1e 100644 --- a/lib/ukintctlr/exportsyms.uk +++ b/lib/ukintctlr/exportsyms.uk @@ -16,3 +16,5 @@ uk_intctlr_register uk_intctlr_simulate_spi uk_intctlr_sgi_op uk_intctlr_spi_get_affinity +uk_intctlr_irq_mask +uk_intctlr_irq_unmask diff --git a/plat/kvm/Config.uk b/plat/kvm/Config.uk index ad3d9766..ef8b104b 100644 --- a/plat/kvm/Config.uk +++ b/plat/kvm/Config.uk @@ -15,6 +15,8 @@ menuconfig PLAT_KVM select HAVE_INTCTLR select HAVE_APIC if ARCH_X86_64 select LIBUKINTCTLR_XPIC if ARCH_X86_64 + select ARM_GENERIC_TIMER if ARCH_ARM_64 + select TSC_I8254 if ARCH_X86_64 imply LIBUKBUS_PLATFORM if ARCH_ARM_64 imply LIBVIRTIO_9P if LIBUK9P imply LIBVIRTIO_NET if LIBUKNETDEV diff --git a/plat/kvm/Makefile.uk b/plat/kvm/Makefile.uk index e9a2eee9..be062819 100644 --- a/plat/kvm/Makefile.uk +++ b/plat/kvm/Makefile.uk @@ -64,8 +64,10 @@ LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/setup.c LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/console.c LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/lcpu.c LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/lcpu_start.S +ifneq ($(CONFIG_HAVE_SYSTICK),y) LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/tscclock.c LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/time.c +endif ifeq ($(findstring y,$(CONFIG_KVM_KERNEL_VGA_CONSOLE) $(CONFIG_KVM_DEBUG_VGA_CONSOLE)),y) LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/vga_console.c endif -- Gitee From 7139fc60fa8e2ffcf889b4f253fd638aac074c17 Mon Sep 17 00:00:00 2001 From: sunhaoyi Date: Sun, 28 Apr 2024 11:29:41 +0800 Subject: [PATCH 23/35] lib/intctlr: Delete flag bit to identify non-tsc interrupts Signed-off-by: sunhaoyi --- lib/tnsystick/tnsystick.c | 11 ----------- lib/ukintctlr/ukintctlr.c | 20 -------------------- plat/common/arm/time.c | 4 ---- plat/kvm/x86/tscclock.c | 5 ----- 4 files changed, 40 deletions(-) diff --git a/lib/tnsystick/tnsystick.c b/lib/tnsystick/tnsystick.c index 10e2c6fa..640d0a67 100644 --- a/lib/tnsystick/tnsystick.c +++ b/lib/tnsystick/tnsystick.c @@ -90,8 +90,6 @@ static inline void systick_update(void) #endif /* CONFIG_LIBTNSYSTICK_SUPPORT_OVERFLOW */ } -extern unsigned long sched_have_pending_events; - int sys_timer_irq_handler(void *arg __unused) { /* 1、update cur_systick */ @@ -109,7 +107,6 @@ int sys_timer_irq_handler(void *arg __unused) #ifdef CONFIG_LIBTNSYSTICK_TICKLESS tn_systick_set_timeout(tn_timer_next_tick()); #endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ - __uk_test_and_clear_bit(0, &sched_have_pending_events); /* todo: Interrupt processing temporarily returns 0 */ return 0; @@ -290,12 +287,6 @@ static void cpu_block_until(__nsec until_ns) ukplat_lcpu_enable_irq(); } -#if (CONFIG_ARCH_ARM_32 || CONFIG_ARCH_ARM_64) -unsigned long sched_have_pending_events; -#else -extern unsigned long sched_have_pending_events; -#endif /* CONFIG_ARCH_ARM_32 || CONFIG_ARCH_ARM_64 */ - /* return ns which based on ticks */ __nsec tn_systick_get_monotonic(void) { @@ -306,7 +297,5 @@ void tn_systick_until(__nsec until) { while (tn_systick_get_monotonic() < until) { cpu_block_until(until); - if (__uk_test_and_clear_bit(0, &sched_have_pending_events)) - break; } } diff --git a/lib/ukintctlr/ukintctlr.c b/lib/ukintctlr/ukintctlr.c index 6a68c27a..a9df9ce8 100644 --- a/lib/ukintctlr/ukintctlr.c +++ b/lib/ukintctlr/ukintctlr.c @@ -147,12 +147,6 @@ recheck: return 0; } -/* - * TODO: This is a temporary solution used to identify non TSC clock - * interrupts in order to stop waiting for interrupts with deadline. - */ -extern unsigned long sched_have_pending_events; - void uk_intctlr_irq_handle(struct __regs *regs, unsigned int irq) { struct irq_handler *h; @@ -186,20 +180,6 @@ void uk_intctlr_irq_handle(struct __regs *regs, unsigned int irq) if (irq_handlers[irq][i].func == NULL) break; h = &irq_handlers[irq][i]; -#ifndef CONFIG_HAVE_SYSTICK - if (irq != ukplat_time_get_irq()) - /* ukplat_time_get_irq() gives the IRQ reserved for a timer, - * responsible to wake up cpu from halt, so it can check if - * it has something to do. Effectively it is OS ticks. - * - * If interrupt comes not from the timer, the - * chances are some work have just - * arrived. Let's kick the scheduler out of - * the halting loop, and let it take care of - * that work. - */ - __uk_test_and_set_bit(0, &sched_have_pending_events); -#endif /* CONFIG_HAVE_SYSTICK */ if (h->func(h->arg) == 1) goto exit; } diff --git a/plat/common/arm/time.c b/plat/common/arm/time.c index 402fca69..b720883f 100644 --- a/plat/common/arm/time.c +++ b/plat/common/arm/time.c @@ -88,14 +88,10 @@ uint32_t generic_timer_get_frequency(int fdt_timer) return fdt32_to_cpu(fdt_freq[0]); } -unsigned long sched_have_pending_events; - void time_block_until(__nsec until) { while (ukplat_monotonic_clock() < until) { generic_timer_cpu_block_until(until); - if (__uk_test_and_clear_bit(0, &sched_have_pending_events)) - break; } } diff --git a/plat/kvm/x86/tscclock.c b/plat/kvm/x86/tscclock.c index 53bccb5e..491850a4 100644 --- a/plat/kvm/x86/tscclock.c +++ b/plat/kvm/x86/tscclock.c @@ -382,14 +382,9 @@ static void tscclock_cpu_block(__u64 until) ukplat_lcpu_halt_irq(); } -unsigned long sched_have_pending_events; - void time_block_until(__snsec until) { while ((__snsec) ukplat_monotonic_clock() < until) { tscclock_cpu_block(until); - - if (__uk_test_and_clear_bit(0, &sched_have_pending_events)) - break; } } -- Gitee From 29e2b18b54982124078bef7a38c5241143af7f94 Mon Sep 17 00:00:00 2001 From: sunhaoyi Date: Mon, 6 May 2024 17:13:24 +0800 Subject: [PATCH 24/35] lib/tnsystick: update suspend cpu wait interrupt function Signed-off-by: sunhaoyi --- lib/tnsystick/tnsystick.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tnsystick/tnsystick.c b/lib/tnsystick/tnsystick.c index 640d0a67..ab9222d7 100644 --- a/lib/tnsystick/tnsystick.c +++ b/lib/tnsystick/tnsystick.c @@ -281,7 +281,7 @@ static void cpu_block_until(__nsec until_ns) until_ticks = ns_to_ticks(until_ns - now_ns); sysclock.ops->set_next(ticks_to_counts(until_ticks), 0); sysclock.ops->unmask_base_irq(); - halt(); + ukplat_lcpu_halt_irq(); } ukplat_lcpu_restore_irqf(flags); ukplat_lcpu_enable_irq(); -- Gitee From 37cb021b7b2d40face4315529b20fc821edb015e Mon Sep 17 00:00:00 2001 From: crazykev Date: Mon, 29 Apr 2024 10:10:53 +0800 Subject: [PATCH 25/35] lib/tnschedprio: improve performance and edge case Signed-off-by: crazykev --- lib/tnschedprio/schedprio.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/tnschedprio/schedprio.c b/lib/tnschedprio/schedprio.c index b8475a12..7a9362c9 100644 --- a/lib/tnschedprio/schedprio.c +++ b/lib/tnschedprio/schedprio.c @@ -23,8 +23,7 @@ static inline void schedprio_schedule(struct schedprio *c, bool yield) { - struct uk_thread *prev, *next, *thread, *tmp; - __snsec now; + struct uk_thread *prev, *next; unsigned long flags; bool runnable; int cmp_value; @@ -32,11 +31,12 @@ static inline void schedprio_schedule(struct schedprio *c, bool yield) if (unlikely(ukplat_lcpu_irqs_disabled())) UK_CRASH("Must not call %s with IRQs disabled\n", __func__); - now = ukplat_monotonic_clock(); prev = uk_thread_current(); flags = ukplat_lcpu_save_irqf(); next = _runq_best(c); + if (!next) + goto out_without_switch; runnable = uk_thread_is_runnable(prev); if (!runnable) { /* Always switch when current thread is not runnable. @@ -56,7 +56,6 @@ static inline void schedprio_schedule(struct schedprio *c, bool yield) goto out_without_switch; else goto switch_thread; - #else goto out_without_switch; #endif @@ -266,7 +265,7 @@ struct uk_sched *tn_schedprio_create(struct uk_alloc *a) struct schedprio *c = NULL; int rc; - uk_pr_info("Initializing cooperative scheduler\n"); + uk_pr_info("Initializing priority scheduler\n"); c = uk_zalloc(a, sizeof(struct schedprio)); if (!c) goto err_out; -- Gitee From 544a4119f4f2d9ac4d67bbeae254cacd94cf64f2 Mon Sep 17 00:00:00 2001 From: crazykev Date: Mon, 29 Apr 2024 10:16:28 +0800 Subject: [PATCH 26/35] lib/plat: compitible legacy API with systick Signed-off-by: crazykev --- include/uk/plat/time.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/uk/plat/time.h b/include/uk/plat/time.h index 03a1eff9..f247a194 100644 --- a/include/uk/plat/time.h +++ b/include/uk/plat/time.h @@ -51,6 +51,7 @@ void ukplat_time_fini(void); __nsec ukplat_monotonic_clock(void); uint32_t ukplat_time_get_irq(void); __nsec ukplat_time_get_ticks(void); +__nsec ukplat_wall_clock(void); #else static inline __nsec ukplat_monotonic_clock(void) { @@ -66,9 +67,12 @@ static inline __nsec ukplat_time_get_ticks(void) { return (__nsec)tn_systick_get_tick(); } -#endif /* CONFIG_HAVE_SYSTICK */ -__nsec ukplat_wall_clock(void); +static inline __nsec ukplat_wall_clock(void) +{ + return tn_systick_get_monotonic(); +} +#endif /* CONFIG_HAVE_SYSTICK */ /* Time tick length */ #define UKPLAT_TIME_TICK_NSEC (UKARCH_NSEC_PER_SEC / CONFIG_HZ) -- Gitee From 2cdf65be3e4e48c3664915627315f71e6329d112 Mon Sep 17 00:00:00 2001 From: crazykev Date: Mon, 29 Apr 2024 10:18:52 +0800 Subject: [PATCH 27/35] lib/tnssytick,unintctlr: improve c++ compatibility Signed-off-by: crazykev --- lib/tnsystick/include/tn/systick.h | 13 +++++++++++-- lib/tnsystick/tnsystick.c | 2 -- lib/ukintctlr/include/uk/intctlr.h | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/tnsystick/include/tn/systick.h b/lib/tnsystick/include/tn/systick.h index e4b1aa40..393a6f83 100644 --- a/lib/tnsystick/include/tn/systick.h +++ b/lib/tnsystick/include/tn/systick.h @@ -18,10 +18,15 @@ #include #include +#include - /**< Maximum number of UINT32 */ +#ifdef __cplusplus +extern "C" { +#endif + +/**< Maximum number of UINT32 */ #define TICK_UINT32_MAX 0xffffffff - /**< Maximum number of UINT64 */ +/**< Maximum number of UINT64 */ #define TICK_UINT64_MAX 0xffffffffffffffff #define TICK_MAX TICK_UINT64_MAX @@ -113,4 +118,8 @@ systick_t ns_to_ticks(__nsec ns); __nsec tn_systick_get_monotonic(void); +#ifdef __cplusplus +} +#endif + #endif /* __TN_LIBTNSYSTICK_H__ */ diff --git a/lib/tnsystick/tnsystick.c b/lib/tnsystick/tnsystick.c index ab9222d7..bbf21371 100644 --- a/lib/tnsystick/tnsystick.c +++ b/lib/tnsystick/tnsystick.c @@ -94,8 +94,6 @@ int sys_timer_irq_handler(void *arg __unused) { /* 1、update cur_systick */ systick_update(); - uk_pr_debug("cur_systick: 0x%x count freq: 0x%x\n", - (unsigned int)cur_systick, sysclock.freq); #ifndef CONFIG_LIBTNSYSTICK_TICKLESS sysclock.ops->set_next(tot_counts_per_tick, 0); diff --git a/lib/ukintctlr/include/uk/intctlr.h b/lib/ukintctlr/include/uk/intctlr.h index 63dea1a2..4c47e77e 100644 --- a/lib/ukintctlr/include/uk/intctlr.h +++ b/lib/ukintctlr/include/uk/intctlr.h @@ -8,7 +8,7 @@ #define __UK_INTCTLR_H__ #ifdef __cplusplus -export "C" { +extern "C" { #endif #ifndef __ASSEMBLY__ -- Gitee From 6eeed62f24d1af0c08ae0a43609456eb282c9d1b Mon Sep 17 00:00:00 2001 From: crazykev Date: Tue, 30 Apr 2024 17:35:13 +0800 Subject: [PATCH 28/35] lib/tntimer,uksched,ukvmem: fix warnnings that compiler complains Signed-off-by: crazykev --- lib/tntimer/tntimer.c | 23 ++++++++++------------- lib/uksched/include/uk/thread.h | 2 +- lib/uksched/thread.c | 9 +++++---- lib/ukvmem/arch/arm/pagefault64.c | 2 +- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/lib/tntimer/tntimer.c b/lib/tntimer/tntimer.c index 3b2450a2..8a11e22b 100644 --- a/lib/tntimer/tntimer.c +++ b/lib/tntimer/tntimer.c @@ -92,15 +92,6 @@ systick_t tn_timer_next_tick(void) return TICK_MAX; } -void tn_timer_delete(struct timer *t) -{ - UK_ASSERT(t); - - uk_list_del(&t->list); - if (timoutListsOverflowed && uk_list_empty(&timer_list_head)) - tn_timer_list_switch(); -} - /* * tn_timer_list_switch * Handles timer list overflow by switching the active list. @@ -111,8 +102,6 @@ void tn_timer_delete(struct timer *t) */ void tn_timer_list_switch(void) { - struct uk_list_head *temp; - UK_ASSERT(!uk_list_empty(&overflow_timer_list_head)); timer_list_head.next = overflow_timer_list_head.next; @@ -121,13 +110,22 @@ void tn_timer_list_switch(void) timoutListsOverflowed = 0; } +void tn_timer_delete(struct timer *t) +{ + UK_ASSERT(t); + + uk_list_del(&t->list); + if (timoutListsOverflowed && uk_list_empty(&timer_list_head)) + tn_timer_list_switch(); +} + void tn_timer_start(struct timer *t) { systick_t cur; systick_t sum; cur = tn_systick_get_tick(); - sum = cur + MAX(1, t->init_tick); + sum = cur + MAX((systick_t)1, t->init_tick); t->timeout_tick = sum; if (sum < cur || sum < t->init_tick) { // 发生了溢出 @@ -141,7 +139,6 @@ void tn_timer_start(struct timer *t) void tn_timer_add(struct timer *in, struct uk_list_head *head) { - struct timer *node; struct timer *t; uk_list_for_each_entry(t, head, list) { diff --git a/lib/uksched/include/uk/thread.h b/lib/uksched/include/uk/thread.h index b9b14734..959dd637 100644 --- a/lib/uksched/include/uk/thread.h +++ b/lib/uksched/include/uk/thread.h @@ -1080,7 +1080,7 @@ void uk_thread_wake(struct uk_thread *thread); * @return * NULL */ -void uk_thread_timeout(struct uk_thread *thread); +void uk_thread_timeout(void *thread); /** * Macro to access a Unikraft thread-local (UKTLS) variable of a diff --git a/lib/uksched/thread.c b/lib/uksched/thread.c index a3064b8a..d4a1adb5 100644 --- a/lib/uksched/thread.c +++ b/lib/uksched/thread.c @@ -526,7 +526,8 @@ void _uk_thread_struct_free_alloc(struct uk_thread *t) #if CONFIG_LIBUKVMEM uk_vas_get_active(), #endif /* CONFIG_LIBUKVMEM */ - t->_mem.auxstack, t->_mem.auxstack_len); + (__uptr)t->_mem.auxstack, + t->_mem.auxstack_len); t->_mem.auxstack_a = NULL; t->_mem.auxstack = NULL; t->_mem.auxstack_len = 0; @@ -1091,7 +1092,7 @@ void uk_thread_release(struct uk_thread *t) #if CONFIG_LIBUKVMEM uk_vas_get_active(), #endif /* CONFIG_LIBUKVMEM */ - auxstack, auxstack_len); + (__uptr)auxstack, auxstack_len); if (a) uk_free(a, t); } @@ -1149,9 +1150,9 @@ void uk_thread_wake(struct uk_thread *thread) ukplat_lcpu_restore_irqf(flags); } -void uk_thread_timeout(struct uk_thread *thread) +void uk_thread_timeout(void *thread) { - uk_thread_wake(thread); + uk_thread_wake((struct uk_thread *)thread); /* TODO: oepn reschedule when reschedule support interrupt ctx*/ // uk_sched_reschedule(); diff --git a/lib/ukvmem/arch/arm/pagefault64.c b/lib/ukvmem/arch/arm/pagefault64.c index 6e3d56b2..65a51be7 100644 --- a/lib/ukvmem/arch/arm/pagefault64.c +++ b/lib/ukvmem/arch/arm/pagefault64.c @@ -40,7 +40,7 @@ static int vmem_arch_pagefault(void *data) rc = vmem_pagefault(vaddr, faulttype, ctx->regs); if (unlikely(rc < 0)) { uk_pr_debug("Cannot handle %s page fault at 0x%"__PRIvaddr - " (ec: 0x%x): %d\n", + " (ec: 0x%lx): %d\n", faultstr[faulttype & UK_VMA_FAULT_ACCESSTYPE], vaddr, ctx->esr, rc); -- Gitee From 3ef2b963a770434f11fb163ce41f1b67296aede7 Mon Sep 17 00:00:00 2001 From: crazykev Date: Mon, 6 May 2024 17:54:48 +0800 Subject: [PATCH 29/35] lib/tnsystick,sysclock,uksched: Improve systick accuracy Signed-off-by: crazykev --- drivers/tnsysclock/Makefile.uk | 2 - .../arm_generic_timer/arm_generic_timer.c | 53 ++--- drivers/tnsysclock/exportsyms.uk | 5 + drivers/tnsysclock/include/tn/sysclock.h | 38 ++++ drivers/tnsysclock/tsc_i8254/tsc_i8254.c | 23 +-- lib/tnschedprio/schedprio.c | 17 +- lib/tnsystick/Config.uk | 9 - lib/tnsystick/Makefile.uk | 4 - lib/tnsystick/exportsyms.uk | 4 +- lib/tnsystick/include/tn/systick.h | 29 +-- lib/tnsystick/include/tn/systick_impl.h | 5 +- lib/tnsystick/tests/test_systick.c | 154 --------------- lib/tnsystick/tests/test_systick.h | 23 --- lib/tnsystick/tnsystick.c | 184 +++++++----------- lib/tntimer/include/tn/{tntimer.h => timer.h} | 0 lib/tntimer/tests/test_tntimer.c | 2 +- lib/tntimer/tntimer.c | 5 +- lib/uksched/include/uk/thread.h | 2 +- lib/uksched/thread.c | 2 +- lib/ukschedcoop/schedcoop.c | 17 +- plat/common/include/uk/plat/common/_time.h | 3 +- 21 files changed, 172 insertions(+), 409 deletions(-) delete mode 100644 lib/tnsystick/tests/test_systick.c delete mode 100644 lib/tnsystick/tests/test_systick.h rename lib/tntimer/include/tn/{tntimer.h => timer.h} (100%) diff --git a/drivers/tnsysclock/Makefile.uk b/drivers/tnsysclock/Makefile.uk index 35e6e0aa..512d8880 100644 --- a/drivers/tnsysclock/Makefile.uk +++ b/drivers/tnsysclock/Makefile.uk @@ -11,8 +11,6 @@ ASINCLUDES-$(CONFIG_SYSCLOCK) += -I$(UK_DRIV_SYSCLOCK_BASE)/include CINCLUDES-$(CONFIG_SYSCLOCK) += -I$(UK_DRIV_SYSCLOCK_BASE)/include CXXINCLUDES-$(CONFIG_SYSCLOCK) += -I$(UK_DRIV_SYSCLOCK_BASE)/include -LIBTNSYSCLOCK_CINCLUDES-y += -I$(CONFIG_UK_BASE)/plat/common/include - $(eval $(call import_lib,$(UK_DRIV_SYSCLOCK_BASE)/arm_generic_timer)) $(eval $(call import_lib,$(UK_DRIV_SYSCLOCK_BASE)/tsc_i8254)) diff --git a/drivers/tnsysclock/arm_generic_timer/arm_generic_timer.c b/drivers/tnsysclock/arm_generic_timer/arm_generic_timer.c index cb083ff4..357cdb7c 100644 --- a/drivers/tnsysclock/arm_generic_timer/arm_generic_timer.c +++ b/drivers/tnsysclock/arm_generic_timer/arm_generic_timer.c @@ -27,7 +27,6 @@ static const char *sysclock_name = "arm generic timer"; struct uk_intctlr_irq irq; uint32_t freq; -static struct sysclock_ops ops; /* Bits definition of cntv_ctl register */ #define ARM_GENERIC_TIMER_ENABLE 0x01 @@ -37,7 +36,7 @@ static struct sysclock_ops ops; static const char *const sysclock_list[] = {"arm,armv8-timer", "arm,armv7-timer", NULL}; -static void sysclock_enable(void) +static inline void gtimer_enable(void) { set_el0(cntv_ctl, get_el0(cntv_ctl) | GT_TIMER_ENABLE); @@ -45,48 +44,63 @@ static void sysclock_enable(void) isb(); } -static inline void sysclock_disable(void) +static inline void gtimer_disable(void) { set_el0(cntv_ctl, get_el0(cntv_ctl) & ~GT_TIMER_ENABLE); isb(); } -static inline void sysclock_clear_status(void) +static inline void gtimer_clear_status(void) { set_el0(cntv_ctl, get_el0(cntv_ctl) & ~GT_TIMER_IRQ_STATUS); isb(); } -static inline void sysclock_update_compare_value(uint64_t new_val) +static inline void gtimer_update_compare_value(uint64_t new_val) { set_el0(cntv_cval, new_val); isb(); } -static inline void sysclock_update_timer_value(uint64_t new_val) +static inline void gtimer_update_timer_value(uint64_t new_val) { set_el0(cntv_tval, new_val); isb(); } -void sysclock_mask_irq(void) +static inline void gtimer_mask_irq(void) { set_el0(cntv_ctl, get_el0(cntv_ctl) | GT_TIMER_MASK_IRQ); isb(); } -void sysclock_unmask_irq(void) +static inline void gtimer_unmask_irq(void) { set_el0(cntv_ctl, get_el0(cntv_ctl) & ~GT_TIMER_MASK_IRQ); isb(); } +/* + * arm generic timer has a 64bit counter reg, we don't need do anything else. + */ +void tn_sysclock_isr_notify(void) {} + +void tn_sysclock_mask_irq(void) +{ + gtimer_mask_irq(); +} + +void tn_sysclock_unmask_irq(void) +{ + gtimer_unmask_irq(); +} + #ifdef CONFIG_ARM64_ERRATUM_858921 /* * The errata #858921 describes that Cortex-A73 (r0p0 - r0p2) counter @@ -97,7 +111,7 @@ void sysclock_unmask_irq(void) * the two read values. If bit[32] is different, keep the first value, * otherwise keep the second value. */ -uint64_t sysclock_get_counts(void) +uint64_t tn_sysclock_get_counts(void) { uint64_t val_1st, val_2nd; @@ -106,20 +120,20 @@ uint64_t sysclock_get_counts(void) return (((val_1st ^ val_2nd) >> 32) & 1) ? val_1st : val_2nd; } #else -uint64_t sysclock_get_counts(void) +uint64_t tn_sysclock_get_counts(void) { return get_el0(cntvct); } #endif -void sysclock_set_next(uint64_t set_counts, uint8_t is_start __unused) +void tn_sysclock_set_next(uint64_t set_counts, uint8_t is_start __unused) { - sysclock_clear_status(); + gtimer_clear_status(); - sysclock_update_timer_value(set_counts); + gtimer_update_compare_value(set_counts); } -uint32_t sysclock_get_frequency(int fdt_timer) +static inline uint32_t sysclock_get_frequency(int fdt_timer) { int len; const uint64_t *fdt_freq; @@ -171,15 +185,10 @@ int tn_sysclock_probe(void) * Mask IRQ before scheduler start working. Otherwise we will get * unexpected timer interrupts when system is booting. */ - sysclock_mask_irq(); - - ops.set_next = sysclock_set_next; - ops.get_count = sysclock_get_counts; - ops.mask_base_irq = sysclock_mask_irq; - ops.unmask_base_irq = sysclock_unmask_irq; + gtimer_mask_irq(); - tn_systick_register(sysclock_name, freq, &irq, &ops); - sysclock_enable(); + tn_systick_register(sysclock_name, freq, &irq); + gtimer_enable(); return 0; } diff --git a/drivers/tnsysclock/exportsyms.uk b/drivers/tnsysclock/exportsyms.uk index 52485168..45921446 100644 --- a/drivers/tnsysclock/exportsyms.uk +++ b/drivers/tnsysclock/exportsyms.uk @@ -1 +1,6 @@ tn_sysclock_probe +tn_sysclock_get_counts +tn_sysclock_isr_notify +tn_sysclock_mask_irq +tn_sysclock_unmask_irq +tn_sysclock_set_next diff --git a/drivers/tnsysclock/include/tn/sysclock.h b/drivers/tnsysclock/include/tn/sysclock.h index a0e531a3..c564b2c6 100644 --- a/drivers/tnsysclock/include/tn/sysclock.h +++ b/drivers/tnsysclock/include/tn/sysclock.h @@ -16,6 +16,44 @@ #ifndef __TN_SYSCLOCK_H__ #define __TN_SYSCLOCK_H__ +/** + * Probe and initialize the configured system clock. + * @return 0 on success, negative errno on error + */ int tn_sysclock_probe(void); +/** + * Get the current system clock count. + * Every system clock driver must provide a unsigned 64-bit count. + * This value can be read from the hardware timer directly or can be + * calculated based on the hardware timer. + * @return The current system clock count. + */ +uint64_t tn_sysclock_get_counts(void); + +/** + * Notify the system clock driver that a time base interrupt has occurred. + * This function is called by the system clock interrupt handler. + */ +void tn_sysclock_isr_notify(void); + +/** + * Mask the system clock interrupt. + */ +void tn_sysclock_mask_irq(void); + +/** + * Unmask the system clock interrupt. + */ +void tn_sysclock_unmask_irq(void); + +/** + * Set the next time-base interrupt occurrence. + * @param set_counts Counts for the next time-base irq occurring + * @param set_auto_reload 1 means that driver can set auto-reload mode if the + * sysclock supports it, 0 means that driver can't set auto-reload mode. + * @return void + */ +void tn_sysclock_set_next(uint64_t set_counts, uint8_t set_auto_reload); + #endif /* __TN_SYSCLOCK_H__ */ diff --git a/drivers/tnsysclock/tsc_i8254/tsc_i8254.c b/drivers/tnsysclock/tsc_i8254/tsc_i8254.c index a0eff799..79f009de 100644 --- a/drivers/tnsysclock/tsc_i8254/tsc_i8254.c +++ b/drivers/tnsysclock/tsc_i8254/tsc_i8254.c @@ -32,7 +32,6 @@ static const char *sysclock_name = "tsc-i8254"; uint64_t tsc_freq; uint64_t i8254_set_threshold; struct uk_intctlr_irq irq; -static struct sysclock_ops ops; static void sysclock_enable(void) { @@ -41,27 +40,28 @@ static void sysclock_enable(void) outb(TIMER_CNTR, 0); } -void sysclock_mask_irq(void) +void tn_sysclock_isr_notify(void){} + +void tn_sysclock_mask_irq(void) { uk_intctlr_irq_mask(irq.id); } -void sysclock_unmask_irq(void) +void tn_sysclock_unmask_irq(void) { uk_intctlr_irq_unmask(irq.id); } -uint64_t sysclock_get_counts(void) +uint64_t tn_sysclock_get_counts(void) { return rdtsc(); } -void sysclock_set_next(uint64_t set_counts, uint8_t is_start __unused) +void tn_sysclock_set_next(uint64_t set_counts, uint8_t set_auto_reload __unused) { uint64_t conuts; - set_counts = MIN(i8254_set_threshold, set_counts); + set_counts = MIN(i8254_set_threshold, set_counts - rdtsc()); conuts = (set_counts * TIMER_HZ) / tsc_freq; - outb(TIMER_MODE, TIMER_SEL0 | TIMER_ONESHOT | TIMER_16BIT); outb(TIMER_CNTR, (conuts & 0xFF)); outb(TIMER_CNTR, ((conuts >> 8) & 0xFF)); @@ -160,14 +160,9 @@ int tn_sysclock_probe(void) * Mask IRQ before scheduler start working. Otherwise we will get * unexpected timer interrupts when system is booting. */ - sysclock_mask_irq(); - - ops.set_next = sysclock_set_next; - ops.get_count = sysclock_get_counts; - ops.mask_base_irq = sysclock_mask_irq; - ops.unmask_base_irq = sysclock_unmask_irq; + tn_sysclock_mask_irq(); - tn_systick_register(sysclock_name, tsc_freq, &irq, &ops); + tn_systick_register(sysclock_name, tsc_freq, &irq); sysclock_enable(); return 0; diff --git a/lib/tnschedprio/schedprio.c b/lib/tnschedprio/schedprio.c index 7a9362c9..307344ac 100644 --- a/lib/tnschedprio/schedprio.c +++ b/lib/tnschedprio/schedprio.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "schedprio.h" static inline void schedprio_schedule(struct schedprio *c, bool yield) @@ -156,7 +157,6 @@ static void schedprio_thread_blocked(struct uk_sched *s, struct uk_thread *t) static __noreturn void idle_thread_fn(void *argp) { struct schedprio *c = (struct schedprio *)argp; - __nsec now, wake_up_time; unsigned long flags; UK_ASSERT(c); @@ -187,19 +187,8 @@ static __noreturn void idle_thread_fn(void *argp) ukplat_lcpu_restore_irqf(flags); /* Read return time set by last schedule operation */ - wake_up_time = ticks_to_ns( - tn_systick_get_tick() + tn_timer_next_tick()); - now = ukplat_monotonic_clock(); - - if (!wake_up_time || wake_up_time > now) { - if (wake_up_time) - ukplat_lcpu_halt_irq_until(wake_up_time); - else - ukplat_lcpu_halt_irq(); - - /* handle pending events if any */ - ukplat_lcpu_irqs_handle_pending(); - } + tn_systick_block_until(tn_systick_get_tick() + + tn_timer_next_tick()); /* try to schedule a thread that might now be available */ schedprio_schedule(c, true); diff --git a/lib/tnsystick/Config.uk b/lib/tnsystick/Config.uk index e9277cc8..ac4c403b 100644 --- a/lib/tnsystick/Config.uk +++ b/lib/tnsystick/Config.uk @@ -13,13 +13,4 @@ config LIBTNSYSTICK_FREQ int "Frequency of triggering kernel systick" default 1000 -config LIBTNSYSTICK_SUPPORT_OVERFLOW - bool "Support systick overflow counts" - default n - -config LIBTNSYSTICK_TEST - bool "Enable unit tests" - default n - select LIBUKTEST - endif diff --git a/lib/tnsystick/Makefile.uk b/lib/tnsystick/Makefile.uk index f9e76f4c..2576f72f 100644 --- a/lib/tnsystick/Makefile.uk +++ b/lib/tnsystick/Makefile.uk @@ -7,7 +7,3 @@ CXXINCLUDES-$(CONFIG_LIBTNSYSTICK) += -I$(LIBTNSYSTICK_BASE)/include LIBTNSYSTICK_CINCLUDES-y += -I$(CONFIG_UK_BASE)/plat/common/include LIBTNSYSTICK_SRCS-$(CONFIG_LIBTNSYSTICK) += $(LIBTNSYSTICK_BASE)/tnsystick.c - -ifneq ($(filter y,$(CONFIG_LIBTNSYSTICK_TEST) $(CONFIG_LIBUKTEST_ALL)),) -LIBTNSYSTICK_SRCS-y += $(LIBTNSYSTICK_BASE)/tests/test_systick.c -endif diff --git a/lib/tnsystick/exportsyms.uk b/lib/tnsystick/exportsyms.uk index 59f9c50c..49b8294b 100644 --- a/lib/tnsystick/exportsyms.uk +++ b/lib/tnsystick/exportsyms.uk @@ -4,7 +4,7 @@ tn_systick_start tn_systick_set_timeout tn_systick_get_irq tn_systick_register -tn_systick_until +tn_systick_block_until tn_systick_get_monotonic ticks_to_ns -ns_to_ticks +ns_to_ticks \ No newline at end of file diff --git a/lib/tnsystick/include/tn/systick.h b/lib/tnsystick/include/tn/systick.h index 393a6f83..cbbdb4fe 100644 --- a/lib/tnsystick/include/tn/systick.h +++ b/lib/tnsystick/include/tn/systick.h @@ -32,35 +32,12 @@ extern "C" { typedef uint64_t systick_t; -/* sysclock oprations */ -struct sysclock_ops { - /* counts for the next time-base irq occurring - * set_auto_reload = 1 means that the sysclock support auto-reload - * mode.When time-base irq occurs periodically,we don't have to reset - * the next interrupt occurrence each time in a subsequent time-base - * interrupt. - * set_auto_reload = 0 means there is no need to work in auto-reloade - * mode for this operation, or the sysclock is working in tickless mode - * If sysclock does not support auto-reload mode, set_auto_reload will - * always be set to 0. - */ - void (*set_next)(uint64_t counts, uint8_t set_auto_reload); - /* Get cumulative hardware sys count */ - uint64_t (*get_count)(void); - /* mask time base interrupt */ - void (*mask_base_irq)(void); - /* Release the time base interrupt mask */ - void (*unmask_base_irq)(void); -}; - /* sysclock oprations */ struct sysclock_desc { /* Name of the system timer */ const char *name; uint32_t freq; struct uk_intctlr_irq *irq; - /* sysclock oprations */ - struct sysclock_ops *ops; }; /** @@ -101,8 +78,10 @@ void tn_systick_start(void); */ void tn_systick_set_timeout(systick_t ticks); -/* adapt original delayed programme */ -void tn_systick_until(__nsec until); +/** + * Wait and halt until the specified systick. + */ +void tn_systick_block_until(systick_t ticks); /** * ticks_to_ns - Convert systicks to ns. diff --git a/lib/tnsystick/include/tn/systick_impl.h b/lib/tnsystick/include/tn/systick_impl.h index 64988d5f..7080c5c7 100644 --- a/lib/tnsystick/include/tn/systick_impl.h +++ b/lib/tnsystick/include/tn/systick_impl.h @@ -67,7 +67,8 @@ static inline void calculate_mult_shift(uint32_t *mult, uint8_t *shift, *shift = sft; } -void tn_systick_register(const char *name, uint32_t freq, - struct uk_intctlr_irq *irq, struct sysclock_ops *ops); +void tn_systick_register(const char *name, + uint32_t freq, + struct uk_intctlr_irq *irq); #endif /* __TN_LIBTNSYSTICK_IMPL_H__ */ diff --git a/lib/tnsystick/tests/test_systick.c b/lib/tnsystick/tests/test_systick.c deleted file mode 100644 index fd3b50c9..00000000 --- a/lib/tnsystick/tests/test_systick.c +++ /dev/null @@ -1,154 +0,0 @@ -/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ssANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include "test_systick.h" - -/* test calculate_mult_shift */ -UK_TESTCASE(tnsystick, test_calculate_mult_shift) -{ - uint64_t test_origin_data, test_target_data; - uint32_t target_per_origin; - uint8_t shift_origin_to_target; - - test_origin_data = 3000000; - test_target_data = 10000000; - - calculate_mult_shift(&target_per_origin, &shift_origin_to_target, - test_origin_data, test_target_data); - - uint64_t test_data = - (test_origin_data * target_per_origin) >> shift_origin_to_target; - - UK_TEST_EXPECT_SNUM_EQ(test_data + 1, test_target_data); -} - -/* test APIs */ -#define TEST_SET_NEXT 1 -#define TEST_GET_COUNT 2 -#define TEST_MASK_BASE_IRQ 3 -#define TEST_UNMASK_BASE_IRQ 4 -#define TEST_IRQ_ID 11 - -struct sysclock_ops test_sysclock_ops; -struct uk_intctlr_irq test_irq; -struct sysclock_desc ori_sysclock; - -static int test_ret; -static uint64_t test_count; -unsigned long flags; - -static void test_systick_set_next(uint64_t counts __unused, - uint8_t set_auto_reload __unused) -{ - test_ret = TEST_SET_NEXT; -} - -static uint64_t test_systick_get_count(void) -{ - test_ret = TEST_GET_COUNT; - return test_count; -} - -static void test_systick_mask_base_irq(void) -{ - test_ret = TEST_MASK_BASE_IRQ; -} -static void test_systick_unmask_base_irq(void) -{ - test_ret = TEST_UNMASK_BASE_IRQ; -} - -static inline void test_systick_init(uint32_t freq) -{ - flags = ukplat_lcpu_save_irqf(); - ori_sysclock = sysclock; - test_irq.id = TEST_IRQ_ID; - test_irq.trigger = 0; - - const char *test_sysclock_name = "test sysclock"; - - test_sysclock_ops.set_next = test_systick_set_next; - test_sysclock_ops.get_count = test_systick_get_count; - test_sysclock_ops.mask_base_irq = test_systick_mask_base_irq; - test_sysclock_ops.unmask_base_irq = test_systick_unmask_base_irq; - - tn_systick_register(test_sysclock_name, freq, &test_irq, - &test_sysclock_ops); - -} - -static inline void test_systick_restore(void) -{ - tn_systick_register(ori_sysclock.name, ori_sysclock.freq, - ori_sysclock.irq, ori_sysclock.ops); - - ukplat_lcpu_restore_irqf(flags); -} - -UK_TESTCASE(tnsystick, test_systick_ops) -{ - test_systick_init(0); - /* test tn_systick_register */ - UK_TEST_EXPECT_PTR_EQ(sysclock.ops, &test_sysclock_ops); - - /* test tn_systick_get_irq */ - UK_TEST_EXPECT_SNUM_EQ(TEST_IRQ_ID, tn_systick_get_irq()); - - /* test tn_systick_start */ - test_ret = 0; - tn_systick_start(); - UK_TEST_EXPECT_SNUM_EQ(test_ret, TEST_UNMASK_BASE_IRQ); - - test_systick_restore(); -} - -/* test tn_systick_get_tick */ -#define TEST_COUNTS 1000000 -UK_TESTCASE(tnsystick, test_get_systick) -{ - systick_t start_tick, dealta_tick, target_tick; - uint64_t start_count, target_count; - - test_systick_init(sysclock.freq); - - /* test case 1: delay TEST_COUNTS counts and updated ticks */ - sys_timer_irq_handler(NULL); - start_count = sysclock.ops->get_count(); - start_tick = tn_systick_get_tick(); - target_count = start_count + TEST_COUNTS; - - test_count = target_count; - sys_timer_irq_handler(NULL); - - dealta_tick = tn_systick_get_tick() - start_tick; - target_tick = TEST_COUNTS * CONFIG_LIBTNSYSTICK_FREQ / sysclock.freq; - - UK_TEST_EXPECT_SNUM_EQ(dealta_tick, target_tick); - - /* test case 2: delay TEST_COUNTS counts but not updated ticks*/ - start_tick = tn_systick_get_tick(); - test_count = target_count + TEST_COUNTS; - dealta_tick = tn_systick_get_tick() - start_tick; - - UK_TEST_EXPECT_SNUM_EQ(dealta_tick, 0); - - test_systick_restore(); -} - -uk_testsuite_register(tnsystick, NULL); diff --git a/lib/tnsystick/tests/test_systick.h b/lib/tnsystick/tests/test_systick.h deleted file mode 100644 index a351c645..00000000 --- a/lib/tnsystick/tests/test_systick.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright 2024 Hangzhou Yingyi Technology Co., Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ssANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __TEST_SYSTICK_H__ -#define __TEST_SYSTICK_H__ - -#include - -extern struct sysclock_desc sysclock; -int sys_timer_irq_handler(void *arg __unused); - -#endif /* __TEST_SYSTICK_H__ */ diff --git a/lib/tnsystick/tnsystick.c b/lib/tnsystick/tnsystick.c index bbf21371..a5be6739 100644 --- a/lib/tnsystick/tnsystick.c +++ b/lib/tnsystick/tnsystick.c @@ -13,22 +13,21 @@ * limitations under the License. */ -#include #include #include -#include -#include -#include #include #include +#include #include /* current tick value */ static systick_t cur_systick; - -#ifdef CONFIG_LIBTNSYSTICK_SUPPORT_OVERFLOW -static uint32_t systick_overflow; -#endif /* CONFIG_LIBTNSYSTICK_SUPPORT_OVERFLOW */ +/* Last count recoreded when systick is updated*/ +static uint64_t last_count; +/* Number of system clock counts per tick */ +static uint32_t counts_per_tick; +/* Flag indicating systick library initialized */ +static uint8_t initialized; struct sysclock_desc sysclock; static uint32_t systick_freq; @@ -37,74 +36,51 @@ static uint32_t systick_freq; static uint8_t shift_tick_to_ns; /* Shift factor for converting ns to ticks */ static uint8_t shift_ns_to_tick; -/* Shift factor for converting counts to ticks */ -static uint8_t shift_count_to_tick; -/* Shift factor for converting ticks to counts */ -static uint8_t shift_tick_to_count; /* Multiplier for converting ticks to nsecs */ static uint32_t ns_per_tick; /* Multiplier for converting nsecs to ticks */ static uint32_t tick_per_ns; -/* Multiplier for converting ticks to counts */ -static uint32_t count_per_tick; -/* Multiplier for converting counts to ticks */ -static uint32_t tick_per_count; -/* Total (absolute) number of counts per tick */ -static uint64_t tot_counts_per_tick; /* Total (absolute) number of nanoseconds per tick */ static uint64_t tot_ns_per_tick; static uint64_t max_convert_ticks; -#ifdef CONFIG_LIBTNSYSTICK_TICKLESS -/* Last count recoreded when systick is updated*/ -static uint64_t last_count; -#endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ -static inline uint64_t counts_to_ticks(uint64_t counts) +/* elapsed_tick returns ticks elasped from last tick interrupt occurred */ +static inline uint32_t elapsed_tick(void) { - return (count_per_tick * counts) >> shift_count_to_tick; -} - -static inline uint64_t ticks_to_counts(uint64_t ticks) -{ - return (tick_per_count * ticks) >> shift_tick_to_count; + return (unsigned long)(tn_sysclock_get_counts() - last_count) + / counts_per_tick; } static inline void systick_update(void) { -#ifdef CONFIG_LIBTNSYSTICK_SUPPORT_OVERFLOW - systick_t last_tick = cur_systick; -#endif /* CONFIG_LIBTNSYSTICK_SUPPORT_OVERFLOW */ - -#ifdef CONFIG_LIBTNSYSTICK_TICKLESS - last_count = sysclock.ops->get_count(); -#endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ + uint32_t diff_tick = elapsed_tick(); - cur_systick = counts_to_ticks(sysclock.ops->get_count()); - -#ifdef CONFIG_LIBTNSYSTICK_SUPPORT_OVERFLOW - if (cur_systick < last_tick) { - systick_overflow++; - uk_pr_warn("systick overflowed %d times!\n", systick_overflow); - } -#endif /* CONFIG_LIBTNSYSTICK_SUPPORT_OVERFLOW */ + cur_systick += diff_tick; + last_count += diff_tick * counts_per_tick; } int sys_timer_irq_handler(void *arg __unused) { - /* 1、update cur_systick */ + /* 1. Let sysclock do per isr ops */ + tn_sysclock_isr_notify(); + + /* 2. Update cur_systick and last_count */ systick_update(); -#ifndef CONFIG_LIBTNSYSTICK_TICKLESS - sysclock.ops->set_next(tot_counts_per_tick, 0); + /* 3. Set next tick for non-tickless mode */ +#ifdef CONFIG_LIBTNSYSTICK_TICKLESS + /* Let set_timeout call from timer unmask clock irq. */ + tn_sysclock_mask_irq(); +#else + tn_sysclock_set_next(last_count + counts_per_tick, 0); + tn_sysclock_unmask_irq(); #endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ + + /* 4. Check timer */ tn_timer_announce(); - /* 3、todo :schedprio to check timeout threads */ - /* 4、set next time-base irq */ -#ifdef CONFIG_LIBTNSYSTICK_TICKLESS - tn_systick_set_timeout(tn_timer_next_tick()); -#endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ + /* 5. TODO: schedprio to check timeout threads */ /* todo: Interrupt processing temporarily returns 0 */ return 0; @@ -113,15 +89,12 @@ int sys_timer_irq_handler(void *arg __unused) systick_t tn_systick_get_tick(void) { #ifdef CONFIG_LIBTNSYSTICK_TICKLESS - - if (sysclock.ops) - return cur_systick - + counts_to_ticks(sysclock.ops->get_count() - - last_count); - else - /* if sysclock is not initialised, return 0 */ + /* It's hard to restrict other library(such as logger) not to call this + * method before init is called, althrough other RTOS did this. + */ + if (unlikely(!initialized)) return 0; - + return cur_systick + elapsed_tick(); #else return cur_systick; #endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ @@ -133,7 +106,7 @@ static void systick_convert_init(void) tot_ns_per_tick = ukarch_time_sec_to_nsec(1) / CONFIG_LIBTNSYSTICK_FREQ; /* Absolute number of counts per tick */ - tot_counts_per_tick = sysclock.freq / CONFIG_LIBTNSYSTICK_FREQ; + counts_per_tick = sysclock.freq / CONFIG_LIBTNSYSTICK_FREQ; /* * Calculate the shift factor and scaling multiplier for @@ -157,27 +130,7 @@ static void systick_convert_init(void) /* We disallow zero tick_per_ns */ UK_BUGON(!tick_per_ns); - /* - * Calculate the shift factor and scaling multiplier for - * converting ticks to counts. - */ - calculate_mult_shift(&count_per_tick, &shift_count_to_tick, - (uint64_t)sysclock.freq, CONFIG_LIBTNSYSTICK_FREQ); - - /* We disallow zero count_per_tick */ - UK_BUGON(!count_per_tick); - - /* - * Calculate the shift factor and scaling multiplier for - * converting counts to ticks. - */ - calculate_mult_shift(&tick_per_count, &shift_tick_to_count, - CONFIG_LIBTNSYSTICK_FREQ, (uint64_t)sysclock.freq); - - /* We disallow zero tick_per_count */ - UK_BUGON(!tick_per_count); - - max_convert_ticks = __MAX_CONVERT_SECS * CONFIG_LIBTNSYSTICK_FREQ; + max_convert_ticks = TICK_MAX / 2 / counts_per_tick; } int tn_systick_init(void) @@ -190,12 +143,12 @@ int tn_systick_init(void) systick_freq = CONFIG_LIBTNSYSTICK_FREQ; if ((systick_freq == 0) || (systick_freq > sysclock.freq)) { - uk_pr_info( + uk_pr_err( "invalid system tick frequency, set it default : %d\n", sysclock.freq); systick_freq = sysclock.freq; } - tot_counts_per_tick = sysclock.freq / CONFIG_LIBTNSYSTICK_FREQ; + counts_per_tick = sysclock.freq / CONFIG_LIBTNSYSTICK_FREQ; /* initialize cur_systick convert value */ systick_convert_init(); @@ -203,15 +156,17 @@ int tn_systick_init(void) uk_pr_debug("sysclock.irq->id : %d\n", sysclock.irq->id); uk_intctlr_irq_register(sysclock.irq->id, sys_timer_irq_handler, NULL); - sysclock.ops->mask_base_irq(); - sysclock.ops->set_next(tot_counts_per_tick, 1); + tn_sysclock_mask_irq(); + systick_update(); + tn_sysclock_set_next(last_count + counts_per_tick, 1); + initialized = 1; return 0; } void tn_systick_start(void) { - sysclock.ops->unmask_base_irq(); + tn_sysclock_unmask_irq(); } uint32_t tn_systick_get_irq(void) @@ -219,21 +174,26 @@ uint32_t tn_systick_get_irq(void) return sysclock.irq->id; } -void tn_systick_set_timeout(systick_t ticks) +void tn_systick_set_timeout(systick_t ticks __maybe_unused) { - if (ticks == TICK_MAX) - sysclock.ops->set_next(ticks_to_counts(max_convert_ticks), 0); - else - sysclock.ops->set_next(ticks_to_counts(ticks), 0); +#ifdef CONFIG_LIBTNSYSTICK_TICKLESS + ticks = MIN(ticks, max_convert_ticks); + ticks = MIN(ticks, TICK_UINT32_MAX / 2); + uint64_t next_count = + (cur_systick + elapsed_tick() + ticks) * counts_per_tick; + + tn_sysclock_set_next(next_count, 0); + tn_sysclock_unmask_irq(); +#endif /* CONFIG_LIBTNSYSTICK_TICKLESS */ } -void tn_systick_register(const char *name, uint32_t freq, - struct uk_intctlr_irq *irq, struct sysclock_ops *ops) +void tn_systick_register(const char *name, + uint32_t freq, + struct uk_intctlr_irq *irq) { sysclock.name = name; sysclock.freq = freq; sysclock.irq = irq; - sysclock.ops = ops; } __nsec ticks_to_ns(systick_t ticks) @@ -264,36 +224,22 @@ systick_t ns_to_ticks(__nsec ns) } } -static void cpu_block_until(__nsec until_ns) -{ - __nsec now_ns; - systick_t until_ticks; - unsigned long flags; - - flags = ukplat_lcpu_save_irqf(); - /* Record current ns */ - now_ns = ticks_to_ns((systick_t)tn_systick_get_tick()); - - if (now_ns < until_ns) { - /* Calculate until_ticks for timer */ - until_ticks = ns_to_ticks(until_ns - now_ns); - sysclock.ops->set_next(ticks_to_counts(until_ticks), 0); - sysclock.ops->unmask_base_irq(); - ukplat_lcpu_halt_irq(); - } - ukplat_lcpu_restore_irqf(flags); - ukplat_lcpu_enable_irq(); -} - /* return ns which based on ticks */ __nsec tn_systick_get_monotonic(void) { return ticks_to_ns((uint64_t)tn_systick_get_tick()); } -void tn_systick_until(__nsec until) +void tn_systick_block_until(systick_t until) { - while (tn_systick_get_monotonic() < until) { - cpu_block_until(until); + unsigned long flags; + + while (tn_systick_get_tick() < until) { + flags = ukplat_lcpu_save_irqf(); + + ukplat_lcpu_halt_irq(); + + ukplat_lcpu_restore_irqf(flags); + ukplat_lcpu_enable_irq(); } } diff --git a/lib/tntimer/include/tn/tntimer.h b/lib/tntimer/include/tn/timer.h similarity index 100% rename from lib/tntimer/include/tn/tntimer.h rename to lib/tntimer/include/tn/timer.h diff --git a/lib/tntimer/tests/test_tntimer.c b/lib/tntimer/tests/test_tntimer.c index aa5a82cf..4cfe6fad 100644 --- a/lib/tntimer/tests/test_tntimer.c +++ b/lib/tntimer/tests/test_tntimer.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include "internal_timer.h" diff --git a/lib/tntimer/tntimer.c b/lib/tntimer/tntimer.c index 8a11e22b..a5f563fc 100644 --- a/lib/tntimer/tntimer.c +++ b/lib/tntimer/tntimer.c @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include +#include #include #include #include @@ -179,8 +179,6 @@ void tn_timer_announce(void) tn_timer_list_switch(); } - - while (!uk_list_empty(&timer_list_head)) { t = uk_list_first_entry( &timer_list_head, struct timer, list); @@ -194,5 +192,6 @@ void tn_timer_announce(void) } } + tn_systick_set_timeout(tn_timer_next_tick()); last_tick = cur; } diff --git a/lib/uksched/include/uk/thread.h b/lib/uksched/include/uk/thread.h index 959dd637..f72183f2 100644 --- a/lib/uksched/include/uk/thread.h +++ b/lib/uksched/include/uk/thread.h @@ -40,7 +40,7 @@ #include #include #include -#include +#include #ifdef __cplusplus extern "C" { diff --git a/lib/uksched/thread.c b/lib/uksched/thread.c index d4a1adb5..eeebf4a5 100644 --- a/lib/uksched/thread.c +++ b/lib/uksched/thread.c @@ -45,7 +45,7 @@ #include #include #include -#include +#include #if CONFIG_LIBUKSCHED_TCB_INIT && !CONFIG_UKARCH_TLS_HAVE_TCB #error CONFIG_LIBUKSCHED_TCB_INIT requires that a TLS contains reserved space for a TCB diff --git a/lib/ukschedcoop/schedcoop.c b/lib/ukschedcoop/schedcoop.c index c7ea2293..45081d0d 100644 --- a/lib/ukschedcoop/schedcoop.c +++ b/lib/ukschedcoop/schedcoop.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "schedcoop.h" static inline void schedcoop_schedule(struct uk_sched *s, bool yield) @@ -160,8 +161,7 @@ static void schedcoop_thread_blocked(struct uk_sched *s, struct uk_thread *t) static __noreturn void idle_thread_fn(void *argp) { - struct schedcoop *c = (struct schedcoop *) argp; - __nsec now, wake_up_time; + struct schedcoop *c = (struct schedcoop *)argp; unsigned long flags; UK_ASSERT(c); @@ -194,16 +194,9 @@ static __noreturn void idle_thread_fn(void *argp) ukplat_lcpu_restore_irqf(flags); /* Read return time set by last schedule operation */ - wake_up_time = ticks_to_ns( - tn_systick_get_tick() + tn_timer_next_tick()); - now = ukplat_monotonic_clock(); - - if (!wake_up_time || wake_up_time > now) { - if (wake_up_time) - ukplat_lcpu_halt_irq_until(wake_up_time); - else - ukplat_lcpu_halt_irq(); - } + tn_systick_block_until(tn_systick_get_tick() + + tn_timer_next_tick()); + /* try to schedule a thread that might now be available */ schedcoop_schedule(&c->sched, true); } diff --git a/plat/common/include/uk/plat/common/_time.h b/plat/common/include/uk/plat/common/_time.h index 2e92fef0..71cfb6a9 100644 --- a/plat/common/include/uk/plat/common/_time.h +++ b/plat/common/include/uk/plat/common/_time.h @@ -38,9 +38,10 @@ #ifndef CONFIG_HAVE_SYSTICK void time_block_until(__snsec until); #else +#include static inline void time_block_until(__snsec until) { - tn_systick_until((__nsec)until); + tn_systick_block_until(ns_to_ticks(until)); } #endif /* CONFIG_HAVE_SYSTICK */ -- Gitee From 9e87b56ab7567a4f490c0961c0dd53deaefb3ccf Mon Sep 17 00:00:00 2001 From: Li Haode Date: Thu, 13 Jun 2024 11:06:51 +0800 Subject: [PATCH 30/35] remove .github dir Signed-off-by: Li Haode --- .github/CODEOWNERS | 95 --------- .github/ISSUE_TEMPLATE/bug_report.yml | 71 ------- .github/ISSUE_TEMPLATE/config.yml | 6 - .github/ISSUE_TEMPLATE/project_backlog.yml | 51 ----- .github/PULL_REQUEST_TEMPLATE.md | 46 ----- .github/dependabot.yml | 11 - .github/labels/arch.yaml | 25 --- .github/labels/area.yaml | 58 ------ .github/labels/arm.yaml | 8 - .github/labels/bug.yaml | 16 -- .github/labels/ci.yaml | 8 - .github/labels/kind.yaml | 28 --- .github/labels/lang.yaml | 66 ------ .github/labels/lib.yaml | 228 --------------------- .github/labels/lifecycle.yaml | 27 --- .github/labels/misc.yaml | 12 -- .github/labels/needs.yaml | 12 -- .github/labels/new.yaml | 24 --- .github/labels/plat.yaml | 84 -------- .github/labels/priority.yaml | 16 -- .github/labels/state.yaml | 28 --- .github/labels/topic.yaml | 60 ------ .github/workflows/actcheck.yaml | 23 --- .github/workflows/checkpatch.yaml | 29 --- .github/workflows/commit-format-check.yaml | 72 ------- .github/workflows/integration.yaml | 193 ----------------- .github/workflows/label.yaml | 28 --- .github/workflows/merge.yaml | 38 ---- .github/workflows/pychecks.yaml | 32 --- .github/workflows/shellcheck.yaml | 33 --- 30 files changed, 1428 deletions(-) delete mode 100644 .github/CODEOWNERS delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml delete mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/project_backlog.yml delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md delete mode 100644 .github/dependabot.yml delete mode 100644 .github/labels/arch.yaml delete mode 100644 .github/labels/area.yaml delete mode 100644 .github/labels/arm.yaml delete mode 100644 .github/labels/bug.yaml delete mode 100644 .github/labels/ci.yaml delete mode 100644 .github/labels/kind.yaml delete mode 100644 .github/labels/lang.yaml delete mode 100644 .github/labels/lib.yaml delete mode 100644 .github/labels/lifecycle.yaml delete mode 100644 .github/labels/misc.yaml delete mode 100644 .github/labels/needs.yaml delete mode 100644 .github/labels/new.yaml delete mode 100644 .github/labels/plat.yaml delete mode 100644 .github/labels/priority.yaml delete mode 100644 .github/labels/state.yaml delete mode 100644 .github/labels/topic.yaml delete mode 100644 .github/workflows/actcheck.yaml delete mode 100644 .github/workflows/checkpatch.yaml delete mode 100644 .github/workflows/commit-format-check.yaml delete mode 100644 .github/workflows/integration.yaml delete mode 100644 .github/workflows/label.yaml delete mode 100644 .github/workflows/merge.yaml delete mode 100644 .github/workflows/pychecks.yaml delete mode 100644 .github/workflows/shellcheck.yaml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 80d96932..00000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,95 +0,0 @@ -# https://help.github.com/articles/about-codeowners/ - -# These owners are the default owners for all Unikraft core files. -* @unikraft/maintainers-core - -# These owners oversee the core parts of Unikraft. -/lib/isrlib @unikraft/maintainers-core -/lib/nolibc @unikraft/maintainers-core -/lib/posix-libdl @unikraft/maintainers-core -/lib/posix-sysinfo @unikraft/maintainers-core -/lib/syscall_shim @unikraft/maintainers-core -/lib/ukargparse @unikraft/maintainers-core -/lib/ukboot @unikraft/maintainers-core -/lib/uklibparam @unikraft/maintainers-core -/lib/ukring @unikraft/maintainers-core -/lib/uksglist @unikraft/maintainers-core -/lib/ukstore @unikraft/maintainers-core -/lib/uktime @unikraft/maintainers-core -/lib/uktimeconv @unikraft/maintainers-core - -# These owners oversee the APIs. -/arch/*/*/include @unikraft/maintainers-api -/arch/*/include @unikraft/maintainers-api -/include @unikraft/maintainers-api -/plat/include @unikraft/maintainers-api - -# These owners oversee all architectures. -/arch @unikraft/maintainers-arch - -# These owners oversee the ARM architecture. -/arch/arm @unikraft/maintainers-arch-arm -/lib/fdt @unikraft/maintainers-arch-arm -/plat/*/arm @unikraft/maintainers-arch-arm -/plat/*/include/*-arm @unikraft/maintainers-arch-arm - -# These owners oversee the x86 architecture. -/arch/x86 @unikraft/maintainers-arch-x86 -/plat/*/include/*-x86 @unikraft/maintainers-arch-x86 -/plat/*/x86 @unikraft/maintainers-arch-x86 - -# These owners oversee all platforms. -/plat @unikraft/maintainers-plat - -# These owners oversee the KVM platform. -/plat/kvm @unikraft/maintainers-plat-kvm - -# These owners oversee the scheduler-related components. -/lib/posix-process @unikraft/maintainers-sched -/lib/uklock @unikraft/maintainers-sched -/lib/ukmpi @unikraft/maintainers-sched -/lib/uksched* @unikraft/maintainers-sched -/lib/uksignal @unikraft/maintainers-sched - -# These owners oversee the memory manangement-related components. -/lib/ukalloc* @unikraft/maintainers-mem -/lib/ukfalloc* @unikraft/maintainers-mem -/lib/ukmmap @unikraft/maintainers-mem - -# These owners oversee the security-related components. -/lib/ubsan @unikraft/maintainers-security -/lib/uksp @unikraft/maintainers-security -/lib/ukswrand @unikraft/maintainers-security - -# These owners oversee the network-related components. -/lib/uknetdev @unikraft/maintainers-net - -# These owners oversee the filesystem-related components. -/lib/9pfs @unikraft/maintainers-fs -/lib/devfs @unikraft/maintainers-fs -/lib/posix-user @unikraft/maintainers-fs -/lib/ramfs @unikraft/maintainers-fs -/lib/uk9p @unikraft/maintainers-fs -/lib/ukblkdev @unikraft/maintainers-fs -/lib/ukcpio @unikraft/maintainers-fs -/lib/vfscore @unikraft/maintainers-fs - -# These owners oversee the device-related components. -/lib/ukbus @unikraft/maintainers-device - -# These owners oversee the build system. -/lib/Config.uk @unikraft/maintainers-build -/lib/Makefile.uk @unikraft/maintainers-build -/Makefile @unikraft/maintainers-build -/Makefile.uk @unikraft/maintainers-build -/support @unikraft/maintainers-build - -# These owners oversee the debugging support. -/lib/ukdebug @unikraft/maintainers-debug - -# These owners oversee internal use of Rust within Unikraft. -/lib/ukrust @unikraft/maintainers-lang-rust - -# These owners oversee testing within Unikraft. -/lib/uktest @unikraft/maintainers-test -tests/test_* @unikraft/maintainers-test diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index b6e4148a..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: 🐞 Report a bug -description: Create a bug report about unexpected behavior. -labels: [kind/bug] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this bug report! - - Please only use this form to submit problems with builds or the runtime of Unikraft unikernels. This includes unexpected or undefined behavior, stacktraces, critical messages, and things just breaking or exploding. - - **Ensure you have tested against the latest changes on `staging` branch before submitting this form.** - - For questions, concerns or help with running Unikraft, please check out our additional resources: - - * [Unikraft Documentation](https://docs.unikraft.org) - * [Getting Started Guide](https://unikraft.org/getting-started) - * [Unikraft Discussions Forum](https://github.com/unikraft/unikraft/discussions) - - type: textarea - id: bug-description - attributes: - label: Describe the bug - description: Please provide a clear and concise description of the bug. - validations: - required: true - - type: textarea - id: steps-to-reproduce - attributes: - label: Steps to reproduce - description: Please provide the steps necessary to reproduce the behavior, for example the command used to run the unikernel, or the sequence of actions, auxiliary components, networking setup, etc. leading up to the error or bug. Please also include any options you set during the configuration step. - placeholder: | - For example, I enabled these options: - - - `CONFIG_LIB9PFS=y` - - ... - validations: - required: false - - type: textarea - id: expected-behavior - attributes: - label: Expected behavior - description: A clear and concise description of what you expected to happen. - placeholder: For example, I expected the unikernel to boot and print "Hello, world!" - validations: - required: false - - type: dropdown - id: architectures - attributes: - label: Which architectures were you using or does this bug affect? - description: If this bug is architecture agnostic or you are unsure then please do not select an architecture listed below. - multiple: true - options: - - x86_64 - - arm - - arm64 - - type: dropdown - id: platforms - attributes: - label: Which platforms were you using or does this bug affect? - description: If this bug is platform agnostic or you are unsure then please do not select an platform listed below. If this affects an external platform (i.e. one in a separate repository) then please open the bug report in the relevant repository. - multiple: true - options: - - kvm - - xen - - linuxu - - type: textarea - id: logs - attributes: - label: Relevant log output - description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. - render: shell diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index d9f879d5..00000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,6 +0,0 @@ -blank_issues_enabled: false - -contact_links: - - name: 💡 Discuss an idea - url: https://github.com/unikraft/unikraft/discussions/new - about: Discuss a feature or usecase which Unikraft could support. diff --git a/.github/ISSUE_TEMPLATE/project_backlog.yml b/.github/ISSUE_TEMPLATE/project_backlog.yml deleted file mode 100644 index ae79f1c1..00000000 --- a/.github/ISSUE_TEMPLATE/project_backlog.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: 📥 Add to the backlog -description: Create an issue for new work to be done which has been discussed. -labels: [kind/enhancement] -body: - - type: markdown - attributes: - value: | - Please only use this form to submit new, well-defined work to the Unikraft project's backlog. Issues under this category have been discussed with the core team. - - If you're intending to request a feature, please [open a discussion using the "Ideas" category](https://github.com/unikraft/unikraft/discussions/new) instead so we can understand your workflow first. If you are unsure about a feature, please [check out our documentation](https://docs.unikraft.org/) which covers existing features and possibilities with Unikraft or filter existing issues labelled under [`kind/enhancement`](https://github.com/unikraft/unikraft/labels/kind/enhancement) to prevent double-posting. - - type: textarea - id: feature-request-summary - attributes: - label: Feature request summary - description: Please provide a quick summary which clearly and concisely describes the feature. For example, highlights of new functionality; proposal of a new architecture or platform; additions to documentation; etc. - validations: - required: true - - type: textarea - id: alternatives - attributes: - label: Describe alternatives - description: A clear and concise description of any alternative solutions or features considered. - validations: - required: false - - type: dropdown - id: related-architectures - attributes: - label: Related architectures - description: Please indicate whether the feature request is related to a specific architecture. If this feature is architecture agnostic or you are unsure then please do not select an architecture listed below. - multiple: false - options: - - x86_64 - - arm - - arm64 - - type: dropdown - id: related-platforms - attributes: - label: Related platforms - description: Please indicate whether the feature request is related to a specific platform. If this feature is platform agnostic or you are unsure then please do not select an platform listed below. - multiple: false - options: - - kvm - - xen - - linuxu - - type: textarea - id: additional-context - attributes: - label: Additional context - description: Add any other context, longer descriptions, screenshot/mock-ups, or links to related material about the feature request. - validations: - required: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 597240d0..00000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,46 +0,0 @@ - - -### Prerequisite checklist - - - - - [ ] Read the [contribution guidelines](https://unikraft.org/docs/contributing/) regarding submitting new changes to the project; - - [ ] Tested your changes against relevant architectures and platforms; - - [ ] Ran the [`checkpatch.uk`](https://github.com/unikraft/unikraft/blob/staging/support/scripts/checkpatch.uk) on your commit series before opening this PR; - - [ ] Updated relevant documentation. - - -### Base target - - - Architecture(s): [e.g. `x86_64` or N/A] - - Platform(s): [e.g. `kvm` or N/A] - - Application(s): [e.g. `app-python3` or N/A] - - -### Additional configuration - - - -### Description of changes - - diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 03043f49..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,11 +0,0 @@ -version: 2 - -updates: - - package-ecosystem: github-actions - directory: / - schedule: - interval: monthly - day: sunday - time: '09:00' - commit-message: - prefix: ".github/workflows" diff --git a/.github/labels/arch.yaml b/.github/labels/arch.yaml deleted file mode 100644 index bc072868..00000000 --- a/.github/labels/arch.yaml +++ /dev/null @@ -1,25 +0,0 @@ -labels: - - name: arch/arm - description: Issues and PRs related to ARM architecture - color: "#1d76db" - apply_on_pr_match_paths: - - arch/arm/** - - plat/common/arm/** - - plat/common/include/arm/** - - - name: arch/arm64 - description: Issues and PRs related to ARM 64-bit architecture - color: "#1d76db" - apply_on_pr_match_paths: - - arch/arm/arm64/** - - plat/common/arm/*64.S - - plat/common/arm/*64.c - - plat/common/include/arm/arm64/** - - - name: arch/x86_64 - description: Issues and PRs related to Intel x86_64 architecture - color: "#c5def5" - apply_on_pr_match_paths: - - arch/x86/** - - plat/common/x86/** - - plat/common/include/x86/** diff --git a/.github/labels/area.yaml b/.github/labels/area.yaml deleted file mode 100644 index 55488027..00000000 --- a/.github/labels/area.yaml +++ /dev/null @@ -1,58 +0,0 @@ -labels: - - name: area/arch - description: Issues and PRs which affect architecture code - color: "#7ec2f7" - apply_on_pr_match_paths: - - arch/** - - - name: area/docs - description: Issues and PRs which affect documentation - color: "#db4eb8" - apply_on_pr_match_paths: - - doc/** - - README.md - - - name: area/exportsyms - description: Issue or PR relates to exporting symbols from a library - color: "#f9822c" - apply_on_pr_match_paths: - - exportsyms.uk - - - name: area/include - description: Issues and PRs which affect headers - color: "#e99695" - apply_on_pr_match_paths: - - include/** - - - name: area/kconfig - description: Issues and PRs which affect KConfig code - color: "#ed8ebd" - apply_on_pr_match_paths: - - Config.uk - - - name: area/lib - description: Issues and PRs which affect internal Unikraft libraries - color: "#ed8ebd" - match_repos: - - unikraft - apply_on_pr_match_paths: - - lib/** - - - name: area/makefile - description: Issues and PRs which affect Makefile code - color: "#ffe5c9" - apply_on_pr_match_paths: - - Makefile.uk - - Makefile - - - name: area/plat - description: Issues and PRs which affect platform code - color: "#f2daa9" - apply_on_pr_match_paths: - - plat/** - - - name: area/support - description: Issues and PRs which affect support code - color: "#bfd4f2" - apply_on_pr_match_paths: - - suuport/** diff --git a/.github/labels/arm.yaml b/.github/labels/arm.yaml deleted file mode 100644 index d7b44846..00000000 --- a/.github/labels/arm.yaml +++ /dev/null @@ -1,8 +0,0 @@ -labels: - - name: arm/smcc - description: Secure Monitor Call Calling Convention on ARM - color: "#0BA2F3" - apply_on_pr_match_paths: - - include/uk/arch/arm/smccc.h - - plat/common/arm/smccc.c - - plat/common/arm/smccc_invoke.S diff --git a/.github/labels/bug.yaml b/.github/labels/bug.yaml deleted file mode 100644 index 4748b9a6..00000000 --- a/.github/labels/bug.yaml +++ /dev/null @@ -1,16 +0,0 @@ -labels: - - name: bug/compile-time - description: Bug occurs during compile-time - color: "#ed5139" - - - name: bug/link-time - description: Bug occurs during link-time - color: "#884239" - - - name: bug/runtime - description: Bug occurs during runtime - color: "#4d2a25" - - - name: bug/fix - description: This PR fixes a bug - color: "#4bcc7a" diff --git a/.github/labels/ci.yaml b/.github/labels/ci.yaml deleted file mode 100644 index 088cd78b..00000000 --- a/.github/labels/ci.yaml +++ /dev/null @@ -1,8 +0,0 @@ -labels: - - name: ci/merged - description: Merged by CI - color: "#d4c5f9" - - - name: ci/wait - description: Tell the CI system to wait before performing any action. - color: "#e99695" diff --git a/.github/labels/kind.yaml b/.github/labels/kind.yaml deleted file mode 100644 index 10d56955..00000000 --- a/.github/labels/kind.yaml +++ /dev/null @@ -1,28 +0,0 @@ -labels: - - name: kind/bug - description: Something isn't working - color: "#d73a4a" - - - name: kind/enhancement - description: Issues and PRs related to increasing functionality - color: "#a2eeef" - - - name: kind/maintenance - description: Chores and meta-tasks - color: "#a295d6" - - - name: kind/project - description: Issue is a substantial contribution - color: "#008672" - - - name: kind/proposal - description: Issue discusses potential new feature or change - color: "#dd75c0" - - - name: kind/question - description: Issue asks a question - color: "#e99695" - - - name: kind/quick-fix - description: Issue or PR is related to a quick fix - color: "#1daf6b" diff --git a/.github/labels/lang.yaml b/.github/labels/lang.yaml deleted file mode 100644 index 4f7f2fe7..00000000 --- a/.github/labels/lang.yaml +++ /dev/null @@ -1,66 +0,0 @@ -labels: - - name: lang/c - description: Issues or PRs which affect code written in C - color: "#bbbbbb" - apply_on_pr_match_paths: - - "**/*\\.c" - - - name: lang/cpp - description: Issues or PRs which affect code written in C++ - color: "#bbbbbb" - apply_on_pr_match_paths: - - "**/*\\.cpp" - - - name: lang/d - description: Issues or PRs which affect code written in Dlang - color: "#9f2725" - apply_on_pr_match_paths: - - "**/*\\.d" - - - name: lang/go - description: Issues or PRs which affect code written in Golang - color: "#58c7d6" - apply_on_pr_match_paths: - - "**/*\\.go" - - - name: lang/javascript - description: Issues or PRs which affect code written in JavaScript - color: "#e1cf27" - apply_on_pr_match_paths: - - "**/*\\.js" - - - name: lang/lua - description: Issues or PRs which affect code written in Lua - color: "#000069" - apply_on_pr_match_paths: - - "**/*\\.lua" - - - name: lang/php - description: Issues or PRs which affect code written in PHP - color: "#60619d" - apply_on_pr_match_paths: - - "**/*\\.php" - - - name: lang/python - description: Issues or PRs which affect code written in Python - color: "#2b5f95" - apply_on_pr_match_paths: - - "**/*\\.py" - - - name: lang/ruby - description: Issues or PRs which affect code written in Ruby - color: "#a80007" - apply_on_pr_match_paths: - - "**/*\\.rb" - - - name: lang/rust - description: Issues or PRs which affect code written in Rust - color: "#8a4521" - apply_on_pr_match_paths: - - "**/*\\.rs" - - - name: lang/wamr - description: Issues or PRs which affect code written in WAMR - color: "#5130ec" - apply_on_pr_match_paths: - - "**/*\\.wamr" diff --git a/.github/labels/lib.yaml b/.github/labels/lib.yaml deleted file mode 100644 index 684f2d6c..00000000 --- a/.github/labels/lib.yaml +++ /dev/null @@ -1,228 +0,0 @@ -labels: - - name: lib/9pfs - description: Issues and PRs which affect the 9p filesystem - color: "#fbca04" - apply_on_pr_match_paths: - - lib/9pfs/** - - - name: lib/devfs - description: Issues and PRs which affect the devfs file system - color: "#fbca04" - apply_on_pr_match_paths: - - lib/devfs/** - - - name: lib/fdt - description: Issues and PRs which affect Flat Device Tree manipulation - color: "#fbca04" - apply_on_pr_match_paths: - - lib/fdt/** - - - name: lib/isrlib - description: Issues and PRs which affect interrupt-safe standard routines - color: "#fbca04" - apply_on_pr_match_paths: - - lib/isrlib/** - - - name: lib/nolibc - description: Issues and PRs which affect the nolibc subset - color: "#fbca04" - apply_on_pr_match_paths: - - lib/nolibc/** - - - name: lib/posix-libdl - description: Issues and PRs which affect POSIX libdl library - color: "#fbca04" - apply_on_pr_match_paths: - - lib/posix-libdl/** - - - name: lib/posix-process - description: Issues and PRs which affect POSIX process-related functions - color: "#fbca04" - apply_on_pr_match_paths: - - lib/posix-process/** - - - name: lib/posix-sysinfo - description: Issues and PRs which affect information about system parameters - color: "#fbca04" - apply_on_pr_match_paths: - - lib/posix-sysinfo/** - - - name: lib/posix-user - description: Issues and PRs which affect POSIX user-related functions - color: "#fbca04" - apply_on_pr_match_paths: - - lib/posix-user/** - - - name: lib/ramfs - description: Issues and PRs which affect the simple RAM file system - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ramfs/** - - - name: lib/syscall_shim - description: Issues and PRs which affect the syscall shim layer - color: "#fbca04" - apply_on_pr_match_paths: - - lib/syscall_shim/** - - - name: lib/ubsan - description: Issues and PRs which affect Undefined Behavior Sanitization - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ubsan/** - - - name: lib/uk9p - description: Issues and PRs which affect the 9p client - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uk9p/** - - - name: lib/ukalloc - description: Issues and PRs which affect the binary buddy page allocator - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukalloc/** - - - name: lib/ukallocbbuddy - description: Issues and PRs which affect the abstraction for memory allocators - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukallocbbuddy/** - - - name: lib/ukallocpool - description: Issues and PRs which affect the memory pool allocator - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukallocpool/** - - - name: lib/ukallocregion - description: Issues and PRs which affect the region-based allocator - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukallocregion/** - - - name: lib/ukargparse - description: Issues and PRs which affect the simple argument parser - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukargparse/** - - - name: lib/ukblkdev - description: Issues and PRs which affect the block driver interface - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukblkdev/** - - - name: lib/ukboot - description: Issues and PRs which affect the Unikraft bootstrapping code - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukboot/** - - - name: lib/ukbus - description: Issues and PRs which affect the abstraction for device buses - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukbus/** - - - name: lib/ukcpio - description: Issues and PRs which affect CPIO archive extraction - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukcpio/** - - - name: lib/ukdebug - description: Issues and PRs which affect debugging and tracing - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukdebug/** - - - name: lib/uklibparam - description: Issues and PRs which affect the library arguments parser - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uklibparam/** - - - name: lib/uklock - description: Issues and PRs which affect multi-task synchronization primitives - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uklock/** - - - name: lib/ukmmap - description: Issues and PRs which affect mmap system call - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukmmap/** - - - name: lib/ukmpi - description: Issues and PRs which affect the Message Passing Interface - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukmpi/** - - - name: lib/uknetdev - description: Issues and PRs which affect the network driver interface - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uknetdev/** - - - name: lib/ukring - description: Issues and PRs which affect the ring buffer interface - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukring/** - - - name: lib/uksched - description: Issues and PRs which affect the abstraction for schedulers - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uksched/** - - - name: lib/ukschedcoop - description: Issues and PRs which affect the cooperative Round-Robin scheduler - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukschedcoop/** - - - name: lib/uksglist - description: Issues and PRs which affect the Scatter Gather List - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uksglist/** - - - name: lib/uksignal - description: Issues and PRs which affect Unikraft signals - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uksignal/** - - - name: lib/uksp - description: Issues and PRs which affect the stack protector - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uksp/** - - - name: lib/ukswrand - description: Issues and PRs which affect the software random number generator - color: "#fbca04" - apply_on_pr_match_paths: - - lib/ukswrand/** - - - name: lib/uktime - description: Issues and PRs which affect time functions - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uktime/** - - - name: lib/uktimeconv - description: Issues and PRs which affect time conversion functions - color: "#fbca04" - apply_on_pr_match_paths: - - lib/uktimeconv/** - - - name: lib/vfscore - description: Issues and PRs which affect VFS Core interface - color: "#fbca04" - apply_on_pr_match_paths: - - lib/vfscore/** diff --git a/.github/labels/lifecycle.yaml b/.github/labels/lifecycle.yaml deleted file mode 100644 index 93c6bc19..00000000 --- a/.github/labels/lifecycle.yaml +++ /dev/null @@ -1,27 +0,0 @@ -labels: - - name: lifecycle/active - description: Indicates that an issue or PR is actively being worked on by a contributor - color: "#8ee234" - apply_after: 0s - remove_after: 720h # 30 days - do_not_remove_if_labels_exist: - - lifecycle/frozen - - - name: lifecycle/stale - description: Denotes an issue or PR has remained open with no activity and has become stale - color: "#795548" - apply_after: 720h # 30 days - remove_after: 4320h # 180 days - do_not_remove_if_labels_exist: - - lifecycle/frozen - - - name: lifecycle/rotten - description: Denotes an issue or PR that has aged beyond stale and will be auto-closed - color: "#795548" - apply_after: 4320h # 180 days - do_not_remove_if_labels_exist: - - lifecycle/frozen - - - name: lifecycle/frozen - description: Indicates that an issue or PR should not be auto-closed due to staleness - color: "#b2fff6" diff --git a/.github/labels/misc.yaml b/.github/labels/misc.yaml deleted file mode 100644 index 87653d0c..00000000 --- a/.github/labels/misc.yaml +++ /dev/null @@ -1,12 +0,0 @@ -labels: - - name: good-first-issue - description: Good for newcomers - color: "#7057ff" - - - name: patchwork-backlog - description: Migrated from patchwork.unikraft.org - color: "#bfd4f2" - - - name: release-note - description: Issue or PR can aid in creating a release note - color: "#c2e0c6" diff --git a/.github/labels/needs.yaml b/.github/labels/needs.yaml deleted file mode 100644 index c782d00e..00000000 --- a/.github/labels/needs.yaml +++ /dev/null @@ -1,12 +0,0 @@ -labels: - - name: needs/documentation - description: Issue or PR needs additional documentation - color: "#d4c5f9" - - - name: needs/rebase - description: Indicates a PR cannot be merged because it has merge conflicts with HEAD - color: "#2e20c1" - apply_when: - - needs_rebase - remove_when: - - no_rebase diff --git a/.github/labels/new.yaml b/.github/labels/new.yaml deleted file mode 100644 index 57612a36..00000000 --- a/.github/labels/new.yaml +++ /dev/null @@ -1,24 +0,0 @@ -labels: - - name: new/library - description: Issues and PRs related to a new library - color: "#7bdb48" - - - name: new/metric - description: Issues and PRs related to a new metric - color: "#7bdb48" - - - name: new/posix-function - description: Issues and PRs related to a new POSIX function - color: "#7bdb48" - - - name: new/primitive - description: Issues and PRs related to a new primitive - color: "#7bdb48" - - - name: new/syscall - description: Issues and PRs related to a new syscall - color: "#7bdb48" - - - name: new/test - description: Issues and PRs related to a new test - color: "#7bdb48" diff --git a/.github/labels/plat.yaml b/.github/labels/plat.yaml deleted file mode 100644 index 211b5e95..00000000 --- a/.github/labels/plat.yaml +++ /dev/null @@ -1,84 +0,0 @@ -labels: - - name: plat/common - description: Issues and PRs related to all platforms - color: "#1d76db" - apply_on_pr_match_paths: - - plat/common/** - - include/uk/plat/common/** - - - name: plat/driver/tap - description: Issues and PRs related to the tap driver - color: "#750210" - apply_on_pr_match_paths: - - plat/drivers/tap/** - - plat/drivers/include/tap/** - - plat/linuxu/tap_io.c - - - name: plat/driver/virtio - description: Issues and PRs related to virtio drivers - color: "#750210" - apply_on_pr_match_paths: - - plat/drivers/virtio/** - - plat/drivers/include/virtio/** - - - name: plat/driver/ofw - description: Issues and PRs related to open firmware drivers - color: "#750210" - apply_on_pr_match_paths: - - plat/drivers/ofw/** - - plat/drivers/include/ofw/** - - - name: plat/driver/gic - description: Issues and PRs related to the GIC driver - color: "#750210" - apply_on_pr_match_paths: - - plat/drivers/gic/** - - plat/drivers/include/gic/** - - - name: plat/driver/pci - description: Issues and PRs related to PCI driver - color: "#750210" - apply_on_pr_match_paths: - - plat/common/include/pci/** - - - name: plat/driver/9p - description: Issues and PRs related to 9p driver - color: "#750210" - apply_on_pr_match_paths: - - plat/*/include/9p/** - - - name: plat/driver/net - description: Issues and PRs related to network driver - color: "#750210" - apply_on_pr_match_paths: - - plat/*/include/net/** - - - name: plat/driver/blk - description: Issues and PRs related to block driver - color: "#750210" - apply_on_pr_match_paths: - - plat/*/include/blk/** - - - name: plat/driver - description: Issues and PRs related to platform drivers - color: "#750210" - apply_on_pr_match_paths: - - plat/drivers/** - - - name: plat/kvm - description: Issues and PRs related to KVM platform - color: "#1f8aa5" - apply_on_pr_match_paths: - - plat/kvm/** - - - name: plat/linuxu - description: Issues and PRs related to Linux Userspace platform - color: "#bfdadc" - apply_on_pr_match_paths: - - plat/linux/** - - - name: plat/xen - description: ssues and PRs related to the Xen platform - color: "#4da81f" - apply_on_pr_match_paths: - - plat/xen/** diff --git a/.github/labels/priority.yaml b/.github/labels/priority.yaml deleted file mode 100644 index f769ce4e..00000000 --- a/.github/labels/priority.yaml +++ /dev/null @@ -1,16 +0,0 @@ -labels: - - name: priority/high - description: Issues and PRs which have a high priority - color: "#d93f0b" - - - name: priority/medium - description: Issues and PRs which have priority - color: "#eb9e34" - - - name: priority/low - description: Issues and PRs which have a very low priority - color: "#A1CBD2" - - - name: priority/nice-to-have - description: Issues and PRs which have a very low priority - color: "#FD93AC" diff --git a/.github/labels/state.yaml b/.github/labels/state.yaml deleted file mode 100644 index 3cdbca61..00000000 --- a/.github/labels/state.yaml +++ /dev/null @@ -1,28 +0,0 @@ -labels: - - name: state/accepted - description: Issue or PR has been accepted - color: "#BBFD97" - - - name: state/action-required - description: Issue or PR requires external change to occur before proceeding - color: "#006b75" - - - name: state/changes-requested - description: Issue or PR requires a change to proceed - color: "#FA7505" - - - name: state/deferred - description: Issue or PR has been deferred - color: "#763F27" - - - name: state/not-applicable - description: Issue or PR is not applicable - color: "#52544A" - - - name: state/rejected - description: Sadly this issue or PR cannot be accepted - color: "#E93303" - - - name: state/superceded - description: Issue or PR is no longer applicable - color: "#5024E8" diff --git a/.github/labels/topic.yaml b/.github/labels/topic.yaml deleted file mode 100644 index c13561cc..00000000 --- a/.github/labels/topic.yaml +++ /dev/null @@ -1,60 +0,0 @@ -labels: - - name: topic/booting - description: Issue or PR pertaining to the boot process - color: "#c5def5" - - - name: topic/build - description: Issue or PR pertaining to the build system - color: "#c5def5" - - - name: topic/ci - description: Issue or PR pertaining to CI/CD - color: "#c5def5" - - - name: topic/concurrency - description: Issue or PR pertaining to concurrency - color: "#c5def5" - - - name: topic/irq - description: Issue or PR pertaining to IRQs - color: "#c5def5" - - - name: topic/metrics - description: Issue or PR pertaining to metrics - color: "#c5def5" - - - name: topic/mm - description: Issue or PR pertaining to memory management - color: "#c5def5" - - - name: topic/mpk - description: Issue or PR pertaining to Memory Protection Keys (MPKs) - color: "#c5def5" - - - name: topic/posix - description: Issue or PR pertaining to POSIX - color: "#c5def5" - - - name: topic/primitive - description: Issue or PR pertaining to Unikraft primitives - color: "#c5def5" - - - name: topic/scheduling - description: Issue or PR pertaining to scheduling - color: "#c5def5" - - - name: topic/smp - description: Issue or PR pertaining to SMP - color: "#c5def5" - - - name: topic/syscall - description: Issue or PR pertaining to syscalls - color: "#c5def5" - - - name: topic/threading - description: Issue or PR pertaining to threading - color: "#c5def5" - - - name: topic/tls - description: Issue or PR pertaining to Thread Local Storage (TLS) - color: "#c5def5" diff --git a/.github/workflows/actcheck.yaml b/.github/workflows/actcheck.yaml deleted file mode 100644 index 292fdc01..00000000 --- a/.github/workflows/actcheck.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: actionlint - -on: - pull_request: - types: [opened, synchronize, reopened] - branches: [staging] - paths: - - '.github/workflows/**' - -jobs: - action-lint: - runs-on: ubuntu-latest - name: Action Lint - steps: - - uses: actions/checkout@v4 - - - name: Install action linter - run: | - mkdir -p "$HOME"/.local/bin - curl -sL https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash | bash -s -- latest "$HOME"/.local/bin - - - name: Check that all workflows are valid - run: actionlint -verbose diff --git a/.github/workflows/checkpatch.yaml b/.github/workflows/checkpatch.yaml deleted file mode 100644 index ae80c29b..00000000 --- a/.github/workflows/checkpatch.yaml +++ /dev/null @@ -1,29 +0,0 @@ -name: checkpatch - -on: - pull_request: - types: [opened, synchronize, reopened] - branches: [staging] - -jobs: - checkpatch: - runs-on: ubuntu-latest - name: checkpatch - steps: - - name: Install governctl - run: | - set -xe - wget -q "https://github.com/unikraft/governance/releases/download/v${GOVERN_VERSION}/governance_${GOVERN_VERSION}_linux_amd64.deb" - sudo dpkg -i "governance_${GOVERN_VERSION}_linux_amd64.deb" - env: - GOVERN_VERSION: 0.1.7 - - - name: Run checkpatch through governctl - run: governctl pr check patch --ignore ${GOVERN_IGNORES} unikraft/unikraft/${PR_NUMBER} - env: - PR_NUMBER: ${{ github.event.number }} - GOVERN_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GOVERN_GITHUB_USER: ${{ secrets.GH_CHECKPATCH_ACTOR }} - GOVERN_NO_RENDER: true - GOVERN_LOG_LEVEL: warn - GOVERN_IGNORES: FILE_PATH_CHANGES,OBSOLETE,ASSIGN_IN_IF,NEW_TYPEDEFS,EMAIL_SUBJECT diff --git a/.github/workflows/commit-format-check.yaml b/.github/workflows/commit-format-check.yaml deleted file mode 100644 index 6d50fa2f..00000000 --- a/.github/workflows/commit-format-check.yaml +++ /dev/null @@ -1,72 +0,0 @@ -name: Commits Formatting Check - -on: - push: - branches: [staging, stable] - pull_request: - types: [opened, synchronize, reopened] - branches: [staging] - -jobs: - commit: - name: Commit and PR Format Check - runs-on: ubuntu-latest - steps: - - name: Commit Lines Length Check - if: ${{ github.actor != 'dependabot' && github.actor != 'dependabot[bot]' }} - uses: gsactions/commit-message-checker@v2 - with: - pattern: '((^(?=(?:.|\n)*(?:^|\n)\[\d\]: .{69,}(?:$|\n)(?:.|\n)*)(?:.|\n)*$)|(^(?!(?:.|\n)*(?:^|\n).{74,}(?:$|\n)(?:.|\n)*)(?:.|\n)*$))' - flags: '' - error: 'The maximum line length of 74 characters is exceeded.' - excludeDescription: 'true' - excludeTitle: 'true' - checkAllCommitMessages: 'true' - accessToken: ${{ secrets.GITHUB_TOKEN }} - - - name: Signed-off-by Check - if: always() - uses: gsactions/commit-message-checker@v2 - with: - pattern: '^Signed-off-by: .+ \<.+\@.+\..+\>$' - error: 'Signed-off-by line is missing.' - excludeDescription: 'true' - excludeTitle: 'true' - checkAllCommitMessages: 'true' - accessToken: ${{ secrets.GITHUB_TOKEN }} - - - name: PR Title Check - if: always() - uses: gsactions/commit-message-checker@v2 - with: - pattern: '^((([a-z0-9\/\.\-\_\*])+)|(\{([a-z0-9\/\.\-\_\*]+, )+[a-z0-9\/\.\-\_\*]+\})){1}: [A-Z0-9].*' - error: 'The PR title must follow the conventional commits format.' - excludeDescription: 'true' - excludeTitle: 'false' - checkAllCommitMessages: 'false' - accessToken: ${{ secrets.GITHUB_TOKEN }} - - - name: PR Title Check Length - if: ${{ github.actor != 'dependabot' && github.actor != 'dependabot[bot]' }} - uses: gsactions/commit-message-checker@v2 - with: - pattern: '^(?!.{75,}).*' - flags: '' - error: 'The maximum line length of 75 characters is exceeded.' - excludeDescription: 'true' - excludeTitle: 'false' - checkAllCommitMessages: 'false' - accessToken: ${{ secrets.GITHUB_TOKEN }} - - - name: PR Description Check - if: ${{ github.actor != 'dependabot' && github.actor != 'dependabot[bot]' }} - uses: gsactions/commit-message-checker@v2 - with: - pattern: '^\S+( \S+)*$' - error: 'The PR description must not be empty.' - flags: 'gm' - excludeDescription: 'false' - excludeTitle: 'true' - checkAllCommitMessages: 'false' - accessToken: ${{ secrets.GITHUB_TOKEN }} - diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml deleted file mode 100644 index 2d31222c..00000000 --- a/.github/workflows/integration.yaml +++ /dev/null @@ -1,193 +0,0 @@ -name: integration - -on: - push: - branches: [staging, stable] - paths-ignore: ['*.md'] - - pull_request: - types: [opened, synchronize, reopened] - branches: [staging] - paths-ignore: ['*.md'] - -jobs: - libc-test: - name: libc-test - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - plat: qemu - arch: x86_64 - - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - - name: Fetch helloworld - uses: actions/checkout@v3 - with: - repository: unikraft/app-helloworld - fetch-depth: 1 - path: _helloworld - - - name: Build and run libc-test via uktest - uses: unikraft/kraftkit@staging - with: - loglevel: debug - workdir: _helloworld - plat: ${{ matrix.plat }} - arch: ${{ matrix.arch }} - execute: true - kraftfile: | - specification: '0.5' - name: helloworld - unikraft: - source: ../ - kconfig: - CONFIG_LIBUKTEST: "y" - CONFIG_LIBUKTEST_ALL: "n" - CONFIG_LIBUKTEST_TEST_MYSELF: "n" - CONFIG_LIBUKTEST_LOG_STATS: "y" - CONFIG_LIBUKDEBUG_ANSI_COLOR: "y" - CONFIG_LIBUKDEBUG_PRINTK_INFO: "y" - CONFIG_LIBDEVFS: "y" - CONFIG_LIBDEVFS_DEV_STDOUT: "y" - CONFIG_LIBDEVFS_DEV_NULL_ZERO: "y" - CONFIG_LIBDEVFS_DEV_ZERO: "y" - CONFIG_STACK_SIZE_PAGE_ORDER: 4 - libraries: - libc-test: - version: staging - kconfig: - CONFIG_LIBLIBCTEST: "y" - CONFIG_LIBLIBCTEST_STRING_TESTS: "y" - CONFIG_LIBLIBCTEST_PTHREAD_TESTS: "y" - CONFIG_LIBLIBCTEST_CONVERSION_TESTS: "y" - CONFIG_LIBLIBCTEST_REGEX_TESTS: "y" - CONFIG_LIBLIBCTEST_FILE_FOLDER_TESTS: "y" - CONFIG_LIBLIBCTEST_TIME_TESTS: "y" - CONFIG_LIBLIBCTEST_NETWORK_TESTS: "y" - CONFIG_LIBLIBCTEST_SORT_TESTS: "y" - CONFIG_LIBLIBCTEST_STRUCTURE_SEARCH_TESTS: "y" - CONFIG_LIBLIBCTEST_SEMAPHORE_TESTS: "y" - CONFIG_LIBLIBCTEST_RANDOM_TESTS: "y" - CONFIG_LIBLIBCTEST_CRYPT_TESTS: "y" - CONFIG_LIBLIBCTEST_ENV_TESTS: "y" - CONFIG_LIBLIBCTEST_MALLOC_TESTS: "y" - CONFIG_LIBLIBCTEST_TGMATH_TESTS: "y" - CONFIG_LIBLIBCTEST_ICONV_TESTS: "y" - CONFIG_LIBLIBCTEST_UDIV_TESTS: "y" - CONFIG_LIBLIBCTEST_MBFUNC_TESTS: "y" - CONFIG_LIBLIBCTEST_SETJMP_TESTS: "y" - CONFIG_LIBLIBCTEST_FPCLASSIFY_TESTS: "y" - CONFIG_LIBLIBCTEST_POSIX_SPAWN_TESTS: "y" - CONFIG_LIBLIBCTEST_ACCESS_TESTS: "y" - musl: - version: staging - kconfig: - CONFIG_MUSL: "y" - CONFIG_LIBMUSL_COMPLEX: "y" - compiler-rt: - version: staging - targets: - - platform: ${{ matrix.plat }} - architecture: ${{ matrix.arch }} - - self-test: - name: self-test - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - plat: qemu - arch: x86_64 - - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - - name: Fetch helloworld - uses: actions/checkout@v3 - with: - repository: unikraft/app-helloworld - fetch-depth: 1 - path: _helloworld - - - name: Build and run all internal tests via uktest - uses: unikraft/kraftkit@staging - with: - loglevel: debug - workdir: _helloworld - plat: ${{ matrix.plat }} - arch: ${{ matrix.arch }} - execute: true - kraftfile: | - specification: '0.5' - name: helloworld - unikraft: - source: ../ - kconfig: - CONFIG_LIBUKTEST: "y" - CONFIG_LIBUKTEST_ALL: "y" - CONFIG_LIBUKTEST_TEST_MYSELF: "y" - CONFIG_LIBUKDEBUG_ANSI_COLOR: "y" - CONFIG_LIBUKDEBUG_PRINTK_INFO: "y" - CONFIG_LIBUKTEST_FAILFAST: "n" - CONFIG_LIBUKTEST_LOG_STATS: "y" - targets: - - platform: ${{ matrix.plat }} - architecture: ${{ matrix.arch }} - - helloworld: - name: helloworld - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - plat: qemu - arch: x86_64 - - plat: qemu - arch: arm64 - - plat: xen - arch: x86_64 - - plat: fc - arch: x86_64 - - plat: linuxu - arch: x86_64 - - plat: linuxu - arch: arm64 - - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - - name: Fetch helloworld - uses: actions/checkout@v3 - with: - repository: unikraft/app-helloworld - fetch-depth: 1 - path: _helloworld - - - name: Build helloworld - uses: unikraft/kraftkit@staging - with: - loglevel: debug - workdir: _helloworld - execute: false - plat: ${{ matrix.plat }} - arch: ${{ matrix.arch }} - kraftfile: | - specification: '0.5' - name: helloworld - unikraft: - source: ../ - targets: - - platform: ${{ matrix.plat }} - architecture: ${{ matrix.arch }} diff --git a/.github/workflows/label.yaml b/.github/workflows/label.yaml deleted file mode 100644 index 4c5f1f6f..00000000 --- a/.github/workflows/label.yaml +++ /dev/null @@ -1,28 +0,0 @@ -name: governctl - -on: - pull_request: - types: [opened, synchronize, reopened] - branches: [staging] - -jobs: - label: - runs-on: ubuntu-latest - name: label - steps: - - name: Install governctl - run: | - set -xe - wget -q "https://github.com/unikraft/governance/releases/download/v${GOVERN_VERSION}/governance_${GOVERN_VERSION}_linux_amd64.deb" - sudo dpkg -i "governance_${GOVERN_VERSION}_linux_amd64.deb" - env: - GOVERN_VERSION: 0.1.7 - - - name: Label PR - run: governctl pr sync labels unikraft/unikraft/${PR_NUMBER} --labels-dir .github/labels - env: - PR_NUMBER: ${{ github.event.number }} - GOVERN_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GOVERN_GITHUB_USER: ${{ secrets.GH_CHECKPATCH_ACTOR }} - GOVERN_NO_RENDER: true - GOVERN_LOG_LEVEL: warn diff --git a/.github/workflows/merge.yaml b/.github/workflows/merge.yaml deleted file mode 100644 index a33d407c..00000000 --- a/.github/workflows/merge.yaml +++ /dev/null @@ -1,38 +0,0 @@ -name: merge - -on: - pull_request_target: - types: [labeled] - -jobs: - merge: - if: ${{ github.event.label.name == 'merged' }} - runs-on: ubuntu-latest - name: merge - steps: - - name: Get Pull Request Number - run: echo "PR_NUMBER=$(echo "$GITHUB_REF" | awk -F / '{print $3}')" >> "$GITHUB_ENV" - shell: bash - - - name: Install governctl - run: | - set -xe - wget -q "https://github.com/unikraft/governance/releases/download/v${GOVERN_VERSION}/governance_${GOVERN_VERSION}_linux_amd64.deb" - sudo dpkg -i "governance_${GOVERN_VERSION}_linux_amd64.deb" - env: - GOVERN_VERSION: 0.1.8 - - - name: Run the merge through governctl - run: | - set -xe - unset GITHUB_TOKEN - governctl pr merge --approve-states "${GOVERN_APPROVE_STATES}" --review-states "${GOVERN_REVIEW_STATES}" --base "staging" --push "unikraft/unikraft/${PR_NUMBER}" - env: - GOVERN_GITHUB_TOKEN: ${{ secrets.GH_MERGE_PAT }} - GOVERN_GITHUB_USER: ${{ secrets.GH_MERGE_ACTOR }} - GOVERN_NO_RENDER: true - GOVERN_LOG_LEVEL: warn - GOVERN_NO_CONFLICTS: true - GOVERN_REVIEW_STATES: approved - GOVERN_APPROVE_STATES: approved - diff --git a/.github/workflows/pychecks.yaml b/.github/workflows/pychecks.yaml deleted file mode 100644 index ba60ef4c..00000000 --- a/.github/workflows/pychecks.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: Python Checks - -on: - push: - branches: [staging, stable] - paths: - - 'support/scripts/**' - - '.github/workflows/pychecks.yaml' - - pull_request: - types: [opened, synchronize, reopened] - branches: [staging] - paths: - - 'support/scripts/**' - - '.github/workflows/pychecks.yaml' - -jobs: - lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: black - uses: psf/black@stable - with: - src: support/scripts - - - name: ruff - uses: chartboost/ruff-action@v1 - if: success() || failure() - with: - src: support/scripts \ No newline at end of file diff --git a/.github/workflows/shellcheck.yaml b/.github/workflows/shellcheck.yaml deleted file mode 100644 index fa506d53..00000000 --- a/.github/workflows/shellcheck.yaml +++ /dev/null @@ -1,33 +0,0 @@ -name: shellcheck - -on: - push: - branches: [staging, stable] - paths: - - 'support/scripts/**' - - '.github/workflows/shellcheck.yaml' - - pull_request: - types: [opened, synchronize, reopened] - branches: [staging] - paths: - - 'support/scripts/**' - - '.github/workflows/shellcheck.yaml' - -permissions: {} - -jobs: - shellcheck: - name: Shellcheck - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Run ShellCheck - uses: ludeeus/action-shellcheck@master - env: - SHELLCHECK_OPTS: -s bash - with: - severity: warning - scandir: support/scripts - format: tty \ No newline at end of file -- Gitee From e93740b11cd8665ff06119103b3134f150efc1fe Mon Sep 17 00:00:00 2001 From: Li Haode Date: Thu, 13 Jun 2024 17:50:57 +0800 Subject: [PATCH 31/35] lib/tntimer: [bugfix] remove dump_timer to eliminate tick bias Signed-off-by: Li Haode --- lib/tntimer/tests/test_tntimer.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/tntimer/tests/test_tntimer.c b/lib/tntimer/tests/test_tntimer.c index 4cfe6fad..71303369 100644 --- a/lib/tntimer/tests/test_tntimer.c +++ b/lib/tntimer/tests/test_tntimer.c @@ -101,14 +101,11 @@ UK_TESTCASE(tntimer, test_tn_timer_list_operations) struct timer *node; struct uk_list_head *timer_list_head = tn_timer_get_list(); - dump_timer(); tn_timer_delete(timer2); - dump_timer(); timer2 = tn_timer_create( t2, *timeout_func1, NULL, TN_TIMER_FLAG_ONE_SHOT); tn_timer_start(timer2); - dump_timer(); systick_t last_tick = tn_timer_next_tick() + tn_systick_get_tick(); -- Gitee From 51a5a6cd5f0a727e4eb8a10b7f294d88b4c9c3bf Mon Sep 17 00:00:00 2001 From: liusai Date: Thu, 23 May 2024 10:13:14 +0800 Subject: [PATCH 32/35] lib/tntrace: add trace module Signed-off-by: liusai --- include/uk/trace_macros.h | 19 +++++ lib/Makefile.uk | 1 + lib/tntimer/Config.uk | 3 + lib/tntimer/Makefile.uk | 4 + lib/tntimer/tntimer.c | 5 ++ lib/tntimer/trace/trace_timer.c | 19 +++++ lib/tntrace/Config.uk | 22 ++++++ lib/tntrace/Makefile.uk | 5 ++ lib/tntrace/include/tn/trace.h | 37 ++++++++++ lib/ukintctlr/Config.uk | 4 + lib/ukintctlr/Makefile.uk | 4 + lib/ukintctlr/exportsyms.uk | 2 + lib/ukintctlr/trace/trace_intctrl.c | 19 +++++ lib/ukintctlr/ukintctlr.c | 4 + lib/uklock/Config.uk | 4 + lib/uklock/Makefile.uk | 4 + lib/uklock/exportsyms.uk | 28 +++++++ lib/uklock/include/uk/mutex.h | 14 ++++ lib/uklock/include/uk/semaphore.h | 19 +++++ lib/uklock/trace/trace_lock.c | 110 ++++++++++++++++++++++++++++ lib/uksched/Config.uk | 3 + lib/uksched/Makefile.uk | 4 + lib/uksched/exportsyms.uk | 4 + lib/uksched/include/uk/sched.h | 3 + lib/uksched/include/uk/sched_impl.h | 2 + lib/uksched/sched.c | 20 +++++ lib/uksched/thread.c | 4 + lib/uksched/trace/trace_sched.c | 91 +++++++++++++++++++++++ 28 files changed, 458 insertions(+) create mode 100644 include/uk/trace_macros.h create mode 100644 lib/tntimer/trace/trace_timer.c create mode 100644 lib/tntrace/Config.uk create mode 100644 lib/tntrace/Makefile.uk create mode 100644 lib/tntrace/include/tn/trace.h create mode 100644 lib/ukintctlr/trace/trace_intctrl.c create mode 100644 lib/uklock/trace/trace_lock.c create mode 100644 lib/uksched/trace/trace_sched.c diff --git a/include/uk/trace_macros.h b/include/uk/trace_macros.h new file mode 100644 index 00000000..29f409c3 --- /dev/null +++ b/include/uk/trace_macros.h @@ -0,0 +1,19 @@ +#ifndef __TN_TRACE_MACROS_H__ +#define __TN_TRACE_MACROS_H__ + +#ifndef CONFIG_LIBTNTRACE + +#define TN_TRACE_FUNC(type, func, ...) do { } while (0) +#define TN_TRACE_FUNC_ENTER(type, func, ...) do { } while (0) +#define TN_TRACE_FUNC_EXIT(type, func, ...) do { } while (0) +#define TN_TRACE_OBJ_FUNC(type, func, obj, ...) do { } while (0) +#define TN_TRACE_OBJ_FUNC_ENTER(type, func, obj, ...) do { } while (0) +#define TN_TRACE_OBJ_FUNC_EXIT(type, func, obj, ...) do { } while (0) + +#else /* !CONFIG_LIBTNTRACE */ + +#include + +#endif /* CONFIG_LIBTNTRACE */ + +#endif /* __TN_TRACE_MACROS_H__ */ diff --git a/lib/Makefile.uk b/lib/Makefile.uk index 0c97ada0..cfdb3262 100644 --- a/lib/Makefile.uk +++ b/lib/Makefile.uk @@ -72,3 +72,4 @@ $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukreloc)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukofw)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tnsystick)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tntimer)) +$(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tntrace)) diff --git a/lib/tntimer/Config.uk b/lib/tntimer/Config.uk index 4cf9ffff..f1149715 100644 --- a/lib/tntimer/Config.uk +++ b/lib/tntimer/Config.uk @@ -9,4 +9,7 @@ if LIBTNTIMER bool "Enable unit tests" default n select LIBUKTEST + config LIBTNTIMER_TRACE + bool "Enable timer trace" + default n endif diff --git a/lib/tntimer/Makefile.uk b/lib/tntimer/Makefile.uk index 8e001a7d..05db071c 100644 --- a/lib/tntimer/Makefile.uk +++ b/lib/tntimer/Makefile.uk @@ -12,3 +12,7 @@ LIBTNTIMER_SRCS-$(CONFIG_LIBTNTIMER) += $(LIBTNTIMER_BASE)/tntimer.c ifneq ($(filter y,$(CONFIG_LIBTNTIMER_TEST) $(CONFIG_LIBUKTEST_ALL)),) LIBTNTIMER_SRCS-y += $(LIBTNTIMER_BASE)/tests/test_tntimer.c endif + +ifneq ($(filter y,$(CONFIG_LIBTNTIMER_TRACE) $(CONFIG_LIBTNTRACE_ALL)),) +LIBTNTIMER_SRCS-y += $(LIBTNTIMER_BASE)/trace/trace_timer.c +endif diff --git a/lib/tntimer/tntimer.c b/lib/tntimer/tntimer.c index a5f563fc..c1cc4168 100644 --- a/lib/tntimer/tntimer.c +++ b/lib/tntimer/tntimer.c @@ -16,6 +16,7 @@ #include #include #include +#include static UK_LIST_HEAD(timer_list_head); static UK_LIST_HEAD(overflow_timer_list_head); @@ -112,6 +113,8 @@ void tn_timer_list_switch(void) void tn_timer_delete(struct timer *t) { + TN_TRACE_OBJ_FUNC(timer, delete, t); + UK_ASSERT(t); uk_list_del(&t->list); @@ -121,6 +124,8 @@ void tn_timer_delete(struct timer *t) void tn_timer_start(struct timer *t) { + TN_TRACE_OBJ_FUNC(timer, start, t); + systick_t cur; systick_t sum; diff --git a/lib/tntimer/trace/trace_timer.c b/lib/tntimer/trace/trace_timer.c new file mode 100644 index 00000000..33b7782e --- /dev/null +++ b/lib/tntimer/trace/trace_timer.c @@ -0,0 +1,19 @@ +#include + +#if defined(CONFIG_LIBTNTRACE_FORMAT) +void tn_trace_timer_delete_format(struct timer *timer) +{ + printf("%s: %p\n", __func__, timer); +} + +void tn_trace_timer_start_format(struct timer *timer) +{ + printf("%s: %p\n", __func__, timer); +} + +#elif defined(CONFIG_LIBTNTRACE_CUSTOM) + +void __weak tn_trace_timer_delete_custom(struct timer *timer) {} +void __weak tn_trace_timer_start_custom(struct timer *timer) {} + +#endif /* CONFIG_LIBTNTRACE_CUSTOM */ diff --git a/lib/tntrace/Config.uk b/lib/tntrace/Config.uk new file mode 100644 index 00000000..9eabf162 --- /dev/null +++ b/lib/tntrace/Config.uk @@ -0,0 +1,22 @@ +menuconfig LIBTNTRACE + bool "tntrace: enable trace service" + default n + select LIBNOLIBC if !HAVE_LIBC + +if LIBTNTRACE + +choice LIBTNTRACE_OUTPUT + prompt "Chooce output method for tracing" + default LIBTNTRACE_FORMAT + config LIBTNTRACE_FORMAT + bool "Use format output" + + config LIBTNTRACE_CUSTOM + bool "Use custome function" +endchoice + +config LIBTNTRACE_ALL + bool "Enable all trace across all libraries" + default y + +endif diff --git a/lib/tntrace/Makefile.uk b/lib/tntrace/Makefile.uk new file mode 100644 index 00000000..f99d5d91 --- /dev/null +++ b/lib/tntrace/Makefile.uk @@ -0,0 +1,5 @@ +$(eval $(call addlib_s,libtntrace,$(CONFIG_LIBTNTRACE))) + +CINCLUDES-$(CONFIG_LIBTNTRACE) += -I$(LIBTNTRACE_BASE)/include + +CXXINCLUDES-$(CONFIG_LIBTNTRACE) += -I$(LIBTNTRACE_BASE)/include diff --git a/lib/tntrace/include/tn/trace.h b/lib/tntrace/include/tn/trace.h new file mode 100644 index 00000000..6e824f12 --- /dev/null +++ b/lib/tntrace/include/tn/trace.h @@ -0,0 +1,37 @@ +#ifndef __TN_TRACE_H__ +#define __TN_TRACE_H__ + +#if defined(CONFIG_LIBTNTRACE_FORMAT) +#define TN_TRACE_FUNC(name, func, ...) \ + tn_trace_ ## name ## _ ## func ## _format(__VA_ARGS__) +#define TN_TRACE_FUNC_ENTER(name, func, ...) \ + tn_trace_ ## name ## _ ## func ## _enter_format(__VA_ARGS__) +#define TN_TRACE_FUNC_EXIT(name, func, ...) \ + tn_trace_ ## name ## _ ## func ## _exit_format(__VA_ARGS__) +#define TN_TRACE_OBJ_FUNC(name, func, obj, ...) \ + tn_trace_ ## name ## _ ## func ## _format(obj, ##__VA_ARGS__) +#define TN_TRACE_OBJ_FUNC_ENTER(name, func, obj, ...) \ + tn_trace_ ## name ## _ ## func ## _enter_format(obj, ##__VA_ARGS__) +#define TN_TRACE_OBJ_FUNC_EXIT(name, func, obj, ...) \ + tn_trace_ ## name ## _ ## func ## _exit_format(obj, ##__VA_ARGS__) + + +#elif defined(CONFIG_LIBTNTRACE_CUSTOM) + +#define TN_TRACE_FUNC(name, func, ...) \ + tn_trace_ ## name ## _ ## func ## _custom(__VA_ARGS__) +#define TN_TRACE_FUNC_ENTER(name, func, ...) \ + tn_trace_ ## name ## _ ## func ## _enter_custom(__VA_ARGS__) +#define TN_TRACE_FUNC_EXIT(name, func, ...) \ + tn_trace_ ## name ## _ ## func ## _exit_custom(__VA_ARGS__) +#define TN_TRACE_OBJ_FUNC(name, func, obj, ...) \ + tn_trace_ ## name ## _ ## func ## _custom(obj, ##__VA_ARGS__) +#define TN_TRACE_OBJ_FUNC_ENTER(name, func, obj, ...) \ + tn_trace_ ## name ## _ ## func ## _enter_custom(obj, ##__VA_ARGS__) +#define TN_TRACE_OBJ_FUNC_EXIT(name, func, obj, ...) \ + tn_trace_ ## name ## _ ## func ## _exit_custom(obj, ##__VA_ARGS__) + + +#endif /* CONFIG_LIBTNTRACE_CUSTOM */ + +#endif /* __TN_TRACE_H__ */ diff --git a/lib/ukintctlr/Config.uk b/lib/ukintctlr/Config.uk index 05edee73..5676c94f 100644 --- a/lib/ukintctlr/Config.uk +++ b/lib/ukintctlr/Config.uk @@ -20,4 +20,8 @@ config LIBUKINTCTLR_TEST default n select LIBUKTEST +config LIBUKINTCTLR_TRACE + bool "Enable isr trace" + default n + endif diff --git a/lib/ukintctlr/Makefile.uk b/lib/ukintctlr/Makefile.uk index 543e1520..f2953ab8 100644 --- a/lib/ukintctlr/Makefile.uk +++ b/lib/ukintctlr/Makefile.uk @@ -10,3 +10,7 @@ ifneq ($(filter y,$(CONFIG_LIBUKINTCTLR_TEST) $(CONFIG_LIBUKTEST_ALL)),) LIBUKINTCTLR_CINCLUDES-y += -I$(CONFIG_UK_BASE)/plat/common/include LIBUKINTCTLR_SRCS-y += $(LIBUKINTCTLR_BASE)/tests/test_intctlr.c endif + +ifneq ($(filter y,$(CONFIG_LIBUKINTCTLR_TRACE) $(CONFIG_LIBTNTRACE_ALL)),) +LIBUKINTCTLR_SRCS-y += $(LIBUKINTCTLR_BASE)/trace/trace_intctrl.c +endif diff --git a/lib/ukintctlr/exportsyms.uk b/lib/ukintctlr/exportsyms.uk index 32d74b1e..6779082e 100644 --- a/lib/ukintctlr/exportsyms.uk +++ b/lib/ukintctlr/exportsyms.uk @@ -18,3 +18,5 @@ uk_intctlr_sgi_op uk_intctlr_spi_get_affinity uk_intctlr_irq_mask uk_intctlr_irq_unmask +tn_trace_isr_enter +tn_trace_isr_exit diff --git a/lib/ukintctlr/trace/trace_intctrl.c b/lib/ukintctlr/trace/trace_intctrl.c new file mode 100644 index 00000000..8ced5924 --- /dev/null +++ b/lib/ukintctlr/trace/trace_intctrl.c @@ -0,0 +1,19 @@ +#include > + +#if defined(CONFIG_LIBTNTRACE_FORMAT) +void tn_trace_isr_handle_enter_format(unsigned int irq) +{ + printf("%s %u\n", __func__, irq); +} + +void tn_trace_isr_handle_exit_format(unsigned int irq) +{ + printf("%s %u\n", __func__, irq); +} + +#elif defined(CONFIG_LIBTNTRACE_CUSTOM) + +void __weak tn_trace_isr_handle_enter_custom(void) {} +void __weak tn_trace_isr_handle_exit_custom(void) {} + +#endif /* CONFIG_LIBTNTRACE_CUSTOM */ diff --git a/lib/ukintctlr/ukintctlr.c b/lib/ukintctlr/ukintctlr.c index a9df9ce8..aa7b8416 100644 --- a/lib/ukintctlr/ukintctlr.c +++ b/lib/ukintctlr/ukintctlr.c @@ -38,6 +38,7 @@ #include #include #include +#include #if CONFIG_LIBUKINTCTLR_ISR_ECTX_ASSERTIONS #include #endif /* CONFIG_LIBUKINTCTLR_ISR_ECTX_ASSERTIONS */ @@ -149,6 +150,7 @@ recheck: void uk_intctlr_irq_handle(struct __regs *regs, unsigned int irq) { + TN_TRACE_FUNC_ENTER(isr, handle, irq); struct irq_handler *h; int i; int rc; @@ -191,6 +193,8 @@ void uk_intctlr_irq_handle(struct __regs *regs, unsigned int irq) */ trace_uk_intctlr_unhandled_irq(irq); + TN_TRACE_FUNC_EXIT(isr, handle, irq); + exit: #if CONFIG_LIBUKINTCTLR_ISR_ECTX_ASSERTIONS ukarch_ectx_assert_equal(ectx); diff --git a/lib/uklock/Config.uk b/lib/uklock/Config.uk index e4ba3e0b..ab0c9064 100644 --- a/lib/uklock/Config.uk +++ b/lib/uklock/Config.uk @@ -45,4 +45,8 @@ if LIBUKLOCK default y help Enable reader-writer based synchronization + + config LIBUKLOCK_TRACE + bool "Enable trace" + default n endif diff --git a/lib/uklock/Makefile.uk b/lib/uklock/Makefile.uk index 8e4c1c50..95f76af3 100644 --- a/lib/uklock/Makefile.uk +++ b/lib/uklock/Makefile.uk @@ -6,3 +6,7 @@ CXXINCLUDES-$(CONFIG_LIBUKLOCK) += -I$(LIBUKLOCK_BASE)/include LIBUKLOCK_SRCS-$(CONFIG_LIBUKLOCK_SEMAPHORE) += $(LIBUKLOCK_BASE)/semaphore.c LIBUKLOCK_SRCS-$(CONFIG_LIBUKLOCK_MUTEX) += $(LIBUKLOCK_BASE)/mutex.c LIBUKLOCK_SRCS-$(CONFIG_LIBUKLOCK_RWLOCK) += $(LIBUKLOCK_BASE)/rwlock.c + +ifneq ($(filter y,$(CONFIG_LIBUKLOCK_TRACE) $(CONFIG_LIBTNTRACE_ALL)),) +LIBUKLOCK_SRCS-y += $(LIBUKLOCK_BASE)/trace/trace_lock.c +endif diff --git a/lib/uklock/exportsyms.uk b/lib/uklock/exportsyms.uk index 39d22368..d4a1ffc3 100644 --- a/lib/uklock/exportsyms.uk +++ b/lib/uklock/exportsyms.uk @@ -10,3 +10,31 @@ uk_rwlock_runlock uk_rwlock_wunlock uk_rwlock_upgrade uk_rwlock_downgrade +tn_trace_uk_semaphore_up_enter_format +tn_trace_uk_semaphore_up_exit_format +tn_trace_uk_semaphore_down_enter_format +tn_trace_uk_semaphore_down_exit_format +tn_trace_uk_semaphore_down_try_enter_format +tn_trace_uk_semaphore_down_try_exit_format +tn_trace_uk_semaphore_down_to_enter_format +tn_trace_uk_semaphore_down_to_exit_format +tn_trace_uk_mutex_lock_enter_format +tn_trace_uk_mutex_lock_exit_format +tn_trace_uk_mutex_trylock_enter_format +tn_trace_uk_mutex_trylock_exit_format +tn_trace_uk_mutex_unlock_enter_format +tn_trace_uk_mutex_unlock_exit_format +tn_trace_uk_semaphore_up_enter_custom +tn_trace_uk_semaphore_up_exit_custom +tn_trace_uk_semaphore_down_enter_custom +tn_trace_uk_semaphore_down_exit_custom +tn_trace_uk_semaphore_down_try_enter_custom +tn_trace_uk_semaphore_down_try_exit_custom +tn_trace_uk_semaphore_down_to_enter_custom +tn_trace_uk_semaphore_down_to_exit_custom +tn_trace_uk_mutex_lock_enter_custom +tn_trace_uk_mutex_lock_exit_custom +tn_trace_uk_mutex_trylock_enter_custom +tn_trace_uk_mutex_trylock_exit_custom +tn_trace_uk_mutex_unlock_enter_custom +tn_trace_uk_mutex_unlock_exit_custom diff --git a/lib/uklock/include/uk/mutex.h b/lib/uklock/include/uk/mutex.h index 57303ac1..2b62caf2 100644 --- a/lib/uklock/include/uk/mutex.h +++ b/lib/uklock/include/uk/mutex.h @@ -49,6 +49,8 @@ #include #endif /* CONFIG_LIBUKLOCK_MUTEX_METRICS */ +#include + #ifdef __cplusplus extern "C" { #endif @@ -116,6 +118,8 @@ static inline void uk_mutex_lock(struct uk_mutex *m) UK_ASSERT(m); + TN_TRACE_OBJ_FUNC_ENTER(uk_mutex, lock, m); + cur = uk_thread_current(); /* If the owner is the current thread, just increment the lock count */ @@ -145,6 +149,8 @@ static inline void uk_mutex_lock(struct uk_mutex *m) _uk_mutex_metrics.total_locks++; ukarch_spin_unlock(&_uk_mutex_metrics_lock); #endif /* CONFIG_LIBUKLOCK_MUTEX_METRICS */ + + TN_TRACE_OBJ_FUNC_EXIT(uk_mutex, lock, m); } static inline int uk_mutex_trylock(struct uk_mutex *m) @@ -153,6 +159,8 @@ static inline int uk_mutex_trylock(struct uk_mutex *m) UK_ASSERT(m); + TN_TRACE_OBJ_FUNC_ENTER(uk_mutex, trylock, m); + cur = uk_thread_current(); /* If the owner is the current thread, just increment the lock count */ @@ -183,6 +191,7 @@ static inline int uk_mutex_trylock(struct uk_mutex *m) _uk_mutex_metrics.total_ok_trylocks++; ukarch_spin_unlock(&_uk_mutex_metrics_lock); #endif /* CONFIG_LIBUKLOCK_MUTEX_METRICS */ + TN_TRACE_OBJ_FUNC_EXIT(uk_mutex, trylock, m); return 1; } @@ -193,6 +202,7 @@ static inline int uk_mutex_trylock(struct uk_mutex *m) _uk_mutex_metrics.total_failed_trylocks++; ukarch_spin_unlock(&_uk_mutex_metrics_lock); #endif /* CONFIG_LIBUKLOCK_MUTEX_METRICS */ + TN_TRACE_OBJ_FUNC_EXIT(uk_mutex, trylock, m); return 0; } @@ -209,6 +219,8 @@ static inline void uk_mutex_unlock(struct uk_mutex *m) UK_ASSERT(m->lock_count > 0); UK_ASSERT(m->owner == uk_thread_current()); + TN_TRACE_OBJ_FUNC_ENTER(uk_mutex, unlock, m); + if (--m->lock_count == 0) { /* Make sure lock_count is visible before resetting the * owner. The lock can be acquired afterwards. @@ -225,6 +237,8 @@ static inline void uk_mutex_unlock(struct uk_mutex *m) _uk_mutex_metrics.total_unlocks++; ukarch_spin_unlock(&_uk_mutex_metrics_lock); #endif /* CONFIG_LIBUKLOCK_MUTEX_METRICS */ + + TN_TRACE_OBJ_FUNC_EXIT(uk_mutex, unlock, m); } #define uk_waitq_wait_event_mutex(wq, condition, mutex) \ diff --git a/lib/uklock/include/uk/semaphore.h b/lib/uklock/include/uk/semaphore.h index 0564a8be..e40d4d6f 100644 --- a/lib/uklock/include/uk/semaphore.h +++ b/lib/uklock/include/uk/semaphore.h @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -59,6 +60,8 @@ static inline void uk_semaphore_down(struct uk_semaphore *s) UK_ASSERT(s); + TN_TRACE_OBJ_FUNC_ENTER(uk_semaphore, down, s); + for (;;) { uk_waitq_wait_event(&s->wait, s->count > 0); uk_spin_lock_irqsave(&(s->sl), irqf); @@ -71,6 +74,8 @@ static inline void uk_semaphore_down(struct uk_semaphore *s) uk_pr_debug("Decreased semaphore %p to %ld\n", s, s->count); #endif uk_spin_unlock_irqrestore(&(s->sl), irqf); + + TN_TRACE_OBJ_FUNC_EXIT(uk_semaphore, down, s); } static inline int uk_semaphore_down_try(struct uk_semaphore *s) @@ -80,6 +85,8 @@ static inline int uk_semaphore_down_try(struct uk_semaphore *s) UK_ASSERT(s); + TN_TRACE_OBJ_FUNC_ENTER(uk_semaphore, down_try, s); + uk_spin_lock_irqsave(&(s->sl), irqf); if (s->count > 0) { ret = 1; @@ -90,6 +97,8 @@ static inline int uk_semaphore_down_try(struct uk_semaphore *s) #endif } uk_spin_unlock_irqrestore(&(s->sl), irqf); + + TN_TRACE_OBJ_FUNC_EXIT(uk_semaphore, down_try, s, ret); return ret; } @@ -103,6 +112,8 @@ static inline __nsec uk_semaphore_down_to(struct uk_semaphore *s, UK_ASSERT(s); + TN_TRACE_OBJ_FUNC_ENTER(uk_semaphore, down_to, s, timeout); + deadline = then + timeout; for (;;) { @@ -120,6 +131,7 @@ static inline __nsec uk_semaphore_down_to(struct uk_semaphore *s, s, s->count); #endif uk_spin_unlock_irqrestore(&(s->sl), irqf); + TN_TRACE_OBJ_FUNC_EXIT(uk_semaphore, down_to, s, timeout); return ukplat_monotonic_clock() - then; } @@ -127,6 +139,8 @@ static inline __nsec uk_semaphore_down_to(struct uk_semaphore *s, #ifdef UK_SEMAPHORE_DEBUG uk_pr_debug("Timed out while waiting for semaphore %p\n", s); #endif + +TN_TRACE_OBJ_FUNC_EXIT(uk_semaphore, down_to, s, timeout); return __NSEC_MAX; } @@ -136,14 +150,19 @@ static inline void uk_semaphore_up(struct uk_semaphore *s) UK_ASSERT(s); + TN_TRACE_OBJ_FUNC_ENTER(uk_semaphore, up, s); + uk_spin_lock_irqsave(&(s->sl), irqf); ++s->count; + #ifdef UK_SEMAPHORE_DEBUG uk_pr_debug("Increased semaphore %p to %ld\n", s, s->count); #endif uk_waitq_wake_up(&s->wait); uk_spin_unlock_irqrestore(&(s->sl), irqf); + + TN_TRACE_OBJ_FUNC_EXIT(uk_semaphore, up, s); } #ifdef __cplusplus diff --git a/lib/uklock/trace/trace_lock.c b/lib/uklock/trace/trace_lock.c new file mode 100644 index 00000000..eb221530 --- /dev/null +++ b/lib/uklock/trace/trace_lock.c @@ -0,0 +1,110 @@ +#include + +#if defined(CONFIG_LIBTNTRACE_FORMAT) +void tn_trace_uk_semaphore_up_enter_format(struct uk_semaphore *semaphore) +{ + printf("%s: %p\n", __func__, semaphore); +} + +void tn_trace_uk_semaphore_up_exit_format(struct uk_semaphore *semaphore) +{ + printf("%s: %p\n", __func__, semaphore); +} + +void tn_trace_uk_semaphore_down_enter_format(struct uk_semaphore *semaphore) +{ + printf("%s: %p\n", __func__, semaphore); +} + +void tn_trace_uk_semaphore_down_exit_format(struct uk_semaphore *semaphore) +{ + printf("%s: %p\n", __func__, semaphore); +} + +void tn_trace_uk_semaphore_down_try_enter_format(struct uk_semaphore *semaphore) +{ + printf("%s: %p\n", __func__, semaphore); +} + +void tn_trace_uk_semaphore_down_try_exit_format(struct uk_semaphore *semaphore, + int ret) +{ + printf("%s: %p %d\n", __func__, semaphore, ret); +} + +void tn_trace_uk_semaphore_down_to_enter_format(struct uk_semaphore *semaphore, + __nsec timeout) +{ + printf("%s: %p %lu\n", __func__, semaphore, timeout); +} + +void tn_trace_uk_semaphore_down_to_exit_format(struct uk_semaphore *semaphore, + __nsec timeout) +{ + printf("%s: %p %lu\n", __func__, semaphore, timeout); +} + +void tn_trace_uk_mutex_lock_enter_format(struct uk_mutex *mutex) +{ + printf("%s: %p\n", __func__, mutex); +} + +void tn_trace_uk_mutex_lock_exit_format(struct uk_mutex *mutex) +{ + printf("%s: %p\n", __func__, mutex); +} + +void tn_trace_uk_mutex_trylock_enter_format(struct uk_mutex *mutex) +{ + printf("%s: %p\n", __func__, mutex); +} + +void tn_trace_uk_mutex_trylock_exit_format(struct uk_mutex *mutex) +{ + printf("%s: %p\n", __func__, mutex); +} + +void tn_trace_uk_mutex_unlock_enter_format(struct uk_mutex *mutex) +{ + printf("%s: %p\n", __func__, mutex); +} + +void tn_trace_uk_mutex_unlock_exit_format(struct uk_mutex *mutex) +{ + printf("%s: %p\n", __func__, mutex); +} + +#elif defined(CONFIG_LIBTNTRACE_CUSTOM) + +void __weak tn_trace_uk_semaphore_up_enter_custom( + struct uk_semaphore *semaphore) +{} +void __weak tn_trace_uk_semaphore_up_exit_custom( + struct uk_semaphore *semaphore) +{} +void __weak tn_trace_uk_semaphore_down_enter_custom( + struct uk_semaphore *semaphore) +{} +void __weak tn_trace_uk_semaphore_down_exit_custom( + struct uk_semaphore *semaphore) +{} +void __weak tn_trace_uk_semaphore_down_try_enter_custom( + struct uk_semaphore *semaphore) +{} +void __weak tn_trace_uk_semaphore_down_try_exit_custom( + struct uk_semaphore *semaphore, int ret) +{} +void __weak tn_trace_uk_semaphore_down_to_enter_custom( + struct uk_semaphore *semaphore, __nsec timeout) +{} +void __weak tn_trace_uk_semaphore_down_to_exit_custom( + struct uk_semaphore *semaphore, __nsec timeout) +{} +void __weak tn_trace_uk_mutex_lock_enter_custom(struct uk_mutex *mutex) {} +void __weak tn_trace_uk_mutex_lock_exit_custom(struct uk_mutex *mutex) {} +void __weak tn_trace_uk_mutex_trylock_enter_custom(struct uk_mutex *mutex) {} +void __weak tn_trace_uk_mutex_trylock_exit_custom(struct uk_mutex *mutex) {} +void __weak tn_trace_uk_mutex_unlock_enter_custom(struct uk_mutex *mutex) {} +void __weak tn_trace_uk_mutex_unlock_exit_custom(struct uk_mutex *mutex) {} + +#endif /* CONFIG_LIBTNTRACE_CUSTOM */ diff --git a/lib/uksched/Config.uk b/lib/uksched/Config.uk index f9b0cee8..4b19aeaa 100644 --- a/lib/uksched/Config.uk +++ b/lib/uksched/Config.uk @@ -62,4 +62,7 @@ if LIBUKSCHED config LIBUKSCHED_TEST bool "Enable unit tests" default n + config LIBUKSCHED_TRACE + bool "Enable trace" + default n endif diff --git a/lib/uksched/Makefile.uk b/lib/uksched/Makefile.uk index 9ebf7337..df905d0a 100644 --- a/lib/uksched/Makefile.uk +++ b/lib/uksched/Makefile.uk @@ -24,3 +24,7 @@ ifneq ($(filter y,$(CONFIG_LIBUKSCHED_TEST) $(CONFIG_LIBUKTEST_ALL)),) LIBUKSCHED_SRCS-y += $(LIBUKSCHED_BASE)/tests/test_sched.c endif + +ifneq ($(filter y,$(CONFIG_LIBUKSCHED_TRACE) $(CONFIG_LIBTNTRACE_ALL)),) +LIBUKSCHED_SRCS-y += $(LIBUKSCHED_BASE)/trace/trace_sched.c +endif diff --git a/lib/uksched/exportsyms.uk b/lib/uksched/exportsyms.uk index 9b1f0537..38a3bb04 100644 --- a/lib/uksched/exportsyms.uk +++ b/lib/uksched/exportsyms.uk @@ -51,3 +51,7 @@ sched_getaffinity uk_syscall_e_sched_setaffinity uk_syscall_r_sched_setaffinity sched_setaffinity +tn_trace_uk_thread_yield_format +tn_trace_uk_thread_switch_format +tn_trace_uk_thread_yield_custom +tn_trace_uk_thread_switch_custom diff --git a/lib/uksched/include/uk/sched.h b/lib/uksched/include/uk/sched.h index 3027e79b..15fd5d19 100644 --- a/lib/uksched/include/uk/sched.h +++ b/lib/uksched/include/uk/sched.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -119,6 +120,8 @@ static inline void uk_sched_yield(void) struct uk_sched *s; struct uk_thread *current = uk_thread_current(); + TN_TRACE_OBJ_FUNC(uk_thread, yield, current); + UK_ASSERT(current); s = current->sched; diff --git a/lib/uksched/include/uk/sched_impl.h b/lib/uksched/include/uk/sched_impl.h index 298b8811..37218fa3 100644 --- a/lib/uksched/include/uk/sched_impl.h +++ b/lib/uksched/include/uk/sched_impl.h @@ -124,6 +124,8 @@ unsigned int uk_sched_thread_gc(struct uk_sched *sched); static inline void uk_sched_thread_switch(struct uk_thread *next) { + TN_TRACE_OBJ_FUNC(uk_thread, switch, next); + struct uk_thread *prev; prev = ukplat_per_lcpu_current(__uk_sched_thread_current); diff --git a/lib/uksched/sched.c b/lib/uksched/sched.c index acfb0dd8..a5ae6fc7 100644 --- a/lib/uksched/sched.c +++ b/lib/uksched/sched.c @@ -41,6 +41,7 @@ #include #include #include +#include struct uk_sched *uk_sched_head; @@ -327,10 +328,14 @@ void uk_sched_thread_exit2(uk_thread_gc_t gc_fn, void *gc_argp) { struct uk_thread *t = uk_thread_current(); + TN_TRACE_OBJ_FUNC_ENTER(uk_thread, exit, t); + t->_gc_fn = gc_fn; t->_gc_argp = gc_argp; uk_sched_thread_terminate(t); UK_CRASH("Unexpectedly returned to exited thread %p\n", t); + + TN_TRACE_OBJ_FUNC_EXIT(uk_thread, exit, t); } /* This function has the __noreturn attribute set */ @@ -344,6 +349,9 @@ void uk_sched_thread_sleep_ns(__nsec nsec) struct uk_thread *thread; thread = uk_thread_current(); + + TN_TRACE_OBJ_FUNC(uk_thread, sleep_ns, thread, nsec); + uk_thread_block_timeout(thread, ns_to_ticks(nsec)); uk_sched_yield(); } @@ -353,6 +361,9 @@ void uk_sched_thread_sleep_tick(systick_t tick) struct uk_thread *thread; thread = uk_thread_current(); + + TN_TRACE_OBJ_FUNC(uk_thread, sleep_tick, thread, tick); + uk_thread_block_timeout(thread, tick); uk_sched_yield(); } @@ -366,6 +377,8 @@ int uk_sched_thread_add(struct uk_sched *s, struct uk_thread *t) UK_ASSERT(t); UK_ASSERT(!t->sched); + TN_TRACE_OBJ_FUNC(uk_thread, add, t); + flags = ukplat_lcpu_save_irqf(); rc = s->thread_add(s, t); @@ -392,12 +405,17 @@ int uk_sched_thread_remove(struct uk_thread *t) UK_ASSERT(t); UK_ASSERT(t->sched); + TN_TRACE_OBJ_FUNC_ENTER(uk_thread, remove, t); + flags = ukplat_lcpu_save_irqf(); s = t->sched; s->thread_remove(s, t); t->sched = NULL; UK_TAILQ_REMOVE(&s->thread_list, t, thread_list); ukplat_lcpu_restore_irqf(flags); + + TN_TRACE_OBJ_FUNC_EXIT(uk_thread, remove, t); + return 0; } @@ -467,5 +485,7 @@ void uk_sched_thread_set_priority(struct uk_thread *thread, int32_t priority) UK_ASSERT(thread->sched); thread->sched->thread_set_prio(thread->sched, thread, priority); + + TN_TRACE_OBJ_FUNC(uk_thread, set_priority, thread, priority); } #endif diff --git a/lib/uksched/thread.c b/lib/uksched/thread.c index eeebf4a5..538b8f03 100644 --- a/lib/uksched/thread.c +++ b/lib/uksched/thread.c @@ -46,6 +46,8 @@ #include #include #include +#include + #if CONFIG_LIBUKSCHED_TCB_INIT && !CONFIG_UKARCH_TLS_HAVE_TCB #error CONFIG_LIBUKSCHED_TCB_INIT requires that a TLS contains reserved space for a TCB @@ -1139,6 +1141,8 @@ void uk_thread_block(struct uk_thread *thread) void uk_thread_wake(struct uk_thread *thread) { + TN_TRACE_OBJ_FUNC(uk_thread, wake, thread); + unsigned long flags; flags = ukplat_lcpu_save_irqf(); diff --git a/lib/uksched/trace/trace_sched.c b/lib/uksched/trace/trace_sched.c new file mode 100644 index 00000000..2dfe2c78 --- /dev/null +++ b/lib/uksched/trace/trace_sched.c @@ -0,0 +1,91 @@ +#include +#include + +#if defined(CONFIG_LIBTNTRACE_FORMAT) +void tn_trace_uk_thread_wake_format(struct uk_thread *thread) +{ + printf("%s: %p\n", __func__, thread); +} + +void tn_trace_uk_thread_yield_format(struct uk_thread *current) +{ + printf("%s: %p\n", __func__, current); +} + +void tn_trace_uk_thread_switch_format(struct uk_thread *next) +{ + struct uk_thread *thread = uk_thread_current(); + + printf("%s: switch from %p to %p\n", __func__, thread, next); +} + +void tn_trace_uk_thread_switch_exit_format(void) +{ + struct uk_thread *thread = uk_thread_current(); + + printf("%s: %p\n", __func__, thread); +} + +void tn_trace_uk_thread_set_priority_format( + struct uk_thread *thread, int32_t priority) +{ + printf("%s: %p %d\n", __func__, thread, priority); +} + +void tn_trace_uk_thread_exit_enter_format(struct uk_thread *thread) +{ + printf("%s: %p\n", __func__, thread); +} + +void tn_trace_uk_thread_exit_exit_format(struct uk_thread *thread) +{ + printf("%s: %p\n", __func__, thread); +} + +void tn_trace_uk_thread_sleep_ns_format(struct uk_thread *thread, __nsec nsec) +{ + printf("%s: %p %lu\n", __func__, thread, nsec); +} + +void tn_trace_uk_thread_sleep_tick_format( + struct uk_thread *thread, systick_t tick) +{ + printf("%s: %p %llu\n", __func__, thread, tick); +} + +void tn_trace_uk_thread_add_format(struct uk_thread *thread) +{ + printf("%s: %p\n", __func__, thread); +} + +void tn_trace_uk_thread_remove_enter_format(struct uk_thread *thread) +{ + printf("%s: %p\n", __func__, thread); +} + +void tn_trace_uk_thread_remove_exit_format(struct uk_thread *thread) +{ + printf("%s: %p\n", __func__, thread); +} + +#elif defined(CONFIG_LIBTNTRACE_CUSTOM) + +void __weak tn_trace_uk_thread_wake_custom(struct uk_thread *thread) {} +void __weak tn_trace_uk_thread_yield_custom(struct uk_thread *current) {} +void __weak tn_trace_uk_thread_switch_custom(struct uk_thread *next) {} +void __weak tn_trace_uk_thread_set_priority_custom( + struct uk_thread *thread, int32_t priority) +{} +void __weak tn_trace_uk_thread_exit_enter_custom(struct uk_thread *thread) {} +void __weak tn_trace_uk_thread_exit_exit_custom(struct uk_thread *thread) {} +void __weak tn_trace_uk_thread_sleep_ns_custom( + struct uk_thread *thread, __nsec nsec) +{} +void __weak tn_trace_uk_thread_sleep_tick_custom( + struct uk_thread *thread, systick_t tick) +{} +void __weak tn_trace_uk_thread_add_custom(struct uk_thread *thread) {} +void __weak tn_trace_uk_thread_remove_enter_custom(struct uk_thread *thread) {} +void __weak tn_trace_uk_thread_remove_exit_custom(struct uk_thread *thread) {} + +#endif /* CONFIG_LIBTNTRACE_CUSTOM */ -- Gitee From c0962a98225ed2b7d464a404f48fb7f39f2cd5ce Mon Sep 17 00:00:00 2001 From: sunhaoyi Date: Thu, 25 Apr 2024 15:08:55 +0800 Subject: [PATCH 33/35] lib/sched: Remove interrupt state restrictions from the scheduler Signed-off-by: sunhaoyi --- lib/tnschedprio/schedprio.c | 3 --- lib/ukschedcoop/schedcoop.c | 3 --- 2 files changed, 6 deletions(-) diff --git a/lib/tnschedprio/schedprio.c b/lib/tnschedprio/schedprio.c index 307344ac..c0d69142 100644 --- a/lib/tnschedprio/schedprio.c +++ b/lib/tnschedprio/schedprio.c @@ -29,9 +29,6 @@ static inline void schedprio_schedule(struct schedprio *c, bool yield) bool runnable; int cmp_value; - if (unlikely(ukplat_lcpu_irqs_disabled())) - UK_CRASH("Must not call %s with IRQs disabled\n", __func__); - prev = uk_thread_current(); flags = ukplat_lcpu_save_irqf(); diff --git a/lib/ukschedcoop/schedcoop.c b/lib/ukschedcoop/schedcoop.c index 45081d0d..0086f1b2 100644 --- a/lib/ukschedcoop/schedcoop.c +++ b/lib/ukschedcoop/schedcoop.c @@ -46,9 +46,6 @@ static inline void schedcoop_schedule(struct uk_sched *s, bool yield) __snsec now; unsigned long flags; - if (unlikely(ukplat_lcpu_irqs_disabled())) - UK_CRASH("Must not call %s with IRQs disabled\n", __func__); - now = ukplat_monotonic_clock(); prev = uk_thread_current(); -- Gitee From 717f34adcba9480f4207f26d32481be6471c2896 Mon Sep 17 00:00:00 2001 From: sunhaoyi Date: Tue, 28 May 2024 16:16:52 +0800 Subject: [PATCH 34/35] lib/tntimer: fix the traversing timer dead loop caused by adding the same timer Signed-off-by: sunhaoyi --- lib/tntimer/tntimer.c | 6 +++--- lib/uksched/include/uk/wait.h | 19 ++++++++++++++----- lib/uksched/thread.c | 1 + 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/tntimer/tntimer.c b/lib/tntimer/tntimer.c index c1cc4168..dfd59aae 100644 --- a/lib/tntimer/tntimer.c +++ b/lib/tntimer/tntimer.c @@ -117,7 +117,7 @@ void tn_timer_delete(struct timer *t) UK_ASSERT(t); - uk_list_del(&t->list); + uk_list_del_init(&t->list); if (timoutListsOverflowed && uk_list_empty(&timer_list_head)) tn_timer_list_switch(); } @@ -175,7 +175,7 @@ void tn_timer_announce(void) t = uk_list_first_entry( &timer_list_head, struct timer, list); - uk_list_del(&t->list); + uk_list_del_init(&t->list); t->timeout_func(t->parameter); if (t->flag & TN_TIMER_FLAG_PERIODIC) tn_timer_start(t); @@ -188,7 +188,7 @@ void tn_timer_announce(void) t = uk_list_first_entry( &timer_list_head, struct timer, list); if (t->timeout_tick <= cur) { - uk_list_del(&t->list); + uk_list_del_init(&t->list); t->timeout_func(t->parameter); if (t->flag & TN_TIMER_FLAG_PERIODIC) tn_timer_start(t); diff --git a/lib/uksched/include/uk/wait.h b/lib/uksched/include/uk/wait.h index 0d5b4eb3..0b370b81 100644 --- a/lib/uksched/include/uk/wait.h +++ b/lib/uksched/include/uk/wait.h @@ -113,8 +113,12 @@ do { \ break; \ } \ uk_waitq_add(wq, &__wait); \ - TN_THREAD_TIMER_START(__current, ns_to_ticks( \ - deadline - ukplat_monotonic_clock())); \ + if (deadline) \ + TN_THREAD_TIMER_START( \ + __current, \ + ns_to_ticks( \ + deadline \ + - ukplat_monotonic_clock())); \ uk_thread_set_blocked(__current); \ uk_sched_thread_blocked(__current); \ ukplat_spin_unlock_irqrestore(&((wq)->sl), \ @@ -148,8 +152,10 @@ do { \ __current = uk_thread_current(); \ ukplat_spin_lock_irqsave(&((wq)->sl), flags); \ uk_waitq_add(wq, &__wait); \ - TN_THREAD_TIMER_START(__current, ns_to_ticks( \ - deadline - ukplat_monotonic_clock())); \ + if (deadline) \ + TN_THREAD_TIMER_START( \ + __current, \ + ns_to_ticks(deadline - ukplat_monotonic_clock())); \ uk_thread_set_blocked(__current); \ uk_sched_thread_blocked(__current); \ ukplat_spin_unlock_irqrestore(&((wq)->sl), flags); \ @@ -203,6 +209,7 @@ void uk_waitq_wake_up(struct uk_waitq *wq) _waitq_foreach_safe(curr, &(wq->wait_list), thread_list, tmp) { uk_thread_wake(curr->thread); + tn_timer_delete(&curr->thread->timer); } ukplat_spin_unlock_irqrestore(&(wq->sl), flags); @@ -217,8 +224,10 @@ void uk_waitq_wake_up_one(struct uk_waitq *wq) ukplat_spin_lock_irqsave(&(wq->sl), flags); head = _waitq_best(wq); - if (head) + if (head) { uk_thread_wake(head->thread); + tn_timer_delete(&head->thread->timer); + } ukplat_spin_unlock_irqrestore(&(wq->sl), flags); if (head) uk_sched_reschedule(); diff --git a/lib/uksched/thread.c b/lib/uksched/thread.c index 538b8f03..fec74fb7 100644 --- a/lib/uksched/thread.c +++ b/lib/uksched/thread.c @@ -248,6 +248,7 @@ static void _uk_thread_struct_init(struct uk_thread *t, t->priv = priv; t->dtor = dtor; t->exec_time = 0; + UK_INIT_LIST_HEAD(&t->timer.list); #ifdef CONFIG_LIBUKSCHED_THREAD_PRIORITY t->prio = prio; -- Gitee From f69ad530cd19bdd7982a9aa4e39dc246269c7eeb Mon Sep 17 00:00:00 2001 From: sunhaoyi Date: Mon, 3 Jun 2024 14:37:15 +0800 Subject: [PATCH 35/35] lib/tnperf: provides performance testing capabilities Signed-off-by: sunhaoyi --- lib/Makefile.uk | 1 + lib/tnperf/Config.uk | 17 ++++++++ lib/tnperf/Makefile.uk | 7 +++ lib/tnperf/exportsyms.uk | 4 ++ lib/tnperf/include/tn/perf.h | 23 ++++++++++ lib/tnperf/include/tn/pmu.h | 68 +++++++++++++++++++++++++++++ lib/tnperf/perf.c | 28 ++++++++++++ lib/tnperf/pmu.c | 84 ++++++++++++++++++++++++++++++++++++ 8 files changed, 232 insertions(+) create mode 100644 lib/tnperf/Config.uk create mode 100644 lib/tnperf/Makefile.uk create mode 100644 lib/tnperf/exportsyms.uk create mode 100644 lib/tnperf/include/tn/perf.h create mode 100644 lib/tnperf/include/tn/pmu.h create mode 100644 lib/tnperf/perf.c create mode 100644 lib/tnperf/pmu.c diff --git a/lib/Makefile.uk b/lib/Makefile.uk index cfdb3262..261c1931 100644 --- a/lib/Makefile.uk +++ b/lib/Makefile.uk @@ -73,3 +73,4 @@ $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/ukofw)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tnsystick)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tntimer)) $(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tntrace)) +$(eval $(call import_lib,$(CONFIG_UK_BASE)/lib/tnperf)) diff --git a/lib/tnperf/Config.uk b/lib/tnperf/Config.uk new file mode 100644 index 00000000..167d39d1 --- /dev/null +++ b/lib/tnperf/Config.uk @@ -0,0 +1,17 @@ +menuconfig LIBTNPERF + bool "tnperf: Operating System Performance Measurement Tools" + default n + +if LIBTNPERF +choice + prompt "Test Data Acquisition Method" +config LIBTNPERF_PMU + bool "PMU registers" + depends on (ARCH_ARM_64 || ARCH_ARM_32) + help + The ARM Cortex processor family in the ARM architecture has + a dedicated set of PMU registers for performance monitoring + and debugging. +endchoice + +endif diff --git a/lib/tnperf/Makefile.uk b/lib/tnperf/Makefile.uk new file mode 100644 index 00000000..7d04408d --- /dev/null +++ b/lib/tnperf/Makefile.uk @@ -0,0 +1,7 @@ +$(eval $(call addlib_s,libtnperf,$(CONFIG_LIBTNPERF))) + +CINCLUDES-$(CONFIG_LIBTNPERF) += -I$(LIBTNPERF_BASE)/include +CXXINCLUDES-$(CONFIG_LIBTNPERF) += -I$(LIBTNPERF_BASE)/include + +LIBTNPERF_SRCS-y += $(LIBTNPERF_BASE)/perf.c +LIBTNPERF_SRCS-$(CONFIG_LIBTNPERF_PMU) += $(LIBTNPERF_BASE)/pmu.c diff --git a/lib/tnperf/exportsyms.uk b/lib/tnperf/exportsyms.uk new file mode 100644 index 00000000..7776f12b --- /dev/null +++ b/lib/tnperf/exportsyms.uk @@ -0,0 +1,4 @@ +tn_perf_init +tn_perf_event_register +tn_perf_event_unregister +tn_perf_read_event_counter diff --git a/lib/tnperf/include/tn/perf.h b/lib/tnperf/include/tn/perf.h new file mode 100644 index 00000000..1a2def02 --- /dev/null +++ b/lib/tnperf/include/tn/perf.h @@ -0,0 +1,23 @@ +#ifndef __TN_PERF_H__ +#define __TN_PERF_H__ + +#include +#if CONFIG_LIBTNPERF_PMU +#include +#endif /* CONFIG_LIBTNPERF_PMU */ + +typedef int (*register_event_func)(uint8_t event_num); +typedef int (*unregister_event_func)(uint8_t event_num); +typedef uint64_t (*read_event_counter_func)(uint8_t event_num); +struct tn_perf_ops { + register_event_func event_register; + unregister_event_func event_unregister; + read_event_counter_func read_counter; +}; + +int tn_perf_init(void); +int tn_perf_event_register(uint8_t event_num); +int tn_perf_event_unregister(uint8_t event_num); +uint64_t tn_perf_read_event_counter(uint8_t event_num); + +#endif /* __TN_PERF_H__ */ diff --git a/lib/tnperf/include/tn/pmu.h b/lib/tnperf/include/tn/pmu.h new file mode 100644 index 00000000..d828f102 --- /dev/null +++ b/lib/tnperf/include/tn/pmu.h @@ -0,0 +1,68 @@ +#ifndef __TN_PMU_H__ +#define __TN_PMU_H__ + +#define SUPPORT_EVENT_NUM 58 +#define EVENT_COUNTER_NUM 6 + +#define SW_INCR 0x00 +#define L1I_CACHE_REFILL 0x01 +#define L1I_TLB_REFILL 0x02 +#define L1D_CACHE_REFILL 0x03 +#define L1D_CACHE 0x04 +#define L1D_TLB_REFILL 0x05 +#define LD_RETIRED 0x06 +#define ST_RETIRED 0x07 +#define INST_RETIRED 0x08 +#define EXC_TAKEN 0x09 +#define EXC_RETURN 0x0A +#define CID_WRITE_RETIRED 0x0B +#define PC_WRITE_RETIRED 0x0C +#define BR_IMMED_RETIRED 0x0D +#define BR_RETURN_RETIRED 0x0E +#define UNALIGNED_LDST_RETIRED 0x0F +#define BR_MIS_PRED 0x10 +#define CPU_CYCLES 0x11 +#define BR_PRED 0x12 +#define MEM_ACCESS 0x13 +#define L1I_CACHE 0x14 +#define L1D_CACHE_WB 0x15 +#define L2D_CACHE 0x16 +#define L2D_CACHE_REFILL 0x17 +#define L2D_CACHE_WB 0x18 +#define BUS_ACCESS 0x19 +#define MEMORY_ERROR 0x1A +#define INST_SPEC 0x1B +#define TTBR_WRITE_RETIRED 0x1C +#define BUS_CYCLES 0x1D +#define CHAIN 0x1E +#define L1D_CACHE_ALLOCATE 0x1F +#define L2D_CACHE_ALLOCATE 0x20 +#define BR_RETIRED 0x21 +#define BR_MIS_PRED_RETIRED 0x22 +#define STALL_FRONTEND 0x23 +#define STALL_BACKEND 0x24 +#define L1D_TLB 0x25 +#define L1I_TLB 0x26 +#define L2I_CACHE 0x27 +#define L2I_CACHE_REFILL 0x28 +#define L3D_CACHE_ALLOCATE 0x29 +#define L3D_CACHE_REFILL 0x2A +#define L3D_CACHE 0x2B +#define L3D_CACHE_WB 0x2C +#define L2D_TLB_REFILL 0x2D +#define L2I_TLB_REFILL 0x2E +#define L2D_TLB 0x2F +#define L2I_TLB 0x30 +#define DTLB_WALK 0x34 +#define ITLB_WALK 0x35 +#define LL_CACHE_RD 0x36 +#define LL_CACHE_MISS_RD 0x37 +#define REMOTE_ACCESS_RD 0x38 +struct pmu_event { + uint8_t enable; + uint8_t counter_num; +}; + +struct tn_perf_ops *tn_pmu_init(); + +#endif /* __TN_PMU_H__ */ diff --git a/lib/tnperf/perf.c b/lib/tnperf/perf.c new file mode 100644 index 00000000..9233eeb8 --- /dev/null +++ b/lib/tnperf/perf.c @@ -0,0 +1,28 @@ +#include +#include +#if CONFIG_LIBTNPERF_PMU +#include +#endif /* CONFIG_LIBTNPERF_PMU */ +struct tn_perf_ops *perf_ops; + +int tn_perf_init(void) +{ +#if CONFIG_LIBTNPERF_PMU + perf_ops = tn_pmu_init(); +#endif /* CONFIG_LIBTNPERF_PMU */ + return 1; +} +int tn_perf_event_register(uint8_t event_num) +{ + return perf_ops->event_register(event_num); +} + +int tn_perf_event_unregister(uint8_t event_num) +{ + return perf_ops->event_unregister(event_num); +} + +uint64_t tn_perf_read_event_counter(uint8_t event_num) +{ + return perf_ops->read_counter(event_num); +} diff --git a/lib/tnperf/pmu.c b/lib/tnperf/pmu.c new file mode 100644 index 00000000..d0e40bea --- /dev/null +++ b/lib/tnperf/pmu.c @@ -0,0 +1,84 @@ +#include +#include +#include + +#define VACANT_COUNTER 0 +#define BUSY_COUNTER 1 + +struct tn_perf_ops tn_pmu_ops; +uint8_t counter[EVENT_COUNTER_NUM] = { 0 }; +uint8_t pmu_event[SUPPORT_EVENT_NUM] = { 0 }; + +static int tn_pmu_event_register(uint8_t event_num) +{ + int counter_num; + + if (event_num == CPU_CYCLES) + return 0; + for (counter_num = 0; counter_num < EVENT_COUNTER_NUM; counter_num++) { + if (counter[counter_num] == BUSY_COUNTER) + continue; + counter[counter_num] = BUSY_COUNTER; + break; + } + if (counter_num == EVENT_COUNTER_NUM) { + printf("counter_num = %d\n", counter_num); + return -1; + } + pmu_event[event_num] = counter_num + 1; + __asm__ volatile("msr PMSELR_EL0, %0" : : "r"(counter_num)); + __asm__ volatile("msr PMXEVTYPER_EL0, %0" : : "r"(event_num)); + return 0; +} +static int tn_pmu_event_unregister(uint8_t event_num) +{ + int counter_num = pmu_event[event_num] - 1; + + counter[counter_num] = VACANT_COUNTER; + pmu_event[event_num] = 0; + return 0; +} +static uint64_t tn_pmu_read_event_counter(uint8_t event_num) +{ + int cnt = 0; + + if (event_num == CPU_CYCLES) { + __asm__ volatile("mrs %0, PMCCNTR_EL0" : "=r"(cnt)); + } else { + switch (pmu_event[event_num]) { + case 1: + __asm__ volatile("mrs %0, PMEVCNTR0_EL0" : "=r"(cnt)); + break; + case 2: + __asm__ volatile("mrs %0, PMEVCNTR1_EL0" : "=r"(cnt)); + break; + case 3: + __asm__ volatile("mrs %0, PMEVCNTR2_EL0" : "=r"(cnt)); + break; + case 4: + __asm__ volatile("mrs %0, PMEVCNTR3_EL0" : "=r"(cnt)); + break; + case 5: + __asm__ volatile("mrs %0, PMEVCNTR4_EL0" : "=r"(cnt)); + break; + case 6: + __asm__ volatile("mrs %0, PMEVCNTR5_EL0" : "=r"(cnt)); + break; + } + } + return cnt; +} + +struct tn_perf_ops *tn_pmu_init(void) +{ + + tn_pmu_ops.event_register = tn_pmu_event_register; + tn_pmu_ops.event_unregister = tn_pmu_event_unregister; + tn_pmu_ops.read_counter = tn_pmu_read_event_counter; + + asm volatile("msr pmcr_el0, %0" : : "r"(17)); + asm volatile("msr PMCNTENSET_EL0, %0" : : "r"(0x8000000f)); + asm volatile("msr PMOVSCLR_EL0, %0" : : "r"(0x8000000f)); + + return &tn_pmu_ops; +} -- Gitee