From: Minep Date: Sun, 1 May 2022 15:47:38 +0000 (+0100) Subject: Restructure the interrupt vector distribution for better matching of their inherit... X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/commitdiff_plain/9440be3a5115a91dcdf8dff05a361cac4b6cea29?hp=0471b0eeea5ea30883c776dd53275ec6b8454ca7 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. --- 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) {