diff --git a/Makefile b/Makefile
index d405284..c0153ad 100644
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,7 @@ OBJS = \
 	ide.o\
 	kalloc.o\
 	lapic.o\
+	ioapic.o\
 	main.o\
 	mp.o\
 	picirq.o\
diff --git a/bio.c b/bio.c
index c1a4bd6..602c915 100644
--- a/bio.c
+++ b/bio.c
@@ -43,7 +43,7 @@ bread(uint dev, uint sector)
 
   acquire(&ide_lock);
   c = ide_start_read(dev & 0xff, sector, b->data, 1);
-  // sleep (c, &ide_lock);
+  sleep (c, &ide_lock);
   ide_finish_read(c);
   release(&ide_lock);
 
diff --git a/defs.h b/defs.h
index c6c333b..1c28cc0 100644
--- a/defs.h
+++ b/defs.h
@@ -57,8 +57,14 @@ void lapic_timerinit(void);
 void lapic_timerintr(void);
 void lapic_enableintr(void);
 void lapic_disableintr(void);
+void lapic_eoi(void);
 int cpu(void);
 
+// ioapic
+extern uchar ioapic_id;
+void ioapic_init(void);
+void ioapic_enable (int irq, int cpu);
+
 // spinlock.c
 struct spinlock;
 void acquire(struct spinlock*);
diff --git a/ide.c b/ide.c
index 27a76fb..e2235a1 100644
--- a/ide.c
+++ b/ide.c
@@ -45,9 +45,12 @@ ide_wait_ready(int check_error)
 void
 ide_init(void)
 {
-  cprintf("ide_init: enable IRQ 14\n");
-  irq_setmask_8259A(irq_mask_8259A & ~(1<<14));
+  if (ncpu < 2) {
+    panic ("ide_init: disk interrupt is going to the second  cpu\n");
+  }
+  ioapic_enable (14, 1); // 14 is IRQ # for IDE
   ide_wait_ready(0);
+  cprintf ("ide_init:done\n");
 }
 
 void
@@ -57,6 +60,7 @@ ide_intr(void)
   cprintf("%d: ide_intr\n", cpu());
   wakeup(&request[tail]);
   release(&ide_lock);
+  lapic_eoi();
 }
 
 int
diff --git a/ioapic.c b/ioapic.c
new file mode 100644
index 0000000..776f895
--- /dev/null
+++ b/ioapic.c
@@ -0,0 +1,82 @@
+#include "types.h"
+#include "mp.h"
+#include "defs.h"
+#include "x86.h"
+#include "traps.h"
+#include "ioapic.h"
+
+struct ioapic {
+  uint ioregsel;  uint p01; uint p02; uint p03;
+  uint iowin;     uint p11; uint p12; uint p13;
+};
+
+
+#define	IOAPIC_REDTBL_LO(i)	(IOAPIC_REDTBL + (i) * 2)
+#define	IOAPIC_REDTBL_HI(i)	(IOAPIC_REDTBL_LO(i) + 1)
+
+static uint
+ioapic_read(struct ioapic *io, int reg)
+{
+  io->ioregsel = reg;
+  return (io->iowin);
+}
+
+static void
+ioapic_write(struct ioapic *io, int reg, uint val)
+{
+  io->ioregsel = reg;
+  io->iowin = val;
+}
+
+void
+ioapic_init(void)
+{
+  struct ioapic *io;
+  uint l, h;
+  int nintr;
+  uchar id;
+  int i;
+
+  io = (struct ioapic *) IO_APIC_BASE;
+  l = ioapic_read(io, IOAPIC_VER);
+  nintr =  ((l & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1;
+  id = ioapic_read(io, IOAPIC_ID) >> APIC_ID_SHIFT;	
+  if (id != ioapic_id)
+    panic ("ioapic_init: id isn't equal to ioapic_id\n");
+  cprintf ("ioapic VER: 0x%x id %d nintr %d\n", l, id, nintr);
+  for (i = 0; i < nintr; i++) {
+    // active-hi and edge-triggered for ISA interrupts
+    // Assume that pin 0 on the first I/O APIC is an ExtINT pin.
+    // Assume that pins 1-15 are ISA interrupts and that all
+    l = ioapic_read(io, IOAPIC_REDTBL_LO(i));
+    l = l & ~IOART_INTMASK;  // allow INTs
+    l |= IOART_INTMSET;
+    l = l & ~IOART_INTPOL;   // active hi
+    l = l & ~IOART_TRGRMOD;  // edgee triggered
+    l = l & ~IOART_DELMOD;   // fixed
+    l = l & ~IOART_DESTMOD;  // physical mode
+    l = l | (IRQ_OFFSET + i); // vector
+    ioapic_write(io, IOAPIC_REDTBL_LO(i), l);
+    h = ioapic_read(io, IOAPIC_REDTBL_HI(i));
+    h &= ~IOART_DEST;
+    ioapic_write(io, IOAPIC_REDTBL_HI(i), h);
+    //    cprintf("intr %d: lo 0x%x hi 0x%x\n", i, l, h);
+  }
+}
+
+void
+ioapic_enable (int irq, int cpu)
+{
+  uint l, h;
+  struct ioapic *io;
+
+  io = (struct ioapic *) IO_APIC_BASE;
+  l = ioapic_read(io, IOAPIC_REDTBL_LO(irq));
+  l = l & ~IOART_INTMASK;  // allow INTs
+  ioapic_write(io, IOAPIC_REDTBL_LO(irq), l);
+  h = ioapic_read(io, IOAPIC_REDTBL_HI(irq));
+  h &= ~IOART_DEST;
+  h |= (cpu << APIC_ID_SHIFT);  // for fun, disk interrupts to cpu 1
+  ioapic_write(io, IOAPIC_REDTBL_HI(irq), h);
+  cprintf("intr %d: lo 0x%x hi 0x%x\n", irq, l, h);
+}
diff --git a/ioapic.h b/ioapic.h
new file mode 100644
index 0000000..cd2fd5c
--- /dev/null
+++ b/ioapic.h
@@ -0,0 +1,90 @@
+#define IO_APIC_BASE 0xFEC00000 /* default physical locations of an IO APIC */
+#define IOAPIC_WINDOW  0x10 /* window register offset */
+
+/* constants relating to APIC ID registers */
+#define APIC_ID_MASK		0xff000000
+#define	APIC_ID_SHIFT		24
+#define	APIC_ID_CLUSTER		0xf0
+#define	APIC_ID_CLUSTER_ID	0x0f
+#define	APIC_MAX_CLUSTER	0xe
+#define	APIC_MAX_INTRACLUSTER_ID 3
+#define	APIC_ID_CLUSTER_SHIFT	4
+
+/* fields in VER */
+#define APIC_VER_VERSION	0x000000ff
+#define APIC_VER_MAXLVT		0x00ff0000
+#define MAXLVTSHIFT		16
+
+/* Indexes into IO APIC */
+#define IOAPIC_ID		0x00
+#define IOAPIC_VER		0x01
+#define IOAPIC_ARB		0x02
+#define IOAPIC_REDTBL		0x10
+#define IOAPIC_REDTBL0		IOAPIC_REDTBL
+#define IOAPIC_REDTBL1		(IOAPIC_REDTBL+0x02)
+#define IOAPIC_REDTBL2		(IOAPIC_REDTBL+0x04)
+#define IOAPIC_REDTBL3		(IOAPIC_REDTBL+0x06)
+#define IOAPIC_REDTBL4		(IOAPIC_REDTBL+0x08)
+#define IOAPIC_REDTBL5		(IOAPIC_REDTBL+0x0a)
+#define IOAPIC_REDTBL6		(IOAPIC_REDTBL+0x0c)
+#define IOAPIC_REDTBL7		(IOAPIC_REDTBL+0x0e)
+#define IOAPIC_REDTBL8		(IOAPIC_REDTBL+0x10)
+#define IOAPIC_REDTBL9		(IOAPIC_REDTBL+0x12)
+#define IOAPIC_REDTBL10		(IOAPIC_REDTBL+0x14)
+#define IOAPIC_REDTBL11		(IOAPIC_REDTBL+0x16)
+#define IOAPIC_REDTBL12		(IOAPIC_REDTBL+0x18)
+#define IOAPIC_REDTBL13		(IOAPIC_REDTBL+0x1a)
+#define IOAPIC_REDTBL14		(IOAPIC_REDTBL+0x1c)
+#define IOAPIC_REDTBL15		(IOAPIC_REDTBL+0x1e)
+#define IOAPIC_REDTBL16		(IOAPIC_REDTBL+0x20)
+#define IOAPIC_REDTBL17		(IOAPIC_REDTBL+0x22)
+#define IOAPIC_REDTBL18		(IOAPIC_REDTBL+0x24)
+#define IOAPIC_REDTBL19		(IOAPIC_REDTBL+0x26)
+#define IOAPIC_REDTBL20		(IOAPIC_REDTBL+0x28)
+#define IOAPIC_REDTBL21		(IOAPIC_REDTBL+0x2a)
+#define IOAPIC_REDTBL22		(IOAPIC_REDTBL+0x2c)
+#define IOAPIC_REDTBL23		(IOAPIC_REDTBL+0x2e)
+
+/*
+ * fields in the IO APIC's redirection table entries
+ */
+#define IOART_DEST	APIC_ID_MASK	/* broadcast addr: all APICs */
+
+#define IOART_RESV	0x00fe0000	/* reserved */
+
+#define IOART_INTMASK	0x00010000	/* R/W: INTerrupt mask */
+#define IOART_INTMCLR	0x00000000	/*       clear, allow INTs */
+#define IOART_INTMSET	0x00010000	/*       set, inhibit INTs */
+
+#define IOART_TRGRMOD	0x00008000	/* R/W: trigger mode */
+#define IOART_TRGREDG	0x00000000	/*       edge */
+#define IOART_TRGRLVL	0x00008000	/*       level */
+
+#define IOART_REM_IRR	0x00004000	/* RO: remote IRR */
+
+#define IOART_INTPOL	0x00002000	/* R/W: INT input pin polarity */
+#define IOART_INTAHI	0x00000000	/*      active high */
+#define IOART_INTALO	0x00002000	/*      active low */
+
+#define IOART_DELIVS	0x00001000	/* RO: delivery status */
+
+#define IOART_DESTMOD	0x00000800	/* R/W: destination mode */
+#define IOART_DESTPHY	0x00000000	/*      physical */
+#define IOART_DESTLOG	0x00000800	/*      logical */
+
+#define IOART_DELMOD	0x00000700	/* R/W: delivery mode */
+#define IOART_DELFIXED	0x00000000	/*       fixed */
+#define IOART_DELLOPRI	0x00000100	/*       lowest priority */
+#define IOART_DELSMI	0x00000200	/*       System Management INT */
+#define IOART_DELRSV1	0x00000300	/*       reserved */
+#define IOART_DELNMI	0x00000400	/*       NMI signal */
+#define IOART_DELINIT	0x00000500	/*       INIT signal */
+#define IOART_DELRSV2	0x00000600	/*       reserved */
+#define IOART_DELEXINT	0x00000700	/*       External INTerrupt */
+
+#define IOART_INTVEC	0x000000ff	/* R/W: INTerrupt vector field */
+
+/* fields in VER */
+#define IOART_VER_VERSION	0x000000ff
+#define IOART_VER_MAXREDIR	0x00ff0000
+#define MAXREDIRSHIFT		16
diff --git a/lapic.c b/lapic.c
index 3aeda2f..f299b86 100644
--- a/lapic.c
+++ b/lapic.c
@@ -173,6 +173,12 @@ lapic_disableintr(void)
   lapic_write(LAPIC_TPR, 0xFF);
 }
 
+void
+lapic_eoi(void)
+{
+  lapic_write (LAPIC_EOI, 0);
+}
+
 int
 cpu(void)
 {
diff --git a/main.c b/main.c
index 3db7eab..021fb51 100644
--- a/main.c
+++ b/main.c
@@ -45,6 +45,7 @@ main0(void)
   cprintf("\nxV6\n\n");
 
   pic_init(); // initialize PIC
+  ioapic_init();
   kinit(); // physical memory allocator
   tvinit(); // trap vectors
   idtinit(); // CPU's idt
diff --git a/mp.c b/mp.c
index 4cb5db8..ece46a4 100644
--- a/mp.c
+++ b/mp.c
@@ -29,12 +29,12 @@ static char* buses[] = {
 	0,
 };
 
-#define APBOOTCODE 0x7000 // XXX hack
-
-static struct mp* mp;  // The MP floating point structure
 struct cpu cpus[NCPU];
 int ncpu;
+uchar ioapic_id;
+
 static struct cpu *bcpu;
+static struct mp* mp;  // The MP floating point structure
 
 static struct mp*
 mp_scan(uchar *addr, int len)
@@ -112,7 +112,6 @@ mp_detect(void)
   if(sum || (pcmp->version != 1 && pcmp->version != 4))
     return 3;
 
-  cprintf("Mp spec rev #: %x imcrp 0x%x\n", mp->specrev, mp->imcrp);
   return 0;
 }
 
@@ -124,12 +123,15 @@ mp_init(void)
   struct mpctb *mpctb;
   struct mppe *proc;
   struct mpbe *bus;
+  struct mpioapic *ioapic;
+  struct mpie *intr;
   int i;
+  uchar byte;
 
   ncpu = 0;
   if ((r = mp_detect()) != 0) return;
 
-  cprintf ("This computer is a multiprocessor!\n");
+  cprintf("Mp spec rev #: %x imcrp 0x%x\n", mp->specrev, mp->imcrp);
 
   /*
    * Run through the table saving information needed for starting
@@ -164,11 +166,14 @@ mp_init(void)
       p += sizeof(struct mpbe);
       continue;
     case MPIOAPIC:
-      cprintf("an I/O APIC\n");
+      ioapic = (struct mpioapic *) p;
+      cprintf("an I/O APIC: id %d %x\n", ioapic->apicno, ioapic->flags);
+      ioapic_id = ioapic->apicno;
       p += sizeof(struct mpioapic);
       continue;
     case MPIOINTR:
-      cprintf("an I/O intr\n");
+      intr = (struct mpie *) p;
+      // cprintf("an I/O intr: type %d flags 0x%x bus %d souce bus irq %d dest ioapic id %d dest ioapic intin %d\n", intr->intr, intr->flags, intr->busno, intr->irq, intr->apicno, intr->intin);
       p += sizeof(struct mpie);
       continue;
     default:
@@ -180,10 +185,18 @@ mp_init(void)
       break;
     }
   }
-  
+
+  if (mp->imcrp) {  // it appears that bochs doesn't support IMCR, and code won't run
+    outb(0x22, 0x70);	/* select IMCR */
+    byte = inb(0x23);	/* current contents */
+    byte |= 0x01;	/* mask external INTR */
+    outb(0x23, byte);	/* disconnect 8259s/NMI */
+  }
+
   cprintf("ncpu: %d boot %d\n", ncpu, bcpu-cpus);
 }
 
+
 int
 mp_bcpu(void)
 {
@@ -192,6 +205,8 @@ mp_bcpu(void)
 
 extern void mpmain(void);
 
+#define APBOOTCODE 0x7000 // XXX hack
+
 void
 mp_startthem(void)
 {
diff --git a/picirq.c b/picirq.c
index 9818090..e774e6d 100644
--- a/picirq.c
+++ b/picirq.c
@@ -67,7 +67,6 @@ pic_init(void)
 
   if (irq_mask_8259A != 0xFFFF)
     irq_setmask_8259A(irq_mask_8259A);
-
 }
 
 void
diff --git a/syscall.c b/syscall.c
index 43be534..77a16cd 100644
--- a/syscall.c
+++ b/syscall.c
@@ -415,6 +415,7 @@ sys_block(void)
   struct inode *ip;
 
   for (i = 0; i < 2; i++) {
+    cprintf ("issue read\n");
     b = bread(1, i);
 
     cprintf("disk 1 sector %d: ", i);