```
includes/asm/cpu.h
-includes/asm-generic/isrm.h
includes/asm/muldiv64.h
includes/asm/hart.h
includes/asm/mempart.h
+++ /dev/null
-/**
- * @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 <lunaix/types.h>
-#include <lunaix/hart_state.h>
-#include <lunaix/device.h>
-
-#include <hal/devtree.h>
-
-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 */
sources([
"exceptions/interrupts.c",
"exceptions/isrdef.c",
- "exceptions/intr_routines.c",
- "exceptions/isrm.c",
"exceptions/intrhnds.S",
])
#include <lunaix/spike.h>
#include <lunaix/process.h>
-#include <asm/x86_isrm.h>
-
#include "asm/x86.h"
#include "asm/hart.h"
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
#include <lunaix/process.h>
#include <lunaix/sched.h>
#include <lunaix/syslog.h>
+#include <lunaix/failsafe.h>
-#include <asm/x86_isrm.h>
+#include <hal/irq.h>
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)
{
}
}
+
+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
+++ /dev/null
-#include <asm/hart.h>
-
-#include <lunaix/process.h>
-#include <lunaix/sched.h>
-#include <lunaix/spike.h>
-#include <lunaix/syslog.h>
-#include <lunaix/trace.h>
-#include <lunaix/failsafe.h>
-
-#include <klibc/strfmt.h>
-
-#include <asm/x86_isrm.h>
-#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
+++ /dev/null
-#include <lunaix/spike.h>
-#include <lunaix/device.h>
-#include <asm/x86_isrm.h>
-
-#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
"cpu.c",
"ps2kbd.c",
"apic_timer.c",
- "ioapic.c",
"mc146818a.c",
"pci.c"
])
\ No newline at end of file
#include "asm/x86.h"
#include "asm/x86_cpu.h"
-
#include "asm/soc/apic.h"
+
#include <asm/hart.h>
#include <lunaix/mm/mmio.h>
#include <lunaix/spike.h>
#include <lunaix/syslog.h>
+#include <lunaix/device.h>
+
+#include <hal/irq.h>
+#include <hal/acpi/acpi.h>
#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
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
#include "apic_timer.h"
#include <hal/hwtimer.h>
+#include <hal/irq.h>
#include <lunaix/clock.h>
#include <lunaix/compiler.h>
#include <lunaix/spike.h>
#include <lunaix/syslog.h>
-#include <asm/x86_isrm.h>
#include "asm/soc/apic.h"
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))) {
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);
wait_until(!(pot->systick_raw + 1));
cpu_disable_interrupt();
- isrm_ivfree(iv_timer);
sysrtc->ops->set_proactive(sysrtc, false);
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 = {
+++ /dev/null
-#include <hal/acpi/acpi.h>
-
-#include <lunaix/mm/mmio.h>
-
-#include <asm/hart.h>
-#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
#include <lunaix/hart_state.h>
#include <hal/hwrtc.h>
+#include <hal/irq.h>
#include <klibc/string.h>
-#include <asm/x86_isrm.h>
#include <asm/x86_pmio.h>
#define RTC_INDEX_PORT 0x70
struct mc146818
{
struct hwrtc_potens* rtc_context;
- u32_t rtc_iv;
+ irq_t irq;
};
#define rtc_state(data) ((struct mc146818*)(data))
}
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);
__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);
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;
}
#include <lunaix/timer.h>
#include <lunaix/hart_state.h>
+#include <hal/irq.h>
+
#include "asm/x86.h"
#include <klibc/string.h>
#include "asm/x86_cpu.h"
-#include <asm/x86_isrm.h>
#include <asm/x86_pmio.h>
#define PS2_PORT_ENC_DATA 0x60
// #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);
*
* 所以,保险的方法是:在初始化后才去设置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;
}
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!
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 */
+++ /dev/null
-#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 */
void
exception_install_handler();
-void
-intr_routine_init();
-
#endif
#endif /* __LUNAIX_I386_ASM_H */
+++ /dev/null
-#ifndef __LUNAIX_X86_ISRM_H
-#define __LUNAIX_X86_ISRM_H
-
-#include <asm-generic/isrm.h>
-
-/**
- * @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 */
#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
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
#include <klibc/string.h>
#include <lunaix/block.h>
-#include <asm-generic/isrm.h>
#include <lunaix/mm/mmio.h>
#include <lunaix/mm/valloc.h>
#include <lunaix/mm/page.h>
LOG_MODULE("AHCI")
-DEFINE_LLIST(ahcis);
+static DEFINE_LLIST(ahcis);
static char sata_ifs[][20] = { "Not detected",
"SATA I (1.5Gbps)",
{
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);
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) {
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);
#include <hal/ahci/ahci.h>
#include <hal/ahci/sata.h>
-#include <asm-generic/isrm.h>
#include <lunaix/mm/valloc.h>
#include <lunaix/syslog.h>
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)) {
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);
}
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;
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
/*---------- 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)
{
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;
def_on_register(pci_register),
def_on_create(pci_create)
};
-EXPORT_DEVICE(pci3hba, &pci_def, load_sysconf);
+EXPORT_DEVICE(pci3hba, &pci_def, load_onboot);
#define __LUNAIX_16550_H
#include <hal/serial.h>
+#include <hal/irq.h>
#include <lunaix/types.h>
#define UART_rRxTX 0
struct serial_dev* sdev;
ptr_t base_addr;
unsigned int base_clk;
- int iv;
+ irq_t irq;
struct
{
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,
}
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;
}
}
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;
#include <lunaix/syslog.h>
#include <asm/x86_pmio.h>
-#include <asm/x86_isrm.h>
#include "16x50.h"
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
int* irqs[] = { &irq4, &irq3, &irq4, &irq3 };
struct uart16550* uart = NULL;
+ struct serial_dev* sdev;
ptr_t base;
// COM 1...4
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;
#include <lunaix/device.h>
-#include <asm-generic/isrm.h>
#include <lunaix/mm/mmio.h>
#include "16x50.h"
#include <lunaix/device.h>
-#include <asm-generic/isrm.h>
#include <lunaix/syslog.h>
#include <lunaix/mm/mmio.h>
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
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);
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);
}
*
*/
#include <lunaix/device.h>
-#include <asm-generic/isrm.h>
#include <asm/x86_pmio.h>
sources([
"dt_interrupt.c",
"dt.c",
- "dtm.c"
+ "dtm.c",
"dtspec.c"
])
\ No newline at end of file
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;
}
}
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;
mscan->loc = loc;
mscan->node_type = FDT_MEM_FREE;
+
+ return true;
}
#define get_size(mscan, val) \
--- /dev/null
+#include <hal/irq.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/owloysius.h>
+
+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;
+}
#define __LUNAIX_AHCI_H
#include "hba.h"
-#include <asm-generic/isrm.h>
+#include <hal/irq.h>
/*
* Macro naming rule:
{
ptr_t mmio_base;
size_t mmio_size;
- int ahci_iv;
+ irq_t irq;
};
void
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 */
#ifndef __LUNAIX_DEVTREE_H
#define __LUNAIX_DEVTREE_H
+#ifdef CONFIG_USE_DEVICETREE
#include <lunaix/types.h>
#include <lunaix/ds/llist.h>
#include <lunaix/ds/hstr.h>
{
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;
};
dtpi_init_empty(struct dtpropi* dtpi)
{
*dtpi = (struct dtpropi) {
- .prop = { 0, 0 },
+ .prop = { {0}, 0 },
.loc = 0
};
}
return true;
}
+#endif
#endif /* __LUNAIX_DEVTREE_H */
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
{
--- /dev/null
+#ifndef __LUNAIX_IRQ_H
+#define __LUNAIX_IRQ_H
+
+#include <lunaix/changeling.h>
+#include <lunaix/device.h>
+#include <lunaix/ds/btrie.h>
+#include <asm/hart.h>
+
+#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 */
#include <lunaix/types.h>
#include <lunaix/changeling.h>
-#include <asm-generic/isrm.h>
+#include "irq.h"
#define PCI_VENDOR_INVLD 0xffff
struct pci_base_addr bar[6];
struct device* bind;
+ struct irq_domain* irq_domain;
};
#define pci_probe_morpher morphable_attrs(pci_probe, mobj)
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
*
}
-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);
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
* @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
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)
#define BTRIE_BITS 4
+/**
+ * key-sorted prefix tree
+ */
struct btrie
{
struct btrie_node* btrie_root;
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
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);
#include <lunaix/mm/valloc.h>
#include <lunaix/spike.h>
-#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;
}
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;
}
{
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;
}
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
#include <lunaix/hart_state.h>
#include <lunaix/kpreempt.h>
-#include <asm-generic/isrm.h>
-
#include <klibc/string.h>
struct thread empty_thread_obj;
sched_ctx.procs_index = to_check->process->pid;
done:
- isrm_notify_eos(0);
run(to_check);
fail("unexpected return from scheduler");
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)
void
run_test(int argc, const char* argv[]);
+static inline int
+should_skip_test()
+{
+ return active_context->stats.failed;
+}
+
#endif /* __COMMON_TEST_BASIC_H */
--- /dev/null
+#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 */
#include <testing/basic.h>
+#include <testing/memchk.h>
#include <stdlib.h>
struct test_context* __test_ctx;
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);
}
__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);
}
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
-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
--- /dev/null
+#include <testing/memchk.h>
+#include <stdio.h>
+
+#include <lunaix/ds/llist.h>
+
+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
--- /dev/null
+%.o: %.c
+ $(call status,CC,$(@F))
+ @$(CC) $(CFLAGS) -c $< -o $@
--- /dev/null
+**.test
\ No newline at end of file
--- /dev/null
+../../../../kernel/ds/btrie.c
\ No newline at end of file
--- /dev/null
+obj-dut := dut/btrie.o
+
+include units_build.mkinc
\ No newline at end of file
--- /dev/null
+#include <lunaix/ds/btrie.h>
+#include <testing/basic.h>
+#include <lunaix/spike.h>
+#include <lunaix/compiler.h>
+
+#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
test
-*.dtb
-*.test
\ No newline at end of file
+*.dtb
\ No newline at end of file
#ifndef __DTTEST_COMMON_H
#define __DTTEST_COMMON_H
-#define __off_t_defined
#include "dut/devtree.h"
#include <lunaix/types.h>
-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
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 :=
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)
#include <lunaix/mm/valloc.h>
+#include <testing/memchk.h>
#include <stddef.h>
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
+++ /dev/null
-MAKEFLAGS += --no-print-directory
-
-include $(LUNAIX_ROOT)/tests/shared/makefile
-
-CFLAGS += -isystem $(unit-test-root)/stubs/includes
\ No newline at end of file
--- /dev/null
+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