问题
Everyone! I just finished writing my Keyboard Driver. Right now the problem is that my PS/2 MOUSE IRQ won't fire(IRQ 12). I tested this by this code:
#include "irq.h"
#define PIC_MASTER_CONTROL 0x20
#define PIC_MASTER_MASK 0x21
#define PIC_SLAVE_CONTROL 0xa0
#define PIC_SLAVE_MASK 0xa1
typedef void(*regs_func)(struct regs *r);
/*Get all irq's*/
extern "C" void irq0(void);
extern "C" void irq1(void);
extern "C" void irq2(void);
extern "C" void irq3(void);
extern "C" void irq4(void);
extern "C" void irq5(void);
extern "C" void irq6(void);
extern "C" void irq7(void);
extern "C" void irq8(void);
extern "C" void irq9(void);
extern "C" void irq10(void);
extern "C" void irq11(void);
extern "C" void irq12(void);
extern "C" void irq13(void);
extern "C" void irq14(void);
extern "C" void irq15(void);
extern void panic(const char* exception);
regs_func irq_routines[16] = {
0,0,0,0,0,0,0,0
,0,0,0,0,0,0,0,0
};
static PORT::Port8Bits p8b_irq;
static SerialPort sp_irq;
//Basically a declaration of IDT_ENTRY in
//idt.c++
struct idt_entry {
uint16_t base_lo;
uint16_t sel; // Kernel segment goes here.
uint8_t always0;
uint8_t flags; // Set using the table.
uint16_t base_hi;
}__attribute__((packed));
//Get the Exact IDT array from idt.c++
extern struct idt_entry idt[256];
static inline void idt_set_gate(uint8_t num, void(*handler)(void), uint16_t sel,
uint8_t flags)
{
idt[num].base_lo = (uintptr_t)handler >> 0 & 0xFFFF;
idt[num].base_hi = (uintptr_t)handler >> 16 & 0xffff;
idt[num].always0 = 0;
idt[num].sel = sel;
idt[num].flags = flags;
}
IRQ::IRQ(){};
IRQ::~IRQ(){};
/* Normally, IRQs 0 to 7 are mapped to entries 8 to 15. This
* is a problem in protected mode, because IDT entry 8 is a
* Double Fault! Without remapping, every time IRQ0 fires,
* you get a Double Fault Exception, which is NOT actually
* what's happening. We send commands to the Programmable
* Interrupt Controller (PICs - also called the 8259's) in
* order to make IRQ0 to 15 be remapped to IDT entries 32 to
* 47 */
void IRQ::irq_remap()
{
// ICW1 - begin initialization
p8b_irq.out(0x11,PIC_MASTER_CONTROL);
p8b_irq.out(0x11,PIC_SLAVE_CONTROL);
// Remap interrupts beyond 0x20 because the first 32 are cpu exceptions
p8b_irq.out(0x20,PIC_MASTER_MASK);
p8b_irq.out(0x27,PIC_SLAVE_MASK);
// ICW3 - setup cascading
p8b_irq.out(0x04,PIC_MASTER_MASK);
p8b_irq.out(0x02,PIC_SLAVE_MASK);
// ICW4 - environment info
p8b_irq.out(0x01,PIC_MASTER_MASK);
p8b_irq.out(0x01,PIC_SLAVE_MASK);
// mask interrupts
p8b_irq.out(0x00,PIC_MASTER_MASK);
p8b_irq.out(0x00,PIC_SLAVE_MASK);
}
void install_handler_irq(int irq, regs_func handler)
{
printf(" \n Installer IRQ %d \n ", irq);
irq_routines[irq] = handler;
}
void uninstall_handler_irq(int irq)
{
irq_routines[irq] = 0;
}
/* First remap the interrupt controllers, and then we install
* the appropriate ISRs to the correct entries in the IDT. This
* is just like installing the exception handlers */
void IRQ::install_irqs()
{
this->irq_remap();
idt_set_gate(32, irq0, 0x08, 0x8E);
idt_set_gate(33, irq1, 0x08, 0x8E);
idt_set_gate(34, irq2, 0x08, 0x8E);
idt_set_gate(35, irq3, 0x08, 0x8E);
idt_set_gate(36, irq4, 0x08, 0x8E);
idt_set_gate(37, irq5, 0x08, 0x8E);
idt_set_gate(38, irq6, 0x08, 0x8E);
idt_set_gate(39, irq7, 0x08, 0x8E);
idt_set_gate(40, irq8, 0x08, 0x8E);
idt_set_gate(41, irq9, 0x08, 0x8E);
idt_set_gate(42, irq10, 0x08, 0x8E);
idt_set_gate(43, irq11, 0x08, 0x8E);
idt_set_gate(44, irq12, 0x08, 0x8E);
idt_set_gate(45, irq13, 0x08, 0x8E);
idt_set_gate(46, irq14, 0x08, 0x8E);
idt_set_gate(47, irq15, 0x08, 0x8E);
}
/* Each of the IRQ ISRs point to this function, rather than
* the 'fault_handler' in 'isrs.c'. The IRQ Controllers need
* to be told when you are done servicing them, so you need
* to send them an "End of Interrupt" command (0x20). There
* are two 8259 chips: The first exists at 0x20, the second
* exists at 0xA0. If the second controller (an IRQ from 8 to
* 15) gets an interrupt, you need to acknowledge the
* interrupt at BOTH controllers, otherwise, you only send
* an EOI command to the first controller. If you don't send
* an EOI, you won't raise any more IRQs */
extern "C" void irq_handler(struct regs *r)
{
/* This is a blank function pointer */
regs_func handler;
/* Find out if we have a custom handler to run for this
* IRQ, and then finally, run it */
handler = irq_routines[r->int_no];
if (handler)
{
handler(r);
}
/* If the IDT entry that was invoked was greater than 40
* (meaning IRQ8 - 15), then we need to send an EOI to
* the slave controller */
if (r->int_no >= 8)
{
p8b_irq.out(0x20,0xA0);
}
/* In either case, we need to send an EOI to the master
* interrupt controller too */
p8b_irq.out(0x20, 0x20);
}
as you can see at the bottom, where my irq_handler is, for each irq i tell it to print the irq_number. Well i have set up my PIT So i get a 0 every second, and then since i set up my keyboard i get a 1 every time i press a key. a 4 at beggining because i enable COM1. BUT , when i move my mouse , i dont get a 12 For some reason... My Mouse Driver is just as follows:
mouse.c++:
#include "mouse.h"
typedef void(*regs_func)(struct regs *r);
extern void install_handler_irq(int irq, regs_func handler);
static PORT::Port8Bits p8b_mouse_drv;
void mouse_ps2_handler(struct regs *r)
{
printf("IRQ 12 \n ");
}
void mouse_wait(unsigned char type)
{
unsigned int _time_out=100000;
if(type==0)
{
while(_time_out--) //Data
{
if((p8b_mouse_drv.in(0x64) & 1)==1)
{
return;
}
}
return;
}
else
{
while(_time_out--) //Signal
{
if((p8b_mouse_drv.in(0x64) & 2)==0)
{
return;
}
}
return;
}
}
unsigned char mouse_read()
{
//Get response from mouse
mouse_wait(0);
return p8b_mouse_drv.in(0x60);
}
void mouse_write(unsigned char a_write)
{
//Wait to be able to send a command
mouse_wait(1);
//Tell the mouse we are sending a command
p8b_mouse_drv.out(0xD4,0x64);
//Wait for the final part
mouse_wait(1);
//Finally write
p8b_mouse_drv.out(a_write,0x60);
}
void MOUSE::install_mouse_driver()
{
mouse_wait(1);
p8b_mouse_drv.out(0xA8,0x64);
mouse_wait(1);
p8b_mouse_drv.out(0x20,0x64);
unsigned char status_byte;
mouse_wait(0);
status_byte = (p8b_mouse_drv.in(0x60) | 2);
mouse_wait(1);
p8b_mouse_drv.out(0x60,0x64);
mouse_wait(1);
p8b_mouse_drv.out(status_byte,0x60);
mouse_write(0xF6);
mouse_read();
mouse_write(0xF4);
mouse_read();
install_handler_irq(12, mouse_ps2_handler);
}
kernel.c++:
#include "types.h"
#include "gdt.h"
#include "stdio.h"
#include "serial.h"
#include "mem.h"
#include "idt.h"
#include "timer.h"
#include "isr.h"
#include "kbd.h"
#include "mouse.h"
#include "irq.h"
//Call all class constructor
//for global objects before
//calling the kernel
typedef void (*constructor)();
extern "C" constructor start_ctors;
extern "C" constructor end_ctors;
extern "C" void callConstructors()
{
for(constructor* i = &start_ctors; i != &end_ctors; i++)
(*i)();
}
extern "C" void kernelMain(void* multiboot_structure,uint32_t magicnumber)
{
cls();
gdt gt;
IDT idt;
ISR isr;
IRQ irq;
SerialPort sp;
isr.install_isrs();
irq.install_irqs();
Timer timer;
timer.install_timer();
KBD kbd;
kbd.install_kbd_driver();
MOUSE mouse;
mouse.install_mouse_driver();
__asm__ __volatile__ ("sti");
// int x = 5/0;
while(1);
err:
while(1);
}
If you want to see my whole project you can go to learning repo: https://github.com/amanuel2/OS_Mirror . I want the IRQ12 to fire so i can start working on my mouse driver. Help would be appreciated.
来源:https://stackoverflow.com/questions/38877152/ps-2-mouse-not-firing