From 9440be3a5115a91dcdf8dff05a361cac4b6cea29 Mon Sep 17 00:00:00 2001 From: Minep Date: Sun, 1 May 2022 16:47:38 +0100 Subject: [PATCH] Restructure the interrupt vector distribution for better matching of their inherit priority, and ... Attempts to resolve the spurious keyboard buffer full irq when after issuing the command to ps/2. Adjust the comments and formatting. --- lunaix-os/includes/arch/x86/interrupts.h | 134 ++++++++--------------- lunaix-os/includes/hal/pic.h | 2 +- lunaix-os/includes/lunaix/common.h | 2 +- lunaix-os/includes/lunaix/timer.h | 4 +- lunaix-os/kernel/asm/x86/idt.c | 10 +- lunaix-os/kernel/mm/pmm.c | 2 +- lunaix-os/kernel/mm/vmm.c | 2 +- lunaix-os/kernel/peripheral/ps2kbd.c | 109 +++++++++++------- lunaix-os/kernel/time/timer.c | 16 ++- lunaix-os/libs/klibc/stdio/sprintf.c | 2 - 10 files changed, 131 insertions(+), 152 deletions(-) diff --git a/lunaix-os/includes/arch/x86/interrupts.h b/lunaix-os/includes/arch/x86/interrupts.h index 2c93c39..664d69d 100644 --- a/lunaix-os/includes/arch/x86/interrupts.h +++ b/lunaix-os/includes/arch/x86/interrupts.h @@ -29,17 +29,18 @@ #define LUNAIX_SYS_PANIC 32 #define EX_INTERRUPT_BEGIN 200 -// APIC related -#define APIC_ERROR_IV 200 -#define APIC_LINT0_IV 201 -#define APIC_TIMER_IV 202 -#define APIC_SPIV_IV 203 // Keyboard -#define PC_KBD_IV 204 +#define PC_KBD_IV 201 #define RTC_TIMER_IV 210 +// 来自APIC的中断有着最高的优先级。 +// APIC related +#define APIC_ERROR_IV 250 +#define APIC_LINT0_IV 251 +#define APIC_SPIV_IV 252 +#define APIC_TIMER_IV 253 #define PC_AT_IRQ_RTC 8 #define PC_AT_IRQ_KBD 1 @@ -60,92 +61,43 @@ typedef struct { typedef void (*int_subscriber)(isr_param*); #pragma region ISR_DECLARATION -void -_asm_isr0(); - -void -_asm_isr1(); - -void -_asm_isr2(); - -void -_asm_isr3(); - -void -_asm_isr4(); - -void -_asm_isr5(); - -void -_asm_isr6(); - -void -_asm_isr7(); - -void -_asm_isr8(); - -void -_asm_isr9(); - -void -_asm_isr10(); - -void -_asm_isr11(); - -void -_asm_isr12(); - -void -_asm_isr13(); -void -_asm_isr14(); - -void -_asm_isr15(); - -void -_asm_isr16(); - -void -_asm_isr17(); - -void -_asm_isr18(); - -void -_asm_isr19(); - -void -_asm_isr20(); - -void -_asm_isr21(); - -void -_asm_isr32(); - -void -_asm_isr200(); - -void -_asm_isr201(); - -void -_asm_isr202(); - -void -_asm_isr203(); - -void -_asm_isr204(); - -void -_asm_isr210(); +#define ISR(iv) void _asm_isr##iv(); + +ISR(0) +ISR(1) +ISR(2) +ISR(3) +ISR(4) +ISR(5) +ISR(6) +ISR(7) +ISR(8) +ISR(9) +ISR(10) +ISR(11) +ISR(12) +ISR(13) +ISR(14) +ISR(15) +ISR(16) +ISR(17) +ISR(18) +ISR(19) +ISR(20) +ISR(21) + +ISR(32) + +ISR(201) + +ISR(210) + +ISR(250) +ISR(251) +ISR(252) +ISR(253) +ISR(254) #pragma endregion diff --git a/lunaix-os/includes/hal/pic.h b/lunaix-os/includes/hal/pic.h index 54f03b0..8fdcd04 100644 --- a/lunaix-os/includes/hal/pic.h +++ b/lunaix-os/includes/hal/pic.h @@ -1,6 +1,6 @@ #ifndef __LUNAIX_PIC_H #define __LUNAIX_PIC_H -// TODO: PIC +// FUTURE: Full PIC implementation for fall back when no APIC is detected. static inline void pic_disable() diff --git a/lunaix-os/includes/lunaix/common.h b/lunaix-os/includes/lunaix/common.h index d9ffeae..51c37f6 100644 --- a/lunaix-os/includes/lunaix/common.h +++ b/lunaix-os/includes/lunaix/common.h @@ -24,7 +24,7 @@ * @member: the name of the member within the struct. * */ -#define container_of(ptr, type, member) ({ \ +#define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) diff --git a/lunaix-os/includes/lunaix/timer.h b/lunaix-os/includes/lunaix/timer.h index 1b36db5..78976a5 100644 --- a/lunaix-os/includes/lunaix/timer.h +++ b/lunaix-os/includes/lunaix/timer.h @@ -23,10 +23,10 @@ struct lx_timer_context { */ uint32_t running_frequency; /** - * @brief Ticks per second relative to desired system running frequency + * @brief Ticks per hertz * */ - ticks_t tps; + ticks_t tphz; }; struct lx_timer { diff --git a/lunaix-os/kernel/asm/x86/idt.c b/lunaix-os/kernel/asm/x86/idt.c index 5474743..e194d87 100644 --- a/lunaix-os/kernel/asm/x86/idt.c +++ b/lunaix-os/kernel/asm/x86/idt.c @@ -22,11 +22,11 @@ _init_idt() { _set_idt_entry(FAULT_GENERAL_PROTECTION, 0x08, _asm_isr13, 0); _set_idt_entry(FAULT_PAGE_FAULT, 0x08, _asm_isr14, 0); - _set_idt_entry(APIC_ERROR_IV, 0x08, _asm_isr200, 0); - _set_idt_entry(APIC_LINT0_IV, 0x08, _asm_isr201, 0); - _set_idt_entry(APIC_TIMER_IV, 0x08, _asm_isr202, 0); - _set_idt_entry(APIC_SPIV_IV, 0x08, _asm_isr203, 0); - _set_idt_entry(PC_KBD_IV, 0x08, _asm_isr204, 0); + _set_idt_entry(APIC_ERROR_IV, 0x08, _asm_isr250, 0); + _set_idt_entry(APIC_LINT0_IV, 0x08, _asm_isr251, 0); + _set_idt_entry(APIC_SPIV_IV, 0x08, _asm_isr252, 0); + _set_idt_entry(APIC_TIMER_IV, 0x08, _asm_isr253, 0); + _set_idt_entry(PC_KBD_IV, 0x08, _asm_isr201, 0); _set_idt_entry(RTC_TIMER_IV, 0x08, _asm_isr210, 0); diff --git a/lunaix-os/kernel/mm/pmm.c b/lunaix-os/kernel/mm/pmm.c index 054b247..dcc70b0 100644 --- a/lunaix-os/kernel/mm/pmm.c +++ b/lunaix-os/kernel/mm/pmm.c @@ -128,7 +128,7 @@ pmm_alloc_page() int pmm_free_page(void* page) { - // TODO: Add kernel reserved memory page check + // XXX: Add kernel reserved memory page check or simply ownership check? uint32_t pg = (uintptr_t)page >> 12; if (pg && pg < max_pg) { diff --git a/lunaix-os/kernel/mm/vmm.c b/lunaix-os/kernel/mm/vmm.c index 928c289..0aa09b8 100644 --- a/lunaix-os/kernel/mm/vmm.c +++ b/lunaix-os/kernel/mm/vmm.c @@ -10,7 +10,7 @@ void vmm_init() { - // TODO: something here? + // XXX: something here? } x86_page_table* diff --git a/lunaix-os/kernel/peripheral/ps2kbd.c b/lunaix-os/kernel/peripheral/ps2kbd.c index 3e5a4a1..fc4151a 100644 --- a/lunaix-os/kernel/peripheral/ps2kbd.c +++ b/lunaix-os/kernel/peripheral/ps2kbd.c @@ -6,7 +6,6 @@ #include #include -#include #include #include @@ -66,20 +65,23 @@ static kbd_keycode_t scancode_set2_shift[] = { }; -#define KBD_STATE_WAIT_KEY 0 -#define KBD_STATE_SPECIAL 1 -#define KBD_STATE_RELEASED 2 +#define KBD_STATE_KWAIT 0x00 +#define KBD_STATE_KSPECIAL 0x01 +#define KBD_STATE_KRELEASED 0x02 +// #define KBD_STATE_CMDPROCS 0x80 void intr_ps2_kbd_handler(const isr_param* param); +static struct kdb_keyinfo_pkt* ps2_keybuffer_next_write(); +// TODO: Abstract the bounded buffer out. void ps2_device_post_cmd(char cmd, char arg) { // 不需要任何的类似lock cmpxchgl的骚操作。 // 这条赋值表达式最多涉及一个内存引用(e.g., movl $1, (cmd_q.lock)),因此是原子的。 cmd_q.lock = 1; int index = (cmd_q.queue_ptr + cmd_q.queue_len) % PS2_CMD_QUEUE_SIZE; - int diff = index - cmd_q.queue_ptr; - if (diff > 0 && diff != cmd_q.queue_len) { + if (index == cmd_q.queue_ptr && cmd_q.queue_len) { // 队列已满! + cmd_q.lock = 0; return; } @@ -98,7 +100,7 @@ void ps2_kbd_init() { memset(&key_buf, 0, sizeof(key_buf)); memset(&kbd_state, 0, sizeof(kbd_state)); kbd_state.translation_table = scancode_set2; - kbd_state.state = KBD_STATE_WAIT_KEY; + kbd_state.state = KBD_STATE_KWAIT; cpu_disable_interrupt(); @@ -164,7 +166,8 @@ void ps2_process_cmd(void* arg) { if (!cmd_q.queue_len || cmd_q.lock) { return; } - + + // kbd_state.state |= KBD_STATE_CMDPROCS; // 处理队列排头的指令 struct ps2_cmd *pending_cmd = &cmd_q.cmd_queue[cmd_q.queue_ptr]; char result; @@ -184,19 +187,6 @@ void ps2_process_cmd(void* arg) { cmd_q.queue_len--; } -static struct kdb_keyinfo_pkt* ps2_keybuffer_next_write() { - int index = (key_buf.read_ptr + key_buf.buffered_len) % PS2_KBD_RECV_BUFFER_SIZE; - if (index == key_buf.read_ptr && key_buf.buffered_len) { - // the reader lagged so much. It is suggested to read from beginning. - key_buf.read_ptr = 0; - key_buf.buffered_len = index; - } - else { - key_buf.buffered_len++; - } - return &key_buf.buffer[index]; -} - void kbd_buffer_key_event(kbd_keycode_t key, uint8_t scancode, kbd_kstate_t state) { // forgive me on these ugly bit-level tricks, // I really hate doing branching on these "fliping switch" things @@ -216,14 +206,15 @@ void kbd_buffer_key_event(kbd_keycode_t key, uint8_t scancode, kbd_kstate_t stat } state = state | kbd_state.key_state; key = key & (0xffdf | -('a' > key || key > 'z' || !(state & KBD_KEY_FCAPSLKED))); - time_t timestamp = clock_systime(); - // TODO: Construct the packet. + if (!key_buf.lock) { struct kdb_keyinfo_pkt* keyevent_pkt = ps2_keybuffer_next_write(); - keyevent_pkt->keycode = key; - keyevent_pkt->scancode = scancode; - keyevent_pkt->state = state; - keyevent_pkt->timestamp = timestamp; + *keyevent_pkt = (struct kdb_keyinfo_pkt) { + .keycode = key, + .scancode = scancode, + .state = state, + .timestamp = clock_systime() + }; } // kprintf(KDEBUG "%c (t=%d, s=%x, c=%d)\n", key & 0x00ff, timestamp, state, key >> 8); @@ -235,11 +226,34 @@ void kbd_buffer_key_event(kbd_keycode_t key, uint8_t scancode, kbd_kstate_t stat } void intr_ps2_kbd_handler(const isr_param* param) { - uint8_t scancode = io_inb(PS2_PORT_ENC_DATA) & 0xff; + + // Do not move this line. It is in the right place and right order. + // This is to ensure we've cleared the output buffer everytime, so it won't pile up across irqs. + uint8_t scancode = io_inb(PS2_PORT_ENC_DATA); kbd_keycode_t key; - // 用于区分0xfe,0xfa等指令返回码。 - if (scancode >= 0xFA) { + /* + * 判断键盘是否处在指令发送状态,防止误触发。(伪输入中断) + * 这是因为我们需要向ps/2设备发送指令(比如控制led灯),而指令会有返回码。 + * 这就会有可能导致ps/2控制器在受到我们的命令后(在ps2_process_cmd中), + * 产生IRQ#1中断(虽然说这种情况取决于底层BIOS实现,但还是会发生,比如QEMU和bochs)。 + * 所以这就是说,当IRQ#1中断产生时,我们的CPU正处在另一个ISR中。这样就会导致所有的外部中断被缓存在APIC内部的 + * FIFO队列里,进行排队等待(APIC长度为二的队列 {IRR, TMR};参考 Intel Manual Vol.3A 10.8.4) + * 那么当ps2_process_cmd执行完后(内嵌在#APIC_TIMER_IV),CPU返回EOI给APIC,APIC紧接着将排在队里的IRQ#1发送给CPU + * 造成误触发。也就是说,我们此时读入的scancode实则上是上一个指令的返回代码。 + * + * Problem 1: + * 但是这种方法有个问题,那就是,假若我们的某一个命令失败了一次,ps/2给出0xfe,我们重传,ps/2收到指令并给出0xfa。 + * 那么这样一来,将会由两个连续的IRQ#1产生。而APIC是最多可以缓存两个IRQ,于是我们就会漏掉一个IRQ,依然会误触发。 + */ + // FIXME: Address Problem #1 + // if ((kbd_state.state & KBD_STATE_CMDPROCS)) { + // kbd_state.state &= ~KBD_STATE_CMDPROCS; + // return; + // } + + // 目前还是使用该方法。。。 + if (scancode >= 0xfa) { return; } @@ -247,34 +261,34 @@ void intr_ps2_kbd_handler(const isr_param* param) { switch (kbd_state.state) { - case KBD_STATE_WAIT_KEY: + case KBD_STATE_KWAIT: if (scancode == 0xf0) { // release code - kbd_state.state = KBD_STATE_RELEASED; + kbd_state.state = KBD_STATE_KRELEASED; } else if (scancode == 0xe0) { - kbd_state.state = KBD_STATE_SPECIAL; + kbd_state.state = KBD_STATE_KSPECIAL; kbd_state.translation_table = scancode_set2_ex; } else { key = kbd_state.translation_table[scancode]; kbd_buffer_key_event(key, scancode, KBD_KEY_FPRESSED); } break; - case KBD_STATE_SPECIAL: + case KBD_STATE_KSPECIAL: if (scancode == 0xf0) { //release code - kbd_state.state = KBD_STATE_RELEASED; + kbd_state.state = KBD_STATE_KRELEASED; } else { key = kbd_state.translation_table[scancode]; kbd_buffer_key_event(key, scancode, KBD_KEY_FPRESSED); - kbd_state.state = KBD_STATE_WAIT_KEY; + kbd_state.state = KBD_STATE_KWAIT; kbd_state.translation_table = scancode_set2; } break; - case KBD_STATE_RELEASED: + case KBD_STATE_KRELEASED: key = kbd_state.translation_table[scancode]; kbd_buffer_key_event(key, scancode, KBD_KEY_FRELEASED); // reset the translation table to scancode_set2 - kbd_state.state = KBD_STATE_WAIT_KEY; + kbd_state.state = KBD_STATE_KWAIT; kbd_state.translation_table = scancode_set2; break; @@ -329,13 +343,24 @@ struct kdb_keyinfo_pkt* kbd_try_read_one() { struct kdb_keyinfo_pkt* pkt_current = &key_buf.buffer[key_buf.read_ptr]; - pkt_copy->keycode = pkt_current->keycode; - pkt_copy->scancode = pkt_current->scancode; - pkt_copy->state = pkt_current->state; - pkt_copy->timestamp = pkt_current->timestamp; + *pkt_copy = *pkt_current; key_buf.buffered_len--; key_buf.read_ptr = (key_buf.read_ptr + 1) % PS2_KBD_RECV_BUFFER_SIZE; key_buf.lock = 0; return pkt_copy; +} + +static struct kdb_keyinfo_pkt* ps2_keybuffer_next_write() { + int index = (key_buf.read_ptr + key_buf.buffered_len) % PS2_KBD_RECV_BUFFER_SIZE; + if (index == key_buf.read_ptr && key_buf.buffered_len) { + // the reader is lagged so much such that the buffer is full. + // It is suggested to read from beginning for nearly up-to-date readings. + key_buf.read_ptr = 0; + key_buf.buffered_len = index; + } + else { + key_buf.buffered_len++; + } + return &key_buf.buffer[index]; } \ No newline at end of file diff --git a/lunaix-os/kernel/time/timer.c b/lunaix-os/kernel/time/timer.c index 73bc0d5..03ef2b4 100644 --- a/lunaix-os/kernel/time/timer.c +++ b/lunaix-os/kernel/time/timer.c @@ -63,8 +63,7 @@ timer_init(uint32_t frequency) // Setup 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 + // 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)); @@ -81,7 +80,7 @@ timer_init(uint32_t frequency) step 4: Startup RTC timer step 5: Write a large value, v, to APIC_TIMER_ICR to start APIC timer (this must be followed immediately after step 4) - step 6: issue a write to EOI and clean up. + step 6: issue a write to EOI and clean up. When the APIC ICR counting down to 0 #APIC_TIMER_IV triggered, save the rtc timer's counter, k, and disable RTC timer immediately (although the @@ -94,6 +93,12 @@ timer_init(uint32_t frequency) */ + #ifdef __LUNAIXOS_DEBUG__ + if (frequency < 1000) { + kprintf(KWARN "Frequency too low. Millisecond timer might be dodgy."); + } + #endif + timer_ctx->base_frequency = 0; rtc_counter = 0; apic_timer_done = 0; @@ -109,14 +114,13 @@ timer_init(uint32_t frequency) wait_until(apic_timer_done); - // cpu_disable_interrupt(); assert_msg(timer_ctx->base_frequency, "Fail to initialize timer (NOFREQ)"); kprintf(KINFO "Base frequency: %u Hz\n", timer_ctx->base_frequency); timer_ctx->running_frequency = frequency; - timer_ctx->tps = timer_ctx->base_frequency / frequency; + timer_ctx->tphz = timer_ctx->base_frequency / frequency; // cleanup intr_unsubscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer); @@ -126,7 +130,7 @@ timer_init(uint32_t frequency) LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_PERIODIC)); intr_subscribe(APIC_TIMER_IV, timer_update); - apic_write_reg(APIC_TIMER_ICR, timer_ctx->tps); + apic_write_reg(APIC_TIMER_ICR, timer_ctx->tphz); } int diff --git a/lunaix-os/libs/klibc/stdio/sprintf.c b/lunaix-os/libs/klibc/stdio/sprintf.c index a48ef1f..460b206 100644 --- a/lunaix-os/libs/klibc/stdio/sprintf.c +++ b/lunaix-os/libs/klibc/stdio/sprintf.c @@ -27,8 +27,6 @@ __sprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs) // This sprintf just a random implementation I found it on Internet . lol. // Of course, with some modifications for porting to LunaixOS :) - // TODO: support floating point. - char numbuf[NUMBUFSIZ]; uint32_t ptr = 0; for (; *fmt; ++fmt) { -- 2.27.0