Каждый! Я только что закончил писать свой драйвер клавиатуры. Сейчас проблема в том, что мой PSQ / 2 MOQ IRQ не сработает (IRQ 12). Я проверил это с помощью этого кода:
#include "irq.h"
#define PIC_MASTER_CONTROL 0x20
#define PIC_MASTER_MASK 0x21
#define PIC_SLAVE_CONTROL 0xa0
#define PIC_SLAVE_MASK 0xa1typedef 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);
}
как вы можете видеть внизу, где находится мой irq_handler, для каждого irq я говорю ему напечатать irq_number. Ну, я настроил свой PIT, поэтому я получаю 0 каждую секунду, а затем, так как я настраиваю свою клавиатуру, я получаю 1 каждый раз, когда я нажимаю клавишу. 4 в начале, потому что я включаю COM1. НО, когда я двигаю мою мышь, я не получаю 12 по какой-то причине … Мой драйвер мыши выглядит следующим образом:
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);
}
Если вы хотите увидеть весь мой проект, вы можете перейти к обучающему репо: https://github.com/amanuel2/OS_Mirror . Я хочу, чтобы IRQ12 сработал, чтобы я мог начать работать с драйвером мыши. Помощь будет оценена.
Задача ещё не решена.
Других решений пока нет …