I think it has to be my interrupts model. I can't think what else would be causing it.
Goes something like...
Code: Select all
open Sys;;
let recv = Array.init 16 (fun _ -> false);;
let waiting = Array.init 16 (fun _ -> []);;
let mask_irq irq = set_signal irq Signal_default;;
let irq_handler irq =
mask_irq irq;
if waiting.(irq) = [] then (
recv.(irq) <- true
) else (
List.iter (fun t -> Thread.wakeup t) waiting.(irq);
);
waiting.(irq) <- [];;
let unmask_irq irq = set_signal irq (Signal_handle irq_handler);;
(* blocks the calling thread *)
let wait irq =
unmask_irq irq;
if recv.(irq) then begin
recv.(irq) <- false;
end else begin
waiting.(irq) <- Thread.self () :: waiting.(irq);
Thread.sleep ()
end;;
IE: The requested IRQ is unmasked when we want to wait for it to be triggered, and masked again when it's been processed. After it's been processed, is an EOI sent to the PIC (not after the interrupt has fired).
Here are some snippets from my signal handling functions...
Code: Select all
void irq_handler(unsigned int irq) {
if ( sigactions[irq] ) {
sigactions[irq](irq);
} else {
/* send EOI for unhandled interrupt */
if(irq < 16) {
if(irq > 7)
out8(0xa0,0x20);
out8(0x20,0x20);
}
}
}
CAMLprim value caml_install_signal_handler(value signal_number, value action)
{
CAMLparam2 (signal_number, action);
void (*act)(int signo), (*oldact)(int signo);
interrupt_handler handler;
CAMLlocal1 (res);
switch(action) {
case Val_int(0): /* Signal_default */
act = 0;
break;
default: /* Signal_handle */
act = handle_signal;
break;
}
oldact = sigactions[Int_val(signal_number)];
sigactions[Int_val(signal_number)] = act;
if (oldact == handle_signal) {
res = caml_alloc_small (1, 0); /* Signal_handle */
Field(res, 0) = Field(caml_signal_handlers, Int_val(signal_number));
}
else
res = Val_int(0); /* Signal_default */
if (Is_block(action)) {
if (caml_signal_handlers == 0) {
caml_signal_handlers = caml_alloc(16, 0);
caml_register_global_root(&caml_signal_handlers);
}
caml_modify(&Field(caml_signal_handlers, Int_val(signal_number)), Field(action, 0));
/* tell PIC that we want to handle signal_number */
switch (Int_val(signal_number)) {
case 0: handler = irq_0; break;
case 1: handler = irq_1; break;
case 2: handler = irq_2; break;
case 3: handler = irq_3; break;
case 4: handler = irq_4; break;
case 5: handler = irq_5; break;
case 6: handler = irq_6; break;
case 7: handler = irq_7; break;
case 8: handler = irq_8; break;
case 9: handler = irq_9; break;
case 10: handler = irq_10; break;
case 11: handler = irq_11; break;
case 12: handler = irq_12; break;
case 13: handler = irq_13; break;
case 14: handler = irq_14; break;
case 15: handler = irq_15; break;
}
set_irq(Int_val(signal_number), handler, INT_GATE|BITS_32|PRESENT|RING_0); /* unmasks automatically */
} else {
/* tell PIC we're not handling this anymore */
unset_irq(Int_val(signal_number)); /* only masks it, handler is still present */
}
caml_process_pending_signals();
CAMLreturn (res);
}
static void handle_signal(int signal_number)
{
if (caml_try_leave_blocking_section_hook()) {
caml_execute_signal(signal_number, 1);
caml_enter_blocking_section_hook();
}else{
caml_record_signal(signal_number);
}
}
void caml_execute_signal(int signal_number, int in_signal_handler)
{
value res;
res = caml_callback_exn(
Field(caml_signal_handlers, signal_number),
Val_int(signal_number));
/* do I need to add this? I think so... */
caml_pending_signals[signal_number] = 0;
/* send EOI .. ocaml function has handled it */
if(signal_number < 16) {
if(signal_number > 7)
out8(0xa0,0x20);
out8(0x20,0x20);
}
if (Is_exception_result(res)) caml_raise(Extract_exception(res));
}
The last function is either called immediately, or for each pending signal at a check for signals in the VM.
Is my approach to handling interrupts wrong/bad? It's worked on real hardware for a network driver, and also keyboard input. And it's worked for everything on virtual machines... though they're not really that representative of actual hardware.
Jonathan
--
On second thought, it can't be interrupts. I turned off mouse interrupt mode, and still I get no packet data from the mouse. It's like it's never ready to send any data to the host...