diff --git a/repos/dde_linux/src/include/lx_emul/alloc.h b/repos/dde_linux/src/include/lx_emul/alloc.h new file mode 100644 index 0000000000..88daeb69f6 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/alloc.h @@ -0,0 +1,34 @@ +/* + * \brief Lx_emul support to allocate memory + * \author Stefan Kalkowski + * \date 2021-03-25 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__ALLOC_H_ +#define _LX_EMUL__ALLOC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void * lx_emul_mem_alloc(unsigned long size); +void * lx_emul_mem_alloc_uncached(unsigned long size); +void * lx_emul_mem_alloc_aligned(unsigned long size, unsigned long align); +unsigned long lx_emul_mem_dma_addr(void * addr); +void lx_emul_mem_free(const void * ptr); +unsigned long lx_emul_mem_size(const void * ptr); +void lx_emul_mem_cache_clean_invalidate(const void * ptr, unsigned long size); +void lx_emul_mem_cache_invalidate(const void * ptr, unsigned long size); + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_EMUL__ALLOC_H_ */ diff --git a/repos/dde_linux/src/include/lx_emul/clock.h b/repos/dde_linux/src/include/lx_emul/clock.h new file mode 100644 index 0000000000..08af86e549 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/clock.h @@ -0,0 +1,33 @@ +/* + * \brief Lx_emul support for device clocks + * \author Stefan Kalkowski + * \date 2021-04-14 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__CLOCK_H_ +#define _LX_EMUL__CLOCK_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct device_node; +struct clk; + +struct clk * lx_emul_clock_get(const struct device_node * node, + const char * name); + +unsigned long lx_emul_clock_get_rate(struct clk * clk); + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_EMUL__CLOCK_H_ */ diff --git a/repos/dde_linux/src/include/lx_emul/debug.h b/repos/dde_linux/src/include/lx_emul/debug.h new file mode 100644 index 0000000000..d09aafcef5 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/debug.h @@ -0,0 +1,29 @@ +/* + * \brief Lx_emul support to debug Linux kernel ports + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__DEBUG_H_ +#define _LX_EMUL__DEBUG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((noreturn)) void lx_emul_trace_and_stop(const char * func); + +void lx_emul_trace(const char * func); + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_EMUL__DEBUG_H_ */ diff --git a/repos/dde_linux/src/include/lx_emul/init.h b/repos/dde_linux/src/include/lx_emul/init.h new file mode 100644 index 0000000000..f8511008c1 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/init.h @@ -0,0 +1,35 @@ +/* + * \brief Lx_emul support to register Linux kernel initialization + * \author Stefan Kalkowski + * \date 2021-03-10 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__INIT_H_ +#define _LX_EMUL__INIT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void lx_emul_initcalls(void); + +void lx_emul_register_initcall(int (*initcall)(void), const char * name); + +void lx_emul_start_kernel(void * dtb); + +int lx_emul_init_task_function(void * dtb); + +extern void * lx_emul_init_task_struct; + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_EMUL__INIT_H_ */ diff --git a/repos/dde_linux/src/include/lx_emul/io_mem.h b/repos/dde_linux/src/include/lx_emul/io_mem.h new file mode 100644 index 0000000000..4f3012d845 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/io_mem.h @@ -0,0 +1,27 @@ +/* + * \brief Lx_emul support for I/O memory + * \author Stefan Kalkowski + * \date 2021-04-17 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__IO_MEM_H_ +#define _LX_EMUL__IO_MEM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void * lx_emul_io_mem_map(unsigned long phys_addr, unsigned long size); + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_EMUL__IO_MEM_H_ */ diff --git a/repos/dde_linux/src/include/lx_emul/irq.h b/repos/dde_linux/src/include/lx_emul/irq.h new file mode 100644 index 0000000000..0a0dcf58f9 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/irq.h @@ -0,0 +1,39 @@ +/* + * \brief Lx_emul support for interrupts + * \author Stefan Kalkowski + * \date 2021-04-14 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__IRQ_H_ +#define _LX_EMUL__IRQ_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct irq_desc; + +void lx_emul_irq_unmask(unsigned int irq); + +void lx_emul_irq_mask(unsigned int irq); + +void lx_emul_irq_eoi(unsigned int irq); + +int lx_emul_irq_task_function(void * data); + +extern void * lx_emul_irq_task_struct; + +unsigned int lx_emul_irq_last(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_EMUL__IRQ_H_ */ diff --git a/repos/dde_linux/src/include/lx_emul/log.h b/repos/dde_linux/src/include/lx_emul/log.h new file mode 100644 index 0000000000..70bb6b3e10 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/log.h @@ -0,0 +1,27 @@ +/* + * \brief Lx_emul support to log messages from the kernel code + * \author Stefan Kalkowski + * \date 2021-03-24 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__LOG_H_ +#define _LX_EMUL__LOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void lx_emul_vprintf(char const *, va_list); + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_EMUL__LOG_H_ */ diff --git a/repos/dde_linux/src/include/lx_emul/page_virt.h b/repos/dde_linux/src/include/lx_emul/page_virt.h new file mode 100644 index 0000000000..c0790fdac3 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/page_virt.h @@ -0,0 +1,59 @@ +/* + * \brief Lx_emul support for page-struct management + * \author Norman Feske + * \date 2021-07-01 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__PAGE_VIRT_H_ +#define _LX_EMUL__PAGE_VIRT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct page; + + +/* + * Accessors for the associative data structure implemented in page_virt.cc + */ + +void lx_emul_associate_page_with_virt_addr(struct page *, void const *virt); +void lx_emul_disassociate_page_from_virt_addr(void const *virt); +struct page *lx_emul_associated_page(void const *virt, unsigned long size); + + +/** + * Return page struct for the page at a given virtual address + * + * If no page struct exists for the virtual address, it is created. + */ +struct page *lx_emul_virt_to_pages(void const *virt, unsigned num); + + +/** + * Release page structs for specified virtual-address range + * + * \param size size of range in bytes + */ +void lx_emul_forget_pages(void const *virt, unsigned long size); + + +/** + * Perform unit test + */ +void lx_emul_associate_page_selftest(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_EMUL__PAGE_VIRT_H_ */ diff --git a/repos/dde_linux/src/include/lx_emul/shadow/asm/bug.h b/repos/dde_linux/src/include/lx_emul/shadow/asm/bug.h new file mode 100644 index 0000000000..16539f52f4 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/shadow/asm/bug.h @@ -0,0 +1,22 @@ +/* + * \brief Shadows Linux kernel asm/bug.h + * \author Stefan Kalkowski + * \date 2021-04-14 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__SHADOW__ASM__BUG_H_ +#define _LX_EMUL__SHADOW__ASM__BUG_H_ + +#include_next + +#undef __WARN_FLAGS +#define __WARN_FLAGS(flags) + +#endif /* _LX_EMUL__SHADOW__ASM__BUG_H_ */ diff --git a/repos/dde_linux/src/include/lx_emul/shadow/asm/current.h b/repos/dde_linux/src/include/lx_emul/shadow/asm/current.h new file mode 100644 index 0000000000..79b2e3d017 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/shadow/asm/current.h @@ -0,0 +1,25 @@ +/* + * \brief Shadows Linux kernel asm/current.h + * \author Stefan Kalkowski + * \date 2021-04-14 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__SHADOW__ASM__CURRENT_H_ +#define _LX_EMUL__SHADOW__ASM__CURRENT_H_ + +#include + +#ifndef __ASSEMBLY__ + +#define current lx_emul_task_get_current() + +#endif /* __ASSEMBLY__ */ + +#endif /* _LX_EMUL__SHADOW__ASM__CURRENT_H_ */ diff --git a/repos/dde_linux/src/include/lx_emul/shadow/asm/irqflags.h b/repos/dde_linux/src/include/lx_emul/shadow/asm/irqflags.h new file mode 100644 index 0000000000..51440df6b5 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/shadow/asm/irqflags.h @@ -0,0 +1,44 @@ +/* + * \brief Shadows Linux kernel asm/irqflags.h + * \author Stefan Kalkowski + * \date 2021-04-14 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef __ASM_IRQFLAGS_H +#define __ASM_IRQFLAGS_H + +static inline void arch_local_irq_enable(void) +{ +} + +static inline void arch_local_irq_disable(void) +{ +} + +static inline unsigned long arch_local_save_flags(void) +{ + return 1; +} + +static inline int arch_irqs_disabled_flags(unsigned long flags) +{ + return flags; +} + +static inline unsigned long arch_local_irq_save(void) +{ + return 1; +} + +static inline void arch_local_irq_restore(unsigned long flags) +{ +} + +#endif diff --git a/repos/dde_linux/src/include/lx_emul/shadow/asm/memory.h b/repos/dde_linux/src/include/lx_emul/shadow/asm/memory.h new file mode 100644 index 0000000000..f0d24e2d05 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/shadow/asm/memory.h @@ -0,0 +1,64 @@ +/* + * \brief Shadows Linux kernel arch/.../asm/memory.h + * \author Norman Feske + * \date 2021-06-25 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef __ASM_MEMORY_H +#define __ASM_MEMORY_H + +#ifndef __ASSEMBLY__ + +#include +#include +#include +#include +#include + +#define PCI_IO_SIZE SZ_16M + +extern u64 vabits_actual; + +#define __tag_reset(addr) (addr) +#define untagged_addr(addr) (addr) + +#define VA_BITS (CONFIG_ARM64_VA_BITS) +#define VA_BITS_MIN (VA_BITS) + +#define PAGE_OFFSET (0) + +#define THREAD_SHIFT PAGE_SHIFT +#define THREAD_SIZE (UL(1) << THREAD_SHIFT) + +#define BPF_JIT_REGION_START 0 +#define BPF_JIT_REGION_END 0 + +#define MT_NORMAL 0 +#define MT_NORMAL_TAGGED 1 +#define MT_NORMAL_NC 2 +#define MT_DEVICE_nGnRnE 4 +#define MT_DEVICE_nGnRE 5 + +#define __va(x) ( lx_emul_trace_and_stop("__va"), (void *)0 ) +#define __pa(v) lx_emul_mem_dma_addr((void *)(v)) + +#define page_to_phys(p) __pa((p)->virtual) +#define page_to_virt(p) ((p)->virtual) + +static inline struct page *virt_to_page(void const *v) { return lx_emul_virt_to_pages(v, 1U); } + +#define pfn_to_page(pfn) ( (struct page *)(__va(pfn << PAGE_SHIFT)) ) +#define page_to_pfn(page) ( page_to_phys(page) >> PAGE_SHIFT ) + +#define PCI_IO_START 0 + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_MEMORY_H */ diff --git a/repos/dde_linux/src/include/lx_emul/shadow/asm/page.h b/repos/dde_linux/src/include/lx_emul/shadow/asm/page.h new file mode 100644 index 0000000000..4108ac02d2 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/shadow/asm/page.h @@ -0,0 +1,47 @@ +/* + * \brief Shadows Linux kernel asm/page.h + * \author Norman Feske + * \date 2021-06-25 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef __ASM_GENERIC_PAGE_H +#define __ASM_GENERIC_PAGE_H + +#ifndef __ASSEMBLY__ + +#include /* for PAGE_SHIFT */ +#include + +/* + * The 'virtual' member of 'struct page' is needed by 'lx_emul_virt_to_phys' + * and 'page_to_virt'. + */ +#define WANT_PAGE_VIRTUAL + +#define clear_page(page) memset((page), 0, PAGE_SIZE) +#define copy_page(to,from) memcpy((to), (from), PAGE_SIZE) + +#define clear_user_page(page, vaddr, pg) clear_page(page) +#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) + +struct page; + +typedef struct page *pgtable_t; + +/* needed by mm/internal.h */ +#define pfn_valid(pfn) (pfn != 0UL) + +#define virt_addr_valid(kaddr) (kaddr != 0UL) + +#endif /* __ASSEMBLY__ */ + +#include + +#endif /* __ASM_GENERIC_PAGE_H */ diff --git a/repos/dde_linux/src/include/lx_emul/shadow/asm/percpu.h b/repos/dde_linux/src/include/lx_emul/shadow/asm/percpu.h new file mode 100644 index 0000000000..9bed35c42d --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/shadow/asm/percpu.h @@ -0,0 +1,27 @@ +/* + * \brief Shadows Linux kernel asm/percpu.h + * \author Stefan Kalkowski + * \date 2021-04-14 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__SHADOW__ASM__PERCPU_H_ +#define _LX_EMUL__SHADOW__ASM__PERCPU_H_ + +#include_next + +static inline unsigned long __dummy_cpu_offset(void) +{ + return 0; +} + +#undef __my_cpu_offset +#define __my_cpu_offset __dummy_cpu_offset() + +#endif /* _LX_EMUL__SHADOW__ASM__PERCPU_H_ */ diff --git a/repos/dde_linux/src/include/lx_emul/shadow/asm/pgtable.h b/repos/dde_linux/src/include/lx_emul/shadow/asm/pgtable.h new file mode 100644 index 0000000000..c894ca19fe --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/shadow/asm/pgtable.h @@ -0,0 +1,81 @@ +/* + * \brief Shadows Linux kernel arch/.../asm/pgtable.h + * \author Norman Feske + * \date 2021-06-25 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef __ASM_PGTABLE_H +#define __ASM_PGTABLE_H + +#ifndef __ASSEMBLY__ + +#include +#include +#include +#include +#include +#include + +#include + +pte_t pte_mkwrite(pte_t pte); + +pte_t pte_get(pte_t pte); +pte_t pte_wrprotect(pte_t pte); +pte_t pte_modify(pte_t pte, pgprot_t prot); +pte_t pte_mkdirty(pte_t pte); + +struct mm_struct; +bool mm_pmd_folded(struct mm_struct *mm); /* needed by linux/mm.h */ + +int pud_none(pud_t pud); + +struct page *pmd_page(pmd_t pmd); + +#define phys_to_ttbr(addr) (addr) + +int pte_none(pte_t pte); +int pte_present(pte_t pte); +int pte_swp_soft_dirty(pte_t pte); +int pte_dirty(pte_t ptr); +int pte_write(pte_t ptr); + +extern pgd_t reserved_pg_dir[PTRS_PER_PGD]; +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; + +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +swp_entry_t __pmd_to_swp_entry(pmd_t pmd); + +#define __swp_type(x) ( lx_emul_trace_and_stop(__func__), 0 ) +#define __swp_offset(x) ( lx_emul_trace_and_stop(__func__), 0 ) + +#define __swp_entry(type, offset) ( lx_emul_trace_and_stop(__func__), (swp_entry_t) { 0 } ) + +#define __swp_entry_to_pte(swp) ((pte_t) { (swp).val }) +pmd_t __swp_entry_to_pmd(swp_entry_t swp); + +int pmd_none(pmd_t pmd); +int pmd_present(pmd_t pmd); +int pmd_trans_huge(pmd_t pmd); +int pmd_devmap(pmd_t pmd); + +int pud_devmap(pud_t pud); +int pud_trans_huge(pud_t pud); + +pgprot_t pgprot_writecombine(pgprot_t prot); + +pte_t mk_pte(struct page * page, pgprot_t prot); + +#define HPAGE_SHIFT PMD_SHIFT +#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_PGTABLE_H */ diff --git a/repos/dde_linux/src/include/lx_emul/shadow/linux/compiler-gcc.h b/repos/dde_linux/src/include/lx_emul/shadow/linux/compiler-gcc.h new file mode 100644 index 0000000000..486cf53d46 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/shadow/linux/compiler-gcc.h @@ -0,0 +1,28 @@ +/* + * \brief Shadow copy of linux/compiler-gcc.h + * \author Stefan Kalkowski + * \date 2021-03-17 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__SHADOW__LINUX__COMPILER_GCC_H_ +#define _LX_EMUL__SHADOW__LINUX__COMPILER_GCC_H_ + +#include_next + +/** + * We have to re-define `asm_volatile_goto`, because the original function + * uses `asm goto(...)`, which is a problem when building PIC code. + */ +#ifdef asm_volatile_goto +#undef asm_volatile_goto +#define asm_volatile_goto(x...) asm volatile("invalid use of asm_volatile_goto") +#endif + +#endif /* _LX_EMUL__SHADOW__LINUX__COMPILER_GCC_H_ */ diff --git a/repos/dde_linux/src/include/lx_emul/shadow/linux/init.h b/repos/dde_linux/src/include/lx_emul/shadow/linux/init.h new file mode 100644 index 0000000000..42f9f2db62 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/shadow/linux/init.h @@ -0,0 +1,35 @@ +/* + * \brief Shadow copy of linux/init.h + * \author Stefan Kalkowski + * \date 2021-03-10 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__SHADOW__LINUX__INIT_H_ +#define _LX_EMUL__SHADOW__LINUX__INIT_H_ + +#include_next +#include + +/** + * We have to re-define certain initcall macros, because the original function + * puts all initcalls into the .init section that is not exported by our + * linker script. + * Instead, we define ctor functions that register the initcalls and their + * priority in our lx_emul environment. + */ +#undef ___define_initcall +#undef __define_initcall + +#define __define_initcall(fn, id) \ + static void __initcall_##fn##id(void)__attribute__((constructor)); \ + static void __initcall_##fn##id() { \ + lx_emul_register_initcall(fn, __func__); }; + +#endif /* _LX_EMUL__SHADOW__LINUX__INIT_H_ */ diff --git a/repos/dde_linux/src/include/lx_emul/shadow/linux/pgtable.h b/repos/dde_linux/src/include/lx_emul/shadow/linux/pgtable.h new file mode 100644 index 0000000000..3dd1b149d5 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/shadow/linux/pgtable.h @@ -0,0 +1,33 @@ +/* + * \brief Shadows Linux kernel linux/pgtable.h + * \author Norman Feske + * \date 2021-06-25 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef __LINUX_PGTABLE_H +#define __LINUX_PGTABLE_H + +#include +#include + +pmd_t *pmd_offset(pud_t *pud, unsigned long address); +pmd_t pmd_swp_clear_soft_dirty(pmd_t pmd); +int pmd_swp_soft_dirty(pmd_t pmd); + +void __init pgtable_cache_init(void); + +#define pgprot_decrypted(prot) (prot) + +pte_t pte_swp_clear_uffd_wp(pte_t pte); +pte_t pte_swp_clear_soft_dirty(pte_t pte); + +pte_t ptep_get(pte_t *ptep); + +#endif /* __LINUX_PGTABLE_H */ diff --git a/repos/dde_linux/src/include/lx_emul/task.h b/repos/dde_linux/src/include/lx_emul/task.h new file mode 100644 index 0000000000..a2024bec26 --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/task.h @@ -0,0 +1,47 @@ +/* + * \brief Lx_emul support to task handling + * \author Stefan Kalkowski + * \date 2021-03-25 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__TASK_H_ +#define _LX_EMUL__TASK_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +enum { SWAPPER_PID, KIRQ_PID, FIRST_PID }; + +struct task_struct; + +struct task_struct * lx_emul_task_get_current(void); + +struct task_struct * lx_emul_task_get(int pid); + +void lx_emul_task_create(struct task_struct * task, + const char * name, + int pid, + int (* threadfn)(void * data), + void * data); + +void lx_emul_task_unblock(struct task_struct * task); + +void lx_emul_task_priority(struct task_struct * task, unsigned long prio); + +void lx_emul_task_schedule(int block); + +void lx_emul_task_name(struct task_struct * task, const char * name); + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_EMUL__TASK_H_ */ diff --git a/repos/dde_linux/src/include/lx_emul/time.h b/repos/dde_linux/src/include/lx_emul/time.h new file mode 100644 index 0000000000..00ef1f41bc --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/time.h @@ -0,0 +1,35 @@ +/* + * \brief Lx_emul support for time + * \author Stefan Kalkowski + * \date 2021-04-30 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__TIME_H_ +#define _LX_EMUL__TIME_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void lx_emul_time_init(void); + +void lx_emul_time_event(unsigned long evt); + +void lx_emul_time_stop(void); + +unsigned long lx_emul_time_counter(void); + +void lx_emul_time_handle(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_EMUL__TIME_H_ */ diff --git a/repos/dde_linux/src/include/lx_kit/byte_range.h b/repos/dde_linux/src/include/lx_kit/byte_range.h new file mode 100644 index 0000000000..a4dcd2c54f --- /dev/null +++ b/repos/dde_linux/src/include/lx_kit/byte_range.h @@ -0,0 +1,44 @@ +/* + * \brief Lx_kit byte-range utility + * \author Norman Feske + * \date 2021-07-02 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_KIT__BYTE_RANGE_H_ +#define _LX_KIT__BYTE_RANGE_H_ + +#include + +namespace Lx_kit { + + using namespace Genode; + + struct Byte_range; +} + + +struct Lx_kit::Byte_range +{ + addr_t start; + size_t size; + + bool intersects(Byte_range const &other) const + { + if (start > other.start + other.size - 1) + return false; + + if (start + size - 1 < other.start) + return false; + + return true; + } +}; + +#endif /* _LX_KIT__BYTE_RANGE_H_ */ diff --git a/repos/dde_linux/src/include/lx_kit/console.h b/repos/dde_linux/src/include/lx_kit/console.h new file mode 100644 index 0000000000..4d2f56607b --- /dev/null +++ b/repos/dde_linux/src/include/lx_kit/console.h @@ -0,0 +1,132 @@ +/* + * \brief Lx_kit format string backend + * \author Stefan Kalkowski + * \author Sebastian Sumpf + * \date 2021-03-17 + * + * Greatly inspired by the former DDE Linux Lx_kit implementation. + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_KIT__CONSOLE_H_ +#define _LX_KIT__CONSOLE_H_ + +#include + +namespace Lx_kit { + class Console; + + using namespace Genode; +} + + +class Lx_kit::Console +{ + private: + + enum { BUF_SIZE = 216 }; + + char _buf[BUF_SIZE + 1]; + unsigned _idx = 0; + + /** + * Convert digit to ASCII value + */ + static inline char _ascii(int digit, int uppercase = 0) + { + if (digit > 9) + return digit + (uppercase ? 'A' : 'a') - 10; + + return digit + '0'; + } + + /** + * Output signed value with the specified base + */ + template + void _out_signed(T value, unsigned base) + { + /** + * for base 8, the number of digits is the number of value bytes times 3 + * at a max, because 0xff is 0o377 and accumulating this implies a + * strictly decreasing factor + */ + char buf[sizeof(value)*3]; + + /* set flag if value is negative */ + int neg = value < 0 ? 1 : 0; + + /* get absolute value */ + value = value < 0 ? -value : value; + + int i = 0; + + /* handle zero as special case */ + if (value == 0) + buf[i++] = _ascii(0); + + /* fill buffer starting with the least significant digits */ + else + for (; value > 0; value /= base) + buf[i++] = _ascii(value % base); + + /* add sign to buffer for negative values */ + if (neg) + _out_char('-'); + + /* output buffer in reverse order */ + for (; i--; ) + _out_char(buf[i]); + } + + + /** + * Output unsigned value with the specified base and padding + */ + template + void _out_unsigned(T value, unsigned base, int pad) + { + /** + * for base 8, the number of digits is the number of value bytes times 3 + * at a max, because 0xff is 0o377 and accumulating this implies a + * strictly decreasing factor + */ + char buf[sizeof(value)*3]; + + int i = 0; + + /* handle zero as special case */ + if (value == 0) { + buf[i++] = _ascii(0); + pad--; + } + + /* fill buffer starting with the least significant digits */ + for (; value > 0; value /= base, pad--) + buf[i++] = _ascii(value % base); + + /* add padding zeros */ + for (; pad-- > 0; ) + _out_char(_ascii(0)); + + /* output buffer in reverse order */ + for (; i--; ) + _out_char(buf[i]); + } + + void _out_char(char c); + void _out_string(const char *str); + void _flush(); + + public: + + void vprintf(const char *format, va_list list); +}; + +#endif /* _LX_KIT__CONSOLE_H_ */ diff --git a/repos/dde_linux/src/include/lx_kit/device.h b/repos/dde_linux/src/include/lx_kit/device.h new file mode 100644 index 0000000000..aa75cf1625 --- /dev/null +++ b/repos/dde_linux/src/include/lx_kit/device.h @@ -0,0 +1,162 @@ +/* + * \brief Globally available Lx_kit environment, needed in the C-ish lx_emul + * \author Stefan Kalkowski + * \date 2021-04-14 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_KIT__DEVICE_H_ +#define _LX_KIT__DEVICE_H_ + +#include +#include +#include +#include +#include +#include +#include + +namespace Lx_kit { + using namespace Genode; + + class Device; + class Device_list; +} + +struct clk { + unsigned long rate; +}; + +class Lx_kit::Device : List::Element +{ + private: + + friend class Device_list; + friend class List; + + using Name = String<64>; + using Type = Platform::Device::Type; + + struct Io_mem : List::Element + { + using Index = Platform::Device::Mmio::Index; + + Index idx; + addr_t addr; + size_t size; + + Constructible io_mem {}; + + bool match(addr_t addr, size_t size); + + Io_mem(unsigned idx, addr_t addr, size_t size) + : idx{idx}, addr(addr), size(size) {} + }; + + struct Irq_handler + { + private: + + Irq_handler(Irq_handler const &); + Irq_handler &operator = (Irq_handler const &); + + Platform::Device::Irq _irq; + Io_signal_handler _handler; + unsigned _number; + + void _handle(); + + public: + + Irq_handler(Platform::Device & dev, + Platform::Device::Irq::Index idx, + unsigned number); + + void ack() { _irq.ack(); } + }; + + struct Irq : List::Element + { + using Index = Platform::Device::Irq::Index; + + Index idx; + unsigned number; + + Constructible handler {}; + + Irq(unsigned idx, unsigned number) + : idx{idx}, number(number) {} + }; + + struct Clock : List::Element + { + unsigned idx; + Name const name; + clk lx_clock; + + Clock(unsigned idx, Name const name) + : idx(idx), name(name), lx_clock{0} {} + }; + + Device(Platform::Connection & plat, + Xml_node & xml, + Heap & heap); + + Platform::Connection & _platform; + Name const _name; + Type const _type; + List _io_mems {}; + List _irqs {}; + List _clocks {}; + Constructible _pdev {}; + + template + void _for_each_io_mem(FN const & fn) { + for (Io_mem * i = _io_mems.first(); i; i = i->next()) fn(*i); } + + template + void _for_each_irq(FN const & fn) { + for (Irq * i = _irqs.first(); i; i = i->next()) fn(*i); } + + template + void _for_each_clock(FN const & fn) { + for (Clock * c = _clocks.first(); c; c = c->next()) fn(*c); } + + public: + + const char * compatible(); + const char * name(); + + void enable(); + clk * clock(const char * name); + clk * clock(unsigned idx); + bool io_mem(addr_t phys_addr, size_t size); + void * io_mem_local_addr(addr_t phys_addr, size_t size); + bool irq_unmask(unsigned irq); + void irq_mask(unsigned irq); + void irq_ack(unsigned irq); +}; + + +class Lx_kit::Device_list : List +{ + private: + + Platform::Connection & _platform; + + public: + + template + void for_each(FN const & fn) { + for (Device * d = first(); d; d = d->next()) fn(*d); } + + Device_list(Heap & heap, Platform::Connection & platform); +}; + +#endif /* _LX_KIT__DEVICE_H_ */ diff --git a/repos/dde_linux/src/include/lx_kit/env.h b/repos/dde_linux/src/include/lx_kit/env.h new file mode 100644 index 0000000000..9244db32cd --- /dev/null +++ b/repos/dde_linux/src/include/lx_kit/env.h @@ -0,0 +1,58 @@ +/* + * \brief Globally available Lx_kit environment, needed in the C-ish lx_emul + * \author Stefan Kalkowski + * \date 2021-03-17 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_KIT__ENV_H_ +#define _LX_KIT__ENV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Lx_kit { + + struct Env; + + /** + * Returns the global Env object available + * + * \param env - pointer to Genode::Env used to construct object initially + */ + Env & env(Genode::Env * env = nullptr); +} + + +struct Lx_kit::Env +{ + Genode::Env & env; + Genode::Heap heap { env.ram(), env.rm() }; + Initcalls initcalls { heap }; + Console console { }; + Platform::Connection platform { env }; + Timer::Connection timer { env }; + Mem_allocator memory { env, heap, platform, CACHED }; + Mem_allocator uncached_memory { env, heap, platform, UNCACHED }; + Scheduler scheduler { }; + Device_list devices { heap, platform }; + Lx_kit::Timeout timeout { timer, scheduler }; + unsigned int last_irq { 0 }; + + Env(Genode::Env & env) : env(env) { } +}; + +#endif /* _LX_KIT__ENV_H_ */ diff --git a/repos/dde_linux/src/include/lx_kit/init.h b/repos/dde_linux/src/include/lx_kit/init.h new file mode 100644 index 0000000000..011d140f61 --- /dev/null +++ b/repos/dde_linux/src/include/lx_kit/init.h @@ -0,0 +1,51 @@ +/* + * \brief Lx_kit backend for Linux kernel initialization + * \author Stefan Kalkowski + * \date 2021-03-10 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_KIT__INIT_H_ +#define _LX_KIT__INIT_H_ + +#include +#include + +namespace Lx_kit { + using namespace Genode; + + void initialize(Env & env); + class Initcalls; +} + + +class Lx_kit::Initcalls +{ + private: + + struct E : List::Element + { + unsigned int prio; + int (* call) (void); + + E(unsigned int p, int (*fn)(void)) : prio(p), call(fn) {} + }; + + Heap & _heap; + List _call_list {}; + + public: + + void add(int (*initcall)(void), unsigned int prio); + void execute_in_order(); + + Initcalls(Heap & heap) : _heap(heap) {} +}; + +#endif /* _LX_KIT__INIT_H_ */ diff --git a/repos/dde_linux/src/include/lx_kit/map.h b/repos/dde_linux/src/include/lx_kit/map.h new file mode 100644 index 0000000000..a578f4824d --- /dev/null +++ b/repos/dde_linux/src/include/lx_kit/map.h @@ -0,0 +1,103 @@ +/* + * \brief Lx_kit associative data structure + * \author Norman Feske + * \date 2021-07-02 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_KIT__MAP_H_ +#define _LX_KIT__MAP_H_ + +#include + +namespace Lx_kit { + + using namespace Genode; + + template + struct Map; +} + + +template +class Lx_kit::Map : Noncopyable +{ + private: + + struct Item : Avl_node + { + ITEM const value; + + template + static Item *_lookup(Item *curr, QUERY const &query) + { + for (;;) { + if (!curr) + return nullptr; + + ITEM const &value = curr->value; + + if (query.matches(value)) + return curr; + + curr = curr->Avl_node::child(value.higher(query.key())); + } + } + + /** + * Avl_node interface + */ + bool higher(Item *other) const { return value.higher(other->value.key); } + + template + Item *lookup(QUERY const &query) { return _lookup(this, query); } + + template + Item(ARGS &&... args) : value{args...} { } + }; + + Avl_tree _items { }; + + Allocator &_alloc; + + template + Item *_lookup(QUERY const &query) + { + return _items.first() ? _items.first()->lookup(query) : nullptr; + } + + public: + + Map(Allocator &alloc) : _alloc(alloc) { } + + template + void insert(ARGS &&... args) + { + _items.insert(new (_alloc) Item(args...)); + } + + template + void remove(QUERY const &query) + { + while (Item *item_ptr = _lookup(query)) { + _items.remove(item_ptr); + destroy(_alloc, item_ptr); + } + } + + template + void apply(QUERY const &query, FN const &fn) + { + Item *item_ptr = _lookup(query); + if (item_ptr) + fn(item_ptr->value); + } +}; + +#endif /* _LX_KIT__MAP_H_ */ diff --git a/repos/dde_linux/src/include/lx_kit/memory.h b/repos/dde_linux/src/include/lx_kit/memory.h new file mode 100644 index 0000000000..737626db3a --- /dev/null +++ b/repos/dde_linux/src/include/lx_kit/memory.h @@ -0,0 +1,77 @@ +/* + * \brief Lx_kit memory allocation backend + * \author Stefan Kalkowski + * \date 2021-03-25 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_KIT__MEMORY_H_ +#define _LX_KIT__MEMORY_H_ + +#include +#include +#include +#include +#include + +namespace Platform { class Connection; }; +namespace Lx_kit { + using namespace Genode; + class Mem_allocator; +} + + +class Lx_kit::Mem_allocator +{ + private: + + class Buffer : Interface + { + private: + + Attached_dataspace _ds; + addr_t const _dma_addr; + + public: + + Buffer(Region_map & rm, + Dataspace_capability cap, + addr_t dma_addr) + : _ds(rm, cap), _dma_addr(dma_addr) {} + + addr_t dma_addr() const { return _dma_addr; } + Attached_dataspace & ds() { return _ds; } + }; + + using Buffer_registry = Registry>; + + Env & _env; + Heap & _heap; + Platform::Connection & _platform; + Cache _cache_attr; + Allocator_avl _mem; + Buffer_registry _buffers {}; + + public: + + Mem_allocator(Env & env, + Heap & heap, + Platform::Connection & platform, + Cache cache_attr); + + Attached_dataspace & alloc_dataspace(size_t size); + + void * alloc(size_t size, size_t align); + addr_t dma_addr(void * addr); + size_t size(const void * ptr); + void free(Attached_dataspace * ds); + bool free(const void * ptr); +}; + +#endif /* _LX_KIT__MEMORY_H_ */ diff --git a/repos/dde_linux/src/include/lx_kit/scheduler.h b/repos/dde_linux/src/include/lx_kit/scheduler.h new file mode 100644 index 0000000000..a80aa580d4 --- /dev/null +++ b/repos/dde_linux/src/include/lx_kit/scheduler.h @@ -0,0 +1,60 @@ +/* + * \brief Scheduler for executing Task objects + * \author Sebastian Sumpf + * \author Josef Soentgen + * \author Norman Feske + * \author Stefan Kalkowski + * \date 2014-10-10 + */ + +/* + * Copyright (C) 2014-2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +namespace Lx_kit { + class Scheduler; + class Task; + + using namespace Genode; +} + + +class Lx_kit::Scheduler +{ + private: + + List _present_list { }; + Task * _current { nullptr }; + + public: + + Task & current(); + + bool active() const; + + void add(Task & task); + void remove(Task & task); + + void schedule(); + void unblock_irq_handler(); + void unblock_time_handler(); + + Task & task(void * t); + + template + void for_each_task(FN const & fn); +}; + + +template +void Lx_kit::Scheduler::for_each_task(FN const & fn) +{ + for (Task * t = _present_list.first(); t; t = t->next()) + fn(*t); +} diff --git a/repos/dde_linux/src/include/lx_kit/task.h b/repos/dde_linux/src/include/lx_kit/task.h new file mode 100644 index 0000000000..263dac2993 --- /dev/null +++ b/repos/dde_linux/src/include/lx_kit/task.h @@ -0,0 +1,104 @@ +/* + * \brief Task represents a cooperatively scheduled thread of control + * \author Sebastian Sumpf + * \author Josef Soentgen + * \author Norman Feske + * \author Stefan Kalkowski + * \date 2014-10-10 + */ + +/* + * Copyright (C) 2014-2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_KIT__TASK_H_ +#define _LX_KIT__TASK_H_ + +#include +#include +#include + +namespace Lx_kit { + class Scheduler; + class Task; + + using namespace Genode; +} + +class Lx_kit::Task : public Genode::List::Element +{ + public: + + using Name = String<64>; + + enum State { INIT, RUNNING, BLOCKED }; + enum Type { NORMAL, IRQ_HANDLER, TIME_HANDLER }; + + private: + + Task(Task const &); + Task &operator = (Task const &); + + State _state { INIT }; + int _priority { 120 }; /* initial value of swapper task */ + Type _type; + Scheduler & _scheduler; + void * const _lx_task; /* pointer of Linux task struct */ + int const _pid; /* Linux process identifier */ + Name _name; /* name of task */ + void * _stack; /* stack pointer */ + jmp_buf _env; /* execution state */ + jmp_buf _saved_env; /* saved state of thread calling run */ + int (* _func) (void *); /* function to call */ + void * _arg; /* argument for function */ + + public: + + Task(int (* func) (void*), + void * arg, + void * task, + int pid, + char const * name, + Scheduler & scheduler, + Type type); + + ~Task(); + + State state() const; + Type type() const; + int priority() const; + Name name() const; + void * lx_task() const; + int pid() const; + + void block(); + void unblock(); + + void priority(int prio); + void name(const char * name); + + bool runnable() const; + + /** + * Run task until next preemption point + */ + void run(); + + /** + * Request scheduling (of other tasks) + * + * Note, this task may not be blocked when calling schedule() depending + * on the use case. + */ + void schedule(); + + /** + * Shortcut to enter blocking state and request scheduling + */ + void block_and_schedule(); +}; + +#endif /* _LX_KIT__TASK_H_ */ diff --git a/repos/dde_linux/src/include/lx_kit/timeout.h b/repos/dde_linux/src/include/lx_kit/timeout.h new file mode 100644 index 0000000000..0b4f132b0e --- /dev/null +++ b/repos/dde_linux/src/include/lx_kit/timeout.h @@ -0,0 +1,47 @@ +/* + * \brief Lx_kit timeout backend + * \author Stefan Kalkowski + * \date 2021-05-05 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_KIT__TIMEOUT_H_ +#define _LX_KIT__TIMEOUT_H_ + +#include + +namespace Lx_kit { + class Scheduler; + class Timeout; + + using namespace Genode; +} + + +class Lx_kit::Timeout +{ + private: + + void _handle(Duration); + + using One_shot = Timer::One_shot_timeout; + + Scheduler & _scheduler; + One_shot _timeout; + + public: + + void start(unsigned long us); + void stop(); + + Timeout(Timer::Connection & timer, + Scheduler & scheduler); +}; + +#endif /* _LX_KIT__TIMEOUT_H_ */ diff --git a/repos/dde_linux/src/include/lx_user/init.h b/repos/dde_linux/src/include/lx_user/init.h new file mode 100644 index 0000000000..eac7cee351 --- /dev/null +++ b/repos/dde_linux/src/include/lx_user/init.h @@ -0,0 +1,27 @@ +/* + * \brief Initialization of activity after Linux kernel initialization finished + * \author Stefan Kalkowski + * \date 2021-06-29 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_USER__INIT_H_ +#define _LX_USER__INIT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void lx_user_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_USER__INIT_H_ */ diff --git a/repos/dde_linux/src/include/lx_user/io.h b/repos/dde_linux/src/include/lx_user/io.h new file mode 100644 index 0000000000..8944f62f67 --- /dev/null +++ b/repos/dde_linux/src/include/lx_user/io.h @@ -0,0 +1,27 @@ +/* + * \brief I/O activity on top of Linux kernel functionality + * \author Stefan Kalkowski + * \date 2021-06-29 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_USER__IO_H_ +#define _LX_USER__IO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void lx_user_handle_io(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_USER__IO_H_ */ diff --git a/repos/dde_linux/src/include/spec/arm_64/lx_kit/arch_execute.h b/repos/dde_linux/src/include/spec/arm_64/lx_kit/arch_execute.h new file mode 100644 index 0000000000..9cd1c7fa00 --- /dev/null +++ b/repos/dde_linux/src/include/spec/arm_64/lx_kit/arch_execute.h @@ -0,0 +1,43 @@ +/** + * \brief Platform specific code + * \author Christian Prochaska + * \date 2019-07-01 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _ARCH_EXECUTE_H_ +#define _ARCH_EXECUTE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define _JBLEN 31 +typedef struct _jmp_buf { long _jb[_JBLEN + 1]; } jmp_buf[1]; + +void _longjmp(jmp_buf, int); +int _setjmp(jmp_buf); + +#ifdef __cplusplus +} +#endif + + +static inline +void arch_execute(void *sp, void *func, void *arg) +{ + asm volatile ("mov x0, %2;" /* set arg */ + "mov sp, %0;" /* set stack */ + "mov x29, xzr;" /* clear frame pointer */ + "br %1;" /* call func */ + "" + : : "r"(sp), "r"(func), "r"(arg) : "r0"); +} + +#endif /* _ARCH_EXECUTE_H_ */ diff --git a/repos/dde_linux/src/lib/lx_emul/alloc.cc b/repos/dde_linux/src/lib/lx_emul/alloc.cc new file mode 100644 index 0000000000..2c9a2c449b --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/alloc.cc @@ -0,0 +1,93 @@ +/* + * \brief Lx_emul backend for memory allocation + * \author Stefan Kalkowski + * \date 2021-03-22 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include +#include +#include + +extern "C" void * lx_emul_mem_alloc_aligned(unsigned long size, unsigned long align) +{ + void * const ptr = Lx_kit::env().memory.alloc(size, align); + lx_emul_forget_pages(ptr, size); + return ptr; +}; + + +extern "C" void * lx_emul_mem_alloc(unsigned long size) +{ + /* always align memory objects to 32 bytes, like malloc, heap etc. */ + void * const ptr = Lx_kit::env().memory.alloc(size, 32); + lx_emul_forget_pages(ptr, size); + return ptr; +}; + + +extern "C" void * lx_emul_mem_alloc_uncached(unsigned long size) +{ + /* always align memory objects to 32 bytes, like malloc, heap etc. */ + void * const ptr = Lx_kit::env().uncached_memory.alloc(size, 32); + lx_emul_forget_pages(ptr, size); + return ptr; +}; + + +extern "C" unsigned long lx_emul_mem_dma_addr(void * addr) +{ + unsigned long ret = Lx_kit::env().memory.dma_addr(addr); + if (ret) + return ret; + if (!(ret = Lx_kit::env().uncached_memory.dma_addr(addr))) + Genode::error(__func__, " called with invalid addr ", addr); + return ret; +} + + +extern "C" void lx_emul_mem_free(const void * ptr) +{ + if (!ptr) + return; + if (Lx_kit::env().memory.free(ptr)) + return; + if (Lx_kit::env().uncached_memory.free(ptr)) + return; + Genode::error(__func__, " called with invalid ptr ", ptr); +}; + + +extern "C" unsigned long lx_emul_mem_size(const void * ptr) +{ + unsigned long ret = 0; + if (!ptr) + return ret; + if ((ret = Lx_kit::env().memory.size(ptr))) + return ret; + if (!(ret = Lx_kit::env().uncached_memory.size(ptr))) + Genode::error(__func__, " called with invalid ptr ", ptr); + return ret; +}; + + +extern "C" void lx_emul_mem_cache_clean_invalidate(const void * addr, + unsigned long size) +{ + Genode::cache_clean_invalidate_data((Genode::addr_t)addr, size); +} + + +extern "C" void lx_emul_mem_cache_invalidate(const void * addr, + unsigned long size) +{ + Genode::cache_invalidate_data((Genode::addr_t)addr, size); +} diff --git a/repos/dde_linux/src/lib/lx_emul/clock.cc b/repos/dde_linux/src/lib/lx_emul/clock.cc new file mode 100644 index 0000000000..78c409e24b --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/clock.cc @@ -0,0 +1,45 @@ +/* + * \brief Lx_emul backend for peripheral clocks + * \author Stefan Kalkowski + * \date 2021-03-22 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include + +extern "C" int of_device_is_compatible(const struct device_node * node, + const char * compat); + +struct clk * lx_emul_clock_get(const struct device_node * node, + const char * name) +{ + using namespace Lx_kit; + + struct clk * ret = nullptr; + + env().devices.for_each([&] (Device & d) { + if (!of_device_is_compatible(node, d.compatible())) + return; + ret = name ? d.clock(name) : d.clock(0U); + if (!ret) warning("No clock ", name, " found for device ", d.name()); + }); + + return ret; +} + + +unsigned long lx_emul_clock_get_rate(struct clk * clk) +{ + if (!clk) + return 0; + + return clk->rate; +} diff --git a/repos/dde_linux/src/lib/lx_emul/clocksource.c b/repos/dde_linux/src/lib/lx_emul/clocksource.c new file mode 100644 index 0000000000..0ac39a5df4 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/clocksource.c @@ -0,0 +1,105 @@ +/* + * \brief Linux DDE timer + * \author Stefan Kalkowski + * \date 2021-03-22 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include +#include +#include +#include + +static u32 dde_timer_rate = 1000000; /* we use microseconds as rate */ + + +static int dde_set_next_event(unsigned long evt, + struct clock_event_device *clk) +{ + lx_emul_time_event(evt); + return 0; +} + + +static int dde_set_state_shutdown(struct clock_event_device *clk) +{ + lx_emul_time_stop(); + return 0; +} + + +static u64 dde_timer_read_counter(void) +{ + return lx_emul_time_counter(); +} + + +static u64 dde_clocksource_read_counter(struct clocksource * cs) +{ + return lx_emul_time_counter(); +} + + +static u64 dde_cyclecounter_read_counter(const struct cyclecounter * cc) +{ + return lx_emul_time_counter(); +} + + +static struct clock_event_device * dde_clock_event_device; + + +void lx_emul_time_init() +{ + static struct clocksource clocksource = { + .name = "dde_counter", + .rating = 400, + .read = dde_clocksource_read_counter, + .mask = CLOCKSOURCE_MASK(56), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + }; + + static struct cyclecounter cyclecounter = { + .read = dde_cyclecounter_read_counter, + .mask = CLOCKSOURCE_MASK(56), + }; + + static struct timecounter timecounter; + + static struct clock_event_device clock_event_device = { + .name = "dde_timer", + .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_SOURCE_VALID_FOR_HRES, + .rating = 400, + .set_state_shutdown = dde_set_state_shutdown, + .set_state_oneshot_stopped = dde_set_state_shutdown, + .set_next_event = dde_set_next_event, + }; + + u64 start_count = dde_timer_read_counter(); + clock_event_device.cpumask = cpumask_of(smp_processor_id()), + dde_clock_event_device = &clock_event_device; + + clocksource_register_hz(&clocksource, dde_timer_rate); + cyclecounter.mult = clocksource.mult; + cyclecounter.shift = clocksource.shift; + timecounter_init(&timecounter, &cyclecounter, start_count); + clockevents_config_and_register(&clock_event_device, dde_timer_rate, 0xf, 0x7fffffff); + sched_clock_register(dde_timer_read_counter, 64, dde_timer_rate); +} + + +void lx_emul_time_handle(void) +{ + dde_clock_event_device->event_handler(dde_clock_event_device); +} + + +struct of_device_id __clk_of_table[] = { }; diff --git a/repos/dde_linux/src/lib/lx_emul/debug.cc b/repos/dde_linux/src/lib/lx_emul/debug.cc new file mode 100644 index 0000000000..7424ac76a5 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/debug.cc @@ -0,0 +1,32 @@ +/* + * \brief Lx_emul backend for Linux kernel' debug functions + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include + +#include + +extern "C" void lx_emul_trace_and_stop(const char * func) +{ + using namespace Genode; + + error("Function ", func, " not implemented yet!"); + log("Backtrace follows:"); + backtrace(); + log("Will sleep forever..."); + sleep_forever(); +} + + +extern "C" void lx_emul_trace(const char *) {} diff --git a/repos/dde_linux/src/lib/lx_emul/init.cc b/repos/dde_linux/src/lib/lx_emul/init.cc new file mode 100644 index 0000000000..1bf6de1f6c --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/init.cc @@ -0,0 +1,55 @@ +/* + * \brief Lx_emul backend for Linux kernel initialization + * \author Stefan Kalkowski + * \date 2021-03-10 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include +#include +#include +#include + +#include + +extern "C" void lx_emul_initcalls() +{ + Lx_kit::env().initcalls.execute_in_order(); +} + + +extern "C" void lx_emul_register_initcall(int (*initcall)(void), + const char * name) +{ + for (unsigned i = 0; i < (sizeof(lx_emul_initcall_order) / sizeof(char*)); + i++) { + if (Genode::strcmp(name, lx_emul_initcall_order[i]) == 0) { + Lx_kit::env().initcalls.add(initcall, i); + return; + } + } + Genode::error("Initcall ", name, " unknown in initcall database!"); +} + + +void lx_emul_start_kernel(void * dtb) +{ + using namespace Lx_kit; + + new (env().heap) Task(lx_emul_init_task_function, dtb, + lx_emul_init_task_struct, SWAPPER_PID, "swapper", + env().scheduler, Task::TIME_HANDLER); + new (env().heap) Task(lx_emul_irq_task_function, nullptr, + lx_emul_irq_task_struct, KIRQ_PID, "kirqd", + env().scheduler, Task::IRQ_HANDLER); + + env().scheduler.schedule(); +} diff --git a/repos/dde_linux/src/lib/lx_emul/io_mem.cc b/repos/dde_linux/src/lib/lx_emul/io_mem.cc new file mode 100644 index 0000000000..3369d7ff3e --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/io_mem.cc @@ -0,0 +1,33 @@ +/* + * \brief Lx_emul backend for I/O memory + * \author Stefan Kalkowski + * \date 2021-03-10 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +void * lx_emul_io_mem_map(unsigned long phys_addr, + unsigned long size) +{ + using namespace Lx_kit; + using namespace Genode; + + void * ret = nullptr; + env().devices.for_each([&] (Device & d) { + if (d.io_mem(phys_addr, size)) + ret = d.io_mem_local_addr(phys_addr, size); + }); + + if (!ret) + error("memory-mapped I/O resource ", Hex(phys_addr), + " (size=", Hex(size), ") unavailable"); + return ret; +} diff --git a/repos/dde_linux/src/lib/lx_emul/irq.cc b/repos/dde_linux/src/lib/lx_emul/irq.cc new file mode 100644 index 0000000000..960621c735 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/irq.cc @@ -0,0 +1,45 @@ +/* + * \brief Lx_emul backend for interrupts + * \author Stefan Kalkowski + * \date 2021-04-22 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +extern "C" void lx_emul_irq_unmask(unsigned int irq) +{ + bool found = false; + Lx_kit::env().devices.for_each([&] (Lx_kit::Device & d) { + if (d.irq_unmask(irq)) found = true; }); + + if (!found) + Genode::error("irq ", irq, " unavailable"); +} + + +extern "C" void lx_emul_irq_mask(unsigned int irq) +{ + Lx_kit::env().devices.for_each([&] (Lx_kit::Device & d) { + d.irq_mask(irq); }); +} + + +extern "C" void lx_emul_irq_eoi(unsigned int irq) +{ + Lx_kit::env().devices.for_each([&] (Lx_kit::Device & d) { + d.irq_ack(irq); }); +} + + +extern "C" unsigned int lx_emul_irq_last() +{ + return Lx_kit::env().last_irq; +} diff --git a/repos/dde_linux/src/lib/lx_emul/irqchip.c b/repos/dde_linux/src/lib/lx_emul/irqchip.c new file mode 100644 index 0000000000..f7f6773596 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/irqchip.c @@ -0,0 +1,200 @@ +/* + * \brief Linux DDE interrupt controller + * \author Stefan Kalkowski + * \date 2021-03-10 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include +#include +#include +#include +#include <../kernel/irq/internals.h> + +static int dde_irq_set_wake(struct irq_data *d, unsigned int on) +{ + lx_emul_trace_and_stop(__func__); + return 0; +} + + +static void dde_irq_unmask(struct irq_data *d) +{ + lx_emul_irq_unmask(d->hwirq); +} + + +static void dde_irq_mask(struct irq_data *d) +{ + lx_emul_irq_mask(d->hwirq); +} + + +static void dde_irq_eoi(struct irq_data *d) +{ + lx_emul_irq_eoi(d->hwirq); +} + + +static int dde_irq_set_type(struct irq_data *d, unsigned int type) +{ + if (type != IRQ_TYPE_LEVEL_HIGH) + lx_emul_trace_and_stop(__func__); + return 0; +} + + +static struct irq_chip dde_irqchip_data_chip = { + .name = "dde-irqs", + .irq_eoi = dde_irq_eoi, + .irq_mask = dde_irq_mask, + .irq_unmask = dde_irq_unmask, + .irq_set_wake = dde_irq_set_wake, + .irq_set_type = dde_irq_set_type, +}; + + +static int dde_domain_translate(struct irq_domain * d, + struct irq_fwspec * fwspec, + unsigned long * hwirq, + unsigned int * type) +{ + if (is_of_node(fwspec->fwnode)) { + if (fwspec->param_count != 3 || fwspec->param[0] != 0) + return -EINVAL; + + *hwirq = fwspec->param[1] + 32; + *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; + return 0; + } + + return -EINVAL; +} + + +static int dde_domain_alloc(struct irq_domain * domain, + unsigned int irq, + unsigned int nr_irqs, + void * data) +{ + struct irq_fwspec *fwspec = data; + irq_hw_number_t hwirq; + unsigned int type; + int err; + int i; + + err = dde_domain_translate(domain, fwspec, &hwirq, &type); + if (err) + return err; + + for (i = 0; i < nr_irqs; i++) { + irq_domain_set_info(domain, irq+i, hwirq+i, &dde_irqchip_data_chip, + domain->host_data, handle_fasteoi_irq, NULL, NULL); + irq_set_probe(irq); + irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq))); + } + + return 0; +} + + +static const struct irq_domain_ops dde_irqchip_data_domain_ops = { + .translate = dde_domain_translate, + .alloc = dde_domain_alloc, + .free = irq_domain_free_irqs_common, +}; + + +static const struct of_device_id dde_of_match[] = { + { .compatible = "arm,gic-v3", .data = (const void *) 4 }, + { .compatible = "arm,gic-400", .data = (const void *) 4 }, + { /* END */ } +}; + +static struct irq_domain *dde_irq_domain; + +static int __init dde_irqchip_init(struct device_node *node, + struct device_node *parent) +{ + dde_irq_domain = irq_domain_create_tree(&node->fwnode, + &dde_irqchip_data_domain_ops, NULL); + if (!dde_irq_domain) + return -ENOMEM; + + irq_set_default_host(dde_irq_domain); + return 0; +} + + +struct of_device_id __irqchip_of_table[] = { + { + .compatible = "arm,gic-v3", + .data = dde_irqchip_init + }, + { + .compatible = "arm,gic-400", + .data = dde_irqchip_init + } +}; + + +int lx_emul_irq_task_function(void * data) +{ + int irq; + + for (;;) { + lx_emul_task_schedule(true); + + if (!dde_irq_domain) + continue; + + irq = irq_find_mapping(dde_irq_domain, lx_emul_irq_last()); + + if (!irq) { + ack_bad_irq(irq); + WARN_ONCE(true, "Unexpected interrupt %d received!\n", lx_emul_irq_last()); + } else { + generic_handle_irq(irq); + } + } + + return 0; +} + + +struct task_struct irq_task = { + .state = 0, + .usage = REFCOUNT_INIT(2), + .flags = PF_KTHREAD, + .prio = MAX_PRIO - 20, + .static_prio = MAX_PRIO - 20, + .normal_prio = MAX_PRIO - 20, + .policy = SCHED_NORMAL, + .cpus_ptr = &irq_task.cpus_mask, + .cpus_mask = CPU_MASK_ALL, + .nr_cpus_allowed = 1, + .mm = NULL, + .active_mm = NULL, + .tasks = LIST_HEAD_INIT(irq_task.tasks), + .real_parent = &irq_task, + .parent = &irq_task, + .children = LIST_HEAD_INIT(irq_task.children), + .sibling = LIST_HEAD_INIT(irq_task.sibling), + .group_leader = &irq_task, + .comm = "kirqd", + .thread = INIT_THREAD, + .pending = { + .list = LIST_HEAD_INIT(irq_task.pending.list), + .signal = {{0}} + }, + .blocked = {{0}}, +}; +void * lx_emul_irq_task_struct = &irq_task; diff --git a/repos/dde_linux/src/lib/lx_emul/log.cc b/repos/dde_linux/src/lib/lx_emul/log.cc new file mode 100644 index 0000000000..828562ca4b --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/log.cc @@ -0,0 +1,18 @@ +/* + * \brief Linux Kernel log messages + * \author Stefan Kalkowski + * \date 2021-03-22 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +extern "C" void lx_emul_vprintf(char const *fmt, va_list va) { + Lx_kit::env().console.vprintf(fmt, va); } diff --git a/repos/dde_linux/src/lib/lx_emul/page_virt.cc b/repos/dde_linux/src/lib/lx_emul/page_virt.cc new file mode 100644 index 0000000000..222aa94df8 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/page_virt.cc @@ -0,0 +1,91 @@ +/* + * \brief Lx_emul backend for page-struct management + * \author Norman Feske + * \date 2021-07-01 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include +#include +#include +#include + +namespace Lx_emul { class Page_info; } + +using addr_t = Genode::addr_t; +using size_t = Genode::size_t; + + +struct Lx_emul::Page_info +{ + struct Key { addr_t virt; } key; + + struct page * page_ptr; + + bool higher(Key const other_key) const + { + return key.virt > other_key.virt; + } + + struct Query_virt_range + { + addr_t virt; + size_t size; + + bool matches(Page_info const &page_info) const + { + size_t const page_size = 4096; + + Lx_kit::Byte_range page_range { page_info.key.virt, page_size }; + Lx_kit::Byte_range virt_range { virt, size }; + + return page_range.intersects(virt_range); + } + + Key key() const { return Key { virt }; } + }; + + struct Query_virt_addr : Query_virt_range + { + Query_virt_addr(void const *virt) : Query_virt_range{(addr_t)virt, 1} { } + }; +}; + + +static Lx_kit::Map &page_registry() +{ + static Lx_kit::Map map { Lx_kit::env().heap }; + return map; +} + + +extern "C" void lx_emul_associate_page_with_virt_addr(struct page *page, void const *virt) +{ + page_registry().insert(Lx_emul::Page_info::Key { (addr_t)virt }, page); +} + + +void lx_emul_disassociate_page_from_virt_addr(void const *virt) +{ + page_registry().remove(Lx_emul::Page_info::Query_virt_addr(virt)); +} + + +struct page *lx_emul_associated_page(void const *virt, unsigned long size) +{ + Lx_emul::Page_info::Query_virt_range query { .virt = (addr_t)virt, .size = size }; + + struct page *page_ptr = nullptr; + page_registry().apply(query, [&] (Lx_emul::Page_info const &page_info) { + page_ptr = page_info.page_ptr; }); + + return page_ptr; +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/arch/arm64/kernel/smp.c b/repos/dde_linux/src/lib/lx_emul/shadow/arch/arm64/kernel/smp.c new file mode 100644 index 0000000000..f746036b63 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/arch/arm64/kernel/smp.c @@ -0,0 +1,16 @@ +/* + * \brief Replaces arch/arm64/kernel/smp.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include + +int cpu_number = 0; diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/arch/arm64/mm/ioremap.c b/repos/dde_linux/src/lib/lx_emul/shadow/arch/arm64/mm/ioremap.c new file mode 100644 index 0000000000..7d4f70248b --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/arch/arm64/mm/ioremap.c @@ -0,0 +1,25 @@ +/* + * \brief Replaces arch/arm64/mm/ioremap.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +void __iomem * __ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot) +{ + return lx_emul_io_mem_map(phys_addr, size); +} + + +void iounmap(volatile void __iomem * io_addr) { } + + diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/drivers/base/power/common.c b/repos/dde_linux/src/lib/lx_emul/shadow/drivers/base/power/common.c new file mode 100644 index 0000000000..6f762305ed --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/drivers/base/power/common.c @@ -0,0 +1,24 @@ +/* + * \brief Replaces drivers/base/power/common.c + * \author Stefan Kalkowski + * \date 2021-03-16 + * + * We do not support power-management by now, so leave it empty. + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include + +int dev_pm_domain_attach(struct device * dev, bool power_on) +{ + return 0; +} + + +void dev_pm_domain_detach(struct device * dev, bool power_off) { } diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/drivers/base/power/main.c b/repos/dde_linux/src/lib/lx_emul/shadow/drivers/base/power/main.c new file mode 100644 index 0000000000..3e5937392a --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/drivers/base/power/main.c @@ -0,0 +1,37 @@ +/* + * \brief Replaces drivers/base/power/main.c + * \author Stefan Kalkowski + * \date 2021-03-16 + * + * We do not support power-management by now, so leave it empty. + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include <../drivers/base/power/power.h> + +void device_pm_add(struct device * dev) { } + + +void device_pm_move_last(struct device * dev) { } + + +void device_pm_remove(struct device * dev) { } + + +void device_pm_sleep_init(struct device * dev) { } + + +void device_pm_check_callbacks(struct device * dev) { } + + +void device_pm_lock(void) { } + + +void device_pm_unlock(void) { } diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/drivers/base/power/runtime.c b/repos/dde_linux/src/lib/lx_emul/shadow/drivers/base/power/runtime.c new file mode 100644 index 0000000000..cc315da22b --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/drivers/base/power/runtime.c @@ -0,0 +1,67 @@ +/* + * \brief Replaces drivers/base/power/runtime.c + * \author Stefan Kalkowski + * \date 2021-03-16 + * + * We do not support power-management by now, so leave it empty. + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include <../drivers/base/power/power.h> + +void pm_runtime_init(struct device * dev) { } + + +int __pm_runtime_resume(struct device * dev,int rpmflags) +{ + return 0; +} + + +int __pm_runtime_idle(struct device * dev,int rpmflags) +{ + return 0; +} + + +void pm_runtime_get_suppliers(struct device * dev) { } + + +int pm_runtime_barrier(struct device * dev) +{ + return 0; +} + + +void pm_runtime_reinit(struct device * dev) { } + + +void pm_runtime_put_suppliers(struct device * dev) { } + + +int pm_generic_runtime_resume(struct device * dev) +{ + return 0; +} + + +int pm_generic_runtime_suspend(struct device * dev) +{ + return 0; +} + + +void pm_runtime_clean_up_links(struct device * dev) { } + + +void pm_runtime_drop_link(struct device_link * link) { } + + +void pm_runtime_new_link(struct device * dev) { } diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/drivers/clk/clk.c b/repos/dde_linux/src/lib/lx_emul/shadow/drivers/clk/clk.c new file mode 100644 index 0000000000..f7b9cd2967 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/drivers/clk/clk.c @@ -0,0 +1,47 @@ +/* + * \brief Replaces drivers/clk/clk.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +unsigned long clk_get_rate(struct clk * clk) +{ + return lx_emul_clock_get_rate(clk); +} + + +int clk_set_rate(struct clk * clk,unsigned long rate) +{ + if (lx_emul_clock_get_rate(clk) != rate) + printk("Error: cannot change clock rate dynamically to %ld\n", rate); + + return 0; +} + + +int clk_prepare(struct clk * clk) +{ + return 0; +} + + +int clk_enable(struct clk * clk) +{ + return 0; +} + + +void clk_disable(struct clk * clk) { } + + +void clk_unprepare(struct clk * clk) { } diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/drivers/clk/clkdev.c b/repos/dde_linux/src/lib/lx_emul/shadow/drivers/clk/clkdev.c new file mode 100644 index 0000000000..e158ece76f --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/drivers/clk/clkdev.c @@ -0,0 +1,27 @@ +/* + * \brief Replaces drivers/clk/clkdev.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include + +struct clk *clk_get(struct device *dev, const char *con_id) +{ + if (!dev || !dev->of_node) + return NULL; + + return lx_emul_clock_get(dev->of_node, con_id); +} + + +void clk_put(struct clk *clk) {} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/fs/exec.c b/repos/dde_linux/src/lib/lx_emul/shadow/fs/exec.c new file mode 100644 index 0000000000..a5cdc689cf --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/fs/exec.c @@ -0,0 +1,21 @@ +/* + * \brief Replaces fs/exec.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +void __set_task_comm(struct task_struct * tsk,const char * buf,bool exec) +{ + strlcpy(tsk->comm, buf, sizeof(tsk->comm)); + lx_emul_task_name(tsk, tsk->comm); +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/cpu.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/cpu.c new file mode 100644 index 0000000000..ebf3d4ad72 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/cpu.c @@ -0,0 +1,45 @@ +/* + * \brief Replaces kernel/cpu.c + * \author Stefan Kalkowski + * \date 2021-03-16 + * + * We hardcode support for a single cpu only. + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +struct cpumask __cpu_online_mask = { .bits[0] = 1 }; +struct cpumask __cpu_possible_mask = { .bits[0] = 1 }; +struct cpumask __cpu_present_mask = { .bits[0] = 1 }; + + +#ifdef CONFIG_HOTPLUG_CPU +void cpus_read_lock(void) { } +void cpus_read_unlock(void) { } +void lockdep_assert_cpus_held(void) { } +#endif /* CONFIG_HOTPLUG_CPU */ + +#define MASK_DECLARE_1(x) [x+1][0] = (1UL << (x)) +#define MASK_DECLARE_2(x) MASK_DECLARE_1(x), MASK_DECLARE_1(x+1) +#define MASK_DECLARE_4(x) MASK_DECLARE_2(x), MASK_DECLARE_2(x+2) +#define MASK_DECLARE_8(x) MASK_DECLARE_4(x), MASK_DECLARE_4(x+4) + +const unsigned long cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)] = { + MASK_DECLARE_8(0), MASK_DECLARE_8(8), + MASK_DECLARE_8(16), MASK_DECLARE_8(24), +#if BITS_PER_LONG > 32 + MASK_DECLARE_8(32), MASK_DECLARE_8(40), + MASK_DECLARE_8(48), MASK_DECLARE_8(56), +#endif +}; + +const DECLARE_BITMAP(cpu_all_bits, NR_CPUS) = CPU_BITS_ALL; +EXPORT_SYMBOL(cpu_all_bits); diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/dma/mapping.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/dma/mapping.c new file mode 100644 index 0000000000..90df148508 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/dma/mapping.c @@ -0,0 +1,107 @@ +/* + * \brief Replaces kernel/dma/mapping.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +#include + +void * dma_alloc_attrs(struct device * dev, + size_t size, + dma_addr_t * dma_handle, + gfp_t flag, + unsigned long attrs) +{ + void * addr; + + if (dev && dev->dma_mem) { + printk("We do not support device DMA memory yet!\n"); + lx_emul_trace_and_stop(__func__); + } + + addr = lx_emul_mem_alloc_uncached(size); + *dma_handle = lx_emul_mem_dma_addr(addr); + return addr; +} + + +void dma_free_attrs(struct device * dev, + size_t size, + void * cpu_addr, + dma_addr_t dma_handle, + unsigned long attrs) +{ + lx_emul_mem_free(cpu_addr); +} + + +int dma_set_mask(struct device *dev, u64 mask) +{ + mask = (dma_addr_t)mask; + + if (!dev->dma_mask || !dma_supported(dev, mask)) + return -EIO; + + *dev->dma_mask = mask; + return 0; +} + + +int dma_set_coherent_mask(struct device *dev, u64 mask) +{ + mask = (dma_addr_t)mask; + + if (!dma_supported(dev, mask)) + return -EIO; + + dev->coherent_dma_mask = mask; + return 0; +} + + +int dma_map_sg_attrs(struct device * dev, + struct scatterlist * sgl, + int nents, + enum dma_data_direction dir, + unsigned long attrs) +{ + int i; + struct scatterlist *sg; + + for_each_sg(sgl, sg, nents, i) { + sg->dma_address = lx_emul_mem_dma_addr(page_address(sg_page(sg))) + sg->offset; + if (!sg->dma_address) + return 0; + sg_dma_len(sg) = sg->length; + lx_emul_mem_cache_clean_invalidate(page_address(sg_page(sg)) + + sg->offset, sg->length); + } + + return nents; +} + + +void dma_unmap_sg_attrs(struct device * dev, + struct scatterlist * sgl, + int nents, + enum dma_data_direction dir, + unsigned long attrs) +{ + int i; + struct scatterlist *sg; + + for_each_sg(sgl, sg, nents, i) { + lx_emul_mem_cache_invalidate(page_address(sg_page(sg)) + sg->offset, + sg->length); + } +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/exit.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/exit.c new file mode 100644 index 0000000000..b2ca7576ba --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/exit.c @@ -0,0 +1,43 @@ +/* + * \brief Replaces kernel/exit.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include + +#include + + +int rcuwait_wake_up(struct rcuwait * w) +{ + if (w && w->task) + return wake_up_process(w->task); + + return 0; +} + + + +void __noreturn do_exit(long code) +{ + struct task_struct *tsk = current; + tsk->exit_code = code; + set_special_state(TASK_DEAD); + + if (tsk->vfork_done) + complete(tsk->vfork_done); + + current->flags |= PF_NOFREEZE; + schedule(); + BUG(); +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/fork.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/fork.c new file mode 100644 index 0000000000..f6ee83e3c2 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/fork.c @@ -0,0 +1,59 @@ +/* + * \brief Replaces kernel/fork.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include +#include +#include +#include +#include + + +pid_t kernel_thread(int (* fn)(void *),void * arg,unsigned long flags) +{ + static int pid_counter = FIRST_PID; + + struct task_struct * task = kmalloc(sizeof(struct task_struct), GFP_KERNEL); + *task = (struct task_struct){ + .state = 0, + .usage = REFCOUNT_INIT(2), + .flags = PF_KTHREAD, + .prio = MAX_PRIO - 20, + .static_prio = MAX_PRIO - 20, + .normal_prio = MAX_PRIO - 20, + .policy = SCHED_NORMAL, + .cpus_ptr = &task->cpus_mask, + .cpus_mask = CPU_MASK_ALL, + .nr_cpus_allowed = 1, + .mm = NULL, + .active_mm = NULL, + .tasks = LIST_HEAD_INIT(task->tasks), + .real_parent = lx_emul_task_get_current(), + .parent = lx_emul_task_get_current(), + .children = LIST_HEAD_INIT(task->children), + .sibling = LIST_HEAD_INIT(task->sibling), + .group_leader = task, + .thread = INIT_THREAD, + .blocked = {{0}}, + .pid = pid_counter++, + .pending = { + .list = LIST_HEAD_INIT(task->pending.list), + .signal = {{0}} + }}; + + task->thread_info.preempt_count = 0; + + lx_emul_task_create(task, "kthread", task->pid, fn, arg); + return task->pid; +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/irq/spurious.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/irq/spurious.c new file mode 100644 index 0000000000..7d48b86715 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/irq/spurious.c @@ -0,0 +1,17 @@ +/* + * \brief Replaces kernel/irq/spurious.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include + +extern bool noirqdebug; +bool noirqdebug = 1; diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/locking/spinlock.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/locking/spinlock.c new file mode 100644 index 0000000000..a689115d27 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/locking/spinlock.c @@ -0,0 +1,91 @@ +/* + * \brief Replaces kernel/locking/spinlock.c + * \author Stefan Kalkowski + * \date 2021-03-16 + * + * We run single-core, cooperatively scheduled. We should never spin. + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +#include +#include + +void __lockfunc _raw_spin_lock(raw_spinlock_t * lock) +{ + if (atomic_read(&lock->raw_lock.val)) { + printk("Error: spinlock contention!"); + lx_emul_trace_and_stop(__func__); + } + atomic_set(&lock->raw_lock.val, 1); +} + + +unsigned long __lockfunc _raw_spin_lock_irqsave(raw_spinlock_t * lock) +{ + unsigned long flags; + local_irq_save(flags); + _raw_spin_lock(lock); + return flags; +} + + +void __lockfunc _raw_spin_unlock(raw_spinlock_t * lock) +{ + atomic_set(&lock->raw_lock.val, 0); +} + + +void __lockfunc _raw_spin_unlock_irqrestore(raw_spinlock_t * lock, + unsigned long flags) +{ + _raw_spin_unlock(lock); + local_irq_restore(flags); +} + + +void __lockfunc _raw_spin_lock_irq(raw_spinlock_t * lock) +{ + _raw_spin_lock_irqsave(lock); +} + + +void __lockfunc _raw_spin_unlock_irq(raw_spinlock_t * lock) +{ + _raw_spin_unlock_irqrestore(lock, 0); +} + + +int __lockfunc _raw_spin_trylock(raw_spinlock_t * lock) +{ + + if (atomic_read(&lock->raw_lock.val)) + return 0; + + _raw_spin_lock(lock); + return 1; +} + + +void __lockfunc _raw_write_lock(rwlock_t * lock) +{ + if (lock->raw_lock.wlocked) { + printk("Error: rwlock contention!"); + lx_emul_trace_and_stop(__func__); + } + lock->raw_lock.wlocked = 1; +} + + +void __lockfunc _raw_write_unlock(rwlock_t * lock) +{ + lock->raw_lock.wlocked = 0; +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/pid.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/pid.c new file mode 100644 index 0000000000..9fb6efa133 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/pid.c @@ -0,0 +1,35 @@ +/* + * \brief Replaces kernel/pid.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +struct pid init_struct_pid = { + .count = REFCOUNT_INIT(1), + .tasks = { + { .first = NULL }, + { .first = NULL }, + { .first = NULL }, + }, + .level = 0, + .numbers = { { + .nr = 0, + .ns = &init_pid_ns, + }, } +}; + + +struct task_struct *find_task_by_pid_ns(pid_t nr, struct pid_namespace *ns) +{ + return lx_emul_task_get(nr); +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/printk/printk.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/printk/printk.c new file mode 100644 index 0000000000..da46ec4ad3 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/printk/printk.c @@ -0,0 +1,42 @@ +/* + * \brief Replaces kernel/printk/printk.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include + +asmlinkage __visible int printk(const char * fmt,...) +{ + va_list args; + va_start(args, fmt); + lx_emul_vprintf(fmt, args); + va_end(args); + return 0; +} + + +asmlinkage int vprintk(const char * fmt, va_list args) +{ + lx_emul_vprintf(fmt, args); + return 0; +} + + +asmlinkage int vprintk_emit(int facility, int level, + const struct dev_printk_info *dev_info, + const char * fmt, va_list args) +{ + lx_emul_vprintf(fmt, args); + return 0; +} + diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/rcu/srcutree.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/rcu/srcutree.c new file mode 100644 index 0000000000..f1704f63ed --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/rcu/srcutree.c @@ -0,0 +1,43 @@ +/* + * \brief Replaces kernel/rcu/srcutree.c.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +int __srcu_read_lock(struct srcu_struct * ssp) +{ + int idx = READ_ONCE(ssp->srcu_idx) & 0x1; + return idx; +} + + +void __srcu_read_unlock(struct srcu_struct * ssp, int idx) { } + + +int init_srcu_struct(struct srcu_struct * ssp) +{ + mutex_init(&ssp->srcu_cb_mutex); + mutex_init(&ssp->srcu_gp_mutex); + ssp->srcu_idx = 0; + ssp->srcu_gp_seq = 0; + ssp->srcu_barrier_seq = 0; + mutex_init(&ssp->srcu_barrier_mutex); + atomic_set(&ssp->srcu_barrier_cpu_cnt, 0); + /* INIT_DELAYED_WORK(&ssp->work, process_srcu); */ + ssp->sda = alloc_percpu(struct srcu_data); + /* init_srcu_struct_nodes(ssp, false); */ + ssp->srcu_gp_seq_needed_exp = 0; + ssp->srcu_last_gp_end = ktime_get_mono_fast_ns(); + smp_store_release(&ssp->srcu_gp_seq_needed, 0); /* Init done. */ + return ssp->sda ? 0 : -ENOMEM; +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/rcu/tree.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/rcu/tree.c new file mode 100644 index 0000000000..007b7c3e9e --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/rcu/tree.c @@ -0,0 +1,26 @@ +/* + * \brief Replaces kernel/rcu/tree.c.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include + +extern void __rcu_read_lock(void); +void __rcu_read_lock(void) { } + + +extern void __rcu_read_unlock(void); +void __rcu_read_unlock(void) { } + +int rcu_needs_cpu(u64 basemono, u64 *nextevt) +{ + return 0; +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/sched/core.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/sched/core.c new file mode 100644 index 0000000000..9a5098e890 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/sched/core.c @@ -0,0 +1,177 @@ +/* + * \brief Replaces kernel/sched/core.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#define CREATE_TRACE_POINTS +#include +#undef CREATE_TRACE_POINTS + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include <../kernel/sched/sched.h> + +void set_user_nice(struct task_struct * p, long nice) +{ + p->static_prio = NICE_TO_PRIO(nice); + p->prio = p->static_prio; + p->normal_prio = p->static_prio; + lx_emul_task_priority(p, p->static_prio); +} + + +int set_cpus_allowed_ptr(struct task_struct * p, + const struct cpumask * new_mask) +{ + return 0; +} + + +static int +try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) +{ + if (!p) lx_emul_trace_and_stop(__func__); + if (!(p->state & state)) + return 0; + + if (p != lx_emul_task_get_current()) + lx_emul_task_unblock(p); + + p->state = TASK_RUNNING; + return 1; +} + + +int wake_up_process(struct task_struct * p) +{ + return try_to_wake_up(p, TASK_NORMAL, 0); +} + + +int default_wake_function(wait_queue_entry_t *curr, + unsigned mode, + int wake_flags, + void *key) +{ + return try_to_wake_up(curr->private, mode, wake_flags); +} + + +asmlinkage __visible void __sched schedule(void) +{ + if (preempt_count()) { + printk("schedule: unexpected preempt_count=%d\n", preempt_count()); + lx_emul_trace_and_stop("abort"); + } + + lx_emul_task_schedule(current->state != TASK_RUNNING); +} + + +#ifdef CONFIG_DEBUG_PREEMPT + +void preempt_count_add(int val) +{ + current_thread_info()->preempt.count += val; +} + + +void preempt_count_sub(int val) +{ + current_thread_info()->preempt.count -= val; +} + +#endif /* CONFIG_DEBUG_PREEMPT */ + + +asmlinkage __visible void __sched notrace preempt_schedule(void) +{ + if (likely(!preemptible())) + return; + + schedule(); +} + + +asmlinkage __visible void __sched notrace preempt_schedule_notrace(void) +{ + if (likely(!preemptible())) + return; + + schedule(); +} + + +unsigned long nr_iowait_cpu(int cpu) +{ + return 0; +} + + +void scheduler_tick(void) +{ + sched_clock_tick(); +} + + +void __sched schedule_preempt_disabled(void) +{ + lx_emul_task_schedule(current->state != TASK_RUNNING); +} + + +int sched_setscheduler_nocheck(struct task_struct * p, int policy, + const struct sched_param * param) +{ + return 0; +} + + +unsigned long wait_task_inactive(struct task_struct * p,long match_state) +{ + struct rq *rq = task_rq(p); + + if (task_running(rq, p)) + schedule(); + + if (task_running(rq, p)) + return 0; + + return 1; +} + + +int wake_up_state(struct task_struct * p, unsigned int state) +{ + p->state = TASK_RUNNING; + lx_emul_task_unblock(p); + return 0; +} + + +#ifdef CONFIG_SMP +#ifdef CONFIG_NO_HZ_COMMON + +int get_nohz_timer_target(void) +{ + return 0; +} + +#endif +#endif diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/smp.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/smp.c new file mode 100644 index 0000000000..effa1b2553 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/smp.c @@ -0,0 +1,18 @@ +/* + * \brief Replaces kernel/smp.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include + +unsigned int nr_cpu_ids = 1; + +unsigned long irq_err_count = 0; diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/softirq.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/softirq.c new file mode 100644 index 0000000000..e85cea401f --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/softirq.c @@ -0,0 +1,74 @@ +/* + * \brief Replaces kernel/softirq.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +#define CREATE_TRACE_POINTS +#include + +#include + +irq_cpustat_t irq_stat; + +int __init __weak arch_probe_nr_irqs(void) +{ + return 0; +} + +int __init __weak arch_early_irq_init(void) +{ + return 0; +} + +unsigned int __weak arch_dynirq_lower_bound(unsigned int from) +{ + return from; +} + +static struct softirq_action actions[NR_SOFTIRQS]; + +void open_softirq(int nr, void (* action)(struct softirq_action *)) +{ + if (nr >= NR_SOFTIRQS) { + printk("Error: %s nr=%d exceeds softirq limit\n", __func__, nr); + return; + } + + actions[nr].action = action; +} + + +inline void raise_softirq_irqoff(unsigned int nr) +{ + if (nr >= NR_SOFTIRQS || !actions[nr].action) + return; + + actions[nr].action(&actions[nr]); +} + + +void raise_softirq(unsigned int nr) +{ + raise_softirq_irqoff(nr); +} + + +void __local_bh_enable_ip(unsigned long ip,unsigned int cnt) +{ + /* + * Called by write_unlock_bh, which reverts preempt_cnt by the + * value SOFTIRQ_LOCK_OFFSET. + */ + __preempt_count_sub(cnt); +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/kernel/stop_machine.c b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/stop_machine.c new file mode 100644 index 0000000000..97679db05e --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/kernel/stop_machine.c @@ -0,0 +1,19 @@ +/* + * \brief Replaces kernel/stop_machine.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include + +int stop_machine(cpu_stop_fn_t fn,void * data,const struct cpumask * cpus) +{ + return (*fn)(data); +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/lib/devres.c b/repos/dde_linux/src/lib/lx_emul/shadow/lib/devres.c new file mode 100644 index 0000000000..d0d0a2e319 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/lib/devres.c @@ -0,0 +1,28 @@ +/* + * \brief Replaces lib/devres.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +void __iomem *devm_ioremap_resource(struct device *dev, + const struct resource *res) +{ + return lx_emul_io_mem_map(res->start, resource_size(res)); +} + + +void __iomem *devm_ioremap(struct device *dev, resource_size_t offset, + resource_size_t size) +{ + return lx_emul_io_mem_map(offset, size); +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/lib/smp_processor_id.c b/repos/dde_linux/src/lib/lx_emul/shadow/lib/smp_processor_id.c new file mode 100644 index 0000000000..ef4eb1c080 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/lib/smp_processor_id.c @@ -0,0 +1,19 @@ +/* + * \brief Replaces lib/smp_processor_id.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include + +notrace unsigned int debug_smp_processor_id(void) +{ + return 0; +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/mm/memblock.c b/repos/dde_linux/src/lib/lx_emul/shadow/mm/memblock.c new file mode 100644 index 0000000000..95337d3e15 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/mm/memblock.c @@ -0,0 +1,24 @@ +/* + * \brief Replaces mm/memblock.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +void * __init memblock_alloc_try_nid(phys_addr_t size, + phys_addr_t align, + phys_addr_t min_addr, + phys_addr_t max_addr, + int nid) +{ + return lx_emul_mem_alloc_aligned(size, align); +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/mm/page_alloc.c b/repos/dde_linux/src/lib/lx_emul/shadow/mm/page_alloc.c new file mode 100644 index 0000000000..ba1ca7dfa2 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/mm/page_alloc.c @@ -0,0 +1,38 @@ +/* + * \brief Replaces mm/page_alloc.c + * \author Stefan Kalkowski + * \date 2021-06-03 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +struct page * __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, + int preferred_nid, nodemask_t * nodemask) +{ + unsigned const num_pages = (1 << order); + void * const ptr = lx_emul_mem_alloc_aligned(PAGE_SIZE*num_pages, PAGE_SIZE); + + return lx_emul_virt_to_pages(ptr, num_pages); +} + + +void __free_pages(struct page * page, unsigned int order) +{ + unsigned i; + unsigned const num_pages = (1 << order); + void * const virt_addr = page->virtual; + + for (i = 0; i < num_pages; i++) + lx_emul_disassociate_page_from_virt_addr(page[i].virtual); + + lx_emul_mem_free(virt_addr); + lx_emul_mem_free(page); +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/mm/percpu.c b/repos/dde_linux/src/lib/lx_emul/shadow/mm/percpu.c new file mode 100644 index 0000000000..406f629675 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/mm/percpu.c @@ -0,0 +1,32 @@ +/* + * \brief Replaces mm/percpu.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +void __percpu * __alloc_percpu(size_t size, size_t align) +{ + return lx_emul_mem_alloc_aligned(size, align); +} + + +void __percpu * __alloc_percpu_gfp(size_t size,size_t align,gfp_t gfp) +{ + return __alloc_percpu(size, align); +} + + +void free_percpu(void __percpu * ptr) +{ + lx_emul_mem_free(ptr); +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/mm/slab_common.c b/repos/dde_linux/src/lib/lx_emul/shadow/mm/slab_common.c new file mode 100644 index 0000000000..693f1aec82 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/mm/slab_common.c @@ -0,0 +1,40 @@ +/* + * \brief Replaces mm/slub.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include <../mm/slab.h> +#include +#include + +void * krealloc(const void * p,size_t new_size,gfp_t flags) +{ + if (!p) + return kmalloc(new_size, flags); + + if (!new_size) { + kfree(p); + return NULL; + } + + lx_emul_trace_and_stop(__func__); +} + + +size_t ksize(const void * objp) +{ + if (objp == NULL) + return 0; + + return __ksize(objp); +} diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/mm/slub.c b/repos/dde_linux/src/lib/lx_emul/shadow/mm/slub.c new file mode 100644 index 0000000000..b8c96f8f2c --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/mm/slub.c @@ -0,0 +1,149 @@ +/* + * \brief Replaces mm/slub.c + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include <../mm/slab.h> +#include +#include + +/* + * We do not use those caches now, + * but it is referenced by some compilation unit + */ +struct kmem_cache * +kmalloc_caches[NR_KMALLOC_TYPES][KMALLOC_SHIFT_HIGH + 1] = { NULL }; + + +void kfree(const void * x) +{ + lx_emul_mem_free(x); +} + +void * __kmalloc(size_t size, gfp_t flags) +{ + /* DMA memory is not implemented yet */ + if (flags & GFP_DMA) lx_emul_trace_and_stop(__func__); + return lx_emul_mem_alloc(size); +} + + +struct kmem_cache * kmem_cache_create(const char * name, + unsigned int size, + unsigned int align, + slab_flags_t flags, + void (* ctor)(void *)) +{ + struct kmem_cache * cache = + __kmalloc(sizeof(struct kmem_cache), GFP_KERNEL); + cache->size = size; + cache->align = align; + return cache; +} + + +void kmem_cache_free(struct kmem_cache * s, void * x) +{ + lx_emul_mem_free(x); +} + + +void * __kmalloc_track_caller(size_t size, + gfp_t gfpflags, + unsigned long caller) +{ + return __kmalloc(size, gfpflags); +} + + +void * __kmalloc_node_track_caller(size_t size, + gfp_t gfpflags, + int node, + unsigned long caller) +{ + return __kmalloc_track_caller(size, gfpflags, caller); +} + + +static inline unsigned int kmem_cache_array_size_per_idx(unsigned idx) +{ + switch (idx) { + case 0: return 0; + case 1: return 96; + case 2: return 192; + default: return 1 << idx; + }; +} + + +void __init kmem_cache_init(void) +{ + unsigned i; + + for (i = 0; i <= KMALLOC_SHIFT_HIGH; i++) { + unsigned int sz = kmem_cache_array_size_per_idx(i); + kmalloc_caches[KMALLOC_NORMAL][i] = + kmem_cache_create("", sz, sz, GFP_KERNEL, NULL); + } +} + + +void * kmem_cache_alloc(struct kmem_cache * s, gfp_t flags) +{ + if (!s) + lx_emul_trace_and_stop(__func__); + return lx_emul_mem_alloc_aligned(s->size, s->align ? s->align : 32); +} + + +size_t __ksize(const void * object) +{ + return lx_emul_mem_size(object); +} + + +#ifdef CONFIG_NUMA + +void * __kmalloc_node(size_t size, gfp_t flags, int node) +{ + return __kmalloc(size, flags); +} + + +void * kmem_cache_alloc_node(struct kmem_cache * s, gfp_t gfpflags, int node) +{ + return kmem_cache_alloc(s, gfpflags); +} + +#endif /* CONFIG_NUMA */ + + +#ifdef CONFIG_TRACING + +void * kmem_cache_alloc_node_trace(struct kmem_cache * s, + gfp_t gfpflags, + int node, + size_t size) +{ + return kmem_cache_alloc(s, gfpflags); +} + + +void * kmem_cache_alloc_trace(struct kmem_cache * s, + gfp_t gfpflags, + size_t size) +{ + return __kmalloc(size, gfpflags); +} + +#endif /* CONFIG_TRACING */ diff --git a/repos/dde_linux/src/lib/lx_emul/start.c b/repos/dde_linux/src/lib/lx_emul/start.c new file mode 100644 index 0000000000..17fea8c263 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/start.c @@ -0,0 +1,163 @@ +/* + * \brief Linux Kernel initialization + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* definitions in drivers/base/base.h */ +extern int devices_init(void); +extern int buses_init(void); +extern int classes_init(void); +extern int platform_bus_init(void); + +enum system_states system_state; + +static __initdata DECLARE_COMPLETION(kthreadd_done); + +static int kernel_init(void * args) +{ + struct task_struct *tsk = current; + set_task_comm(tsk, "init"); + + wait_for_completion(&kthreadd_done); + + workqueue_init(); + + /* the following calls are from driver_init() of drivers/base/init.c */ + devices_init(); + buses_init(); + classes_init(); + of_core_init(); + platform_bus_init(); + + lx_emul_initcalls(); + + system_state = SYSTEM_RUNNING; + + lx_user_init(); + lx_emul_task_schedule(true); + return 0; +} + + +static void timer_loop(void) +{ + for (;;) { + tick_nohz_idle_enter(); + lx_emul_task_schedule(true); + lx_emul_time_handle(); + tick_nohz_idle_exit(); + } +} + + +int lx_emul_init_task_function(void * dtb) +{ + int pid; + + /* Set dummy task registers used in IRQ and time handling */ + static struct pt_regs regs; + set_irq_regs(®s); + + /* Run emulation library self-tests before starting kernel */ + lx_emul_associate_page_selftest(); + + /** + * Here we do the minimum normally done start_kernel() of init/main.c + */ + + /* calls from setup_arch of arch/arm64/kernel/setup.c */ + early_init_dt_scan(dtb); + unflatten_device_tree(); + + jump_label_init(); + kmem_cache_init(); + radix_tree_init(); + workqueue_init_early(); + + early_irq_init(); + irqchip_init(); + + tick_init(); + init_timers(); + hrtimers_init(); + timekeeping_init(); + + /* arch/arm64/kernel/time.c */ + lx_emul_time_init(); /* replaces timer_probe() */ + tick_setup_hrtimer_broadcast(); + lpj_fine = 1000000 / HZ; + /* arch/arm64/kernel/time.c end */ + + sched_clock_init(); + + kernel_thread(kernel_init, NULL, CLONE_FS); + pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); + kthreadd_task = find_task_by_pid_ns(pid, NULL);; + + system_state = SYSTEM_SCHEDULING; + + complete(&kthreadd_done); + + lx_emul_task_schedule(false); + + timer_loop(); + + return 0; +} + + +struct task_struct init_task = { + .state = 0, + .usage = REFCOUNT_INIT(2), + .flags = PF_KTHREAD, + .prio = MAX_PRIO - 20, + .static_prio = MAX_PRIO - 20, + .normal_prio = MAX_PRIO - 20, + .policy = SCHED_NORMAL, + .cpus_ptr = &init_task.cpus_mask, + .cpus_mask = CPU_MASK_ALL, + .nr_cpus_allowed = 1, + .mm = NULL, + .active_mm = NULL, + .tasks = LIST_HEAD_INIT(init_task.tasks), + .real_parent = &init_task, + .parent = &init_task, + .children = LIST_HEAD_INIT(init_task.children), + .sibling = LIST_HEAD_INIT(init_task.sibling), + .group_leader = &init_task, + .comm = INIT_TASK_COMM, + .thread = INIT_THREAD, + .pending = { + .list = LIST_HEAD_INIT(init_task.pending.list), + .signal = {{0}} + }, + .blocked = {{0}}, +}; +void * lx_emul_init_task_struct = &init_task; diff --git a/repos/dde_linux/src/lib/lx_emul/task.cc b/repos/dde_linux/src/lib/lx_emul/task.cc new file mode 100644 index 0000000000..5ee3123575 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/task.cc @@ -0,0 +1,77 @@ +/* + * \brief Lx_emul task backend + * \author Stefan Kalkowski + * \date 2021-05-05 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include + +extern "C" struct task_struct * lx_emul_task_get_current(void) +{ + return (struct task_struct*) + Lx_kit::env().scheduler.current().lx_task(); +} + + +extern "C" +void lx_emul_task_create(struct task_struct * task, + const char * name, + int pid, + int (* threadfn)(void * data), + void * data) +{ + new (Lx_kit::env().heap) Lx_kit::Task(threadfn, + data, + (void*)task, pid, name, + Lx_kit::env().scheduler, + Lx_kit::Task::NORMAL); +} + + +extern "C" void lx_emul_task_unblock(struct task_struct * t) +{ + Lx_kit::env().scheduler.task((void*)t).unblock(); +} + + +extern "C" void lx_emul_task_priority(struct task_struct * t, + unsigned long prio) +{ + Lx_kit::env().scheduler.task((void*)t).priority(prio); +} + + +extern "C" void lx_emul_task_schedule(int block) +{ + Lx_kit::Task & task = Lx_kit::env().scheduler.current(); + if (block) task.block(); + task.schedule(); +} + + +extern "C" struct task_struct * lx_emul_task_get(int pid) +{ + void * ret = nullptr; + + Lx_kit::env().scheduler.for_each_task([&] (Lx_kit::Task & task) { + if (pid == task.pid()) + ret = task.lx_task(); + }); + + return (task_struct*) ret; +} + + +extern "C" void lx_emul_task_name(struct task_struct * t, const char * name) +{ + Lx_kit::env().scheduler.task((void*)t).name(name); +} diff --git a/repos/dde_linux/src/lib/lx_emul/time.cc b/repos/dde_linux/src/lib/lx_emul/time.cc new file mode 100644 index 0000000000..3fc8ca17cd --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/time.cc @@ -0,0 +1,36 @@ +/* + * \brief Lx_emul time backend + * \author Stefan Kalkowski + * \date 2021-05-05 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include +#include + + +extern "C" void lx_emul_time_event(unsigned long evt) +{ + Lx_kit::env().timeout.start(evt); +} + + +extern "C" void lx_emul_time_stop() +{ + Lx_kit::env().timeout.stop(); +} + + +extern "C" unsigned long lx_emul_time_counter() +{ + unsigned long ret = Lx_kit::env().timer.curr_time().trunc_to_plain_us().value; + return ret; +} diff --git a/repos/dde_linux/src/lib/lx_emul/virt_to_page.c b/repos/dde_linux/src/lib/lx_emul/virt_to_page.c new file mode 100644 index 0000000000..2827795739 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/virt_to_page.c @@ -0,0 +1,93 @@ +/* + * \brief Linux DDE virt-to-page implementation + * \author Norman Feske + * \date 2021-07-02 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include + + +struct page *lx_emul_virt_to_pages(void const *virt, unsigned count) +{ + /* sanitize argument */ + void * const page_aligned_virt = (void *)((uintptr_t)virt & PAGE_MASK); + + struct page *page = lx_emul_associated_page(page_aligned_virt, 1); + + if (!page) { + unsigned i; + struct page * p = kzalloc(sizeof(struct page)*count, 0); + page = p; + for (i = 0; i < count; i++, p++) { + p->virtual = (void*)((uintptr_t)page_aligned_virt + i*PAGE_SIZE); + init_page_count(page); + lx_emul_associate_page_with_virt_addr(p, p->virtual); + } + + } + + /* consistency check */ + if (page_aligned_virt != page->virtual) + BUG(); + + return page; +} + + +void lx_emul_forget_pages(void const *virt, unsigned long size) +{ + for (;;) { + struct page *page = lx_emul_associated_page(virt, size); + if (!page) + return; + + lx_emul_disassociate_page_from_virt_addr(page->virtual); + kfree(page); + } +} + + +#define LX_EMUL_ASSERT(cond) { if (!(cond)) {\ + printk("assertion failed at line %d: %s\n", __LINE__, #cond); \ + lx_emul_trace_and_stop("abort"); } } + + +void lx_emul_associate_page_selftest() +{ + struct page *p1 = (struct page *)1; + struct page *p2 = (struct page *)2; + struct page *p3 = (struct page *)3; + + void *v1 = (void *)0x11000; + void *v2 = (void *)0x12000; + void *v3 = (void *)0x13000; + + lx_emul_associate_page_with_virt_addr(p1, v1); + lx_emul_associate_page_with_virt_addr(p2, v2); + lx_emul_associate_page_with_virt_addr(p3, v3); + + LX_EMUL_ASSERT(lx_emul_associated_page(v1, 1) == p1); + LX_EMUL_ASSERT(lx_emul_associated_page(v2, 1) == p2); + LX_EMUL_ASSERT(lx_emul_associated_page(v3, 1) == p3); + + LX_EMUL_ASSERT(lx_emul_associated_page((void *)((uintptr_t)v1 + 4095), 1) == p1); + LX_EMUL_ASSERT(lx_emul_associated_page((void *)((uintptr_t)v1 - 1), 1) == NULL); + LX_EMUL_ASSERT(lx_emul_associated_page((void *)((uintptr_t)v2 & PAGE_MASK), 1) == p2); + + LX_EMUL_ASSERT(lx_emul_associated_page((void *)0x10000, 0x10000) == p2); + lx_emul_disassociate_page_from_virt_addr(v2); + LX_EMUL_ASSERT(lx_emul_associated_page((void *)0x10000, 0x10000) == p3); + lx_emul_disassociate_page_from_virt_addr(v3); + LX_EMUL_ASSERT(lx_emul_associated_page((void *)0x10000, 0x10000) == p1); + lx_emul_disassociate_page_from_virt_addr(v1); + LX_EMUL_ASSERT(lx_emul_associated_page((void *)0x10000, 0x10000) == NULL); +} diff --git a/repos/dde_linux/src/lib/lx_kit/console.cc b/repos/dde_linux/src/lib/lx_kit/console.cc new file mode 100644 index 0000000000..df8ec38bdf --- /dev/null +++ b/repos/dde_linux/src/lib/lx_kit/console.cc @@ -0,0 +1,338 @@ +/* + * \brief Lx_kit format string backend + * \author Stefan Kalkowski + * \author Sebastian Sumpf + * \date 2021-03-17 + * + * Greatly inspired by the former DDE Linux Lx_kit implementation. + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +/* Genode includes */ +#include +#include + +/* local includes */ +#include + + +namespace Lx_kit { class Format_command; } + + +/** + * Format string command representation + */ +class Lx_kit::Format_command +{ + public: + + enum Type { INT, UINT, STRING, CHAR, PTR, PERCENT, VA_FORMAT, MAC, + IPV4, INVALID }; + enum Length { DEFAULT, LONG, SIZE_T, LONG_LONG }; + + private: + + /** + * Read decimal value from string + */ + int decode_decimal(const char *str, int *consumed) + { + int res = 0; + while (1) { + char c = str[*consumed]; + + if (!c || c < '0' || c > '0' + 9) + return res; + + res = (res * 10) + c - '0'; + (*consumed)++; + } + } + + public: + + Type type = INVALID; /* format argument type */ + Length length = DEFAULT; /* format argument length */ + int padding = 0; /* min number of characters to print */ + int base = 10; /* base of numeric arguments */ + bool zeropad = false; /* pad with zero instead of space */ + bool uppercase = false; /* use upper case for hex numbers */ + bool prefix = false; /* prefix with 0x */ + int consumed = 0; /* nb of consumed format string chars */ + + /** + * Constructor + * + * \param format begin of command in format string + */ + explicit Format_command(const char *format) + { + /* check for command begin and eat the character */ + if (format[consumed] != '%') + return; + if (!format[++consumed]) + return; + + /* check for %$x syntax */ + prefix = (format[consumed] == '#') || (format[consumed] == '.'); + if (prefix && !format[++consumed]) + return; + + /* heading zero indicates zero-padding */ + zeropad = (format[consumed] == '0'); + + /* read decimal padding value */ + padding = decode_decimal(format, &consumed); + if (!format[consumed]) + return; + + /* decode length */ + switch (format[consumed]) { + + case 'l': + { + /* long long ints are marked by a subsequenting 'l' character */ + bool is_long_long = (format[consumed + 1] == 'l'); + + length = is_long_long ? LONG_LONG : LONG; + consumed += is_long_long ? 2 : 1; + break; + } + + case 'z': + case 'Z': + + length = SIZE_T; + consumed++; + break; + + case 'p': + + length = LONG; + break; + + default: + break; + } + + if (!format[consumed]) + return; + + /* decode type */ + switch (format[consumed]) { + + case 'd': + case 'i': type = INT; base = 10; break; + case 'o': type = UINT; base = 8; break; + case 'u': type = UINT; base = 10; break; + case 'x': type = UINT; base = 16; break; + case 'X': type = UINT; base = 16; uppercase = 1; break; + case 'p': type = PTR; base = 16; break; + case 'c': type = CHAR; break; + case 's': type = STRING; break; + case '%': type = PERCENT; break; + + case 0: return; + default: break; + } + + /* eat type character */ + consumed++; + + if (type != PTR || !format[consumed]) + return; + + switch (format[consumed]) { + + case 'V': type = VA_FORMAT; break; + case 'M': type = MAC; base = 16; padding = 2; break; + + case 'I': + + if (format[consumed + 1] != '4') break; + consumed++; + type = IPV4; base = 10; + break; + + default: return; + } + + consumed++; + } + + int numeric() + { + return (type == INT || type == UINT || type == PTR); + } +}; + + +void Lx_kit::Console::_flush() +{ + if (!_idx) + return; + + _buf[_idx] = 0; + log(Cstring(_buf)); + _idx = 0; +} + + +void Lx_kit::Console::_out_char(char c) +{ + if (c == '\n' || _idx == BUF_SIZE || c == 0) + _flush(); + else + _buf[_idx++] = c; +} + + +void Lx_kit::Console::_out_string(const char *str) +{ + if (str) + while (*str) _out_char(*str++); + else + _flush(); +} + + +void Lx_kit::Console::vprintf(const char *format, va_list list) +{ + while (*format) { + + /* eat and output plain characters */ + if (*format != '%') { + _out_char(*format++); + continue; + } + + /* parse format argument descriptor */ + Format_command cmd(format); + + /* read numeric argument from va_list */ + long long numeric_arg = 0; + if (cmd.numeric()) { + switch (cmd.length) { + + case Format_command::LONG_LONG: + + numeric_arg = va_arg(list, long long); + break; + + case Format_command::LONG: + + numeric_arg = (cmd.type == Format_command::UINT) ? + (long long)va_arg(list, unsigned long) : va_arg(list, long); + break; + + case Format_command::SIZE_T: + + numeric_arg = va_arg(list, size_t); + break; + + case Format_command::DEFAULT: + + numeric_arg = (cmd.type == Format_command::UINT) ? + (long long)va_arg(list, unsigned int) : va_arg(list, int); + break; + } + } + + /* call type-specific output routines */ + switch (cmd.type) { + + case Format_command::INT: + + if (cmd.length == Format_command::LONG_LONG) + _out_signed(numeric_arg, cmd.base); + else + _out_signed(numeric_arg, cmd.base); + break; + + case Format_command::UINT: + + if (cmd.prefix && cmd.base == 16) + _out_string("0x"); + + if (cmd.length == Format_command::LONG_LONG) { + + _out_unsigned(numeric_arg, cmd.base, cmd.padding); + break; + } + + /* fall through */ + + case Format_command::PTR: + + _out_unsigned(numeric_arg, cmd.base, cmd.padding); + break; + + case Format_command::CHAR: + + _out_char(va_arg(list, int)); + break; + + case Format_command::STRING: + + _out_string(va_arg(list, const char *)); + break; + + case Format_command::PERCENT: + + _out_char('%'); + break; + + case Format_command::VA_FORMAT: /* %pV */ + { + struct va_format + { + const char *fmt; + va_list *va; + }; + + va_list va; + va_format *vf = va_arg(list, va_format *); + va_copy(va, *vf->va); + vprintf(vf->fmt, va); + va_end(va); + } + break; + + case Format_command::MAC: /* %pM */ + { + unsigned char const *mac = va_arg(list, unsigned char const *); + for (int i = 0; i < 6; i++) { + if (i) _out_char(':'); + _out_unsigned(mac[i], cmd.base, cmd.padding); + } + break; + } + + case Format_command::IPV4: /* %pI4 */ + { + unsigned char const *ip = va_arg(list, unsigned char const *); + for (int i = 0; i < 4; i++) { + if (i) _out_char('.'); + _out_unsigned(ip[i], cmd.base, cmd.padding); + } + } + break; + + case Format_command::INVALID: + + _out_string(""); + /* consume the argument of the unsupported command */ + va_arg(list, long); + break; + } + + /* proceed with format string after command */ + format += cmd.consumed; + } +} diff --git a/repos/dde_linux/src/lib/lx_kit/device.cc b/repos/dde_linux/src/lib/lx_kit/device.cc new file mode 100644 index 0000000000..a43a11e55d --- /dev/null +++ b/repos/dde_linux/src/lib/lx_kit/device.cc @@ -0,0 +1,240 @@ +/* + * \brief Lx_kit device + * \author Stefan Kalkowski + * \date 2021-05-05 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include + +using namespace Lx_kit; + + +/******************** + ** Device::Io_mem ** + ********************/ + +bool Device::Io_mem::match(addr_t addr, size_t size) +{ + return (this->addr <= addr) && + ((this->addr + this->size) >= (addr + size)); +} + + +/************************* + ** Device::Irq_handler ** + *************************/ + +void Device::Irq_handler::_handle() +{ + env().last_irq = _number; + env().scheduler.unblock_irq_handler(); + env().scheduler.schedule(); +} + + +Device::Irq_handler::Irq_handler(Platform::Device & dev, + Platform::Device::Irq::Index idx, + unsigned number) +: + _irq(dev, idx), + _handler(Lx_kit::env().env.ep(), *this, &Irq_handler::_handle), + _number(number) +{ + _irq.sigh_omit_initial_signal(_handler); + _irq.ack(); +} + + +/************ + ** Device ** + ************/ + +const char * Device::compatible() +{ + return _type.name.string(); +} + + +const char * Device::name() +{ + return _name.string(); +} + + +clk * Device::clock(const char * name) +{ + clk * ret = nullptr; + _for_each_clock([&] (Clock & c) { + if (c.name == name) { + enable(); + ret = &c.lx_clock; + } + }); + return ret; +} + + +clk * Device::clock(unsigned idx) +{ + clk * ret = nullptr; + _for_each_clock([&] (Clock & c) { + if (c.idx == idx) { + enable(); + ret = &c.lx_clock; + } + }); + return ret; +} + + +bool Device::io_mem(addr_t phys_addr, size_t size) +{ + bool ret = false; + _for_each_io_mem([&] (Io_mem & io) { + if (io.match(phys_addr, size)) + ret = true; + }); + return ret; +} + + +void * Device::io_mem_local_addr(addr_t phys_addr, size_t size) +{ + void * ret = nullptr; + _for_each_io_mem([&] (Io_mem & io) { + if (!io.match(phys_addr, size)) + return; + + enable(); + + if (!io.io_mem.constructed()) + io.io_mem.construct(*_pdev, io.idx); + + ret = (void*)((addr_t)io.io_mem->local_addr() + + (phys_addr - io.addr)); + }); + return ret; +} + + +bool Device::irq_unmask(unsigned number) +{ + bool ret = false; + + _for_each_irq([&] (Irq & irq) { + if (irq.number != number) + return; + + enable(); + + if (irq.handler.constructed()) + return; + + irq.handler.construct(*_pdev, irq.idx, number); + ret = true; + }); + + return ret; +} + + +void Device::irq_mask(unsigned number) +{ + if (!_pdev.constructed()) + return; + + _for_each_irq([&] (Irq & irq) { + if (irq.number != number) + return; + irq.handler.destruct(); + }); + +} + + +void Device::irq_ack(unsigned number) +{ + if (!_pdev.constructed()) + return; + + _for_each_irq([&] (Irq & irq) { + if (irq.number != number) + return; + irq.handler->ack(); + }); +} + + +void Device::enable() +{ + if (_pdev.constructed()) + return; + + _pdev.construct(_platform, _type); + + _platform.update(); + _platform.with_xml([&] (Xml_node & xml) { + xml.for_each_sub_node("device", [&] (Xml_node node) { + if (_name != node.attribute_value("name", Device::Name())) + return; + + node.for_each_sub_node("clock", [&] (Xml_node node) { + clk * c = clock(node.attribute_value("name", Device::Name()).string()); + if (!c) + return; + c->rate = node.attribute_value("rate", 0UL); + }); + }); + }); +} + + +Device::Device(Platform::Connection & plat, + Xml_node & xml, + Heap & heap) +: + _platform(plat), + _name(xml.attribute_value("name", Device::Name())), + _type{xml.attribute_value("type", Device::Name())} +{ + unsigned i = 0; + xml.for_each_sub_node("io_mem", [&] (Xml_node node) { + addr_t addr = node.attribute_value("phys_addr", 0UL); + size_t size = node.attribute_value("size", 0UL); + _io_mems.insert(new (heap) Io_mem(i++, addr, size)); + }); + + i = 0; + xml.for_each_sub_node("irq", [&] (Xml_node node) { + _irqs.insert(new (heap) Irq(i++, node.attribute_value("number", 0U))); + }); + + i = 0; + xml.for_each_sub_node("clock", [&] (Xml_node node) { + Device::Name name = node.attribute_value("name", Device::Name()); + _clocks.insert(new (heap) Device::Clock(i++, name)); + }); +} + + +/***************** + ** Device_list ** + *****************/ + +Device_list::Device_list(Heap & heap, Platform::Connection & platform) +: + _platform(platform) +{ + _platform.with_xml([&] (Xml_node & xml) { + xml.for_each_sub_node("device", [&] (Xml_node node) { + insert(new (heap) Device(_platform, node, heap)); + }); + }); +} diff --git a/repos/dde_linux/src/lib/lx_kit/env.cc b/repos/dde_linux/src/lib/lx_kit/env.cc new file mode 100644 index 0000000000..ad7feeb19e --- /dev/null +++ b/repos/dde_linux/src/lib/lx_kit/env.cc @@ -0,0 +1,21 @@ +/* + * \brief Lx_kit environment + * \author Stefan Kalkowski + * \date 2021-03-16 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include + + +Lx_kit::Env & Lx_kit::env(Genode::Env * env) +{ + static Lx_kit::Env environment(*env); + return environment; +} diff --git a/repos/dde_linux/src/lib/lx_kit/init.cc b/repos/dde_linux/src/lib/lx_kit/init.cc new file mode 100644 index 0000000000..c3e904bc0c --- /dev/null +++ b/repos/dde_linux/src/lib/lx_kit/init.cc @@ -0,0 +1,47 @@ +/* + * \brief Lx_kit backend for Linux kernel initialization + * \author Stefan Kalkowski + * \date 2021-03-10 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include + +#include +#include + +namespace Lx_kit { class Initcalls; } + + +void Lx_kit::Initcalls::add(int (*initcall)(void), unsigned int prio) { + _call_list.insert(new (_heap) E(prio, initcall)); } + + +void Lx_kit::Initcalls::execute_in_order() +{ + unsigned min = ~0U; + unsigned max = 0; + for (E * entry = _call_list.first(); entry; entry = entry->next()) { + if (entry->prio < min) min = entry->prio; + if (entry->prio > max) max = entry->prio; + } + + for (unsigned i = min; i <= max; i++) { + for (E * entry = _call_list.first(); entry; entry = entry->next()) { + if (entry->prio == i) entry->call(); + } + } +} + + +void Lx_kit::initialize(Genode::Env & env) +{ + Lx_kit::env(&env); + env.exec_static_constructors(); +} diff --git a/repos/dde_linux/src/lib/lx_kit/memory.cc b/repos/dde_linux/src/lib/lx_kit/memory.cc new file mode 100644 index 0000000000..a7dc51ea95 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_kit/memory.cc @@ -0,0 +1,148 @@ +/* + * \brief Lx_kit memory allocation backend + * \author Stefan Kalkowski + * \date 2021-03-25 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +/* Genode includes */ +#include +#include +#include +#include + +/* local includes */ +#include + + +Genode::Attached_dataspace & Lx_kit::Mem_allocator::alloc_dataspace(size_t size) +{ + Ram_dataspace_capability ds_cap; + + try { + size_t ds_size = align_addr(size, 12); + ds_cap = _platform.alloc_dma_buffer(ds_size, _cache_attr); + addr_t dma_addr = _platform.dma_addr(ds_cap); + + Buffer & buffer = *new (_heap) + Registered(_buffers, _env.rm(), ds_cap, dma_addr); + addr_t addr = (addr_t)buffer.ds().local_addr(); + + /* map eager by touching all pages once */ + for (size_t sz = 0; sz < ds_size; sz += 4096) { + touch_read((unsigned char const volatile*)(addr + sz)); } + + return buffer.ds(); + } catch (Out_of_caps) { + _platform.free_dma_buffer(ds_cap); + throw; + } +} + + +void * Lx_kit::Mem_allocator::alloc(size_t size, size_t align) +{ + if (!size) + return nullptr; + + void * out_addr = nullptr; + + if (_mem.alloc_aligned(size, &out_addr, log2(align)).error()) { + + /* + * Restrict the minimum buffer size to avoid the creation of + * a separate dataspaces for tiny allocations. + */ + size_t const min_buffer_size = 256*1024; + + /* + * Allocate one excess byte that is not officially registered at + * the '_mem' ranges. This way, two virtual consecutive ranges + * (that must be assumed to belong to non-contiguous physical + * ranges) can never be merged when freeing an allocation. Such + * a merge would violate the assumption that a both the virtual + * and physical addresses of a multi-page allocation are always + * contiguous. + */ + Attached_dataspace & ds = alloc_dataspace(max(size + 1, min_buffer_size)); + + _mem.add_range((addr_t)ds.local_addr(), ds.size() - 1); + + /* re-try allocation */ + _mem.alloc_aligned(size, &out_addr, log2(align)); + } + + if (!out_addr) { + error("memory allocation failed for ", size, " align ", align); + backtrace(); + } + else + memset(out_addr, 0, size); + + return out_addr; +} + + +Genode::addr_t Lx_kit::Mem_allocator::dma_addr(void * addr) +{ + addr_t ret = 0UL; + + _buffers.for_each([&] (Buffer & b) { + addr_t other = (addr_t)addr; + addr_t addr = (addr_t)b.ds().local_addr(); + if (addr > other || (addr+b.ds().size()) <= other) + return; + + /* byte offset of 'addr' from start of block */ + addr_t const offset = other - addr; + ret = b.dma_addr() + offset; + }); + + return ret; +} + + +bool Lx_kit::Mem_allocator::free(const void * ptr) +{ + if (!_mem.valid_addr((addr_t)ptr)) + return false; + + _mem.free(const_cast(ptr)); + return true; +} + + +void Lx_kit::Mem_allocator::free(Attached_dataspace * ds) +{ + Dataspace_capability cap = ds->cap(); + + Registered * buffer = nullptr; + _buffers.for_each([&] (Buffer & b) { + if (&b.ds() == ds) + buffer = static_cast*>(&b); + }); + + destroy(_heap, buffer); + _platform.free_dma_buffer(static_cap_cast(cap)); +} + + +Genode::size_t Lx_kit::Mem_allocator::size(const void * ptr) +{ + return ptr ? _mem.size_at(ptr) : 0; +} + + +Lx_kit::Mem_allocator::Mem_allocator(Genode::Env & env, + Heap & heap, + Platform::Connection & platform, + Cache cache_attr) +: + _env(env), _heap(heap), _platform(platform), + _cache_attr(cache_attr), _mem(&heap) {} diff --git a/repos/dde_linux/src/lib/lx_kit/scheduler.cc b/repos/dde_linux/src/lib/lx_kit/scheduler.cc new file mode 100644 index 0000000000..d6182b3ba9 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_kit/scheduler.cc @@ -0,0 +1,129 @@ +/* + * \brief Scheduler for executing Lx::Task objects + * \author Sebastian Sumpf + * \author Josef Soentgen + * \author Norman Feske + * \author Stefan Kalkowski + * \date 2014-10-10 + */ + +/* + * Copyright (C) 2014-2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +/* Genode includes */ +#include +#include +#include + +#include +#include + +using namespace Genode; +using namespace Lx_kit; + +Task & Scheduler::current() +{ + if (!_current) { + error("Lx_kit::Scheduler::_current is zero!"); + backtrace(); + sleep_forever(); + } + + return *_current; +} + + +bool Scheduler::active() const +{ + return _current != nullptr; +} + + +void Scheduler::add(Task & task) +{ + Task * prev = nullptr; + Task * next = _present_list.first(); + + for (; next; prev = next, next = prev->next()) { + if (next->priority() >= task.priority()) + break; + } + _present_list.insert(&task, prev); +} + + +void Scheduler::remove(Task & task) +{ + _present_list.remove(&task); +} + + +void Scheduler::unblock_irq_handler() +{ + for (Task * t = _present_list.first(); t; t = t->next()) { + if (t->type() == Task::IRQ_HANDLER) t->unblock(); + } +} + + +void Scheduler::unblock_time_handler() +{ + for (Task * t = _present_list.first(); t; t = t->next()) { + if (t->type() == Task::TIME_HANDLER) t->unblock(); + } +} + + +Task & Scheduler::task(void * lx_task) +{ + for (Task * t = _present_list.first(); t; t = t->next()) { + if (t->lx_task() == lx_task) + return *t; + } + error("Lx_kit::Scheduler cannot find task ", lx_task); + sleep_forever(); +} + + +void Scheduler::schedule() +{ + /* + * Iterate over all tasks and run first runnable. + * + * (1) If one runnable tasks was run start over from beginning of + * list. + * + * (2) If no task is runnable quit scheduling (break endless + * loop). + */ + while (true) { + bool at_least_one = false; + + /* update jiffies before running task */ + //Lx::timer_update_jiffies(); + + for (Task * t = _present_list.first(); t; t = t->next()) { + + if (!t->runnable()) + continue; + + /* update current before running task */ + _current = t; + t->run(); + at_least_one = true; + + if (!t->runnable()) + break; + } + + if (!at_least_one) + break; + } + + /* clear current as no task is running */ + _current = nullptr; +} diff --git a/repos/dde_linux/src/lib/lx_kit/spec/arm_64/setjmp.S b/repos/dde_linux/src/lib/lx_kit/spec/arm_64/setjmp.S new file mode 100644 index 0000000000..b49ad43553 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_kit/spec/arm_64/setjmp.S @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2014 Andrew Turner + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Andrew Turner + * under sponsorship from the FreeBSD Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* needed parts from */ +#define __FBSDID(x) +#define ENTRY(sym) .text; .globl sym; .align 2; .type sym,#function; sym: +#define END(sym) .size sym, . - sym +/* end of */ + +__FBSDID("$FreeBSD: releng/12.0/lib/libc/aarch64/gen/setjmp.S 313146 2017-02-03 11:51:06Z andrew $"); + +/* needed parts from */ +#define _JB_SIGMASK 22 +#define _JB_MAGIC__SETJMP 0xfb5d25837d7ff700 +/* end of */ + +ENTRY(_setjmp) + /* Store the magic value and stack pointer */ + ldr x8, .Lmagic + mov x9, sp + stp x8, x9, [x0], #16 + + /* Store the general purpose registers and lr */ + stp x19, x20, [x0], #16 + stp x21, x22, [x0], #16 + stp x23, x24, [x0], #16 + stp x25, x26, [x0], #16 + stp x27, x28, [x0], #16 + stp x29, lr, [x0], #16 + +#ifndef _STANDALONE + /* Store the vfp registers */ + stp d8, d9, [x0], #16 + stp d10, d11, [x0], #16 + stp d12, d13, [x0], #16 + stp d14, d15, [x0] +#endif + + /* Return value */ + mov x0, #0 + ret + .align 3 +.Lmagic: + .quad _JB_MAGIC__SETJMP +END(_setjmp) + +ENTRY(_longjmp) + /* Check the magic value */ + ldr x8, [x0], #8 + ldr x9, .Lmagic + cmp x8, x9 + b.ne botch + + /* Restore the stack pointer */ + ldr x8, [x0], #8 + mov sp, x8 + + /* Restore the general purpose registers and lr */ + ldp x19, x20, [x0], #16 + ldp x21, x22, [x0], #16 + ldp x23, x24, [x0], #16 + ldp x25, x26, [x0], #16 + ldp x27, x28, [x0], #16 + ldp x29, lr, [x0], #16 + +#ifndef _STANDALONE + /* Restore the vfp registers */ + ldp d8, d9, [x0], #16 + ldp d10, d11, [x0], #16 + ldp d12, d13, [x0], #16 + ldp d14, d15, [x0] +#endif + + /* Load the return value */ + mov x0, x1 + ret + +botch: + b botch +END(_longjmp) diff --git a/repos/dde_linux/src/lib/lx_kit/task.cc b/repos/dde_linux/src/lib/lx_kit/task.cc new file mode 100644 index 0000000000..727cb8ac0b --- /dev/null +++ b/repos/dde_linux/src/lib/lx_kit/task.cc @@ -0,0 +1,152 @@ +/* + * \brief Lx::Task represents a cooperatively scheduled thread of control + * \author Sebastian Sumpf + * \author Josef Soentgen + * \author Norman Feske + * \date 2014-10-10 + */ + +/* + * Copyright (C) 2014-2017 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include +#include +#include + +using namespace Lx_kit; + +bool Task::runnable() const +{ + switch (_state) { + case INIT: return true; + case RUNNING: return true; + case BLOCKED: return false; + } + error("Invalid task state?!"); + return false; +} + + +static inline void * _alloc_stack(const char * name) +{ + enum { STACK_SIZE = 32 * 1024 }; + Genode::Thread * th = Genode::Thread::myself(); + return th->alloc_secondary_stack(name, STACK_SIZE); +} + + +Task::State Task::state() const { return _state; } + + +Task::Type Task::type() const { return _type; } + + +void * Task::lx_task() const { return _lx_task; } + + +int Task::pid() const { return _pid; } + + +int Task::priority() const { return _priority; } + + +void Task::priority(int prio) +{ + _scheduler.remove(*this); + _priority = prio; + _scheduler.add(*this); +} + + +void Task::name(const char * name) { _name = Task::Name(name); } + + +Task::Name Task::name() const { return _name; } + + +void Task::block() +{ + if (_state == RUNNING) _state = BLOCKED; +} + + +void Task::unblock() +{ + if (_state == BLOCKED) _state = RUNNING; +} + + +void Task::run() +{ + /* + * Save the execution environment. The scheduled task returns to this point + * after execution, i.e., at the next preemption point. + */ + if (_setjmp(_saved_env)) + return; + + if (_state == INIT) { + /* setup execution environment and call task's function */ + _state = RUNNING; + + /* switch stack and call '_func(_arg)' */ + arch_execute(_stack, (void *)_func, _arg); + } else { + /* restore execution environment */ + _longjmp(_env, 1); + } + + /* never reached */ + error("unexpected return of task"); + sleep_forever(); +} + + +void Task::schedule() +{ + /* + * Save the execution environment. The task will resume from here on next + * schedule. + */ + if (_setjmp(_env)) + return; + + /* return to thread calling run() */ + _longjmp(_saved_env, 1); +} + + +void Task::block_and_schedule() +{ + block(); + schedule(); +} + + +Task::Task(int (* func)(void*), + void * arg, + void * lx_task, + int pid, + char const * name, + Scheduler & scheduler, + Type type) +: _type(type), + _scheduler(scheduler), + _lx_task(lx_task), + _pid(pid), + _name(name), + _stack(_alloc_stack(name)), + _func(func), + _arg(arg) +{ + _scheduler.add(*this); +} + + +Task::~Task() { _scheduler.remove(*this); } diff --git a/repos/dde_linux/src/lib/lx_kit/timeout.cc b/repos/dde_linux/src/lib/lx_kit/timeout.cc new file mode 100644 index 0000000000..acbc14b838 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_kit/timeout.cc @@ -0,0 +1,39 @@ +/* + * \brief Lx_kit timeout backend + * \author Stefan Kalkowski + * \date 2021-05-05 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include + +void Lx_kit::Timeout::start(unsigned long us) +{ + _timeout.schedule(Microseconds(us)); +} + + +void Lx_kit::Timeout::stop() +{ + _timeout.discard(); +} + + +void Lx_kit::Timeout::_handle(Genode::Duration) +{ + _scheduler.unblock_time_handler(); + _scheduler.schedule(); +} + + +Lx_kit::Timeout::Timeout(Timer::Connection & timer, + Scheduler & scheduler) +: + _scheduler(scheduler), + _timeout(timer, *this, &Timeout::_handle) { }