#include <hal/acpi/acpi.h>
#include <hal/ioapic.h>
#include <klibc/stdio.h>
+#include <lunaix/isrm.h>
#include <lunaix/lxconsole.h>
#include <lunaix/peripheral/serial.h>
#include <lunaix/syslog.h>
while (1)
;
}
-
-extern uint8_t
-ioapic_get_irq(acpi_context* acpi_ctx, uint8_t old_irq);
-
void
sdbg_init()
{
- intr_subscribe(UART_COM1, sdbg_loop);
- intr_subscribe(INSTR_DEBUG, sdbg_loop); // #DB
- intr_subscribe(INSTR_BREAK, sdbg_loop); // #BRK
+ isrm_bindiv(INSTR_DEBUG, sdbg_loop); // #DB
+ isrm_bindiv(INSTR_BREAK, sdbg_loop); // #BRK
- acpi_context* acpi_ctx = acpi_get_context();
- uint8_t irq = ioapic_get_irq(acpi_ctx, COM1_IRQ);
- ioapic_redirect(irq, UART_COM1, 0, IOAPIC_DELMOD_FIXED);
+ isrm_bindirq(COM1_IRQ, sdbg_loop);
}
\ No newline at end of file
return sum == 0;
}
+uint8_t
+acpi_gistranslate(uint8_t old_irq)
+{
+ if (old_irq >= 24) {
+ return old_irq;
+ }
+ acpi_intso_t* int_override = ctx->madt.irq_exception[old_irq];
+ return int_override ? (uint8_t)int_override->gsi : old_irq;
+}
+
#define VIRTUAL_BOX_PROBLEM
acpi_rsdp_t*
#include <hal/pci.h>
#include <klibc/string.h>
#include <lunaix/block.h>
+#include <lunaix/isrm.h>
#include <lunaix/mm/mmio.h>
#include <lunaix/mm/pmm.h>
#include <lunaix/mm/valloc.h>
pci_write_cspace(ahci_dev->cspace_base, PCI_REG_STATUS_CMD, cmd);
- pci_setup_msi(ahci_dev, AHCI_HBA_IV);
- intr_subscribe(AHCI_HBA_IV, __ahci_hba_isr);
+ pci_setup_msi(ahci_dev, isrm_ivexalloc(__ahci_hba_isr));
memset(&hba, 0, sizeof(hba));
static volatile uintptr_t _ioapic_base;
-uint8_t
-ioapic_get_irq(acpi_context* acpi_ctx, uint8_t old_irq);
-
void
ioapic_init()
{
acpi_context* acpi_ctx = acpi_get_context();
_ioapic_base = ioremap(acpi_ctx->madt.ioapic->ioapic_addr & ~0xfff, 4096);
-
- // Remap the IRQ 8 (rtc timer's vector) to RTC_TIMER_IV in ioapic
- // (Remarks IRQ 8 is pin INTIN8)
- // See IBM PC/AT Technical Reference 1-10 for old RTC IRQ
- // See Intel's Multiprocessor Specification for IRQ - IOAPIC INTIN
- // mapping config.
-
- // The ioapic_get_irq is to make sure we capture those overriden IRQs
-
- // grab ourselves these irq numbers
- uint8_t irq_rtc = ioapic_get_irq(acpi_ctx, PC_AT_IRQ_RTC);
-
- // PC_AT_IRQ_RTC -> RTC_TIMER_IV, fixed, edge trigged, polarity=high,
- // physical, APIC ID 0
- ioapic_redirect(irq_rtc, RTC_TIMER_IV, 0, IOAPIC_DELMOD_FIXED);
-}
-
-uint8_t
-ioapic_get_irq(acpi_context* acpi_ctx, uint8_t old_irq)
-{
- if (old_irq >= 24) {
- return old_irq;
- }
- acpi_intso_t* int_override = acpi_ctx->madt.irq_exception[old_irq];
- return int_override ? (uint8_t)int_override->gsi : old_irq;
}
void
unsigned int ss;
} __attribute__((packed)) isr_param;
-typedef void (*int_subscriber)(const isr_param*);
-
-void
-intr_subscribe(const uint8_t vector, int_subscriber);
-
-void
-intr_unsubscribe(const uint8_t vector, int_subscriber);
-
-void intr_set_fallback_handler(int_subscriber);
-
void
intr_handler(isr_param* param);
acpi_context*
acpi_get_context();
+uint8_t
+acpi_gistranslate(uint8_t old_irq);
+
#endif /* __LUNAIX_ACPI_ACPI_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 <arch/x86/interrupts.h>
+#include <lunaix/types.h>
+
+#define IV_BASE 32
+#define IV_OS IV_BASE
+#define IV_EX 48
+#define IV_MAX 256
+
+typedef void (*isr_cb)(const isr_param*);
+
+void
+isrm_init();
+
+void
+isrm_ivfree(uint32_t iv);
+
+uint32_t
+isrm_ivosalloc(isr_cb handler);
+
+uint32_t
+isrm_ivexalloc(isr_cb handler);
+
+uint32_t
+isrm_bindirq(uint32_t irq, isr_cb irq_handler);
+
+uint32_t
+isrm_bindiv(uint32_t iv, isr_cb handler);
+
+isr_cb
+isrm_get(uint32_t iv);
+
+#endif /* __LUNAIX_ISRM_H */
// 获取v最近的最大k倍数
#define ROUNDUP(v, k) (((v) + (k)-1) & ~((k)-1))
-// 获取v最近的最小k倍数
+// 获取v最近的最小k倍数 (k=2^m)
#define ROUNDDOWN(v, k) ((v) & ~((k)-1))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
--- /dev/null
+#include <hal/acpi/acpi.h>
+#include <hal/ioapic.h>
+
+#include <lunaix/isrm.h>
+#include <lunaix/spike.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_MAX - IV_BASE) / 8];
+static isr_cb handlers[IV_MAX];
+
+extern void
+intr_routine_fallback(const isr_param* param);
+
+void
+isrm_init()
+{
+ for (size_t i = 0; i < 256; i++) {
+ handlers[i] = intr_routine_fallback;
+ }
+}
+
+static inline uint32_t
+__ivalloc_within(size_t a, size_t b, isr_cb handler)
+{
+ a = (a - IV_BASE) / 8;
+ b = (b - IV_BASE) / 8;
+ for (size_t i = a; i < b; i++) {
+ char chunk = iv_bmp[i], j = 0;
+ if (chunk == 0xff)
+ continue;
+ while ((chunk & 0x1)) {
+ chunk >>= 1;
+ j++;
+ }
+ iv_bmp[i] |= 1 << j;
+ uint32_t iv = IV_BASE + i * 8 + j;
+ handlers[iv] = handler ? handler : intr_routine_fallback;
+ return iv;
+ }
+ return 0;
+}
+
+uint32_t
+isrm_ivosalloc(isr_cb handler)
+{
+ return __ivalloc_within(IV_BASE, IV_EX, handler);
+}
+
+uint32_t
+isrm_ivexalloc(isr_cb handler)
+{
+ return __ivalloc_within(IV_EX, IV_MAX, handler);
+}
+
+void
+isrm_ivfree(uint32_t iv)
+{
+ assert(iv < 256);
+ if (iv >= IV_BASE) {
+ iv_bmp[(iv - IV_BASE) / 8] &= ~(1 << ((iv - IV_BASE) % 8));
+ }
+ handlers[iv] = intr_routine_fallback;
+}
+
+uint32_t
+isrm_bindirq(uint32_t irq, isr_cb irq_handler)
+{
+ uint32_t iv;
+ if (!(iv = isrm_ivexalloc(irq_handler))) {
+ panickf("out of IV resource. (irq=%d)", irq);
+ return 0; // never reach
+ }
+
+ // PC_AT_IRQ_RTC -> RTC_TIMER_IV, fixed, edge trigged, polarity=high,
+ // physical, APIC ID 0
+ ioapic_redirect(acpi_gistranslate(irq), iv, 0, IOAPIC_DELMOD_FIXED);
+ return iv;
+}
+
+uint32_t
+isrm_bindiv(uint32_t iv, isr_cb handler)
+{
+ assert(iv < 256);
+ if (iv >= IV_BASE) {
+ iv_bmp[(iv - IV_BASE) / 8] |= 1 << ((iv - IV_BASE) % 8);
+ }
+ handlers[iv] = handler;
+}
+
+isr_cb
+isrm_get(uint32_t iv)
+{
+ assert(iv < 256);
+ return handlers[iv];
+}
\ No newline at end of file
#include <arch/x86/interrupts.h>
#include <arch/x86/tss.h>
+
#include <hal/apic.h>
#include <hal/cpu.h>
+
+#include <lunaix/isrm.h>
#include <lunaix/mm/page.h>
#include <lunaix/mm/vmm.h>
#include <lunaix/process.h>
#include <lunaix/syslog.h>
#include <lunaix/tty/tty.h>
-LOG_MODULE("intr")
-
-static int_subscriber subscribers[256];
-
-static int_subscriber fallback = (int_subscriber)0;
-
-void
-intr_subscribe(const uint8_t vector, int_subscriber subscriber)
-{
- subscribers[vector] = subscriber;
-}
-
-void
-intr_unsubscribe(const uint8_t vector, int_subscriber subscriber)
-{
- if (subscribers[vector] == subscriber) {
- subscribers[vector] = (int_subscriber)0;
- }
-}
-
-void
-intr_set_fallback_handler(int_subscriber subscribers)
-{
- fallback = subscribers;
-}
+LOG_MODULE("INTR")
extern x86_page_table* __kernel_ptd;
isr_param* lparam = &__current->intr_ctx;
if (lparam->vector <= 255) {
- int_subscriber subscriber = subscribers[lparam->vector];
- if (subscriber) {
- subscriber(param);
- goto done;
- }
- }
-
- if (fallback) {
- fallback(lparam);
+ isr_cb subscriber = isrm_get(lparam->vector);
+ subscriber(param);
goto done;
}
done:
// for all external interrupts except the spurious interrupt
// this is required by Intel Manual Vol.3A, section 10.8.1 & 10.8.5
- if (lparam->vector >= EX_INTERRUPT_BEGIN &&
- lparam->vector != APIC_SPIV_IV) {
+ if (lparam->vector >= IV_EX && lparam->vector != APIC_SPIV_IV) {
apic_done_servicing();
}
#include <arch/x86/interrupts.h>
+
+#include <lunaix/isrm.h>
#include <lunaix/lxconsole.h>
#include <lunaix/process.h>
#include <lunaix/sched.h>
void
intr_routine_init()
{
- intr_subscribe(FAULT_DIVISION_ERROR, intr_routine_divide_zero);
- intr_subscribe(FAULT_GENERAL_PROTECTION, intr_routine_general_protection);
- intr_subscribe(FAULT_PAGE_FAULT, intr_routine_page_fault);
- intr_subscribe(FAULT_STACK_SEG_FAULT, intr_routine_page_fault);
-
- intr_subscribe(LUNAIX_SYS_PANIC, intr_routine_sys_panic);
- intr_subscribe(LUNAIX_SCHED, intr_routine_sched);
+ 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);
- intr_subscribe(APIC_SPIV_IV, intr_routine_apic_spi);
- intr_subscribe(APIC_ERROR_IV, intr_routine_apic_error);
+ isrm_bindiv(LUNAIX_SYS_PANIC, intr_routine_sys_panic);
+ isrm_bindiv(LUNAIX_SCHED, intr_routine_sched);
- intr_set_fallback_handler(intr_routine_fallback);
+ isrm_bindiv(APIC_SPIV_IV, intr_routine_apic_spi);
+ isrm_bindiv(APIC_ERROR_IV, intr_routine_apic_error);
}
\ No newline at end of file
#include <lunaix/device.h>
#include <lunaix/foptions.h>
#include <lunaix/input.h>
+#include <lunaix/isrm.h>
#include <lunaix/lxconsole.h>
#include <lunaix/mm/mmio.h>
#include <lunaix/mm/page.h>
void
_kernel_pre_init()
{
+ // interrupts
_init_idt();
+ isrm_init();
intr_routine_init();
+ // memory
pmm_init(MEM_1MB + (_k_init_mb_info->mem_upper << 10));
vmm_init();
_kernel_init()
{
int errno = 0;
+
+ // allocators
cake_init();
valloc_init();
+ // crt
tty_init(ioremap(VGA_FRAMEBUFFER, PG_SIZE));
tty_set_theme(VGA_COLOR_WHITE, VGA_COLOR_BLACK);
+ // file system & device subsys
vfs_init();
fsm_init();
input_init();
sched_init();
+ syscall_install();
+
spawn_proc0();
}
#include <lunaix/clock.h>
#include <lunaix/common.h>
#include <lunaix/input.h>
+#include <lunaix/isrm.h>
#include <lunaix/peripheral/ps2kbd.h>
#include <lunaix/syslog.h>
#include <lunaix/timer.h>
// 至此,PS/2控制器和设备已完成初始化,可以正常使用。
- // 将我们的键盘驱动挂载到第204号中断上(已由IOAPIC映射至IRQ#1),
- intr_subscribe(PC_KBD_IV, intr_ps2_kbd_handler);
-
// 搞一个计时器,将我们的 ps2_process_cmd
// 挂上去。每隔5毫秒执行排在队头的命令。
// 为什么只执行队头的命令,而不是全部的命令?
*
* 所以,保险的方法是:在初始化后才去设置ioapic,这样一来我们就能有一个稳定的IRQ#1以放心使用。
*/
- uint8_t irq_kbd = ioapic_get_irq(acpi_ctx, PC_AT_IRQ_KBD);
- ioapic_redirect(irq_kbd, PC_KBD_IV, 0, IOAPIC_DELMOD_FIXED);
+ isrm_bindirq(PC_AT_IRQ_KBD, intr_ps2_kbd_handler);
done:
cpu_enable_interrupt();
int fdstdin = dup2(stdout, 1);
pid_t p;
- // if (!fork()) {
- // _pconsole_main();
- // }
if (!(p = fork())) {
#ifndef USE_DEMO
init_proc_user_space(__current);
+ // user space
asm volatile("movw %0, %%ax\n"
"movw %%ax, %%es\n"
"movw %%ax, %%ds\n"
// 锁定所有系统预留页(内存映射IO,ACPI之类的),并且进行1:1映射
lock_reserved_memory();
- rtc_init();
+ // firmware
acpi_init(_k_init_mb_info);
+
+ // die
apic_init();
ioapic_init();
+
+ // debugger
serial_init();
sdbg_init();
+
+ // timers & clock
+ rtc_init();
timer_init(SYS_TIMER_FREQUENCY_HZ);
clock_init();
+
+ // peripherals & chipset features
ps2_kbd_init();
pci_init();
block_init();
ahci_init();
- syscall_install();
-
+ // console
console_start_flushing();
console_flush();
+ // expose cake allocator states to vfs
cake_export();
+
unlock_reserved_memory();
+ // clean up
for (size_t i = 0; i < (uintptr_t)(&__init_hhk_end); i += PG_SIZE) {
vmm_del_mapping(PD_REFERENCED, (void*)i);
pmm_free_page(KERNEL_PID, (void*)i);
}
+ // reserve higher half
for (size_t i = L1_INDEX(KERNEL_MM_BASE); i < 1023; i++) {
vmm_set_mapping(PD_REFERENCED, i << 22, 0, 0, VMAP_NOMAP);
}
#include <arch/x86/interrupts.h>
+#include <lunaix/isrm.h>
#include <lunaix/process.h>
#include <lunaix/sched.h>
#include <lunaix/syscall.h>
void
syscall_install()
{
- intr_subscribe(LUNAIX_SYS_CALL, syscall_hndlr);
+ isrm_bindiv(LUNAIX_SYS_CALL, syscall_hndlr);
}
\ No newline at end of file
#include <hal/apic.h>
#include <hal/rtc.h>
+#include <lunaix/isrm.h>
#include <lunaix/mm/cake.h>
#include <lunaix/mm/valloc.h>
#include <lunaix/sched.h>
#include <lunaix/syslog.h>
#include <lunaix/timer.h>
+#include <hal/acpi/acpi.h>
+
#define LVT_ENTRY_TIMER(vector, mode) (LVT_DELIVERY_FIXED | mode | vector)
LOG_MODULE("TIMER");
// Setup APIC timer
+ // Remap the IRQ 8 (rtc timer's vector) to RTC_TIMER_IV in ioapic
+ // (Remarks IRQ 8 is pin INTIN8)
+ // See IBM PC/AT Technical Reference 1-10 for old RTC IRQ
+ // See Intel's Multiprocessor Specification for IRQ - IOAPIC INTIN
+ // mapping config.
+
+ // grab ourselves these irq numbers
+ uint32_t iv_rtc = isrm_bindirq(PC_AT_IRQ_RTC, temp_intr_routine_rtc_tick);
+ uint32_t iv_timer = isrm_ivexalloc(temp_intr_routine_apic_timer);
+
// 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(APIC_TIMER_IV, LVT_TIMER_ONESHOT));
+ LVT_ENTRY_TIMER(iv_timer, LVT_TIMER_ONESHOT));
// Set divider to 64
apic_write_reg(APIC_TIMER_DCR, APIC_TIMER_DIV64);
rtc_counter = 0;
apic_timer_done = 0;
- intr_subscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer);
- intr_subscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick);
-
rtc_enable_timer(); // start RTC timer
apic_write_reg(APIC_TIMER_ICR, APIC_CALIBRATION_CONST); // start APIC timer
timer_ctx->tphz = timer_ctx->base_frequency / frequency;
// cleanup
- intr_unsubscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer);
- intr_unsubscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick);
+ isrm_ivfree(iv_timer);
+ isrm_ivfree(iv_rtc);
- apic_write_reg(APIC_TIMER_LVT,
- LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_PERIODIC));
- intr_subscribe(APIC_TIMER_IV, timer_update);
+ apic_write_reg(
+ APIC_TIMER_LVT,
+ LVT_ENTRY_TIMER(isrm_ivexalloc(timer_update), LVT_TIMER_PERIODIC));
apic_write_reg(APIC_TIMER_ICR, timer_ctx->tphz);