From f89517343bf062d299d54408eea2f9387bfefb6d Mon Sep 17 00:00:00 2001 From: Lunaixsky Date: Sun, 15 Dec 2024 01:40:25 +0000 Subject: [PATCH 1/1] Unifying External Interrupt System (#51) * rework external irq system, introduce hierarchical irq * add btrie_map() for allocating free slot, remove isrm * rewrite the btrie key allocation algorithm for better uniformity * optimize the tests makefiles, add unit tests for btrie key allocator * add simple memory allocation monitor for checking leakage and usage * reduce verbosity of unit test ouput, some clean up * make irq specifier to be provided when assigining irq * general fix around. --- lunaix-os/arch/README.md | 1 - .../arch/generic/includes/asm-generic/isrm.h | 130 -------- lunaix-os/arch/x86/LBuild | 2 - lunaix-os/arch/x86/arch.c | 9 - lunaix-os/arch/x86/exceptions/interrupts.c | 97 +++++- lunaix-os/arch/x86/exceptions/intr_routines.c | 105 ------ lunaix-os/arch/x86/exceptions/isrm.c | 239 ------------- lunaix-os/arch/x86/hal/LBuild | 1 - lunaix-os/arch/x86/hal/apic.c | 182 ++++++++-- lunaix-os/arch/x86/hal/apic_timer.c | 30 +- lunaix-os/arch/x86/hal/ioapic.c | 89 ----- lunaix-os/arch/x86/hal/mc146818a.c | 24 +- lunaix-os/arch/x86/hal/ps2kbd.c | 11 +- lunaix-os/arch/x86/includes/asm/soc/apic.h | 6 - lunaix-os/arch/x86/includes/asm/soc/ioapic.h | 16 - lunaix-os/arch/x86/includes/asm/x86.h | 3 - lunaix-os/arch/x86/includes/asm/x86_isrm.h | 42 --- lunaix-os/arch/x86/includes/asm/x86_ivs.h | 4 +- lunaix-os/hal/LBuild | 6 +- lunaix-os/hal/ahci/ahci.c | 8 +- lunaix-os/hal/ahci/ahci_pci.c | 7 +- lunaix-os/hal/ahci/io_event.c | 6 +- lunaix-os/hal/bus/pci.c | 85 +++-- lunaix-os/hal/char/uart/16x50.h | 7 +- lunaix-os/hal/char/uart/16x50_base.c | 8 +- lunaix-os/hal/char/uart/16x50_isa.c | 19 +- lunaix-os/hal/char/uart/16x50_mmio.c | 1 - lunaix-os/hal/char/uart/16x50_pci.c | 28 +- lunaix-os/hal/char/uart/16x50_pmio.c | 1 - lunaix-os/hal/devtree/LBuild | 2 +- lunaix-os/hal/devtree/devtree.h | 8 +- lunaix-os/hal/devtree/dt.c | 4 +- lunaix-os/hal/irq.c | 194 +++++++++++ lunaix-os/includes/hal/ahci/ahci.h | 6 +- lunaix-os/includes/hal/devtree.h | 12 +- lunaix-os/includes/hal/devtreem.h | 2 +- lunaix-os/includes/hal/irq.h | 180 ++++++++++ lunaix-os/includes/hal/pci.h | 35 +- lunaix-os/includes/listings/changeling.lst | 3 +- lunaix-os/includes/listings/device_potens.lst | 8 +- lunaix-os/includes/lunaix/device.h | 2 + lunaix-os/includes/lunaix/ds/btrie.h | 20 +- lunaix-os/kernel/ds/btrie.c | 313 +++++++++++++++--- lunaix-os/kernel/process/sched.c | 3 - lunaix-os/tests/includes/testing/basic.h | 27 +- lunaix-os/tests/includes/testing/memchk.h | 24 ++ lunaix-os/tests/shared/framework.c | 19 +- lunaix-os/tests/shared/makefile | 13 +- lunaix-os/tests/shared/memchk.c | 72 ++++ lunaix-os/tests/shared/mkobj.mkinc | 3 + lunaix-os/tests/units/.gitignore | 1 + lunaix-os/tests/units/btrie/dut/btrie.c | 1 + lunaix-os/tests/units/btrie/makefile | 3 + lunaix-os/tests/units/btrie/test-alloc.c | 201 +++++++++++ lunaix-os/tests/units/btrie/tests.txt | 1 + lunaix-os/tests/units/device-tree/.gitignore | 3 +- lunaix-os/tests/units/device-tree/common.h | 1 - lunaix-os/tests/units/device-tree/makefile | 40 +-- lunaix-os/tests/units/makefile | 12 +- lunaix-os/tests/units/stubs/valloc.c | 45 ++- lunaix-os/tests/units/test_build.mkinc | 5 - lunaix-os/tests/units/units_build.mkinc | 24 ++ 62 files changed, 1500 insertions(+), 954 deletions(-) delete mode 100644 lunaix-os/arch/generic/includes/asm-generic/isrm.h delete mode 100644 lunaix-os/arch/x86/exceptions/intr_routines.c delete mode 100644 lunaix-os/arch/x86/exceptions/isrm.c delete mode 100644 lunaix-os/arch/x86/hal/ioapic.c delete mode 100644 lunaix-os/arch/x86/includes/asm/soc/ioapic.h delete mode 100644 lunaix-os/arch/x86/includes/asm/x86_isrm.h create mode 100644 lunaix-os/hal/irq.c create mode 100644 lunaix-os/includes/hal/irq.h create mode 100644 lunaix-os/tests/includes/testing/memchk.h create mode 100644 lunaix-os/tests/shared/memchk.c create mode 100644 lunaix-os/tests/shared/mkobj.mkinc create mode 100644 lunaix-os/tests/units/.gitignore create mode 120000 lunaix-os/tests/units/btrie/dut/btrie.c create mode 100644 lunaix-os/tests/units/btrie/makefile create mode 100644 lunaix-os/tests/units/btrie/test-alloc.c create mode 100644 lunaix-os/tests/units/btrie/tests.txt delete mode 100644 lunaix-os/tests/units/test_build.mkinc create mode 100644 lunaix-os/tests/units/units_build.mkinc diff --git a/lunaix-os/arch/README.md b/lunaix-os/arch/README.md index 68fa2a0..5c49276 100644 --- a/lunaix-os/arch/README.md +++ b/lunaix-os/arch/README.md @@ -60,7 +60,6 @@ Lunaix provide bunch of headers that **MUST** be implemented in order to behave ``` includes/asm/cpu.h -includes/asm-generic/isrm.h includes/asm/muldiv64.h includes/asm/hart.h includes/asm/mempart.h diff --git a/lunaix-os/arch/generic/includes/asm-generic/isrm.h b/lunaix-os/arch/generic/includes/asm-generic/isrm.h deleted file mode 100644 index 0d4a15a..0000000 --- a/lunaix-os/arch/generic/includes/asm-generic/isrm.h +++ /dev/null @@ -1,130 +0,0 @@ -/** - * @file irqm.h - * @author Lunaixsky - * @brief ISR Manager, managing the interrupt service routine allocations - * @version 0.1 - * @date 2022-10-18 - * - * @copyright Copyright (c) 2022 - * - */ -#ifndef __LUNAIX_ISRM_H -#define __LUNAIX_ISRM_H - -#include -#include -#include - -#include - -typedef void (*isr_cb)(const struct hart_state*); - -typedef struct { - ptr_t msi_addr; - reg_t msi_data; - int mapped_iv; -} msi_vector_t; -#define msi_addr(msiv) ((msiv).msi_addr) -#define msi_data(msiv) ((msiv).msi_data) -#define msi_vect(msiv) ((msiv).mapped_iv) - -typedef void* msienv_t; - -void -isrm_init(); - -/** - * @brief Release a iv resource - * - * @param iv - */ -void -isrm_ivfree(int iv); - -/** - * @brief Begin MSI allocation for given device - * - * @param iv - */ -msienv_t -isrm_msi_start(struct device* dev); - -/** - * @brief Query number of msi avaliable for the device - */ -int -isrm_msi_avaliable(msienv_t msienv); - -/** - * @brief Allocate a msi resource within defined msi resource list - * for the device, indexed by `index` - */ -msi_vector_t -isrm_msi_alloc(msienv_t msienv, cpu_t cpu, int index, isr_cb handler); - -/** - * @brief Set the sideband information will be used for upcoming - * allocations - */ -void -isrm_msi_set_sideband(msienv_t msienv, ptr_t sideband); - -/** - * @brief Done MSI allocation - */ -void -isrm_msi_done(msienv_t msienv); - -static inline must_inline msi_vector_t -isrm_msi_alloc_simple(struct device* dev, cpu_t cpu, isr_cb handler) -{ - msi_vector_t v; - msienv_t env; - - env = isrm_msi_start(dev); - v = isrm_msi_alloc(env, cpu, 0, handler); - isrm_msi_done(env); - - return v; -} - -/** - * @brief Bind the iv according to given device tree node - * - * @param node - */ -int -isrm_bind_dtn(struct dtn_intr* node); - -/** - * @brief Get the handler associated with the given iv - * - * @param iv - * @return isr_cb - */ -isr_cb -isrm_get(int iv); - -ptr_t -isrm_get_payload(const struct hart_state*); - -void -isrm_set_payload(int iv, ptr_t); - -/** - * @brief Notify end of interrupt event - * - * @param id - */ -void -isrm_notify_eoi(cpu_t id, int iv); - -/** - * @brief Notify end of scheduling event - * - * @param id - */ -void -isrm_notify_eos(cpu_t id); - -#endif /* __LUNAIX_ISRM_H */ diff --git a/lunaix-os/arch/x86/LBuild b/lunaix-os/arch/x86/LBuild index 9ae2145..941453b 100644 --- a/lunaix-os/arch/x86/LBuild +++ b/lunaix-os/arch/x86/LBuild @@ -3,8 +3,6 @@ use("hal") sources([ "exceptions/interrupts.c", "exceptions/isrdef.c", - "exceptions/intr_routines.c", - "exceptions/isrm.c", "exceptions/intrhnds.S", ]) diff --git a/lunaix-os/arch/x86/arch.c b/lunaix-os/arch/x86/arch.c index e98bdd9..1d68e15 100644 --- a/lunaix-os/arch/x86/arch.c +++ b/lunaix-os/arch/x86/arch.c @@ -3,8 +3,6 @@ #include #include -#include - #include "asm/x86.h" #include "asm/hart.h" @@ -14,19 +12,12 @@ void exception_init() { exception_install_handler(); - isrm_init(); - intr_routine_init(); } -extern void -syscall_hndlr(const struct hart_state* hstate); - void arch_preinit() { exception_init(); - - isrm_bindiv(LUNAIX_SYS_CALL, syscall_hndlr); } void diff --git a/lunaix-os/arch/x86/exceptions/interrupts.c b/lunaix-os/arch/x86/exceptions/interrupts.c index ceb3853..9941a5c 100644 --- a/lunaix-os/arch/x86/exceptions/interrupts.c +++ b/lunaix-os/arch/x86/exceptions/interrupts.c @@ -5,11 +5,28 @@ #include #include #include +#include -#include +#include LOG_MODULE("INTR") +extern void +intr_routine_page_fault(const struct hart_state* state); + +extern void +syscall_hndlr(const struct hart_state* hstate); + +extern void +apic_ack_interrupt(irq_t irq); + +static void noret +__set_panic(const char* msg, const struct hart_state* state) +{ + ERROR("panic: %s", msg); + failsafe_diagnostic(); +} + static inline void update_thread_context(struct hart_state* state) { @@ -26,23 +43,83 @@ update_thread_context(struct hart_state* state) } } + +static bool +__handle_internal_vectors(const struct hart_state* state) +{ + switch (hart_vector_stamp(state)) + { + case FAULT_DIVISION_ERROR: + __set_panic("div zero", state); + break; + + case FAULT_GENERAL_PROTECTION: + __set_panic("general protection", state); + break; + + case FAULT_PAGE_FAULT: + intr_routine_page_fault(state); + break; + + case FAULT_INVALID_OPCODE: + __set_panic("invalid opcode", state);; + break; + + case LUNAIX_SCHED: + apic_ack_interrupt(NULL); + schedule(); + break; + + case APIC_SPIV_IV: + break; + + case APIC_ERROR_IV: + __set_panic("apic error", state);; + break; + + case LUNAIX_SYS_CALL: + syscall_hndlr(state); + break; + + default: + return false; + } + + return true; +} + +static bool +__handle_external_irq(const struct hart_state* state) +{ + irq_t irq; + int ex_iv; + + ex_iv = hart_vector_stamp(state); + irq = irq_find(irq_get_default_domain(), ex_iv); + + if (unlikely(!irq)) { + return false; + } + + irq_serve(irq, state); + apic_ack_interrupt(irq); + return true; +} + struct hart_state* intr_handler(struct hart_state* state) { update_thread_context(state); volatile struct exec_param* execp = state->execp; - if (execp->vector <= 255) { - isr_cb subscriber = isrm_get(execp->vector); - subscriber(state); - goto done; + + if (__handle_internal_vectors(state)) { + return state; } -done: - - if (execp->vector > IV_BASE_END) { - isrm_notify_eoi(0, execp->vector); + if (__handle_external_irq(state)) { + return state; } - return state; + __set_panic("unknown interrupt", state); } \ No newline at end of file diff --git a/lunaix-os/arch/x86/exceptions/intr_routines.c b/lunaix-os/arch/x86/exceptions/intr_routines.c deleted file mode 100644 index 5e18496..0000000 --- a/lunaix-os/arch/x86/exceptions/intr_routines.c +++ /dev/null @@ -1,105 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include "asm/soc/apic.h" -#include "asm/x86.h" - -LOG_MODULE("INTR") - -extern void -intr_routine_page_fault(const struct hart_state* state); - -extern u32_t debug_resv; - -void -__print_panic_msg(const char* msg, const struct hart_state* state) -{ - ERROR("panic: %s", msg); - failsafe_diagnostic(); -} - -void -intr_routine_divide_zero(const struct hart_state* state) -{ - __print_panic_msg("div zero", state); -} - -void -intr_routine_general_protection(const struct hart_state* state) -{ - __print_panic_msg("general protection", state); -} - -void -intr_routine_invl_opcode(const struct hart_state* state) -{ - __print_panic_msg("invalid opcode", state); -} - -void -intr_routine_sys_panic(const struct hart_state* state) -{ -#ifdef CONFIG_ARCH_X86_64 - __print_panic_msg((char*)(state->registers.rdi), state); -#else - __print_panic_msg((char*)(state->registers.edi), state); -#endif -} - -void -intr_routine_fallback(const struct hart_state* state) -{ - __print_panic_msg("unknown interrupt", state); -} - -/** - * @brief ISR for Spurious interrupt - * - * @param struct hart_state passed by CPU - */ -void -intr_routine_apic_spi(const struct hart_state* state) -{ - // FUTURE: do nothing for now -} - -void -intr_routine_apic_error(const struct hart_state* state) -{ - u32_t error_reg = apic_read_reg(APIC_ESR); - char buf[32]; - ksprintf(buf, "APIC error, ESR=0x%x", error_reg); - - failsafe_diagnostic(); -} - -void -intr_routine_sched(const struct hart_state* state) -{ - schedule(); -} - -void -intr_routine_init() -{ - isrm_bindiv(FAULT_DIVISION_ERROR, intr_routine_divide_zero); - isrm_bindiv(FAULT_GENERAL_PROTECTION, intr_routine_general_protection); - isrm_bindiv(FAULT_PAGE_FAULT, intr_routine_page_fault); - isrm_bindiv(FAULT_STACK_SEG_FAULT, intr_routine_page_fault); - isrm_bindiv(FAULT_INVALID_OPCODE, intr_routine_invl_opcode); - - isrm_bindiv(LUNAIX_SYS_PANIC, intr_routine_sys_panic); - isrm_bindiv(LUNAIX_SCHED, intr_routine_sched); - - isrm_bindiv(APIC_SPIV_IV, intr_routine_apic_spi); - isrm_bindiv(APIC_ERROR_IV, intr_routine_apic_error); -} \ No newline at end of file diff --git a/lunaix-os/arch/x86/exceptions/isrm.c b/lunaix-os/arch/x86/exceptions/isrm.c deleted file mode 100644 index 86eec04..0000000 --- a/lunaix-os/arch/x86/exceptions/isrm.c +++ /dev/null @@ -1,239 +0,0 @@ -#include -#include -#include - -#include "asm/x86.h" -#include "asm/soc/ioapic.h" -#include "asm/soc/apic.h" - -/* - total: 256 ivs - 0~31: reserved for sys use (x32) - 32~47: reserved for os use (x16) - 48~ : free to allocate for external hardware use. (x208) -*/ - -static char iv_bmp[(IV_EX_END - IV_BASE_END) / 8]; -static isr_cb handlers[TOTAL_IV]; -static ptr_t ivhand_payload[TOTAL_IV]; - -static struct x86_intc arch_intc_ctx; - -extern void -intr_routine_fallback(const struct hart_state* state); - -void -isrm_init() -{ - for (size_t i = 0; i < TOTAL_IV; i++) { - handlers[i] = intr_routine_fallback; - } -} - -static inline int -__ivalloc_within(size_t a, size_t b, isr_cb handler) -{ - a = (a - IV_BASE_END); - b = (b - IV_BASE_END); - u8_t j = a % 8; - u8_t k = 0; - - for (size_t i = a / 8; i < b / 8; i++, k += 8) { - u8_t chunk = iv_bmp[i]; - - if (chunk == 0xff) - continue; - - chunk >>= j; - while ((chunk & 0x1) && k <= b) { - chunk >>= 1; - j++; - k++; - } - - if (j == 8) { - j = 0; - continue; - } - - if (k > b) { - break; - } - - iv_bmp[i] |= 1 << j; - - int iv = IV_BASE_END + i * 8 + j; - handlers[iv] = handler ? handler : intr_routine_fallback; - - return iv; - } - - return 0; -} - -int -isrm_ivosalloc(isr_cb handler) -{ - return __ivalloc_within(IV_BASE_END, IV_EX_BEGIN, handler); -} - -int -isrm_ivexalloc(isr_cb handler) -{ - return __ivalloc_within(IV_EX_BEGIN, IV_EX_END, handler); -} - -void -isrm_ivfree(int iv) -{ - assert(iv < 256); - - if (iv >= IV_BASE_END) { - iv_bmp[(iv - IV_BASE_END) / 8] &= ~(1 << ((iv - IV_BASE_END) % 8)); - } - - handlers[iv] = intr_routine_fallback; -} - -int -isrm_bindirq(int irq, isr_cb irq_handler) -{ - int iv; - if (!(iv = isrm_ivexalloc(irq_handler))) { - fail("out of IV resource."); - return 0; // never reach - } - - // fixed, edge trigged, polarity=high - isrm_irq_attach(irq, iv, 0, IRQ_DEFAULT); - - return iv; -} - -void -isrm_bindiv(int iv, isr_cb handler) -{ - assert(iv < 256); - - if (iv >= IV_BASE_END) { - iv_bmp[(iv - IV_BASE_END) / 8] |= 1 << ((iv - IV_BASE_END) % 8); - } - - handlers[iv] = handler; -} - -isr_cb -isrm_get(int iv) -{ - assert(iv < 256); - - return handlers[iv]; -} - -ptr_t -isrm_get_payload(const struct hart_state* state) -{ - int iv = state->execp->vector; - assert(iv < 256); - - return ivhand_payload[iv]; -} - -void -isrm_set_payload(int iv, ptr_t payload) -{ - assert(iv < 256); - - ivhand_payload[iv] = payload; -} - -void -isrm_irq_attach(int irq, int iv, cpu_t dest, u32_t flags) -{ - arch_intc_ctx.irq_attach(&arch_intc_ctx, irq, iv, dest, flags); -} - -void -isrm_notify_eoi(cpu_t id, int iv) -{ - arch_intc_ctx.notify_eoi(&arch_intc_ctx, id, iv); -} - -void -isrm_notify_eos(cpu_t id) -{ - isrm_notify_eoi(id, LUNAIX_SCHED); -} - -msienv_t -isrm_msi_start(struct device* dev) -{ - /* - * In x86, the MSI topology is rather simple, as the only - * source is the PCI itself, and the write destination is - * explictly defined in specification, so we don't need the - * msienv to hold dynamically probed address - */ - return NULL; -} - -int -isrm_msi_avaliable(msienv_t msienv) -{ - return 1; -} - -msi_vector_t -isrm_msi_alloc(msienv_t msienv, cpu_t cpu, int index, isr_cb handler) -{ - unsigned int iv = isrm_ivexalloc(handler); - - // we ignore the cpu redirection for now. - return (msi_vector_t){ - .msi_addr = __APIC_BASE_PADDR, - .msi_data = iv, - .mapped_iv = iv - }; -} - -void -isrm_msi_set_sideband(msienv_t msienv, ptr_t sideband) -{ - return; -} - -void -isrm_msi_done(msienv_t msienv) -{ - return; -} - - - -int -isrm_bind_dtn(struct dtn_intr* node) -{ - fail("not supported"); -} - - -static int -__intc_create(struct device_def* devdef, morph_t* obj) -{ - apic_init(); - ioapic_init(); - - arch_intc_ctx.name = "i386_apic"; - arch_intc_ctx.irq_attach = ioapic_irq_remap; - arch_intc_ctx.notify_eoi = apic_on_eoi; - - return 0; -} - - -static struct device_def i386_intc = { - def_device_class(INTEL, CFG, INTC), - def_device_name("i386 apic"), - def_on_create(__intc_create) -}; -EXPORT_DEVICE(i386_intc, &i386_intc, load_sysconf); \ No newline at end of file diff --git a/lunaix-os/arch/x86/hal/LBuild b/lunaix-os/arch/x86/hal/LBuild index f3a3cae..870f743 100644 --- a/lunaix-os/arch/x86/hal/LBuild +++ b/lunaix-os/arch/x86/hal/LBuild @@ -4,7 +4,6 @@ sources([ "cpu.c", "ps2kbd.c", "apic_timer.c", - "ioapic.c", "mc146818a.c", "pci.c" ]) \ No newline at end of file diff --git a/lunaix-os/arch/x86/hal/apic.c b/lunaix-os/arch/x86/hal/apic.c index ddc2e31..8e9a013 100644 --- a/lunaix-os/arch/x86/hal/apic.c +++ b/lunaix-os/arch/x86/hal/apic.c @@ -11,24 +11,85 @@ #include "asm/x86.h" #include "asm/x86_cpu.h" - #include "asm/soc/apic.h" + #include #include #include #include +#include + +#include +#include #include "pic.h" LOG_MODULE("APIC") +#define IOAPIC_IOREGSEL 0x00 +#define IOAPIC_IOWIN 0x10 +#define IOAPIC_IOREDTBL_BASE 0x10 + +#define IOAPIC_REG_ID 0x00 +#define IOAPIC_REG_VER 0x01 +#define IOAPIC_REG_ARB 0x02 + +#define IOAPIC_DELMOD_FIXED 0b000 +#define IOAPIC_DELMOD_LPRIO 0b001 +#define IOAPIC_DELMOD_NMI 0b100 + +#define IOAPIC_MASKED (1 << 16) +#define IOAPIC_TRIG_LEVEL (1 << 15) +#define IOAPIC_INTPOL_L (1 << 13) +#define IOAPIC_DESTMOD_LOGIC (1 << 11) + +#define IOAPIC_BASE_VADDR 0x2000 + +#define IOAPIC_REG_SEL *((volatile u32_t*)(_ioapic_base + IOAPIC_IOREGSEL)) +#define IOAPIC_REG_WIN *((volatile u32_t*)(_ioapic_base + IOAPIC_IOWIN)) + + +#define LVT_ENTRY_LINT0(vector) (LVT_DELIVERY_FIXED | vector) + +// Pin LINT#1 is configured for relaying NMI, but we masked it here as I think +// it is too early for that +// LINT#1 *must* be edge trigged (Intel manual vol3. 10-14) +#define LVT_ENTRY_LINT1 (LVT_DELIVERY_NMI | LVT_MASKED | LVT_TRIGGER_EDGE) +#define LVT_ENTRY_ERROR(vector) (LVT_DELIVERY_FIXED | vector) + + +static volatile ptr_t _ioapic_base; static volatile ptr_t _apic_base; void -apic_setup_lvts(); +apic_write_reg(unsigned int reg, unsigned int val) +{ + *(unsigned int*)(_apic_base + reg) = val; +} void +apic_ack_interrupt(irq_t irq) +{ + *(unsigned int*)(_apic_base + APIC_EOI) = 0; +} + +unsigned int +apic_read_reg(unsigned int reg) +{ + return *(unsigned int*)(_apic_base + (reg)); +} + + +static void +apic_setup_lvts() +{ + apic_write_reg(APIC_LVT_LINT0, LVT_ENTRY_LINT0(APIC_LINT0_IV)); + apic_write_reg(APIC_LVT_LINT1, LVT_ENTRY_LINT1); + apic_write_reg(APIC_LVT_ERROR, LVT_ENTRY_ERROR(APIC_ERROR_IV)); +} + +static void apic_init() { // ensure that external interrupt is disabled @@ -85,40 +146,109 @@ apic_init() apic_write_reg(APIC_SPIVR, spiv); } -#define LVT_ENTRY_LINT0(vector) (LVT_DELIVERY_FIXED | vector) +static void +ioapic_init() +{ + acpi_context* acpi_ctx = acpi_get_context(); -// Pin LINT#1 is configured for relaying NMI, but we masked it here as I think -// it is too early for that -// LINT#1 *must* be edge trigged (Intel manual vol3. 10-14) -#define LVT_ENTRY_LINT1 (LVT_DELIVERY_NMI | LVT_MASKED | LVT_TRIGGER_EDGE) -#define LVT_ENTRY_ERROR(vector) (LVT_DELIVERY_FIXED | vector) + _ioapic_base = + ioremap(acpi_ctx->madt.ioapic->ioapic_addr & ~0xfff, 4096); +} -void -apic_setup_lvts() +static void +ioapic_write(u8_t sel, u32_t val) { - apic_write_reg(APIC_LVT_LINT0, LVT_ENTRY_LINT0(APIC_LINT0_IV)); - apic_write_reg(APIC_LVT_LINT1, LVT_ENTRY_LINT1); - apic_write_reg(APIC_LVT_ERROR, LVT_ENTRY_ERROR(APIC_ERROR_IV)); + IOAPIC_REG_SEL = sel; + IOAPIC_REG_WIN = val; } -void -apic_on_eoi(struct x86_intc* intc_ctx, cpu_t cpu, int iv) +static u32_t +ioapic_read(u8_t sel) +{ + IOAPIC_REG_SEL = sel; + return IOAPIC_REG_WIN; +} + +static void +__ioapic_install_line(struct irq_domain *domain, irq_t irq) +{ + struct irq_line_wire *line; + u8_t reg_sel; + u32_t ioapic_fg; + + line = irq->line; + reg_sel = IOAPIC_IOREDTBL_BASE + line->domain_mapped * 2; + ioapic_fg = IOAPIC_DELMOD_FIXED; + + // Write low 32 bits + ioapic_write(reg_sel, (irq->vector | ioapic_fg) & 0x1FFFF); + + // Write high 32 bits + ioapic_write(reg_sel + 1, 0); +} + +static int +__ioapic_translate_irq(struct irq_domain *domain, irq_t irq, void *irq_extra) { - // for all external interrupts except the spurious interrupt - // this is required by Intel Manual Vol.3A, section 10.8.1 & 10.8.5 - if (iv >= IV_EX_BEGIN && iv != APIC_SPIV_IV) { - *(unsigned int*)(_apic_base + APIC_EOI) = 0; + struct irq_line_wire *line; + + if (irq->type == IRQ_LINE) { + line = irq->line; + line->domain_mapped = acpi_gsimap(line->domain_local); } + + return 0; } -unsigned int -apic_read_reg(unsigned int reg) +static int +__ioapic_install_irq(struct irq_domain *domain, irq_t irq) { - return *(unsigned int*)(_apic_base + (reg)); + if (irq->vector == IRQ_VECTOR_UNSET) { + irq->vector = btrie_map(&domain->irq_map, IV_EX_BEGIN, IV_EX_END, irq); + } + else { + irq_record(domain, irq); + } + + if (irq->type == IRQ_MESSAGE) { + irq->msi->wr_addr = __APIC_BASE_PADDR; + } + else { + __ioapic_install_line(domain, irq); + } + + return 0; } -void -apic_write_reg(unsigned int reg, unsigned int val) + +static struct irq_domain_ops apic_domain_ops = { + .map_irq = __ioapic_translate_irq, + .install_irq = __ioapic_install_irq +}; + +static int +apic_device_create(struct device_def* def, morph_t* morph) { - *(unsigned int*)(_apic_base + reg) = val; -} \ No newline at end of file + int err; + struct device* dev; + struct irq_domain* domain; + + apic_init(); + ioapic_init(); + + dev = device_allocsys(NULL, NULL); + domain = irq_create_domain(dev, &apic_domain_ops); + + irq_set_default_domain(domain); + register_device(dev, &def->class, "apic"); + irq_attach_domain(NULL, domain); + + return 0; +} + +static struct device_def apic_devdef = { + def_device_class(INTEL, CFG, INTC), + def_device_name("x86 APIC"), + def_on_create(apic_device_create) +}; +EXPORT_DEVICE(x86_apic, &apic_devdef, load_sysconf); \ No newline at end of file diff --git a/lunaix-os/arch/x86/hal/apic_timer.c b/lunaix-os/arch/x86/hal/apic_timer.c index 816fde3..178928c 100644 --- a/lunaix-os/arch/x86/hal/apic_timer.c +++ b/lunaix-os/arch/x86/hal/apic_timer.c @@ -1,12 +1,12 @@ #include "apic_timer.h" #include +#include #include #include #include #include -#include #include "asm/soc/apic.h" LOG_MODULE("timer(apic)") @@ -15,20 +15,20 @@ LOG_MODULE("timer(apic)") #define APIC_BASETICKS 0x100000 static void -temp_intr_routine_apic_timer(const struct hart_state* state) +apic_timer_count_stop(irq_t irq, const struct hart_state* state) { struct hwtimer_pot* pot; - pot = (struct hwtimer_pot*)isrm_get_payload(state); + pot = irq_payload(irq, struct hwtimer_pot); pot->systick_raw = (ticks_t)-1; } static void -apic_timer_tick_isr(const struct hart_state* state) +apic_timer_tick_isr(irq_t irq, const struct hart_state* state) { struct hwtimer_pot* pot; - pot = (struct hwtimer_pot*)isrm_get_payload(state); + pot = irq_payload(irq, struct hwtimer_pot); pot->systick_raw++; if (likely(__ptr(pot->callback))) { @@ -39,20 +39,19 @@ apic_timer_tick_isr(const struct hart_state* state) static void __apic_timer_calibrate(struct hwtimer_pot* pot, u32_t hertz) { + irq_t irq; ticks_t base_freq = 0; cpu_disable_interrupt(); - // Setup APIC timer - - // grab ourselves these irq numbers - u32_t iv_timer = isrm_ivexalloc(temp_intr_routine_apic_timer); - isrm_set_payload(iv_timer, __ptr(pot)); + irq = irq_declare_direct(apic_timer_count_stop); + irq_set_payload(irq, pot); + irq_assign(irq_get_default_domain(), irq, NULL); // Setup a one-shot timer, we will use this to measure the bus speed. So we // can then calibrate apic timer to work at *nearly* accurate hz apic_write_reg(APIC_TIMER_LVT, - LVT_ENTRY_TIMER(iv_timer, LVT_TIMER_ONESHOT)); + LVT_ENTRY_TIMER(irq->vector, LVT_TIMER_ONESHOT)); // Set divider to 64 apic_write_reg(APIC_TIMER_DCR, APIC_TIMER_DIV64); @@ -89,7 +88,6 @@ __apic_timer_calibrate(struct hwtimer_pot* pot, u32_t hertz) wait_until(!(pot->systick_raw + 1)); cpu_disable_interrupt(); - isrm_ivfree(iv_timer); sysrtc->ops->set_proactive(sysrtc, false); @@ -101,14 +99,12 @@ __apic_timer_calibrate(struct hwtimer_pot* pot, u32_t hertz) assert_msg(base_freq, "Fail to initialize timer (NOFREQ)"); INFO("hw: %u Hz; os: %u Hz", base_freq, hertz); + irq_set_servant(irq, apic_timer_tick_isr); + apic_write_reg(APIC_TIMER_ICR, base_freq / hertz); - - iv_timer = isrm_ivexalloc(apic_timer_tick_isr); - isrm_set_payload(iv_timer, __ptr(pot)); - apic_write_reg( APIC_TIMER_LVT, - LVT_ENTRY_TIMER(iv_timer, LVT_TIMER_PERIODIC)); + LVT_ENTRY_TIMER(irq->vector, LVT_TIMER_PERIODIC)); } static struct hwtimer_pot_ops potops = { diff --git a/lunaix-os/arch/x86/hal/ioapic.c b/lunaix-os/arch/x86/hal/ioapic.c deleted file mode 100644 index e03d4b5..0000000 --- a/lunaix-os/arch/x86/hal/ioapic.c +++ /dev/null @@ -1,89 +0,0 @@ -#include - -#include - -#include -#include "asm/soc/ioapic.h" -#include "asm/x86.h" - -#define IOAPIC_IOREGSEL 0x00 -#define IOAPIC_IOWIN 0x10 -#define IOAPIC_IOREDTBL_BASE 0x10 - -#define IOAPIC_REG_ID 0x00 -#define IOAPIC_REG_VER 0x01 -#define IOAPIC_REG_ARB 0x02 - -#define IOAPIC_DELMOD_FIXED 0b000 -#define IOAPIC_DELMOD_LPRIO 0b001 -#define IOAPIC_DELMOD_NMI 0b100 - -#define IOAPIC_MASKED (1 << 16) -#define IOAPIC_TRIG_LEVEL (1 << 15) -#define IOAPIC_INTPOL_L (1 << 13) -#define IOAPIC_DESTMOD_LOGIC (1 << 11) - -#define IOAPIC_BASE_VADDR 0x2000 - -#define IOAPIC_REG_SEL *((volatile u32_t*)(_ioapic_base + IOAPIC_IOREGSEL)) -#define IOAPIC_REG_WIN *((volatile u32_t*)(_ioapic_base + IOAPIC_IOWIN)) - -static volatile ptr_t _ioapic_base; - -void -ioapic_init() -{ - // Remapping the IRQs - - acpi_context* acpi_ctx = acpi_get_context(); - - _ioapic_base = - ioremap(acpi_ctx->madt.ioapic->ioapic_addr & ~0xfff, 4096); -} - -void -ioapic_write(u8_t sel, u32_t val) -{ - IOAPIC_REG_SEL = sel; - IOAPIC_REG_WIN = val; -} - -u32_t -ioapic_read(u8_t sel) -{ - IOAPIC_REG_SEL = sel; - return IOAPIC_REG_WIN; -} - -void -ioapic_irq_remap(struct x86_intc* intc, int irq, int iv, cpu_t dest, u32_t flags) -{ - /* - FIXME move it to HAL level. since every platform might have their own - wiring, thus gsi mapping is required all the time - */ - irq = acpi_gsimap(irq); - u8_t reg_sel = IOAPIC_IOREDTBL_BASE + irq * 2; - - u32_t ioapic_fg = 0; - - if ((flags & IRQ_TYPE) == IRQ_TYPE_FIXED) { - ioapic_fg |= IOAPIC_DELMOD_FIXED; - } else { - ioapic_fg |= IOAPIC_DELMOD_NMI; - } - - if ((flags & IRQ_TRIG_LEVEL)) { - ioapic_fg |= IOAPIC_TRIG_LEVEL; - } - - if (!(flags & IRQ_VE_HI)) { - ioapic_fg |= IOAPIC_INTPOL_L; - } - - // Write low 32 bits - ioapic_write(reg_sel, (iv | ioapic_fg) & 0x1FFFF); - - // Write high 32 bits - ioapic_write(reg_sel + 1, (dest << 24)); -} \ No newline at end of file diff --git a/lunaix-os/arch/x86/hal/mc146818a.c b/lunaix-os/arch/x86/hal/mc146818a.c index f5bc285..fcb5d7f 100644 --- a/lunaix-os/arch/x86/hal/mc146818a.c +++ b/lunaix-os/arch/x86/hal/mc146818a.c @@ -15,10 +15,10 @@ #include #include +#include #include -#include #include #define RTC_INDEX_PORT 0x70 @@ -57,7 +57,7 @@ struct mc146818 { struct hwrtc_potens* rtc_context; - u32_t rtc_iv; + irq_t irq; }; #define rtc_state(data) ((struct mc146818*)(data)) @@ -132,10 +132,11 @@ rtc_setwalltime(struct hwrtc_potens* rtc, datetime_t* datetime) } static void -__rtc_tick(const struct hart_state* hstate) +__rtc_tick(irq_t irq, const struct hart_state* hstate) { - struct mc146818* state = (struct mc146818*)isrm_get_payload(hstate); + struct mc146818* state; + state = irq_payload(irq, struct mc146818); state->rtc_context->live++; (void)rtc_read_reg(RTC_REG_C); @@ -164,8 +165,12 @@ static int __rtc_calibrate(struct hwrtc_potens* pot) { struct mc146818* state; + struct device* rtc_dev; + u8_t reg; + + rtc_dev = potens_dev(pot); - u8_t reg = rtc_read_reg(RTC_REG_A); + reg = rtc_read_reg(RTC_REG_A); reg = (reg & ~0x7f) | RTC_FREQUENCY_1024HZ | RTC_DIVIDER_33KHZ; rtc_write_reg(RTC_REG_A, reg); @@ -177,9 +182,12 @@ __rtc_calibrate(struct hwrtc_potens* pot) pot->base_freq = RTC_TIMER_BASE_FREQUENCY; - state = (struct mc146818*)potens_dev(pot)->underlay; - state->rtc_iv = isrm_bindirq(PC_AT_IRQ_RTC, __rtc_tick); - isrm_set_payload(state->rtc_iv, __ptr(state)); + state = (struct mc146818*)rtc_dev->underlay; + + state->irq = irq_declare_line(__rtc_tick, PC_AT_IRQ_RTC); + irq_set_payload(state->irq, state); + + irq_assign(irq_owning_domain(rtc_dev), state->irq, NULL); return 0; } diff --git a/lunaix-os/arch/x86/hal/ps2kbd.c b/lunaix-os/arch/x86/hal/ps2kbd.c index ee4a67e..1df42bd 100644 --- a/lunaix-os/arch/x86/hal/ps2kbd.c +++ b/lunaix-os/arch/x86/hal/ps2kbd.c @@ -6,12 +6,13 @@ #include #include +#include + #include "asm/x86.h" #include #include "asm/x86_cpu.h" -#include #include #define PS2_PORT_ENC_DATA 0x60 @@ -189,7 +190,7 @@ static struct input_device* kbd_idev; // #define KBD_DBGLOG static void -intr_ps2_kbd_handler(const struct hart_state* hstate); +intr_ps2_kbd_handler(irq_t irq, const struct hart_state* hstate); static u8_t ps2_issue_cmd_wretry(char cmd, u16_t arg); @@ -309,7 +310,9 @@ ps2_kbd_create(struct device_def* devdef, morph_t* obj) * * 所以,保险的方法是:在初始化后才去设置ioapic,这样一来我们就能有一个稳定的IRQ#1以放心使用。 */ - isrm_bindirq(PC_AT_IRQ_KBD, intr_ps2_kbd_handler); + + irq_t irq = irq_declare_line(intr_ps2_kbd_handler, PC_AT_IRQ_KBD); + irq_assign(irq_owning_domain(kbd_idev->dev_if), irq, NULL); return 0; @@ -401,7 +404,7 @@ kbd_buffer_key_event(kbd_keycode_t key, u8_t scancode, kbd_kstate_t state) } static void -intr_ps2_kbd_handler(const struct hart_state* hstate) +intr_ps2_kbd_handler(irq_t irq, const struct hart_state* hstate) { // This is important! Don't believe me? try comment it out and run on Bochs! diff --git a/lunaix-os/arch/x86/includes/asm/soc/apic.h b/lunaix-os/arch/x86/includes/asm/soc/apic.h index 40c395c..83ad3ed 100644 --- a/lunaix-os/arch/x86/includes/asm/soc/apic.h +++ b/lunaix-os/arch/x86/includes/asm/soc/apic.h @@ -72,10 +72,4 @@ apic_read_reg(unsigned int reg); void apic_write_reg(unsigned int reg, unsigned int val); -void -apic_init(); - -void -apic_on_eoi(struct x86_intc* intc_ctx, cpu_t cpu, int iv); - #endif /* __LUNAIX_APIC_H */ diff --git a/lunaix-os/arch/x86/includes/asm/soc/ioapic.h b/lunaix-os/arch/x86/includes/asm/soc/ioapic.h deleted file mode 100644 index d87ab18..0000000 --- a/lunaix-os/arch/x86/includes/asm/soc/ioapic.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __LUNAIX_IOAPIC_H -#define __LUNAIX_IOAPIC_H - -#include "asm/x86.h" - -void -ioapic_init(); - -void -ioapic_irq_remap(struct x86_intc*, - int irq, - int iv, - cpu_t dest, - u32_t flags); - -#endif /* __LUNAIX_IOAPIC_H */ diff --git a/lunaix-os/arch/x86/includes/asm/x86.h b/lunaix-os/arch/x86/includes/asm/x86.h index 33515a1..8f1e3d0 100644 --- a/lunaix-os/arch/x86/includes/asm/x86.h +++ b/lunaix-os/arch/x86/includes/asm/x86.h @@ -95,8 +95,5 @@ typedef struct x86_sysdesc x86_segdesc_t; void exception_install_handler(); -void -intr_routine_init(); - #endif #endif /* __LUNAIX_I386_ASM_H */ diff --git a/lunaix-os/arch/x86/includes/asm/x86_isrm.h b/lunaix-os/arch/x86/includes/asm/x86_isrm.h deleted file mode 100644 index b486080..0000000 --- a/lunaix-os/arch/x86/includes/asm/x86_isrm.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef __LUNAIX_X86_ISRM_H -#define __LUNAIX_X86_ISRM_H - -#include - -/** - * @brief Bind a given irq and associated handler to an iv - * - * @param iv iv allocated by system - */ -int -isrm_bindirq(int irq, isr_cb irq_handler); - -/** - * @brief Bind given iv with it's associated handler - * - * @param iv - * @param handler - */ -void -isrm_bindiv(int iv, isr_cb handler); - -void -isrm_irq_attach(int irq, int iv, cpu_t dest, u32_t flags); - -/** - * @brief Allocate an iv resource for os services - * - * @param iv - */ -int -isrm_ivosalloc(isr_cb handler); - -/** - * @brief Allocate an iv resource for external events - * - * @param iv - */ -int -isrm_ivexalloc(isr_cb handler); - -#endif /* __LUNAIX_X86_ISRM_H */ diff --git a/lunaix-os/arch/x86/includes/asm/x86_ivs.h b/lunaix-os/arch/x86/includes/asm/x86_ivs.h index 0a5eed2..0dbe921 100644 --- a/lunaix-os/arch/x86/includes/asm/x86_ivs.h +++ b/lunaix-os/arch/x86/includes/asm/x86_ivs.h @@ -33,11 +33,11 @@ #define LUNAIX_SYS_CALL 33 // begin allocatable iv resources -#define IV_EX_BEGIN 50 #define LUNAIX_SCHED 50 +#define IV_EX_BEGIN 51 // end allocatable iv resources -#define IV_EX_END 249 +#define IV_EX_END 249 // 来自APIC的中断有着最高的优先级。 // APIC related diff --git a/lunaix-os/hal/LBuild b/lunaix-os/hal/LBuild index 673a8fc..6ff2713 100644 --- a/lunaix-os/hal/LBuild +++ b/lunaix-os/hal/LBuild @@ -8,4 +8,8 @@ use("timer") use("bus") if config("use_devicetree"): - use("devtree") \ No newline at end of file + use("devtree") + +sources([ + "irq.c" +]) \ No newline at end of file diff --git a/lunaix-os/hal/ahci/ahci.c b/lunaix-os/hal/ahci/ahci.c index 04a7104..5ff1cc2 100644 --- a/lunaix-os/hal/ahci/ahci.c +++ b/lunaix-os/hal/ahci/ahci.c @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -35,7 +34,7 @@ LOG_MODULE("AHCI") -DEFINE_LLIST(ahcis); +static DEFINE_LLIST(ahcis); static char sata_ifs[][20] = { "Not detected", "SATA I (1.5Gbps)", @@ -80,10 +79,9 @@ ahci_driver_init(struct ahci_driver_param* param) { struct ahci_driver* ahci_drv = vzalloc(sizeof(*ahci_drv)); struct ahci_hba* hba = &ahci_drv->hba; - ahci_drv->id = param->ahci_iv; - - isrm_set_payload(param->ahci_iv, (ptr_t)&ahcis); + ahci_drv->id = param->irq->vector; + irq_set_payload(param->irq, &ahcis); llist_append(&ahcis, &ahci_drv->ahci_drvs); hba->base = (hba_reg_t*)ioremap(param->mmio_base, param->mmio_size); diff --git a/lunaix-os/hal/ahci/ahci_pci.c b/lunaix-os/hal/ahci/ahci_pci.c index 4435da1..2bc0ad9 100644 --- a/lunaix-os/hal/ahci/ahci_pci.c +++ b/lunaix-os/hal/ahci/ahci_pci.c @@ -11,7 +11,7 @@ ahci_pci_create(struct device_def* def, morph_t* morphed) struct device* dev; struct pci_base_addr* bar6; struct ahci_driver* ahci_drv; - msi_vector_t msiv; + irq_t irq; probe = changeling_try_reveal(morphed, pci_probe_morpher); if (!probe) { @@ -29,12 +29,13 @@ ahci_pci_create(struct device_def* def, morph_t* morphed) assert(pci_capability_msi(probe)); - msiv = pci_msi_setup_simple(probe, ahci_hba_isr); + irq = pci_declare_msi_irq(ahci_hba_isr, probe); + pci_assign_msi(probe, irq, NULL); struct ahci_driver_param param = { .mmio_base = bar6->start, .mmio_size = bar6->size, - .ahci_iv = msi_vect(msiv), + .irq = irq, }; ahci_drv = ahci_driver_init(¶m); diff --git a/lunaix-os/hal/ahci/io_event.c b/lunaix-os/hal/ahci/io_event.c index 608634d..b751cdc 100644 --- a/lunaix-os/hal/ahci/io_event.c +++ b/lunaix-os/hal/ahci/io_event.c @@ -1,18 +1,18 @@ #include #include -#include #include #include LOG_MODULE("io_evt") void -ahci_hba_isr(const struct hart_state* hstate) +ahci_hba_isr(irq_t irq, const struct hart_state* hstate) { struct ahci_hba* hba; struct ahci_driver *pos, *n; - struct llist_header* ahcis = (struct llist_header*)isrm_get_payload(hstate); + struct llist_header* ahcis; + ahcis = irq_payload(irq, struct llist_header); llist_for_each(pos, n, ahcis, ahci_drvs) { if (pos->id == hart_vector_stamp(hstate)) { diff --git a/lunaix-os/hal/bus/pci.c b/lunaix-os/hal/bus/pci.c index 3052a90..0543d0a 100644 --- a/lunaix-os/hal/bus/pci.c +++ b/lunaix-os/hal/bus/pci.c @@ -107,6 +107,7 @@ __pci_add_prober(pciaddr_t loc, ptr_t pci_base, int devinfo) prober->cspace_base = pci_base; prober->intr_info = intr; prober->loc = loc; + prober->irq_domain = irq_get_domain(pci_bridge); changeling_morph_anon(pci_probers, prober->mobj, pci_probe_morpher); @@ -271,12 +272,12 @@ pci_scan() } static void -__pci_config_msi(struct pci_probe* probe, msi_vector_t msiv) +__pci_config_msi(struct pci_probe* probe, irq_t irq) { // PCI LB Spec. (Rev 3) Section 6.8 & 6.8.1 - ptr_t msi_addr = msi_addr(msiv); - u32_t msi_data = msi_data(msiv); + ptr_t msi_addr = irq->msi->wr_addr; + u32_t msi_data = irq->msi->message; pci_reg_t reg1 = pci_read_cspace(probe->cspace_base, probe->msi_loc); pci_reg_t msg_ctl = reg1 >> 16; @@ -306,39 +307,26 @@ __pci_config_msi(struct pci_probe* probe, msi_vector_t msiv) pci_write_cspace(probe->cspace_base, probe->msi_loc, reg1); } -msienv_t -pci_msi_start(struct pci_probe* probe) +irq_t +pci_declare_msi_irq(irq_servant callback, struct pci_probe* probe) { - /* - As a PCI bridge/root complex can be initialised from device tree node, - in that case, general information such as routing, rid remapping, - are vital to all msi setup of all peripherals under it. - - Therefore, a wrapper around isrm_msi_* is needed in order to - improve overall readability and usability, where the bridge - device instance that contain these information will be - automatically passed to the underlay as credential to perform - configuration. - */ - - msienv_t env; - - env = isrm_msi_start(pci_bridge); - isrm_msi_set_sideband(env, pci_requester_id(probe)); - - return env; + return irq_declare_msg(callback, probe->loc, probe->loc); } -msi_vector_t -pci_msi_setup_at(msienv_t msienv, struct pci_probe* probe, - int i, isr_cb handler) +int +pci_assign_msi(struct pci_probe* probe, irq_t irq, void* irq_spec) { - msi_vector_t msiv; + int err = 0; - msiv = isrm_msi_alloc(msienv, 0, i, handler); - __pci_config_msi(probe, msiv); + assert(irq->type == IRQ_MESSAGE); - return msiv; + err = irq_assign(probe->irq_domain, irq, irq_spec); + if (err) { + return err; + } + + __pci_config_msi(probe, irq); + return 0; } size_t @@ -532,6 +520,29 @@ EXPORT_TWIFS_PLUGIN(pci_devs, pci_build_fsmapping); /*---------- PCI 3.0 HBA device definition ----------*/ +static int +__pci_irq_install(struct irq_domain* domain, irq_t irq) +{ + struct irq_domain* parent; + int err; + + parent = domain->parent; + err = parent->ops->install_irq(parent, irq); + if (err) { + return err; + } + + if (irq->type == IRQ_MESSAGE) { + irq->msi->message = irq->vector; + } + + return 0; +} + +static struct irq_domain_ops pci_irq_ops = { + .install_irq = __pci_irq_install +}; + static int pci_register(struct device_def* def) { @@ -543,15 +554,19 @@ pci_register(struct device_def* def) static int pci_create(struct device_def* def, morph_t* obj) { - devtree_link_t devtree_node; + struct irq_domain *pci_domain; + pci_bridge = device_allocsys(NULL, NULL); +#ifdef CONFIG_USE_DEVICETREE + devtree_link_t devtree_node; devtree_node = changeling_try_reveal(obj, dt_node_morpher); - - pci_bridge = device_allocsys(NULL, NULL); device_set_devtree_node(pci_bridge, devtree_node); +#endif - register_device(pci_bridge, &def->class, "pci_bridge"); + pci_domain = irq_create_domain(pci_bridge, &pci_irq_ops); + irq_attach_domain(irq_get_default_domain(), pci_domain); + register_device(pci_bridge, &def->class, "pci_bridge"); pci_scan(); return 0; @@ -564,4 +579,4 @@ static struct device_def pci_def = { def_on_register(pci_register), def_on_create(pci_create) }; -EXPORT_DEVICE(pci3hba, &pci_def, load_sysconf); +EXPORT_DEVICE(pci3hba, &pci_def, load_onboot); diff --git a/lunaix-os/hal/char/uart/16x50.h b/lunaix-os/hal/char/uart/16x50.h index 40ebe94..4a2c8a5 100644 --- a/lunaix-os/hal/char/uart/16x50.h +++ b/lunaix-os/hal/char/uart/16x50.h @@ -2,6 +2,7 @@ #define __LUNAIX_16550_H #include +#include #include #define UART_rRxTX 0 @@ -70,7 +71,7 @@ struct uart16550 struct serial_dev* sdev; ptr_t base_addr; unsigned int base_clk; - int iv; + irq_t irq; struct { @@ -227,10 +228,10 @@ int uart_general_tx(struct serial_dev* sdev, u8_t* data, size_t len); void -uart_handle_irq_overlap(int iv, struct llist_header* ports); +uart_handle_irq_overlap(irq_t irq, struct llist_header* ports); void -uart_handle_irq(int iv, struct uart16550 *uart); +uart_handle_irq(irq_t irq, struct uart16550 *uart); static inline struct serial_dev* uart_create_serial(struct uart16550* uart, struct devclass* class, diff --git a/lunaix-os/hal/char/uart/16x50_base.c b/lunaix-os/hal/char/uart/16x50_base.c index 8b3930f..5b14445 100644 --- a/lunaix-os/hal/char/uart/16x50_base.c +++ b/lunaix-os/hal/char/uart/16x50_base.c @@ -103,13 +103,13 @@ uart_general_exec_cmd(struct serial_dev* sdev, u32_t req, va_list args) } void -uart_handle_irq_overlap(int iv, struct llist_header* ports) +uart_handle_irq_overlap(irq_t irq, struct llist_header* ports) { struct uart16550 *pos, *n; llist_for_each(pos, n, ports, local_ports) { int is = uart_intr_identify(pos); - if (iv == pos->iv && (is == UART_CHR_TIMEOUT)) { + if (irq == pos->irq && (is == UART_CHR_TIMEOUT)) { goto done; } } @@ -117,11 +117,11 @@ uart_handle_irq_overlap(int iv, struct llist_header* ports) return; done: - uart_handle_irq(iv, pos); + uart_handle_irq(irq, pos); } void -uart_handle_irq(int iv, struct uart16550 *uart) +uart_handle_irq(irq_t irq, struct uart16550 *uart) { char tmpbuf[32]; char recv; diff --git a/lunaix-os/hal/char/uart/16x50_isa.c b/lunaix-os/hal/char/uart/16x50_isa.c index 3958223..152317a 100644 --- a/lunaix-os/hal/char/uart/16x50_isa.c +++ b/lunaix-os/hal/char/uart/16x50_isa.c @@ -2,7 +2,6 @@ #include #include -#include #include "16x50.h" @@ -11,10 +10,9 @@ LOG_MODULE("16x50-isa"); static DEFINE_LLIST(com_ports); static void -com_irq_handler(const struct hart_state* hstate) +com_irq_handler(irq_t irq, const struct hart_state* hstate) { - int vector = hart_vector_stamp(hstate); - uart_handle_irq_overlap(vector, &com_ports); + uart_handle_irq_overlap(irq, &com_ports); } int @@ -25,6 +23,7 @@ isa16x50_create_once(struct device_def* def) int* irqs[] = { &irq4, &irq3, &irq4, &irq3 }; struct uart16550* uart = NULL; + struct serial_dev* sdev; ptr_t base; // COM 1...4 @@ -37,20 +36,20 @@ isa16x50_create_once(struct device_def* def) continue; } + sdev = uart_create_serial(uart, &def->class, &com_ports, "S"); + int irq = *irqs[i]; if (irq) { /* * Since these irqs are overlapped, this particular setup is needed * to avoid double-bind */ - uart->iv = isrm_bindirq(irq, com_irq_handler); + uart->irq = irq_declare_line(com_irq_handler, irq); + irq_assign(irq_owning_domain(sdev->dev), uart->irq, NULL); *((volatile int*)irqs[i]) = 0; } - - INFO("base: 0x%x, irq=%d", - base, irq, uart->iv); - - uart_create_serial(uart, &def->class, &com_ports, "S"); + + INFO("base: 0x%x, irq=%d", base, irq); } return 0; diff --git a/lunaix-os/hal/char/uart/16x50_mmio.c b/lunaix-os/hal/char/uart/16x50_mmio.c index e211625..4762ef1 100644 --- a/lunaix-os/hal/char/uart/16x50_mmio.c +++ b/lunaix-os/hal/char/uart/16x50_mmio.c @@ -1,5 +1,4 @@ #include -#include #include #include "16x50.h" diff --git a/lunaix-os/hal/char/uart/16x50_pci.c b/lunaix-os/hal/char/uart/16x50_pci.c index 20beda1..bba016f 100644 --- a/lunaix-os/hal/char/uart/16x50_pci.c +++ b/lunaix-os/hal/char/uart/16x50_pci.c @@ -1,5 +1,4 @@ #include -#include #include #include @@ -15,23 +14,14 @@ static DEFINE_LLIST(pci_ports); static void -uart_msi_irq_handler(const struct hart_state* hstate) +uart_msi_irq_handler(irq_t irq, const struct hart_state* hstate) { - int vector; struct uart16550* uart; - vector = hart_vector_stamp(hstate); - uart = (struct uart16550*)isrm_get_payload(hstate); + uart = irq_payload(irq, struct uart16550); assert(uart); - uart_handle_irq(vector, uart); -} - -static void -uart_intx_irq_handler(const struct hart_state* hstate) -{ - int vector = hart_vector_stamp(hstate); - uart_handle_irq_overlap(vector, &pci_ports); + uart_handle_irq(irq, uart); } static bool @@ -56,7 +46,7 @@ pci16x50_pci_create(struct device_def* def, morph_t* obj) struct pci_probe* probe; struct uart16550* uart; struct serial_dev* sdev; - msi_vector_t msiv; + irq_t irq; probe = changeling_reveal(obj, pci_probe_morpher); @@ -102,16 +92,16 @@ pci16x50_pci_create(struct device_def* def, morph_t* obj) sdev = uart_create_serial(uart, &def->class, &pci_ports, "PCI"); - msiv = pci_msi_setup_simple(probe, uart_msi_irq_handler); - isrm_set_payload(msi_vect(msiv), __ptr(uart)); + irq = pci_declare_msi_irq(uart_msi_irq_handler, probe); + irq_set_payload(irq, uart); + pci_assign_msi(probe, irq, NULL); - INFO("base: 0x%x (%s), irq=%d (%s)", + INFO("base: 0x%x (%s), %s", bar->start, pci_bar_mmio_space(bar) ? "mmio" : "pmio", - msi_vect(msiv), pci_capability_msi(probe) ? "msi" : "intx, re-routed"); - uart->iv = msi_vect(msiv); + uart->irq = irq; pci_bind_instance(probe, sdev->dev); } diff --git a/lunaix-os/hal/char/uart/16x50_pmio.c b/lunaix-os/hal/char/uart/16x50_pmio.c index ea550cb..3b97105 100644 --- a/lunaix-os/hal/char/uart/16x50_pmio.c +++ b/lunaix-os/hal/char/uart/16x50_pmio.c @@ -9,7 +9,6 @@ * */ #include -#include #include diff --git a/lunaix-os/hal/devtree/LBuild b/lunaix-os/hal/devtree/LBuild index 97f3109..000d52b 100644 --- a/lunaix-os/hal/devtree/LBuild +++ b/lunaix-os/hal/devtree/LBuild @@ -1,6 +1,6 @@ sources([ "dt_interrupt.c", "dt.c", - "dtm.c" + "dtm.c", "dtspec.c" ]) \ No newline at end of file diff --git a/lunaix-os/hal/devtree/devtree.h b/lunaix-os/hal/devtree/devtree.h index 1bfe891..66fe7dc 100644 --- a/lunaix-os/hal/devtree/devtree.h +++ b/lunaix-os/hal/devtree/devtree.h @@ -11,10 +11,16 @@ propeq(struct fdt_blob* fdt, fdt_loc_t loc, const char* key) return streq(fdt_prop_key(fdt, loc), key); } +static inline ptr_t +__prop_val_ptr(struct fdt_prop* prop) +{ + return __ptr(prop) + sizeof(struct fdt_prop); +} + static inline void __mkprop_ptr(fdt_loc_t loc, struct dtp_val* val) { - val->ptr_val = __ptr(loc.prop->val); + val->ptr_val = __prop_val_ptr(loc.prop); val->size = loc.prop->len; } diff --git a/lunaix-os/hal/devtree/dt.c b/lunaix-os/hal/devtree/dt.c index a426551..63286b1 100644 --- a/lunaix-os/hal/devtree/dt.c +++ b/lunaix-os/hal/devtree/dt.c @@ -121,7 +121,7 @@ fdt_find_prop(const struct fdt_blob* fdt, fdt_loc_t loc, } if (likely(val)) { - val->encoded = (dt_enc_t)loc.prop->val; + val->encoded = (dt_enc_t)__prop_val_ptr(loc.prop); val->size = loc.prop->len; } return true; @@ -152,6 +152,8 @@ fdt_memscan_begin(struct fdt_memscan* mscan, const struct fdt_blob* fdt) mscan->loc = loc; mscan->node_type = FDT_MEM_FREE; + + return true; } #define get_size(mscan, val) \ diff --git a/lunaix-os/hal/irq.c b/lunaix-os/hal/irq.c new file mode 100644 index 0000000..cee6767 --- /dev/null +++ b/lunaix-os/hal/irq.c @@ -0,0 +1,194 @@ +#include +#include +#include + +static struct irq_domain* default_domain = NULL; +static DEFINE_LLIST(irq_domains); + +static void +__default_servant(irq_t irq, const struct hart_state* state) +{ + return; +} + +struct irq_domain* +irq_create_domain(struct device* intc_dev, const struct irq_domain_ops* ops) +{ + struct irq_domain* domain; + + assert(ops->install_irq); + + domain = new_potens(potens(INT_DOMAIN), struct irq_domain); + device_grant_potens(intc_dev, potens_meta(domain)); + + btrie_init(&domain->irq_map, ilog2(8)); + llist_append(&irq_domains, &domain->list); + domain->ops = ops; + + return domain; +} + +struct irq_domain* +irq_owning_domain(struct device* dev) +{ +#ifdef CONFIG_USE_DEVICETREE + struct device* intc; + struct dtn* intr_parent; + struct potens_meta* domain_m; + + intr_parent = dev->devtree_node->intr.parent; + intc = resolve_device_morph(dt_mobj(intr_parent)); + + if (!intc) { + return NULL; + } + + domain_m = device_get_potens(intc, potens(INT_DOMAIN)); + return !domain_m ?: get_potens(domain_m, struct irq_domain); +#else + return default_domain; +#endif +} + +int +irq_attach_domain(struct irq_domain* parent, struct irq_domain* child) +{ +#ifndef CONFIG_USE_DEVICETREE + parent = parent ?: default_domain; + child->parent = parent; +#endif + return 0; +} + +static void +__irq_create_line(irq_t irq, ptr_t local_int) +{ + struct irq_line_wire *line; + + line = valloc(sizeof(*line)); + line->domain_local = local_int; + line->domain_mapped = local_int; + + irq->line = line; +} + +static void +__irq_create_msi(irq_t irq, ptr_t message) +{ + struct irq_msi_wire *msi; + + msi = valloc(sizeof(*msi)); + msi->message = message; + + irq->msi = msi; +} + +irq_t +irq_declare(enum irq_type type, irq_servant callback, ptr_t data) +{ + irq_t irq; + + irq = valloc(sizeof(*irq)); + *irq = (struct irq_object) { + .type = type, + .serve = callback ?: __default_servant, + .vector = IRQ_VECTOR_UNSET + }; + + if (type == IRQ_LINE) { + __irq_create_line(irq, data); + } + + else if (type == IRQ_MESSAGE) { + __irq_create_msi(irq, data); + } + + return irq; +} + +void +irq_revoke(irq_t irq) +{ + if (--(irq->ref) > 0) { + return; + } + vfree(irq); +} + +int +irq_assign(struct irq_domain* domain, irq_t irq, void* irq_spec) +{ + int err = 0; + if (domain->ops->map_irq) { + err = domain->ops->map_irq(domain, irq, irq_spec); + if (err) { + return err; + } + } + + /* + A domain controller may choose to forward the interrupt + (i.e., irq became transparent and belongs to the higher domain) + We allow controller decide whether to record the irq under its wing + */ + err = domain->ops->install_irq(domain, irq); + if (err) { + return err; + } + + irq->domain = domain; + return 0; +} + +irq_t +irq_find(struct irq_domain* domain, int local_irq) +{ + irq_t irq = NULL; + struct irq_domain* current; + + // Find recursively, in case of irq forwarding + + current = domain ?: default_domain; + while (current && !irq) { + irq = (irq_t)btrie_get(¤t->irq_map, local_irq); + current = irq_parent_domain(current); + } + + return irq; +} + +void +irq_record(struct irq_domain* domain, irq_t irq) +{ + irq->ref++; + btrie_set(&domain->irq_map, irq->vector, irq); +} + +void +irq_set_default_domain(struct irq_domain* domain) +{ + assert(!default_domain); + default_domain = domain; +} + +int +irq_forward_install(struct irq_domain* current, irq_t irq) +{ + struct irq_domain* parent; + + parent = irq_parent_domain(current); + + if (irq->type == IRQ_LINE) { + irq->line->domain_local = irq->line->domain_mapped; + } + + irq->domain = parent; + return parent->ops->install_irq(parent, irq); +} + +struct irq_domain* +irq_get_default_domain() +{ + assert(default_domain); + return default_domain; +} diff --git a/lunaix-os/includes/hal/ahci/ahci.h b/lunaix-os/includes/hal/ahci/ahci.h index 7eaf10d..9cf80fc 100644 --- a/lunaix-os/includes/hal/ahci/ahci.h +++ b/lunaix-os/includes/hal/ahci/ahci.h @@ -2,7 +2,7 @@ #define __LUNAIX_AHCI_H #include "hba.h" -#include +#include /* * Macro naming rule: @@ -26,7 +26,7 @@ struct ahci_driver_param { ptr_t mmio_base; size_t mmio_size; - int ahci_iv; + irq_t irq; }; void @@ -59,6 +59,6 @@ struct ahci_driver* ahci_driver_init(struct ahci_driver_param* param); void -ahci_hba_isr(const struct hart_state* hstate); +ahci_hba_isr(irq_t irq, const struct hart_state* hstate); #endif /* __LUNAIX_AHCI_H */ diff --git a/lunaix-os/includes/hal/devtree.h b/lunaix-os/includes/hal/devtree.h index e7e0cf3..111617e 100644 --- a/lunaix-os/includes/hal/devtree.h +++ b/lunaix-os/includes/hal/devtree.h @@ -1,6 +1,7 @@ #ifndef __LUNAIX_DEVTREE_H #define __LUNAIX_DEVTREE_H +#ifdef CONFIG_USE_DEVICETREE #include #include #include @@ -46,14 +47,14 @@ struct dtp_val { union { - union { - const char* str_val; - const char* str_lst; - }; ptr_t ptr_val; dt_enc_t encoded; union dtp_baseval* ref; + union { + const char* str_val; + const char* str_lst; + }; }; unsigned int size; }; @@ -669,7 +670,7 @@ static inline void dtpi_init_empty(struct dtpropi* dtpi) { *dtpi = (struct dtpropi) { - .prop = { 0, 0 }, + .prop = { {0}, 0 }, .loc = 0 }; } @@ -727,4 +728,5 @@ dtpi_next_val(struct dtpropi* dtpi, struct dtp_val* val, int cells) return true; } +#endif #endif /* __LUNAIX_DEVTREE_H */ diff --git a/lunaix-os/includes/hal/devtreem.h b/lunaix-os/includes/hal/devtreem.h index 2b0904d..d235cd7 100644 --- a/lunaix-os/includes/hal/devtreem.h +++ b/lunaix-os/includes/hal/devtreem.h @@ -13,7 +13,7 @@ struct device; typedef struct dtn* devtree_link_t; -#define dt_node_morpher morphable_attrs(dt_node, mobj) +#define dt_node_morpher morphable_attrs(dtn, mobj) struct dtm_driver_info { diff --git a/lunaix-os/includes/hal/irq.h b/lunaix-os/includes/hal/irq.h new file mode 100644 index 0000000..41be4b0 --- /dev/null +++ b/lunaix-os/includes/hal/irq.h @@ -0,0 +1,180 @@ +#ifndef __LUNAIX_IRQ_H +#define __LUNAIX_IRQ_H + +#include +#include +#include +#include + +#define IRQ_VECTOR_UNSET ((unsigned)-1) + +struct irq_domain; +typedef struct irq_object* irq_t; +typedef void (*irq_servant)(irq_t, const struct hart_state*); + +struct irq_domain_ops +{ + int + (*install_irq)(struct irq_domain*, irq_t); + + int + (*map_irq)(struct irq_domain*, irq_t, void* irq_extra); + + int + (*remove_irq)(struct irq_domain*, irq_t); +}; + +struct irq_domain +{ + POTENS_META; + + struct llist_header list; + + struct irq_domain* parent; + struct btrie irq_map; + const struct irq_domain_ops* ops; + void* object; +}; + +enum irq_type +{ + IRQ_DIRECT, + IRQ_LINE, + IRQ_MESSAGE +}; + +struct irq_line_wire +{ + ptr_t domain_local; + ptr_t domain_mapped; +}; + +struct irq_msi_wire +{ + ptr_t message; + ptr_t sideband; + ptr_t wr_addr; +}; + +struct irq_object +{ + enum irq_type type; + unsigned int vector; + + union { + struct irq_line_wire* line; + struct irq_msi_wire* msi; + }; + + irq_servant serve; + void* payload; + + struct irq_domain* domain; + int ref; +}; + +struct irq_domain* +irq_create_domain(struct device* intc_dev, const struct irq_domain_ops* ops); + +struct irq_domain* +irq_owning_domain(struct device* dev); + +int +irq_attach_domain(struct irq_domain* parent, struct irq_domain* child); + +irq_t +irq_declare(enum irq_type, irq_servant, ptr_t); + +void +irq_revoke(irq_t); + +int +irq_assign(struct irq_domain* domain, irq_t, void*); + +irq_t +irq_find(struct irq_domain* domain, int local_irq); + +void +irq_record(struct irq_domain* domain, irq_t irq); + +void +irq_set_default_domain(struct irq_domain*); + +struct irq_domain* +irq_get_default_domain(); + +int +irq_forward_install(struct irq_domain* current, irq_t irq); + +static inline void +irq_serve(irq_t irq, struct hart_state* state) +{ + irq->serve(irq, state); +} + +static inline void +irq_set_servant(irq_t irq, irq_servant callback) +{ + irq->serve = callback; +} + +static inline void +irq_bind_vector(irq_t irq, int vector) +{ + irq->vector = vector; +} + +static inline void +irq_set_payload(irq_t irq, void* payload) +{ + irq->payload = payload; +} + +static inline void +irq_set_domain_object(struct irq_domain* domain, void* obj) +{ + domain->object = obj; +} + +#define irq_payload(irq, type) ((type*)(irq)->payload) +#define irq_domain_obj(domain, type) ((type*)(domain)->object) + +static inline irq_t +irq_declare_line(irq_servant callback, int local_irq) +{ + return irq_declare(IRQ_LINE, callback, (int)local_irq); +} + +static inline irq_t +irq_declare_msg(irq_servant callback, + ptr_t message, ptr_t sideband) +{ + irq_t irq; + irq = irq_declare(IRQ_MESSAGE, callback, message); + irq->msi->sideband = sideband; + + return irq; +} + +static inline irq_t +irq_declare_direct(irq_servant callback) +{ + return irq_declare(IRQ_DIRECT, callback, 0); +} + +static inline struct irq_domain* +irq_get_domain(struct device* maybe_intc) +{ + struct potens_meta* domain_m; + + domain_m = device_get_potens(maybe_intc, potens(INT_DOMAIN)); + return domain_m ? get_potens(domain_m, struct irq_domain) : NULL; +} + +static inline struct irq_domain* +irq_parent_domain(struct irq_domain* domain) +{ + return domain->parent; +} + +#endif /* __LUNAIX_IRQ_H */ diff --git a/lunaix-os/includes/hal/pci.h b/lunaix-os/includes/hal/pci.h index 37815fe..22b3dd9 100644 --- a/lunaix-os/includes/hal/pci.h +++ b/lunaix-os/includes/hal/pci.h @@ -8,7 +8,7 @@ #include #include -#include +#include "irq.h" #define PCI_VENDOR_INVLD 0xffff @@ -86,6 +86,7 @@ struct pci_probe struct pci_base_addr bar[6]; struct device* bind; + struct irq_domain* irq_domain; }; #define pci_probe_morpher morphable_attrs(pci_probe, mobj) @@ -115,6 +116,12 @@ pci_register_driver(struct device_def* def, pci_id_checker_t checker); size_t pci_bar_sizing(struct pci_probe* probe, u32_t* bar_out, u32_t bar_num); +irq_t +pci_declare_msi_irq(irq_servant callback, struct pci_probe* probe); + +int +pci_assign_msi(struct pci_probe* probe, irq_t irq, void* irq_spec); + /** * @brief Bind an abstract device instance to the pci device * @@ -128,32 +135,6 @@ pci_bind_instance(struct pci_probe* probe, struct device* dev) } -msienv_t -pci_msi_start(struct pci_probe* probe); - -msi_vector_t -pci_msi_setup_at(msienv_t msienv, struct pci_probe* probe, - int i, isr_cb handler); - -static inline void -pci_msi_done(msienv_t env) -{ - isrm_msi_done(env); -} - -static inline msi_vector_t -pci_msi_setup_simple(struct pci_probe* probe, isr_cb handler) -{ - msienv_t env; - msi_vector_t msiv; - - env = pci_msi_start(probe); - msiv = pci_msi_setup_at(env, probe, 0, handler); - pci_msi_done(env); - - return msiv; -} - int pci_bind_driver(struct pci_registry* reg); diff --git a/lunaix-os/includes/listings/changeling.lst b/lunaix-os/includes/listings/changeling.lst index aecd7d4..62253e9 100644 --- a/lunaix-os/includes/listings/changeling.lst +++ b/lunaix-os/includes/listings/changeling.lst @@ -4,4 +4,5 @@ morphable(pci_probe), morphable(device_meta), morphable(device_cat), morphable(device_alias), -morphable(device), \ No newline at end of file +morphable(device), +morphable(irq_object), \ No newline at end of file diff --git a/lunaix-os/includes/listings/device_potens.lst b/lunaix-os/includes/listings/device_potens.lst index 9534b9a..9b80f90 100644 --- a/lunaix-os/includes/listings/device_potens.lst +++ b/lunaix-os/includes/listings/device_potens.lst @@ -17,4 +17,10 @@ potens(HWTIMER), * @brief RTC capability. * */ -potens(HWRTC), \ No newline at end of file +potens(HWRTC), + +/** + * @brief Interrupt controller (domain) capability + * + */ +potens(INT_DOMAIN), \ No newline at end of file diff --git a/lunaix-os/includes/lunaix/device.h b/lunaix-os/includes/lunaix/device.h index f1ce4d0..7a469a1 100644 --- a/lunaix-os/includes/lunaix/device.h +++ b/lunaix-os/includes/lunaix/device.h @@ -353,11 +353,13 @@ device_create(struct device* dev, struct device* device_alloc(struct device_meta* parent, u32_t type, void* underlay); +#ifdef CONFIG_USE_DEVICETREE static inline void device_set_devtree_node(struct device* dev, devtree_link_t node) { dev->devtree_node = node; } +#endif static inline struct device* must_inline device_allocsys(struct device_meta* parent, void* underlay) diff --git a/lunaix-os/includes/lunaix/ds/btrie.h b/lunaix-os/includes/lunaix/ds/btrie.h index bcf0250..d24cf84 100644 --- a/lunaix-os/includes/lunaix/ds/btrie.h +++ b/lunaix-os/includes/lunaix/ds/btrie.h @@ -6,6 +6,9 @@ #define BTRIE_BITS 4 +/** + * key-sorted prefix tree + */ struct btrie { struct btrie_node* btrie_root; @@ -14,12 +17,13 @@ struct btrie struct btrie_node { - struct llist_header children; - struct llist_header siblings; struct llist_header nodes; struct btrie_node* parent; unsigned long index; void* data; + + struct btrie_node** children; + int children_cnt; }; void @@ -28,9 +32,21 @@ btrie_init(struct btrie* btrie, unsigned int order); void* btrie_get(struct btrie* root, unsigned long index); +/** + * Set an object into btrie tree at given location, + * override if another object is already present. + */ void btrie_set(struct btrie* root, unsigned long index, void* data); +/** + * Map an object into btrie tree, return the index the object + * mapped to + */ +unsigned long +btrie_map(struct btrie* root, + unsigned long start, unsigned long end, void* data); + void* btrie_remove(struct btrie* root, unsigned long index); diff --git a/lunaix-os/kernel/ds/btrie.c b/lunaix-os/kernel/ds/btrie.c index 72758fb..8971759 100644 --- a/lunaix-os/kernel/ds/btrie.c +++ b/lunaix-os/kernel/ds/btrie.c @@ -13,45 +13,124 @@ #include #include -#define BTRIE_INSERT 1 +enum btrie_query_mode { + BTRIE_FIND, + BTRIE_FIND_PARENT, + BTRIE_INSERT +}; -struct btrie_node* -__btrie_traversal(struct btrie* root, unsigned long index, int options) +#define remove_visit_flag(node) ((struct btrie_node*)(__ptr(node) & ~1)) + +static inline void +__btrie_addchild(struct btrie* root, + struct btrie_node* parent, struct btrie_node* child) +{ + if (unlikely(!parent->children)) { + parent->children = vcalloc(sizeof(parent), 1 << root->order); + } + + parent->children_cnt++; + parent->children[child->index] = child; +} + +static inline struct btrie_node* +__btrie_get_child(struct btrie_node* node, int index) +{ + if (unlikely(!node || !node->children)) { + return NULL; + } + + return remove_visit_flag(node->children[index]); +} + +static inline bool +__btrie_child_visited(struct btrie_node* node, int index) +{ + if (unlikely(!node || !node->children)) { + return false; + } + + return !!(__ptr(node->children[index]) & 1); +} + +static inline void +__btrie_visit_child(struct btrie_node* node, int index) +{ + if (unlikely(!node || !node->children)) { + return; + } + + node->children[index] + = (struct btrie_node*)(__ptr(node->children[index]) | 1); +} + +static inline void +__btrie_unvisit_child(struct btrie_node* node, int index) +{ + if (unlikely(!node || !node->children)) { + return; + } + + node->children[index] = remove_visit_flag(node->children[index]); +} + +static inline void +__btrie_free_node(struct btrie_node* node) +{ + vfree_safe(node->children); + vfree(node); +} + +static inline bool +__full_node(struct btrie* root, struct btrie_node* node) +{ + return node->children_cnt == 1 << root->order; +} + +static inline struct btrie_node* +__btrie_create(struct btrie* root, struct btrie_node* parent, int index) { - unsigned long lz; - unsigned long bitmask; - unsigned long i = 0; - struct btrie_node* tree = root->btrie_root; + struct btrie_node* node; - lz = index ? ICEIL(msbitl - clzl(index), root->order) : 0; + node = vzalloc(sizeof(struct btrie_node)); + node->index = index; + node->parent = parent; + + if (likely(parent)) { + llist_append(&root->btrie_root->nodes, &node->nodes); + __btrie_addchild(root, parent, node); + } + + return node; +} + +static struct btrie_node* +__btrie_traversal(struct btrie* root, + unsigned long key, enum btrie_query_mode mode) +{ + unsigned long lz, bitmask, i = 0; + struct btrie_node *subtree, *tree = root->btrie_root; + + lz = !key ? 0 : (msbitl - clzl(key)) / root->order; lz = lz * root->order; bitmask = ((1 << root->order) - 1) << lz; - // Time complexity: O(log_2(log_2(N))) where N is the index to lookup + // Time complexity: O(log_2(log_2(N))) where N is the key to lookup while (bitmask && tree) { - i = (index & bitmask) >> lz; - struct btrie_node *subtree = 0, *pos, *n; - - llist_for_each(pos, n, &tree->children, siblings) - { - if (pos->index == i) { - subtree = pos; - break; - } - } + i = (key & bitmask) >> lz; + subtree = __btrie_get_child(tree, i); - if (!subtree && (options & BTRIE_INSERT)) { - struct btrie_node* new_tree = vzalloc(sizeof(struct btrie_node)); - new_tree->index = i; - new_tree->parent = tree; - llist_init_head(&new_tree->children); + if (!lz && mode == BTRIE_FIND_PARENT) { + break; + } - llist_append(&tree->children, &new_tree->siblings); - llist_append(&root->btrie_root->nodes, &new_tree->nodes); - tree = new_tree; - } else { + if (!subtree && (mode != BTRIE_FIND)) { + tree = __btrie_create(root, tree, i); + } + else { tree = subtree; } + bitmask = bitmask >> root->order; lz -= root->order; } @@ -59,29 +138,149 @@ __btrie_traversal(struct btrie* root, unsigned long index, int options) return tree; } +#define check_partial(loc, start, end, mask) \ + (((long)(start) - (long)mask - 1) <= (long)loc && loc < end) + +static inline struct btrie_node* +__get_immediate_node(struct btrie* tree, struct btrie_node *root, + unsigned long start, unsigned long end, unsigned long loc) +{ + unsigned int index; + unsigned long mask; + struct btrie_node *node; + + mask = (1UL << tree->order) - 1; + index = loc & mask; + for (unsigned long i = 0; i <= mask; ++i, index = (index + 1) & mask) + { + loc = (loc & ~mask) + index; + node = __btrie_get_child(root, index); + + if (loc < start || loc >= end) { + continue; + } + + if (!node) { + return __btrie_create(tree, root, index); + } + + if (!node->data) { + return node; + } + } + + return NULL; +} + +static struct btrie_node* +__btrie_find_free(struct btrie* tree, struct btrie_node *root, + unsigned long start, unsigned long end, unsigned long loc) +{ + unsigned long mask, next_loc; + struct btrie_node *node, *found; + + if (!root) return NULL; + + mask = (1UL << tree->order) - 1; + + __btrie_visit_child(root->parent, root->index); + + if (!__full_node(tree, root)) { + found = __get_immediate_node(tree, root, start, end, loc); + if (found) goto done; + } + + for (unsigned int i = 0; i <= mask; i++) + { + next_loc = ((loc & ~mask) + i) << tree->order; + + if (!next_loc || !check_partial(next_loc, start, end, mask)) { + continue; + } + + if (__btrie_child_visited(root, i)) { + continue; + } + + node = __btrie_get_child(root, i); + node = node ?: __btrie_create(tree, root, i); + + found = __btrie_find_free(tree, node, start, end, next_loc); + + if (found) { + goto done; + } + } + + loc >>= tree->order; + found = __btrie_find_free(tree, root->parent, start, end, loc + 1); + +done: + __btrie_unvisit_child(root->parent, root->index); + return found; +} + +static unsigned long +__btrie_alloc_slot(struct btrie* tree, struct btrie_node **slot, + unsigned long start, unsigned long end) +{ + unsigned int od; + unsigned long result, mask; + struct btrie_node *found, *node; + + od = 0; + mask = (1 << od) - 1; + found = tree->btrie_root; + result = 0; + + if (!start && !__btrie_get_child(found, 0)) { + *slot = __btrie_create(tree, found, 0); + return 0; + } + + found = __btrie_traversal(tree, start, BTRIE_FIND_PARENT); + found = __btrie_find_free(tree, found, start, end, start); + + node = found; + while (node) + { + result |= node->index << od; + od += tree->order; + node = node->parent; + } + + *slot = found; + return found ? result : -1UL; +} + void btrie_init(struct btrie* btrie, unsigned int order) { - btrie->btrie_root = vzalloc(sizeof(struct btrie_node)); - llist_init_head(&btrie->btrie_root->nodes); - llist_init_head(&btrie->btrie_root->children); + btrie->btrie_root = __btrie_create(btrie, NULL, 0); btrie->order = order; + + llist_init_head(&btrie->btrie_root->nodes); } void* btrie_get(struct btrie* root, unsigned long index) { - struct btrie_node* node = __btrie_traversal(root, index, 0); + struct btrie_node* node; + + node = __btrie_traversal(root, index, BTRIE_FIND); if (!node) { return NULL; } + return node->data; } void btrie_set(struct btrie* root, unsigned long index, void* data) { - struct btrie_node* node = __btrie_traversal(root, index, BTRIE_INSERT); + struct btrie_node* node; + + node = __btrie_traversal(root, index, BTRIE_INSERT); node->data = data; } @@ -90,29 +289,53 @@ __btrie_rm_recursive(struct btrie_node* node) { struct btrie_node* parent = node->parent; - if (parent) { - llist_delete(&node->siblings); - llist_delete(&node->nodes); - vfree(node); - if (llist_empty(&parent->children) && !parent->data) { - __btrie_rm_recursive(parent); - } + if (!parent) { + return; + } + + parent->children[node->index] = NULL; + parent->children_cnt--; + __btrie_free_node(node); + + if (!parent->children_cnt && !parent->data) { + __btrie_rm_recursive(parent); } } +unsigned long +btrie_map(struct btrie* root, + unsigned long start, unsigned long end, void* data) +{ + struct btrie_node* node = NULL; + unsigned long alloced; + + alloced = __btrie_alloc_slot(root, &node, start, end); + + if (!node) + return -1; + + node->data = data; + return alloced; +} + void* btrie_remove(struct btrie* root, unsigned long index) { - struct btrie_node* node = __btrie_traversal(root, index, 0); + void* data; + struct btrie_node* node; + + node = __btrie_traversal(root, index, BTRIE_FIND); if (!node) { return 0; } - void* data = node->data; - if (!llist_empty(&node->children)) { + + data = node->data; + if (!node->children_cnt) { node->data = NULL; } else { __btrie_rm_recursive(node); } + return data; } @@ -122,8 +345,8 @@ btrie_release(struct btrie* tree) struct btrie_node *pos, *n; llist_for_each(pos, n, &tree->btrie_root->nodes, nodes) { - vfree(pos); + __btrie_free_node(pos); } - vfree(tree->btrie_root); + __btrie_free_node(tree->btrie_root); } \ No newline at end of file diff --git a/lunaix-os/kernel/process/sched.c b/lunaix-os/kernel/process/sched.c index 31775bf..e9f61b3 100644 --- a/lunaix-os/kernel/process/sched.c +++ b/lunaix-os/kernel/process/sched.c @@ -20,8 +20,6 @@ #include #include -#include - #include struct thread empty_thread_obj; @@ -221,7 +219,6 @@ schedule() sched_ctx.procs_index = to_check->process->pid; done: - isrm_notify_eos(0); run(to_check); fail("unexpected return from scheduler"); diff --git a/lunaix-os/tests/includes/testing/basic.h b/lunaix-os/tests/includes/testing/basic.h index a81dc4f..ea2261b 100644 --- a/lunaix-os/tests/includes/testing/basic.h +++ b/lunaix-os/tests/includes/testing/basic.h @@ -13,35 +13,44 @@ struct test_context struct { int passed; int failed; + int skipped; }; - int countings[2]; + int countings[3]; }; union { struct { int total_passed; int total_failed; + int total_skipped; }; - int total_countings[2]; + int total_countings[3]; }; } stats; }; #define fmt_passed "[\x1b[32;49mPASS\x1b[0m]" #define fmt_failed "[\x1b[31;49mFAIL\x1b[0m]" +#define fmt_skiped "[\x1b[33;49mSKIP\x1b[0m]" #define active_context \ ({ extern struct test_context* __test_ctx; __test_ctx; }) #define _expect(expr, act, exp, type_fmt) \ do { \ + if(should_skip_test()) { \ + printf(" @%s:%03d ....... ", __FILE__, __LINE__); \ + printf(fmt_skiped "\n"); \ + active_context->stats.skipped++; \ + break; \ + } \ + \ int failed = !(expr); \ - printf(" @%s:%03d ....... ", __FILE__, __LINE__); \ - if (failed) \ + if (failed) { \ + printf(" @%s:%03d ....... ", __FILE__, __LINE__); \ printf(fmt_failed " (expect: " type_fmt ", got: " type_fmt ")\n",\ exp, act); \ - else \ - printf(fmt_passed "\n"); \ + } \ active_context->stats.countings[failed]++; \ } while(0) @@ -88,4 +97,10 @@ end_testcase(); void run_test(int argc, const char* argv[]); +static inline int +should_skip_test() +{ + return active_context->stats.failed; +} + #endif /* __COMMON_TEST_BASIC_H */ diff --git a/lunaix-os/tests/includes/testing/memchk.h b/lunaix-os/tests/includes/testing/memchk.h new file mode 100644 index 0000000..77db92d --- /dev/null +++ b/lunaix-os/tests/includes/testing/memchk.h @@ -0,0 +1,24 @@ +#ifndef __COMMON_TEST_MEMCHK_H +#define __COMMON_TEST_MEMCHK_H + +struct valloc_stats +{ + unsigned long alloced; + unsigned long freed; + unsigned long nr_vfree_calls; + + unsigned int nr_valloc_calls; +}; + +extern struct valloc_stats valloc_stat; + +void +memchk_log_alloc(unsigned long addr, unsigned long size); + +void +memchk_log_free(unsigned long addr); + +void +memchk_print_stats(); + +#endif /* __COMMON_TEST_MEMCHK_H */ diff --git a/lunaix-os/tests/shared/framework.c b/lunaix-os/tests/shared/framework.c index ad1aebc..e8adb43 100644 --- a/lunaix-os/tests/shared/framework.c +++ b/lunaix-os/tests/shared/framework.c @@ -1,4 +1,5 @@ #include +#include #include struct test_context* __test_ctx; @@ -13,11 +14,15 @@ main(int argc, const char* argv[]) run_test(argc, argv); printf( - "All test done: %d passed, %d failed\n", + "All test done: %d passed, %d failed, %d skipped\n\n", __test_ctx->stats.total_passed, - __test_ctx->stats.total_failed + __test_ctx->stats.total_failed, + __test_ctx->stats.total_skipped ); - printf("************\n\n"); + + memchk_print_stats(); + + printf("\n************\n\n"); exit(__test_ctx->stats.total_failed > 0); } @@ -33,6 +38,7 @@ begin_testcase(const char* name) __test_ctx->name = name; __test_ctx->stats.countings[0] = 0; __test_ctx->stats.countings[1] = 0; + __test_ctx->stats.countings[2] = 0; printf("%s\n", name); } @@ -40,11 +46,14 @@ begin_testcase(const char* name) void end_testcase() { - printf("..... passed: %d, failed: %d\n\n", - __test_ctx->stats.passed, __test_ctx->stats.failed); + printf("..... passed: %d, failed: %d, %d skipped\n\n", + __test_ctx->stats.passed, + __test_ctx->stats.failed, + __test_ctx->stats.skipped); __test_ctx->stats.total_passed += __test_ctx->stats.passed; __test_ctx->stats.total_failed += __test_ctx->stats.failed; + __test_ctx->stats.total_skipped += __test_ctx->stats.skipped; __test_ctx->name = NULL; } \ No newline at end of file diff --git a/lunaix-os/tests/shared/makefile b/lunaix-os/tests/shared/makefile index 0484be2..6d38283 100644 --- a/lunaix-os/tests/shared/makefile +++ b/lunaix-os/tests/shared/makefile @@ -9,12 +9,9 @@ CFLAGS += -idirafter $(lunaix-root)/includes \ -I $(test-root)/includes \ -Wno-discarded-qualifiers \ -Wno-scalar-storage-order \ - -g + -Werror \ + -g \ + -D__off_t_defined - -%.o: %.c - $(call status,CC,$(@F)) - @$(CC) $(CFLAGS) -c $< -o $@ - - -obj-shared := $(test-shared-root)/framework.o +obj-shared := $(test-shared-root)/framework.o \ + $(test-shared-root)/memchk.o diff --git a/lunaix-os/tests/shared/memchk.c b/lunaix-os/tests/shared/memchk.c new file mode 100644 index 0000000..b695201 --- /dev/null +++ b/lunaix-os/tests/shared/memchk.c @@ -0,0 +1,72 @@ +#include +#include + +#include + +extern void *malloc(size_t); +extern void *calloc(size_t, size_t); +extern void free(void*); + +struct valloc_stats valloc_stat = { }; +static DEFINE_LLIST(records); + +struct addr_record { + struct llist_header link; + unsigned long addr; + unsigned long size; +}; + +void +memchk_log_alloc(unsigned long addr, unsigned long size) +{ + valloc_stat.alloced += size; + valloc_stat.nr_valloc_calls++; + + struct addr_record *record; + + record = malloc(sizeof(struct addr_record)); + record->addr = addr; + record->size = size; + + llist_append(&records, &record->link); +} + +void +memchk_log_free(unsigned long addr) +{ + valloc_stat.nr_vfree_calls++; + + struct addr_record *pos, *n; + llist_for_each(pos, n, &records, link) + { + if (pos->addr == addr) { + valloc_stat.freed += pos->size; + llist_delete(&pos->link); + + free(pos); + return; + } + } + + printf("[\x1b[33;49mWARN\x1b[0m] freeing undefined pointer: 0x%lx\n", addr); +} + + +void +memchk_print_stats() +{ + long leaked; + + leaked = valloc_stat.alloced - valloc_stat.freed; + printf("valloc() statistics:\n"); + printf(" allocated: %lu bytes\n", valloc_stat.alloced); + printf(" freed: %lu bytes\n", valloc_stat.freed); + printf(" leaked: %lu bytes\n", leaked); + printf(" vfree_call: %u times\n", valloc_stat.nr_vfree_calls); + printf(" valloc_call: %u times\n", valloc_stat.nr_valloc_calls); + + if (leaked) + { + printf("[\x1b[33;49mWARN\x1b[0m] memory leakage detected\n"); + } +} \ No newline at end of file diff --git a/lunaix-os/tests/shared/mkobj.mkinc b/lunaix-os/tests/shared/mkobj.mkinc new file mode 100644 index 0000000..edbc75f --- /dev/null +++ b/lunaix-os/tests/shared/mkobj.mkinc @@ -0,0 +1,3 @@ +%.o: %.c + $(call status,CC,$(@F)) + @$(CC) $(CFLAGS) -c $< -o $@ diff --git a/lunaix-os/tests/units/.gitignore b/lunaix-os/tests/units/.gitignore new file mode 100644 index 0000000..70105d4 --- /dev/null +++ b/lunaix-os/tests/units/.gitignore @@ -0,0 +1 @@ +**.test \ No newline at end of file diff --git a/lunaix-os/tests/units/btrie/dut/btrie.c b/lunaix-os/tests/units/btrie/dut/btrie.c new file mode 120000 index 0000000..3abae1b --- /dev/null +++ b/lunaix-os/tests/units/btrie/dut/btrie.c @@ -0,0 +1 @@ +../../../../kernel/ds/btrie.c \ No newline at end of file diff --git a/lunaix-os/tests/units/btrie/makefile b/lunaix-os/tests/units/btrie/makefile new file mode 100644 index 0000000..7a4f83b --- /dev/null +++ b/lunaix-os/tests/units/btrie/makefile @@ -0,0 +1,3 @@ +obj-dut := dut/btrie.o + +include units_build.mkinc \ No newline at end of file diff --git a/lunaix-os/tests/units/btrie/test-alloc.c b/lunaix-os/tests/units/btrie/test-alloc.c new file mode 100644 index 0000000..92439d9 --- /dev/null +++ b/lunaix-os/tests/units/btrie/test-alloc.c @@ -0,0 +1,201 @@ +#include +#include +#include +#include + +#define WIDTH 8 + +static void no_inline +__alloc_simple() +{ + struct btrie tree; + struct btrie_node *root; + btrie_init(&tree, ilog2(WIDTH)); + + expect_long(btrie_map(&tree, 0, 100, (void*)1), 0); + expect_long(btrie_map(&tree, 0, 100, (void*)2), 1); + expect_long(btrie_map(&tree, 0, 100, (void*)3), 2); + expect_long(btrie_map(&tree, 0, 100, (void*)4), 3); + + root = tree.btrie_root; + expect_notnull(root->children); + expect_int(root->children_cnt, 4); + + for (int i = 0; i < 4; i++) + { + expect_notnull(root->children[i]); + expect_int(root->children[i]->index, i); + expect_ulong((ptr_t)root->children[i]->data, i + 1); + } + + for (int i = 4; i < WIDTH; i++) + { + expect_null(root->children[i]); + } + + btrie_release(&tree); +} + +static void no_inline +__alloc_edge() +{ + struct btrie tree; + struct btrie_node *root; + btrie_init(&tree, ilog2(WIDTH)); + + expect_long(btrie_map(&tree, 7, 100, (void*)1), 7); + expect_long(btrie_map(&tree, 7, 100, (void*)2), 8); + expect_long(btrie_map(&tree, 7, 100, (void*)3), 9); + expect_long(btrie_map(&tree, 7, 100, (void*)4), 10); + + root = tree.btrie_root; + expect_notnull(root->children); + expect_int(root->children_cnt, 2); + + expect_notnull(root->children[7]); + expect_int(root->children[7]->index, 7); + expect_ulong((ptr_t)root->children[7]->data, 1); + + expect_notnull(root->children[1]); + root = root->children[1]; + + for (int i = 0; i < 3; i++) + { + expect_notnull(root->children[i]); + expect_int(root->children[i]->index, i); + expect_ulong((ptr_t)root->children[i]->data, i + 2); + } + + btrie_release(&tree); +} + +static void no_inline +__alloc_narrow() +{ + struct btrie tree; + struct btrie_node *root; + btrie_init(&tree, ilog2(WIDTH)); + + expect_long(btrie_map(&tree, 4, 7, (void*)1), 4); + expect_long(btrie_map(&tree, 4, 7, (void*)2), 5); + expect_long(btrie_map(&tree, 4, 7, (void*)3), 6); + expect_long(btrie_map(&tree, 4, 7, (void*)4), -1); + + root = tree.btrie_root; + expect_notnull(root->children); + expect_int(root->children_cnt, 3); + + for (int i = 0; i < 4; ++i) + { + expect_null(root->children[i]); + } + + for (int i = 4, j = 1; i < WIDTH - 1; ++i, ++j) + { + expect_notnull(root->children[i]); + expect_int(root->children[i]->index, i); + expect_ulong((ptr_t)root->children[i]->data, j); + } + + btrie_release(&tree); +} + +static void no_inline +__alloc_narrow_partial() +{ + struct btrie tree; + struct btrie_node *root; + btrie_init(&tree, ilog2(WIDTH)); + + expect_long(btrie_map(&tree, 15, 17, (void*)1), 15); + expect_long(btrie_map(&tree, 15, 17, (void*)2), 16); + expect_long(btrie_map(&tree, 15, 17, (void*)3), -1); + + root = tree.btrie_root; + expect_notnull(root->children); + expect_int(root->children_cnt, 2); + + // check left subtree + + root = root->children[1]; + expect_notnull(root); + expect_int(root->children_cnt, 1); + + int i = 0; + for (; i < WIDTH - 1; ++i) + { + expect_null(root->children[i]); + } + + // i = WIDTH - 1 + expect_notnull(root->children[i]); + expect_int(root->children[i]->index, i); + expect_ulong((ptr_t)root->children[i]->data, 1); + + // check right subtree + + root = tree.btrie_root; + root = root->children[2]; + expect_notnull(root); + expect_int(root->children_cnt, 1); + + i = 0; + expect_notnull(root->children[i]); + expect_int(root->children[i]->index, i); + expect_ulong((ptr_t)root->children[i]->data, 2); + + for (i++; i < WIDTH; ++i) + { + expect_null(root->children[i]); + } + + btrie_release(&tree); +} + +static void no_inline +__alloc_dense() +{ + int mis_alloc = 0; + struct btrie tree; + btrie_init(&tree, ilog2(WIDTH)); + + for (size_t i = 0; i < 1000; i++) + { + if (btrie_map(&tree, 0, 1001, (void*)i+1) == -1UL) + { + mis_alloc++; + } + } + + expect_int(mis_alloc, 0); + btrie_release(&tree); +} + +static void no_inline +__alloc_retrive() +{ + struct btrie tree; + struct btrie_node *root; + btrie_init(&tree, ilog2(WIDTH)); + + expect_long(btrie_map(&tree, 4, 7, (void*)1), 4); + expect_long(btrie_map(&tree, 4, 7, (void*)2), 5); + expect_long(btrie_map(&tree, 4, 7, (void*)3), 6); + + expect_ulong(__ptr(btrie_get(&tree, 6)), 3); + expect_ulong(__ptr(btrie_get(&tree, 5)), 2); + expect_ulong(__ptr(btrie_get(&tree, 4)), 1); + + btrie_release(&tree); +} + +void +run_test(int argc, const char* argv[]) +{ + testcase("simple_alloc", __alloc_simple()); + testcase("simple_edge", __alloc_edge()); + testcase("simple_narrow", __alloc_narrow()); + testcase("narrow_partial", __alloc_narrow_partial()); + testcase("alloc_dense", __alloc_dense()); + testcase("alloc_get", __alloc_retrive()); +} \ No newline at end of file diff --git a/lunaix-os/tests/units/btrie/tests.txt b/lunaix-os/tests/units/btrie/tests.txt new file mode 100644 index 0000000..a85a68a --- /dev/null +++ b/lunaix-os/tests/units/btrie/tests.txt @@ -0,0 +1 @@ +alloc diff --git a/lunaix-os/tests/units/device-tree/.gitignore b/lunaix-os/tests/units/device-tree/.gitignore index 06e925a..662a34e 100644 --- a/lunaix-os/tests/units/device-tree/.gitignore +++ b/lunaix-os/tests/units/device-tree/.gitignore @@ -1,3 +1,2 @@ test -*.dtb -*.test \ No newline at end of file +*.dtb \ No newline at end of file diff --git a/lunaix-os/tests/units/device-tree/common.h b/lunaix-os/tests/units/device-tree/common.h index 94c2370..0eeb508 100644 --- a/lunaix-os/tests/units/device-tree/common.h +++ b/lunaix-os/tests/units/device-tree/common.h @@ -1,7 +1,6 @@ #ifndef __DTTEST_COMMON_H #define __DTTEST_COMMON_H -#define __off_t_defined #include "dut/devtree.h" #include diff --git a/lunaix-os/tests/units/device-tree/makefile b/lunaix-os/tests/units/device-tree/makefile index 4d9d530..b008c5f 100644 --- a/lunaix-os/tests/units/device-tree/makefile +++ b/lunaix-os/tests/units/device-tree/makefile @@ -1,38 +1,18 @@ -include test_build.mkinc +obj-dut := dut/dt_interrupt.o \ + dut/dt.o \ + dut/dtspec.o \ + dut/changeling.o -tests := $(shell cat tests.txt) - -obj = dut/dt_interrupt.o \ - dut/dt.o \ - dut/dtspec.o \ - dut/changeling.o \ - -dtbs := $(addprefix samples/,$(addsuffix .dtb,$(tests))) - -tests := $(addsuffix .test,$(tests)) -run_tests := $(addprefix run.,$(tests)) +BIN_DEPS += load.%.o +CFLAGS += -DCONFIG_USE_DEVICETREE -Wp,-w +.PRECIOUS: %.dtb %.dtb: %.dts $(call status,DTC,$^) @dtc -q -I dts -O dtb $^ -o $@ -.PHONY: all run clean - -load.%.o:: load.c +load.%.o: load.c samples/%.dtb $(call status,CC,$@) - @$(CC) $(CFLAGS) -DTEST_DTBFILE=\"samples/$*.dtb\" -c $^ -o $@ - -%.test: $(obj-shared) $(obj-stubs) $(obj) test-%.o load.%.o - $(call status,LD,$@) - @$(CC) $^ -o $@ - -run.%.test: %.test - $(call status,RUN,$^) - @./$^ - -all: $(dtbs) $(tests) - -run: $(dtbs) $(tests) $(run_tests) + @$(CC) $(CFLAGS) -DTEST_DTBFILE=\"samples/$*.dtb\" -c $< -o $@ -clean: - @rm -f *.o $(obj) $(test) $(dtbs) \ No newline at end of file +include units_build.mkinc \ No newline at end of file diff --git a/lunaix-os/tests/units/makefile b/lunaix-os/tests/units/makefile index 66cf8ab..866c718 100644 --- a/lunaix-os/tests/units/makefile +++ b/lunaix-os/tests/units/makefile @@ -1,8 +1,12 @@ LUNAIX_ROOT ?= $(shell realpath ../../) -include test_build.mkinc +include $(LUNAIX_ROOT)/tests/shared/makefile +include $(LUNAIX_ROOT)/tests/shared/mkobj.mkinc -__test-dir := device-tree +MAKEFLAGS += --no-print-directory +CFLAGS += -isystem $(unit-test-root)/stubs/includes + +__test-dir := device-tree btrie test-dir := $(addprefix test-,$(__test-dir)) obj-stubs := @@ -11,7 +15,9 @@ obj-tmp := include stubs/makefile obj-stubs += $(addprefix $(unit-test-root)/stubs/,$(obj-tmp)) -export obj-stubs LUNAIX_ROOT +BIN_DEPS := $(obj-stubs) $(obj-shared) + +export BIN_DEPS CFLAGS LUNAIX_ROOT test-%: $(call status,MK,$*) @$(MAKE) $(MKFLAGS) -C $* $(_ACT) -I $(CURDIR) diff --git a/lunaix-os/tests/units/stubs/valloc.c b/lunaix-os/tests/units/stubs/valloc.c index 0d02922..c8897e2 100644 --- a/lunaix-os/tests/units/stubs/valloc.c +++ b/lunaix-os/tests/units/stubs/valloc.c @@ -1,56 +1,85 @@ #include +#include #include extern void *malloc(size_t); extern void *calloc(size_t, size_t); extern void free(void*); +static inline void* +_my_malloc(size_t size) +{ + void* ptr; + + ptr = malloc(size); + memchk_log_alloc((unsigned long)ptr, size); + + return ptr; +} + +static inline void* +_my_calloc(size_t size, int n) +{ + void* ptr; + + ptr = calloc(size, n); + memchk_log_alloc((unsigned long)ptr, size * n); + + return ptr; +} + +static inline void +_my_free(void* addr) +{ + memchk_log_free((unsigned long)addr); +} + void* valloc(unsigned int size) { - return malloc(size); + return _my_malloc(size); } void* vzalloc(unsigned int size) { - return calloc(size, 1); + return _my_calloc(size, 1); } void* vcalloc(unsigned int size, unsigned int count) { - return calloc(size, count); + return _my_calloc(size, count); } void vfree(void* ptr) { - free(ptr); + _my_free(ptr); } void vfree_safe(void* ptr) { - if (ptr) free(ptr); + if (ptr) _my_free(ptr); } void* valloc_dma(unsigned int size) { - return malloc(size); + return _my_malloc(size); } void* vzalloc_dma(unsigned int size) { - return calloc(size, 1); + return _my_calloc(size, 1); } void vfree_dma(void* ptr) { - free(ptr); + _my_free(ptr); } void diff --git a/lunaix-os/tests/units/test_build.mkinc b/lunaix-os/tests/units/test_build.mkinc deleted file mode 100644 index 1a3fcdb..0000000 --- a/lunaix-os/tests/units/test_build.mkinc +++ /dev/null @@ -1,5 +0,0 @@ -MAKEFLAGS += --no-print-directory - -include $(LUNAIX_ROOT)/tests/shared/makefile - -CFLAGS += -isystem $(unit-test-root)/stubs/includes \ No newline at end of file diff --git a/lunaix-os/tests/units/units_build.mkinc b/lunaix-os/tests/units/units_build.mkinc new file mode 100644 index 0000000..29b64ad --- /dev/null +++ b/lunaix-os/tests/units/units_build.mkinc @@ -0,0 +1,24 @@ +include $(LUNAIX_ROOT)/tests/shared/mkobj.mkinc +include $(LUNAIX_ROOT)/makeinc/utils.mkinc + +tests := $(addsuffix .test,$(shell cat tests.txt)) +run_tests := $(addprefix run.,$(tests)) + +BIN_DEPS += $(obj-dut) + +.PHONY: all run clean + +%.test: $(BIN_DEPS) test-%.o + $(call status,LD,$@) + @$(CC) $^ -o $@ + +run.%.test: %.test + $(call status,RUN,$^) + @./$^ + +all: $(tests) + +run: $(tests) $(run_tests) + +clean: + @rm -f *.o $(tests) $(obj-dut) $(TO_CLEAN) \ No newline at end of file -- 2.27.0